用Jackson自定義JSON反序列化

2016-01-01    分類:JAVA開發、程式設計開發、首頁精華1人評論發表於2016-01-01

本文由碼農網 – 小峰原創翻譯,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃

我們將REST API編碼成JSON格式,然後將它解碼到POJO。Jackson的org.codehaus.jackson.map.ObjectMapper“只能”開箱即用,並且在大多數情況下我們並不能做任何其他事情。但有時我們確實需要一個定製的反序列化器以滿足我們的定製需求,所以本教程將指導大家如何建立自定義的反序列化。

比方說,我們有以下實體:

public class User {
private Long id;
private String name;
private String email;
public Long getId() {
return id;
}
public User setId(Long id) {
this.id = id;
return this;
}
public String getName() {
return name;
}
public User setName(String name) {
this.name = name;
return this;
}
public String getEmail() {
return email;
}
public User setEmail(String email) {
this.email = email;
return this;
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("User{");
sb.append("id=").append(id);
sb.append(", name='").append(name).append('\'');
sb.append(", email='").append(email).append('\'');
sb.append('}');
return sb.toString();
}
}
public class Program {
private Long id;
private String name;
private User createdBy;
private String contents;
  public Program(Long id, String name, String contents, User createdBy) {
    this.id = id;
    this.name = name;
    this.contents = contents;
    this.createdBy = createdBy;
  }
public Program() {}
public Long getId() {
return id;
}
  public Program setId(Long id) {
    this.id = id;
    return this;
  }
  public String getName() {
  return name;
  }
  public Program setName(String name) {
    this.name = name;
    return this;
  }
  public User getCreatedBy() {
  return createdBy;
  }
  public Program setCreatedBy(User createdBy) {
    this.createdBy = createdBy;
    return this;
  }
  public String getContents() {
  return contents;
  }
  public Program setContents(String contents) {
  this.contents = contents;
  return this;
  }
  @Override
  public String toString() {
    final StringBuffer sb = new StringBuffer("Program{");
    sb.append("id=").append(id);
    sb.append(", name='").append(name).append('\'');
    sb.append(", createdBy=").append(createdBy);
    sb.append(", contents='").append(contents).append('\'');
    sb.append('}');
    return sb.toString();
  }
}

讓我們序列化/排列第一個物件:

User user = new User();
user.setId(1L);
user.setEmail("example@example.com");
user.setName("Bazlur Rahman");
Program program = new Program();
program.setId(1L);
program.setName("Program @# 1");
program.setCreatedBy(user);
program.setContents("Some contents");
ObjectMapper objectMapper = new ObjectMapper();
final String json = objectMapper.writeValueAsString(program);
System.out.println(json);

以上程式碼會產生以下JSON:

{
"id": 1,
"name": "Program @# 1",
"createdBy": {
"id": 1,
"name": "Bazlur Rahman",
"email": "example@example.com"
},
"contents": "Some contents"
}

這樣做反方向的事情就很容易了。如果我們有這個JSON,那麼就可以使用如下的ObjectMapper反序列化到程式物件:

String jsonString = "{\"id\":1,\"name\":\"Program @# 1\",\"createdBy\":{\"id\":1,\"name\":\"Bazlur Rahman\",\"email\":\"example@example.com\"},\"contents\":\"Some contents\"}";
final Program program1 = objectMapper.readValue(jsonString, Program.class);
 System.out.println(program1);

現在,假設,這不是真正的情況,我們需要有一個來自於API的不同的JSON,而且這個API不匹配我們的程式類:

{
"id": 1,
"name": "Program @# 1",
"ownerId": 1
"contents": "Some contents"
}

從這個JSON字串中,你可以看到,它有owenerId這個不同的欄位。

現在如果你想像先前我們做的那樣序列化此JSON,那麼就會出現異常。

有兩種方法可以避免異常和這樣的序列化:忽略未知欄位,或編寫自定義的反序列化器。

忽略未知欄位

忽略`onwerId`。新增以下注釋到程式類中

@JsonIgnoreProperties(ignoreUnknown = true)
public class Program {}

編寫自定義的反序列化器

但是有些時候,你確實需要`owerId`這個欄位。比方說,你需要涉及使用者類的ID。

在這種情況下,你需要編寫自定義的解串器:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import java.io.IOException;
public class ProgramDeserializer extends JsonDeserializer<Program> {
  @Override
  public Program deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
    ObjectCodec oc = jp.getCodec();
    JsonNode node = oc.readTree(jp);
    final Long id = node.get("id").asLong();
    final String name = node.get("name").asText();
    final String contents = node.get("contents").asText();
    final long ownerId = node.get("ownerId").asLong();
    User user = new User();
    user.setId(ownerId);
    return new Program(id, name, contents, user);
  }
}

正如你所看到的,首先你得從JonsParser訪問JsonNode。然後使用get方法,你就可以很容易地提取來自於JsonNode的資訊。你必須確保欄位名的正確。如果有拼寫錯誤的話,就會導致異常。

最後,你得註冊ProgramDeserializer到`ObjectMapper`。

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Program.class, new ProgramDeserializer());
mapper.registerModule(module);
String newJsonString = "{\"id\":1,\"name\":\"Program @# 1\",\"ownerId\":1,\"contents\":\"Some contents\"}";
final Program program2 = mapper.readValue(newJsonString, Program.class);

你也可以使用註釋來直接註冊反序列化器:

@JsonDeserialize(using = ProgramDeserializer.<b>class</b>)
public class Program {}

完整的原始碼請見:https://github.com/rokon12/json-deserializer<wbr><wbr><wbr>

譯文連結:http://www.codeceo.com/article/jackson-json-deserialization.html
英文原文:Custom JSON Deserialization with Jackson
翻譯作者:碼農網 – 小峰
轉載必須在正文中標註並保留原文連結、譯文連結和譯者等資訊。]

相關文章