杰克逊处理JSON数据:无法识别的字段,未标记为可忽略

993

我需要将特定的JSON字符串转换为Java对象。我正在使用Jackson来处理JSON。输入JSON不受我的控制(我从Web服务中读取)。这是我的输入JSON:

{"wrapper":[{"id":"13","name":"Fred"}]}

以下是一个简化的使用案例:

private void tryReading() {
    String jsonStr = "{\"wrapper\"\:[{\"id\":\"13\",\"name\":\"Fred\"}]}";
    ObjectMapper mapper = new ObjectMapper();  
    Wrapper wrapper = null;
    try {
        wrapper = mapper.readValue(jsonStr , Wrapper.class);
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println("wrapper = " + wrapper);
}

我的实体类是:

public Class Student { 
    private String name;
    private String id;
    //getters & setters for name & id here
}

我的包装类基本上是一个容器对象,用于获取我的学生列表:

public Class Wrapper {
    private List<Student> students;
    //getters & setters here
}

我一直收到这个错误,而“wrapper”返回null。我不确定缺少了什么。可以有人帮忙吗?

org.codehaus.jackson.map.exc.UnrecognizedPropertyException: 
    Unrecognized field "wrapper" (Class Wrapper), not marked as ignorable
 at [Source: java.io.StringReader@1198891; line: 1, column: 13] 
    (through reference chain: Wrapper["wrapper"])
 at org.codehaus.jackson.map.exc.UnrecognizedPropertyException
    .from(UnrecognizedPropertyException.java:53)

3
我发现这个很有用,可以避免创建一个包装类:Map dummy<String,Student> = myClientResponse.getEntity(new GenericType<Map<String, Student>>(){}); 然后 Student myStudent = dummy.get("wrapper"); - pulkitsinghal
9
JSON应该长这样:String jsonStr = "{"students":[{"id":"13","name":"Fred"}]}"; 如果你期望在REST POST请求中接收封装对象。 - Dmitri Algazin
4
相关(但不同)问题:使用Jackson忽略JSON对象上的新字段 - sleske
6
顺便说一下,大多数回答这个问题的答案实际上回答了一个不同的问题,即类似于我链接的那个问题。 - sleske
8
大多数答案只是帮助掩盖问题,而不是真正解决它 :( - NoobEditor
显示剩余2条评论
51个回答

20

以下代码对我起作用:

ObjectMapper mapper =new ObjectMapper();    
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);

18
我尝试了以下方法,对于使用Jackson读取这样的JSON格式是有效的。请使用已建议的解决方案:在getter上使用注释 @JsonProperty("wrapper")。 您的包装类。
public Class Wrapper{ 
  private List<Student> students;
  //getters & setters here 
} 

我的封装类建议

public Class Wrapper{ 

  private StudentHelper students; 

  //getters & setters here 
  // Annotate getter
  @JsonProperty("wrapper")
  StudentHelper getStudents() {
    return students;
  }  
} 


public class StudentHelper {

  @JsonProperty("Student")
  public List<Student> students; 

  //CTOR, getters and setters
  //NOTE: If students is private annotate getter with the annotation @JsonProperty("Student")
}

但是这会给你一个格式为:

{"wrapper":{"student":[{"id":13,"name":Fred}]}}

此外,更多信息请参阅https://github.com/FasterXML/jackson-annotations


欢迎来到stackoverflow。提示:您可以使用工具栏中的“{}”符号来格式化您的代码片段。 - Leigh

18

Jackson抱怨无法在你的Wrapper类中找到名为“wrapper”的字段。这是因为你的JSON对象有一个名为“wrapper”的属性。

我认为解决方法是将Wrapper类的字段从“students”改名为“wrapper”。


谢谢Jim。我尝试了那个方法,但它并没有解决问题。我在想是否有些注释我漏掉了。 - jshree
1
嗯,如果您在Java中创建等效数据,然后使用Jackson将其写成JSON,会发生什么呢?如果上面的JSON和这个JSON之间有任何差异,那么这就是出错的线索。 - Jim Ferrans
这个答案对我起作用了,使用了问题中的示例。 - sleske

16
如果您想在应用程序中将 @JsonIgnoreProperties 应用于所有类,则最好的方法是覆盖Spring Boot默认的Jackson对象。 在应用程序配置文件中定义一个bean以创建Jackson对象映射器,如下所示。
@Bean
    public ObjectMapper getObjectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return mapper;
    }

现在,你不需要标记每个类,它会忽略所有未知属性。


为什么不创建一个执行相同功能的静态方法呢?创建Bean的意义是什么? - Prasannjeet Singh

14

当读取Json流并且需要仅获取某些字段时,此解决方案是通用的。忽略在你的域类中未映射正确的字段:

import org.codehaus.jackson.annotate.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)

使用类似 jsonschema2pojo 这样的工具生成所需的域类,例如从 json 响应的模式中生成 Student 类。您可以通过任何在线 json 到模式转换器来实现后者。


12

Java 11及更新版本的简单解决方案:

var mapper = new ObjectMapper()
        .registerModule(new JavaTimeModule())
        .disable(FAIL_ON_UNKNOWN_PROPERTIES)
        .disable(WRITE_DATES_AS_TIMESTAMPS)
        .enable(ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT);

忽略属性时,禁用 'FAIL_ON_UNKNOWN_PROPERTIES' 是很重要的。


请注意,在org.codehaus.jackson.map.ObjectMapper中,方法disable还有其他参数;在这里您所提到的是com.fasterxml.jackson.databind.ObjectMapper。 - Sorin-Alexandru Cristescu

11

由于JSON属性和Java属性的名称不匹配,请将“students”字段注释如下:

public Class Wrapper {
    @JsonProperty("wrapper")
    private List<Student> students;
    //getters & setters here
}

11

问题在于你的JSON中的属性名为"wrapper",而Wrapper.class中的属性名为"students"。

所以可以采取以下方式进行解决:

  1. 更正类或JSON中属性的名称。
  2. 根据StaxMan的评论对属性变量进行注释。
  3. 对setter进行注释(如果存在)。

9

在我发了45个帖子并经过10年之后,似乎没有人给出我情况下的正确答案。

@Data //Lombok
public class MyClass {
    private int foo;
    private int bar;

    @JsonIgnore
    public int getFoobar() {
      return foo + bar;
    }
}

在我的情况下,我们有一个名为getFoobar()的方法,但没有foobar属性(因为它是由其他属性计算得出的)。类上的@JsonIgnoreProperties不起作用。解决方法是在该方法上使用@JsonIgnore注解。

你应该在这里提出你遇到的具体问题,然后用你的解决方案回答自己的问题。你所添加的内容并不是原始问题所要求的解决方案。如果你把你的具体问题作为一个问题提出来,你将会帮助更多的人。 - DRaehal
@DRaehal Stackoverflow的主要目的不仅仅是回答单次使用的问题,而是成为未来谷歌搜索者有用问题和答案的存储库。这是Google上的第一个结果,因此有各种各样的答案。 - BlueRaja - Danny Pflughoeft
3
因为这也帮助了我,所以我点了个赞。在尝试使用@JsonIgnoreProperties和添加虚拟成员后,我找到了这个方法,它完全满足了我的需求。谢谢。 - bdetweiler

7
这可能不是与OP相同的问题,但如果有人遇到了我遇到的相同错误,那么这将帮助他们解决问题。当我使用来自不同依赖项的ObjectMapper作为JsonProperty注释时,我也遇到了与OP相同的错误。
以下内容可行:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.annotation.JsonProperty;

无法工作:

import org.codehaus.jackson.map.ObjectMapper; //org.codehaus.jackson:jackson-mapper-asl:1.8.8
import com.fasterxml.jackson.annotation.JsonProperty; //com.fasterxml.jackson.core:jackson-databind:2.2.3

谢谢!import com.fasterxml.jackson.annotation.JsonProperty 对我有用,而不是其他的 :-) - phil
这真是让我崩溃了!谢谢。 - Gaspar
这个!!浪费了1小时的时间来找出问题所在。 - NRJ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接