使用动态根名称反序列化JSON

时间:2019-09-11 03:46:03

标签: java json jackson

我有以下工作代码可以反序列化JSON消息。如您所见,JSON消息的根名称为“ response”,我也相应地对Response类进行了注释以表明这一点。但是,实际上,JSON消息将从其他系统接收,并且根名称可以是“ response”之外的任何名称。如何处理不同的根名称?

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
import com.fasterxml.jackson.annotation.JsonTypeName;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Test {

    public static void main(String... args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        String responseMessage =
                "{" + 
                "  \"response\" : {" + 
                "    \"body\" : {" + 
                "      \"country\" : \"Vietnam\"" + 
                "    }" + 
                "  }" + 
                "}";
        Response response = mapper.readValue(responseMessage, Response.class);
    }

}

class Body {

    private String country;

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

}

@JsonTypeName("response")
@JsonTypeInfo(include = As.WRAPPER_OBJECT, use = Id.NAME)
class Response {

    private Body body;

    public Body getBody() {
        return body;
    }

    public void setBody(Body body) {
        this.body = body;
    }

}

3 个答案:

答案 0 :(得分:0)

简单的答案是将其反序列化为Map<String, Body>。要手动执行此操作,您需要使用以下代码:

mapper.readValue(response, new TypeReference<Map<String, Body>>() {})

请注意,如果您使用的是像Spring这样的框架(通常应该这样),则应该让该框架为您处理序列化。

答案 1 :(得分:0)

您可以通过两种方式解决此问题

将Response,Body类设为静态

    static class Body {

        private String country;

        public String getCountry() {
            return country;
        }

        public void setCountry(String country) {
            this.country = country;
        }

    }

    @JsonTypeName("response")
    @JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME)
    static class Response {

        private Body body;

        public Body getBody() {
            return body;
        }

        public void setBody(Body body) {
            this.body = body;
        }
    }


将响应和身体类别设为公开

  • 创建名为Body.java的新类文件
public class Body {

        private String country;

        public String getCountry() {
            return country;
        }

        public void setCountry(String country) {
            this.country = country;
        }

    }

  • Response.java文件
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeName;

@JsonTypeName("response")
@JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME)
public class Response {

    private Body body;

    public Body getBody() {
        return body;
    }

    public void setBody(Body body) {
        this.body = body;
    }

}

然后调用主方法

    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        String responseMessage =
                "{" +
                        "  \"response\" : {" +
                        "    \"body\" : {" +
                        "      \"country\" : \"Vietnam\"" +
                        "    }" +
                        "  }" +
                        "}";
        Response response = mapper.readValue(responseMessage, Response.class);
        System.out.println(response.getBody().getCountry());
}

问题原因:

  

杰克逊拒绝尝试使用非静态内胆的基本原因   反序列化的类(序列化实际上可以正常工作)是   因为没有通用的方法来实例化此类-那里   不是零参数构造函数,也不是@JsonCreator注释其他   构造函数或工厂方法(或单字符串参数)   构造函数,但我离题了)。杰克逊无法实例化它们。

     

理论上,如果知道   封闭父类实例是。但实际上这两者都是   复杂且不必要的-通常省略“静态”是   可以是偶然的,也可以是偶然的,可以添加来制作东西   工作。

参考:http://www.cowtowncoder.com/blog/archives/2010/08/entry_411.html

答案 2 :(得分:0)

您可以编写自定义反序列化程序,以跳过包装程序或使用@JsonAnySetter注释。参见以下示例:

import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.Map;

public class JsonApp {

  public static void main(String[] args) throws Exception {
    ObjectMapper mapper = new ObjectMapper();
    String responseMessage =
        "{  \"response\" : {"
            + "    \"body\" : {"
            + "      \"country\" : \"Vietnam\""
            + "    }"
            + "  }"
            + "}";
    Response response = mapper.readValue(responseMessage, Response.class);
    System.out.println(response.getBody());
  }
}

class Body {

  private String country;

  // getters, setters, toString
}

class Response {

  private Body body;

  @JsonAnySetter
  public void setAny(String anyPropertyName, Map<String, Body> body) {
    for (Body item : body.values()) {
      this.body = item;
    }
  }

  // getters, setters
}

上面的代码显示:

Body{country='Vietnam'}