我们将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://gith