【问题标题】:Jackson to parse complex objects杰克逊解析复杂对象
【发布时间】:2017-07-21 07:22:20
【问题描述】:

我想用杰克逊解析 json 对象。我的对象结构类似于: LiveShow.java:

@JsonIgnoreProperties(ignoreUnknown = true)
public class LiveShow implements Serializable{

    @JsonProperty("showid")
    public String showid;
    @JsonProperty("time")
    public String time;
    @JsonProperty("provider")
    public int provider;
    @JsonProperty("sponser")
    public String sponser;


    @JsonCreator
    public LiveShow(@JsonProperty("showid") String showid, 
            @JsonProperty("time") String time,
            @JsonProperty("provider") int provider,
            @JsonProperty("sponser") String sponser) {
        super();
        this.showid= showid;
        this.time = time;
        this.provider = provider;
        this.sponser = sponser;
    } 

    public String getShowid() {
        return showid;
    }

    public void setTopid(String showid) {
        this.showid = showid;
    }

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }

    public int getProvider() {
        return provider;
    }

    public void setProvider(int provider) {
        this.provider = provider;
    }

    public String getSponser() {
        return sponser;
    }

    public void setSponser(String sponser) {
        this.sponser = sponser;
    }
}

MonthlyShows.java:

@JsonIgnoreProperties(ignoreUnknown = true)
//@JsonInclude(Include.NON_NULL)
public class MonthlyShows implements Serializable{
    @JsonProperty("live_shows")
    public LiveShow[] live_shows;
    @JsonProperty("month")
    public String month;
    @JsonCreator
    public MonthlyShows(@JsonProperty("live_shows") LiveShow[] live_shows, 
            @JsonProperty("month") String month) {
        super();
        setLive_shows(live_shows);
        setMonth(month);
    }

    public LiveShow[] getLive_shows() {
        return live_shows;
    }

    public void setLive_shows(LiveShow[] live_shows) {
        try{
            this.live_shows = new LiveShow[live_shows.length];
            for (int i = 0; i < live_shows.length; i++)
                this.live_shows[i] = live_shows[i];
            }catch(Exception e){

                System.err.println("live_shows is null");
                e.printStackTrace();
            }
    }

    public String getMonth() {
        return month;
    }

    public void setMonth(String month) {
        this.month = month;
    }
}

我如何解析对象:

ObjectMapper mapper = new ObjectMapper();
MonthlyShows showsInApril = mapper.readValue(jsonString, TypeFactory.defaultInstance().constructType(MonthlyShows.class));
System.out.println("month:" + showsInApril.month);
for(LiveShow s : showsInApril.live_shows)
    System.out.println(s.showid+ "\t" + s.time + "\t" + s.provider);

我得到空指针异常,我理解这意味着我无法解析这样的复合/复杂对象。

java.lang.NullPointerException
    at MonthlyShows.setLive_shows(MonthlyShows.java:49)
    at MonthlyShows.<init>(LiveRelevanceJudgments.java:25)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
    at java.lang.reflect.Constructor.newInstance(Unknown Source)
    at com.fasterxml.jackson.databind.introspect.AnnotatedConstructor.call(AnnotatedConstructor.java:114)
    at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromObjectWith(StdValueInstantiator.java:256)
    at com.fasterxml.jackson.databind.deser.impl.PropertyBasedCreator.build(PropertyBasedCreator.java:135)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:444)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1123)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:298)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:133)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3789)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2817)
    at Test.main(Test.java:189)

月份:四月

有没有办法解决这个问题?

编辑:

我正在解析的 json 对象的示例是:

{
    "live_shows":[
        {"showid":"show1","time":"02216629","provider":0,"sponser":"governmental"},
        {"showid":"show2","time":"00050340","provider":2,"sponser":"business"}
    ],
    "month":"April"
}

我修复了 Nico 在下面的 cmets 中指出的属性类型。 + 根据要求提供完整的课程

【问题讨论】:

  • 能否显示您发送的 JSON 以重现此错误?
  • 您将时间的长值作为字符串发送。
  • 请格式化您的代码和 json 格式以获得更好的可读性。最好包含整个 MonthlyShows 类,因为这是抛出 NPE 的地方
  • 这些类中有getter 和setter 吗?如果没有,请在为所有属性编写 getter 和 setter 并通过它们访问变量之后尝试。
  • @Nikhil Sahu 感谢您的建议。我添加了 getter 和 setter 并相应地编辑了问题。不幸的是,问题仍然存在。

标签: java json parsing jackson


【解决方案1】:

您的 json 字符串格式错误。您将 time 声明为 long 类型,但您发送的是 String 值。
只是一个带有数值的小注释,不允许前导零。
例如:“时间”:02216629 是错误的。正确值为:22166299

有时我想清楚地看到一个 json。我将创建一个示例对象并打印为 json 值。例如: 你也可以使用 ObjectMapper 来做到这一点。

例如:

ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.valueToTree(monthlyShows);

然后得到一个经过验证的json

{"live_shows":[{"showid":"s101","time":1500624568893,"provider":1,"sponser":"ABC sponser"}],"month":"July"}

【讨论】:

  • 正如 Nico 上面指出的,我修改了 LiveShow.java 类本身,并将时间从 long 更改为 String,因为这个 json 对象是从端点 API 检索的。谢谢。你能告诉我如何在我的上下文中使用 jsonNode 吗?
  • 哦,很简单。只需创建一个 MonthlyShows 对象并将对象转换为 JsonNode 作为我上面的代码,然后使用 System.out 或 logger 打印为字符串。
  • 感谢@PhongTn 的解释。由于某种原因,它不起作用,我仍然收到上面报告的空指针异常
  • 嗯。只需使用您的代码编写一个示例,一切似乎都很好。存储库位于GitHub 您如何获得“jsonString”?您的输入来自文件还是流?我认为可能是“jsonString”在从输入解析后格式不正确。
  • 嗯,你在检查我的样品吗?刚刚更新了从文件中读取的方法,一切正常。您可以查看GitHub。我通常从事 RESTful 项目处理来自 HTTP 请求的 JSON 数据。因此,如果您愿意,我可以编写一个带有 HTTP 端点的示例。另外,你能上传你的项目吗?
【解决方案2】:

您可以使用@JsonInclude(Include.NON_NULL) 来避免空属性的反序列化:

@JsonInclude(Include.NON_NULL)
public class MonthlyShows {

  @JsonProperty("live_shows")
  public LiveShow[] live_shows;
  ...
}

并以这种方式更改您的 MonthlyShows 构造函数:

@JsonCreator
public MonthlyShows(@JsonProperty("live_shows") LiveShow[] live_shows, 
@JsonProperty("month") String month) {
  super();
  this.live_shows = live_shows;
  this.month = month;
}

这里是完整的代码示例:

public class DeserializationTests {

private ObjectMapper mapper;

@Before
public void setUp() {
mapper = new ObjectMapper();
}

@Test
public void deserializeFullMonthlyShows() throws Exception {
String jsonString = "{\"live_shows\":[{\"showid\":\"showid1\",\"time\":14000000000,\"provider\":1,\"sponser\":\"sponser1\"},{\"showid\":\"showid2\",\"time\":15000000000,\"provider\":2,\"sponser\":\"sponser2\"}],\"month\": \"April\"}";
MonthlyShows showsInApril = mapper.readValue(jsonString, MonthlyShows.class);
printOutMonthlyShows(showsInApril);
}

@Test
public void deserializeEmptyMonthlyShows() throws Exception {
String jsonString = "{\"live_shows\":[],\"month\": \"April\"}";
MonthlyShows showsInApril = mapper.readValue(jsonString, MonthlyShows.class);
printOutMonthlyShows(showsInApril);
}

@Test
public void deserializeNoShows() throws Exception {
String jsonString = "{\"month\": \"April\"}";
MonthlyShows showsInApril = mapper.readValue(jsonString, MonthlyShows.class);
System.out.println("month:" + showsInApril.month);
Assert.assertNull(showsInApril.live_shows);
}

@Test
public void deserializeWrongMonthlyShows() throws Exception {
String jsonString = "{\"live_shows\":[{\"showid\":\"showid1\",\"time\":\"14000000000\",\"provider\":1,\"sponser\":\"sponser1\"},{\"showid\":\"showid2\",\"time\":\"15000000000\",\"provider\":2,\"sponser\":\"sponser2\"}],\"month\": \"April\"}";
MonthlyShows showsInApril = mapper.readValue(jsonString, MonthlyShows.class);
printOutMonthlyShows(showsInApril);
}

@Test
public void deserializeTheJsonYouProvide() throws Exception {
ObjectMapper mapper = new ObjectMapper();
String jsonString = "{\"live_shows\":[{\"showid\":\"show1\",\"time\":\"02216629\",\"provider\":0,\"sponser\":\"governmental\"},{\"showid\":\"show2\",\"time\":\"00050340\",\"provider\":2,\"sponser\":\"business\"}],\"month\":\"April\"}";
MonthlyShows showsInApril = mapper.readValue(jsonString, MonthlyShows.class);
printOutMonthlyShows(showsInApril);
}

private void printOutMonthlyShows(MonthlyShows showsInApril) {
System.out.println("month:" + showsInApril.month);
for (LiveShow s : showsInApril.live_shows)
    System.out.println(s.showid + "\t" + s.time + "\t" + s.provider);
}
}

这是我的 pom.xml 的 sn-p:

...
<properties>
    <jackson.version>2.8.6</jackson.version>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.fasterxml.jackson</groupId>
            <artifactId>jackson-bom</artifactId>
            <version>${jackson.version}</version>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.jaxrs</groupId>
        <artifactId>jackson-jaxrs-json-provider</artifactId>
        <version>${jackson.version}</version>
    </dependency>
</dependencies>
...

【讨论】:

  • 这在 live_shows 数组为空时非常有用,但我正在解析的不是空数组。感谢您提供示例代码。但是,我的问题是:数组包含 Liveshow 对象,我得到空指针异常!
  • 我在我的项目中使用了您的测试示例,但仍然出现错误。你真的试过吗?这会很奇怪。
  • 您使用的是什么版本的 Jackson?
  • @sareem 2.8.6。我用我的 pom 的 sn-p 更新我的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-25
  • 2019-07-27
  • 2014-08-22
相关资源
最近更新 更多