Java 使用Jackson自定义JSON反序列化

Java 使用Jackson自定义JSON反序列化,java,json,jackson,flickr,Java,Json,Jackson,Flickr,我在用电话。调用该方法时,默认JSON结果为: { “用户”:{ “id”:”21207597@N07", “用户名”:{ “_内容”:“牙买加人” } }, “stat”:“ok” } 我想将此响应解析为Java对象: public类FlickrAccount{ 私有字符串id; 私有字符串用户名; //…getter&setter。。。 } JSON属性的映射应如下所示: class FlickrAccountJsonDeserializer extends JsonDeserializ

我在用电话。调用该方法时,默认JSON结果为:

{
“用户”:{
“id”:”21207597@N07",
“用户名”:{
“_内容”:“牙买加人”
}
},
“stat”:“ok”
}
我想将此响应解析为Java对象:

public类FlickrAccount{
私有字符串id;
私有字符串用户名;
//…getter&setter。。。
}
JSON属性的映射应如下所示:

class FlickrAccountJsonDeserializer extends JsonDeserializer<FlickrAccount> {

    @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;
    }
}
“用户”->“id”==>FlickrAccount.id
“用户”->“用户名”->“\u内容”==>FlickrAccount.username
不幸的是,我无法找到一个好的、优雅的方法来使用注释来实现这一点。到目前为止,我的方法是将JSON字符串读入
Map
并从中获取值

Map value=new ObjectMapper().readValue(response.getStream(),
新类型引用(){
});
@抑制警告(“未选中”)
Map user=(Map)value.get(“用户”);
stringid=(String)user.get(“id”);
@抑制警告(“未选中”)
字符串用户名=(字符串)((映射)user.get(“用户名”).get(“内容”);
FlickrAccount帐户=新的FlickrAccount();
帐户设置id(id);
account.setUsername(用户名);
但我认为,这是有史以来最不优雅的方式。有没有简单的方法,使用注释或自定义反序列化器

这对我来说是很明显的,但当然不行:

public类FlickrAccount{
@JsonProperty(“user.id”)私有字符串id;
@JsonProperty(“user.username.\u content”)私有字符串用户名;
//…接二连三。。。
}

您必须在FlickrAccount中将Username作为一个类,并给它一个_contentfield

因为我不想实现自定义类(
Username
)来映射用户名,所以我采用了一种更加优雅但仍然相当丑陋的方法:

ObjectMapper mapper=new ObjectMapper();
JsonNode=mapper.readTree(in);
JsonNode user=node.get(“用户”);
FlickrAccount帐户=新的FlickrAccount();
account.setId(user.get(“id”).asText());
account.setUsername(user.get(“username”).get(“_content”).astex());
它仍然不像我希望的那样优雅,但至少我摆脱了所有难看的演员。 此解决方案的另一个优点是,我的域类(
FlickrAccount
)没有受到任何Jackson注释的污染

基于此,我决定使用我认为最直接的解决方案。使用带有自定义反序列化程序的
@JsonDeserialize
注释:

@JsonDeserialize(使用=FlickrAccountDeserializer.class)
公共类FlickrAccount{
...
}
但是反序列化程序不使用任何内部类,只使用上面的
JsonNode

类FlickrAccountDeserializer扩展JsonDeserializer{
@凌驾
公共FlickrAccount反序列化(JsonParser jp,反序列化上下文ctxt)抛出
IOException,JsonProcessingException{
FlickrAccount帐户=新的FlickrAccount();
JsonNode=jp.readValueAsTree();
JsonNode user=node.get(“用户”);
account.setId(user.get(“id”).asText());
account.setUsername(user.get(“username”).get(“_content”).astex());
返回帐户;
}
}

您可以为此类编写自定义反序列化程序。它可能是这样的:

class FlickrAccountJsonDeserializer extends JsonDeserializer<FlickrAccount> {

    @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;
    }
}

您还可以使用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);
SimpleModule=newsimpleModule();
module.setDeserializerModifier(新的BeanDeserializerModifier(){
@重写公共JsonDeserializer modifyDeserializer(
反序列化配置、BeanDescription beanDesc、JsonDeserializer反序列化程序){
if(beanDesc.getBeanClass()==YourClass.class){
返回新的YourClassDeserializer(反序列化器);
}
返回反序列化器;
}});
ObjectMapper ObjectMapper=新的ObjectMapper();
objectMapper.registerModule(模块);
readValue(json,类类型);
我是这样做的:

public class FlickrAccount {
  private String id;
  @JsonDeserialize(converter = ContentConverter.class)
  private String username;
  
  private static class ContentConverter extends StdConverter<Map<String, String>, String> {
    @Override
    public String convert(Map<String, String> content) {
      return content.get("_content"));
    }
  }
}
public类FlickrAccount{
私有字符串id;
@JsonDeserialize(converter=ContentConverter.class)
私有字符串用户名;
私有静态类ContentConverter扩展StdConverter{
@凌驾
公共字符串转换(地图内容){
返回内容。获取(“_内容”);
}
}
}

JSON将用户名表示为一个对象,因此当您映射它时,它将映射为一个对象。这并不可怕,你可以在FlickrAccount类中放置一个getUsername方法来返回用户名。_content值,这样在使用中它将是透明的。是的,但不是我想要的或需要的。有一个描述一个特性的程序,它可以满足我的需求,但是它仍然是开放的。谢谢。我在这篇文章中缺少的部分是注释。尽管对象是在模块中注册的类型的子类,但我必须提供@JsonDeserialize注释,而不需要创建内部静态类来建模json模式。