关于Java:JSON的Jackson :未被识别的字段,未标记为可忽略的

Jackson with JSON: Unrecognized field, not marked as ignorable

我需要把某个JSON字符串转换成Java对象。我正在使用Jackson处理JSON。我无法控制输入JSON(我从Web服务读取)。这是我的输入json:

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

下面是一个简化的用例:

1
2
3
4
5
6
7
8
9
10
11
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);
}

我的实体类是:

1
2
3
4
5
public Class Student {
    private String name;
    private String id;
    //getters & setters for name & id here
}

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

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

我一直收到这个错误,"wrapper"返回null。我不知道遗漏了什么。有人能帮忙吗?

1
2
3
4
5
6
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)


您可以使用杰克逊的类级注释:

1
2
3
4
import com.fasterxml.jackson.annotation.JsonIgnoreProperties

@JsonIgnoreProperties
class { ...&nbsp;}

它将忽略您在POJO中没有定义的所有属性。当您只是在JSON中查找一些属性,并且不想编写整个映射时非常有用。更多信息请访问杰克逊的网站。如果要忽略任何未声明的属性,则应编写:

1
@JsonIgnoreProperties(ignoreUnknown = true)


你可以使用

1
2
ObjectMapper objectMapper = getObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

它将忽略所有未声明的属性。


第一个答案几乎是正确的,但是需要的是更改getter方法,而不是字段--字段是私有的(并且不是自动检测的);此外,如果两个字段都可见,getter比字段具有优先权。(也有方法使私有字段可见,但是如果您想要getter,则没有太多意义)

因此getter应该命名为getWrapper(),或者加上注释:

1
@JsonProperty("wrapper")

如果您喜欢getter方法名。


使用Jackson 2.6.0,这对我很有用:

1
2
3
private static final ObjectMapper objectMapper =
    new ObjectMapper()
        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

以及设置:

1
@JsonIgnoreProperties(ignoreUnknown = true)


它可以通过两种方式实现:

  • 标记POJO以忽略未知属性

    1
    @JsonIgnoreProperties(ignoreUnknown = true)
  • 配置用于序列化/反序列化pojo/json的objectmapper,如下所示:

    1
    2
    3
    4
    5
    ObjectMapper mapper =new ObjectMapper();            
    // for Jackson version 1.X        
    mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    // for Jackson version 2.X
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

  • 这对我来说非常有效

    1
    2
    3
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.configure(
        DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);

    @JsonIgnoreProperties(ignoreUnknown = true)注释没有。


    这比所有方法都好。请参考此属性。

    1
    2
    3
    4
    5
    6
    import com.fasterxml.jackson.databind.DeserializationFeature;
    import com.fasterxml.jackson.databind.ObjectMapper;

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        projectVO = objectMapper.readValue(yourjsonstring, Test.class);


    如果你用的是杰克逊2.0

    1
    2
    ObjectMapper mapper = new ObjectMapper();
    mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);


    根据文档,您可以忽略所选字段或所有Uknown字段:

    1
    2
    3
    4
    5
    6
     // to prevent specified fields from being serialized or deserialized
     // (i.e. not include in JSON output; or being set even if they were included)
     @JsonIgnoreProperties({"internalId","secretKey" })

     // To ignore any unknown properties in JSON input without exception:
     @JsonIgnoreProperties(ignoreUnknown=true)


    它适用于我,代码如下:

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

    杰克逊抱怨说,因为它在类包装器中找不到名为"包装器"的字段。这样做是因为JSON对象有一个名为"wrapper"的属性。

    我认为解决方法是将包装类的字段重命名为"wrapper",而不是"students"。


    我已经尝试了下面的方法,它适用于与Jackson一起读取这种JSON格式。使用已经建议的解决方案:用@JsonProperty("wrapper")注释getter

    你的包装类

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

    包装类的建议

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    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")
    }

    但是,这将为您提供以下格式的输出:

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

    有关更多信息,请参阅https://github.com/fasterxml/jackson-annotations

    希望这有帮助


    此解决方案在读取JSON流时是通用的,只需要获取一些字段,而域类中未正确映射的字段可以忽略:

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

    一个详细的解决方案是使用一个工具,比如jsonschema2pojo,从json响应的模式中自动生成所需的域类,比如student。您可以通过任何在线JSON-to-Schema转换器实现后者。


    因为JSON属性和Java属性的名称不匹配,所以注释以下字段的学生

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


    正如没人提到的,我以为我会…

    问题是JSON中的属性称为"wrapper",wrapper.class中的属性称为"students"。

    所以要么…

  • 更正类或JSON中属性的名称。
  • 根据statxman的注释注释属性变量。
  • 注释setter(如果有)

  • 要么改变

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

    1
    2
    3
    4
    public Class Wrapper {
        private List<Student> wrapper;
        //getters & setters here
    }

    ----或者----

    将JSON字符串更改为

    1
    {"students":[{"id":"13","name":"Fred"}]}

    你的输入

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

    指示它是一个对象,具有名为"wrapper"的字段,该字段是学生的集合。所以我的建议是,

    1
    Wrapper = mapper.readValue(jsonStr , Wrapper.class);

    其中Wrapper定义为

    1
    2
    3
    class Wrapper {
        List<Student> wrapper;
    }

    我通过简单地更改pojo类的setter和getter方法的签名来解决这个问题。我所要做的就是更改getObject方法以匹配映射器正在查找的内容。在我的例子中,我最初有一个getImageURL,但是JSON数据有一个image_URL,它正在抛出映射器。我将setter和getter都改为getimage_url和setimage_url。

    希望这有帮助。


    对我有用的是把财产公之于众。它为我解决了这个问题。


    就我而言,唯一的一行

    @JsonIgnoreProperties(ignoreUnknown = true)

    也没用。

    只要添加

    1
    @JsonInclude(Include.NON_EMPTY)

    杰克逊2.4.0


    这对我很管用

    1
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

    新的FireBase Android引入了一些巨大的变化;在文档副本下面:

    [https://firebase.google.com/support/guides/firebase-android]:

    更新Java模型对象

    与2 .x SDK一样,FielBASE数据库会自动将您传递给EDCOX1×1的Java对象转换成JSON,并可以使用EDCOX1×2将JSON读入Java对象。

    在新SDK中,当将JSON读入具有EDCOX1×2Ω的Java对象时,JSON中的未知属性现在默认被忽略,因此不再需要EDCOX1 OR 4 }。

    为了在将Java对象写入JSON时排除字段/吸附器,注释现在被称为EDCOX1×5,而不是EDCOX1(6)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    BEFORE

    @JsonIgnoreExtraProperties(ignoreUnknown=true)
    public class ChatMessage {
       public String name;
       public String message;
       @JsonIgnore
       public String ignoreThisField;
    }

    dataSnapshot.getValue(ChatMessage.class)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    AFTER

    public class ChatMessage {
       public String name;
       public String message;
       @Exclude
       public String ignoreThisField;
    }

    dataSnapshot.getValue(ChatMessage.class)

    如果JSON中没有Java类中的额外属性,则会在日志文件中看到此警告:

    1
    W/ClassMapper: No setter/field for ignoreThisProperty found on class com.firebase.migrationguide.ChatMessage

    您可以通过在类上放置一个@IgnoreExtraProperties注释来消除此警告。如果希望FireBase数据库的行为与2.x SDK中的行为相同,并且在存在未知属性时引发异常,则可以在类上放置@ThrowOnExtraProperties注释。


    将类字段设置为public而不是private。

    1
    2
    3
    4
    5
    public Class Student {
        public String name;
        public String id;
        //getters & setters for name & id here
    }


    POJO应定义为

    响应类

    1
    2
    3
    4
    public class Response {
        private List<Wrapper> wrappers;
        // getter and setter
    }

    包装类

    1
    2
    3
    4
    5
    public class Wrapper {
        private String id;
        private String name;
        // getters and setters
    }

    和映射器读取值

    1
    Response response = mapper.readValue(jsonStr , Response.class);


    这可能是一个非常晚的响应,但只要将POJO更改为此值,就可以解决问题中提供的JSON字符串(因为输入字符串不在您的控制范围内,如您所说):

    1
    2
    3
    4
    public class Wrapper {
        private List<Student> wrapper;
        //getters & setters here
    }


    其他的可能性,这是一个在application.properties物业spring.jackson.deserialization.fail-on-unknown-properties=false,它不会在你需要的任何其他应用程序的代码的变化。当你认为是稳定的合同,你可以删除该物业或标记的真实。


    谷歌把我带到这里,我惊讶地看到答案…所有的建议都是绕过错误(在开发过程中,它总是在后面咬4折),而不是解决错误,直到这位先生相信这样做而恢复过来!

    1
    objectMapper.readValue(responseBody, TargetClass.class)

    用于将JSON字符串转换为类对象,缺少的是TargetClass应具有公共getter/setters。OP的问题片段中也缺少相同的内容!:)

    通过Lombok,您的课程如下应该可以工作!!

    1
    2
    3
    4
    5
    @Data
    @Builder
    public class TargetClass {
        private String a;
    }

    在我的例子中,它很简单:REST服务JSON对象被更新(添加了一个属性),但是REST客户机JSON对象没有更新。一旦我更新了JSON客户机对象,"无法识别的字段…"异常就消失了。


    JSON字符串未与映射类内联。更改输入字符串

    1
    String jsonStr ="{"students"\:[{"id":"13","name":"Fred"}]}";

    或者更改映射类

    1
    2
    3
    4
    public class Wrapper {
        private List<Student> wrapper;
        //getters & setters here
    }

    您只需将列表字段从"students"更改为"wrapper",JSON文件就会被映射器查找。


    在我的例子中,错误是由于以下原因造成的

    • 最初它工作正常,然后我重命名了一个变量,使代码中的更改导致了这个错误。

    • 然后我也申请了杰克逊的无知财产,但它不起作用。

    • 最后,在重新定义getter和setters方法之后变量名已解决此错误

    所以一定要重新定义getter和setter。


    将包装类更改为

    1
    2
    3
    4
    5
    public Class Wrapper {

              @JsonProperty("wrapper")  // add this line
              private List<Student> students;
    }

    这样做的目的是将students字段识别为json对象的Wrapper键。

    另外,我个人更喜欢使用lombok注释作为getter和setter

    1
    2
    3
    4
    5
    6
    7
    @Getter
    @Setter
    public Class Wrapper {

              @JsonProperty("wrapper")  // add this line
              private List<Student> students;
    }

    由于我没有用lombok和@JsonProperty一起测试上述代码,所以我建议您将以下代码添加到包装类中,并重写lombok的默认getter和setter。

    1
    2
    3
    4
    5
    6
    7
    public List<Student> getWrapper(){
         return students;
    }

    public void setWrapper(List<Student> students){
         this.students = students;
    }

    也可以使用Jackson来反序列化列表。


    您需要验证正在解析的类的所有字段,使其与原始JSONObject中的字段相同。这对我和我的情况都有帮助。

    @JsonIgnoreProperties(ignoreUnknown = true)一点帮助都没有。