使用Jackson自定义JSON反序列化

我正在使用Flickr API 。 调用flickr.test.login方法时,默认的JSON结果为:

 { "user": { "id": "21207597@N07", "username": { "_content": "jamalfanaian" } }, "stat": "ok" } 

我想将此响应解析为Java对象:

 public class FlickrAccount { private String id; private String username; // ... getter & setter ... } 

应该像这样映射JSON属性:

 "user" -> "id" ==> FlickrAccount.id "user" -> "username" -> "_content" ==> FlickrAccount.username 

不幸的是,我无法使用Annotations找到一个漂亮,优雅的方法。 到目前为止,我的方法是将JSON字符串读入Map并从那里获取值。

 Map value = new ObjectMapper().readValue(response.getStream(), new TypeReference<HashMap>() { }); @SuppressWarnings( "unchecked" ) Map user = (Map) value.get("user"); String id = (String) user.get("id"); @SuppressWarnings( "unchecked" ) String username = (String) ((Map) user.get("username")).get("_content"); FlickrAccount account = new FlickrAccount(); account.setId(id); account.setUsername(username); 

但我认为,这是迄今为止最不优雅的方式。 有没有简单的方法,使用注释还是自定义反序列化器?

这对我来说非常明显,但当然它不起作用:

 public class FlickrAccount { @JsonProperty( "user.id" ) private String id; @JsonProperty( "user.username._content" ) private String username; // ... getter and setter ... } 

您可以为此类编写自定义反序列化程序。 它可能看起来像这样:

 class FlickrAccountJsonDeserializer extends JsonDeserializer { @Override public FlickrAccount deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { Root root = jp.readValueAs(Root.class); FlickrAccount account = new FlickrAccount(); if (root != null && root.user != null) { account.setId(root.user.id); if (root.user.username != null) { account.setUsername(root.user.username.content); } } return account; } private static class Root { public User user; public String stat; } private static class User { public String id; public UserName username; } private static class UserName { @JsonProperty("_content") public String content; } } 

之后,您必须为您的类定义序列化程序。 你可以这样做:

 @JsonDeserialize(using = FlickrAccountJsonDeserializer.class) class FlickrAccount { ... } 

由于我不想实现自定义类( Username )只是为了映射用户名,我更优雅一点,但仍然很丑陋的方法:

 ObjectMapper mapper = new ObjectMapper(); JsonNode node = mapper.readTree(in); JsonNode user = node.get("user"); FlickrAccount account = new FlickrAccount(); account.setId(user.get("id").asText()); account.setUsername(user.get("username").get("_content").asText()); 

它仍然没有我希望的那么优雅,但至少我摆脱了所有丑陋的演员。 此解决方案的另一个优点是,我的域类( FlickrAccount )不受任何Jackson注释的污染。

基于@MichałZiober的回答 ,我决定使用 – 在我看来 – 最直接的解决方案。 将@JsonDeserialize注释与自定义反序列化器一起使用:

 @JsonDeserialize( using = FlickrAccountDeserializer.class ) public class FlickrAccount { ... } 

但是反序列化器不使用任何内部类,只是如上所述的JsonNode

 class FlickrAccountDeserializer extends JsonDeserializer { @Override public FlickrAccount deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { FlickrAccount account = new FlickrAccount(); JsonNode node = jp.readValueAsTree(); JsonNode user = node.get("user"); account.setId(user.get("id").asText()); account.setUsername(user.get("username").get("_content").asText()); return account; } } 

您也可以使用SimpleModule。

  SimpleModule module = new SimpleModule(); module.setDeserializerModifier(new BeanDeserializerModifier() { @Override public JsonDeserializer modifyDeserializer( DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer deserializer) { if (beanDesc.getBeanClass() == YourClass.class) { return new YourClassDeserializer(deserializer); } return deserializer; }}); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(module); objectMapper.readValue(json, classType); 

您必须在FlickrAccount中将Username设为一个类,并为其指定一个_content字段

Interesting Posts