代码之家  ›  专栏  ›  技术社区  ›  user2083529

将JSON字段包装为POJO的实例变量

  •  2
  • user2083529  · 技术社区  · 5 年前

    我正在尝试将某些JSON字段映射到类实例变量。

    我的样本 类的外观如下:

    public class Person {
       private String name;
       private Address address;
    
       //many more fields 
    
       //getters and setters
    }
    

    样品 地址 类别为:

    public class Address {
       private String street;
       private String city;
       //many more fields 
    
       // getters and setters
    }
    

    要反序列化到我的Person类的JSON对象不包含“地址”字段。看起来像:

    {
    "name":"Alexander",
    "street":"abc 12",
    "city":"London"
    }
    

    是否有一种方法可以将JSON反序列化到地址字段也正确映射的PersonPojo?

    我已经使用了一个自定义地址反序列化器,如这里许多文章中所提到的。但是,不会调用它,因为JSON对象不包含“地址”字段。

    我通过使用jsonnode手工映射每个字段来解决这个问题,但是在我的实际项目中,这不是一个好的解决方案。

    使用杰克逊有没有解决这个问题的办法? 另外,如果之前有人问过这个问题,那么我会代表我道歉,因为我一直在努力寻找解决方案,可能还没有看到它。.

    3 回复  |  直到 5 年前
        1
  •  2
  •   Michał Ziober    5 年前

    @JsonUnwrapped 为这个问题引入了注释。模型:

    class Person {
        private String name;
    
        @JsonUnwrapped
        private Address address;
    
        // getters, setters, toString
    }
    class Address {
        private String street;
        private String city;
    
        // getters, setters, toString
    }
    

    用途:

    ObjectMapper mapper = new ObjectMapper();
    String json = "{\"name\":\"Alexander\",\"street\":\"abc 12\",\"city\":\"London\"}";
    System.out.println(mapper.readValue(json, Person.class));
    

    印刷品:

    Person{name='Alexander', address=Address{street='abc 12', city='London'}}
    

    有关详细信息,请阅读:

    1. Jackson Annotation Examples
    2. Annotation Type JsonUnwrapped
    3. Jackson JSON - Using @JsonUnwrapped to serialize/deserialize properties as flattening data structure
        2
  •  2
  •   Willis Blackburn    5 年前

    我认为这里并没有一个反序列化问题,而是一个普遍的Java问题:如何确定 address 字段始终包含一个值。你所要做的就是分配 地址 到中的默认值 Person 构造函数,或为生成和分配默认值 地址 Person.getAddress 方法。

        3
  •  0
  •   pirho    5 年前

    我理解你的问题,所以这是关于平面JSON的 Address 与相同级别的字段 Person . 即使不是这样,这也会对你有所帮助。 JsonDeserializer 很好,但你需要把它应用到 因为它是所有字段所在的级别。

    像这样:

    public class CustomDeserializer extends JsonDeserializer<Person> {
    
        // need to use separate ObjectMapper to prevent recursion
        // this om will not be registered with this custom deserializer
        private final ObjectMapper om;
        {
            om = new ObjectMapper();
            // this is needed because flat json contains unknown fields
            // for both types.
            om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        }
    
        @Override
        public Person deserialize(JsonParser parser, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
            // make a string of json tree so not any particular object
            String json = om.readTree(parser).toString();
            // deserialize it as person (ignoring unknown fields)
            Person person = om.readValue(json, Person.class);
            // set address deserializing it from teh same string, same manner
            person.setAddress(om.readValue(json, Address.class));
            return person;
        }
    
    }
    

    当然,这不是唯一的方法,也可能没有最佳的性能,但它只是关于如何在自定义反序列化程序中进行反序列化。如果你 和; 地址 对象有10个字段,每个字段使用该字段都不应该是问题。

    更新

    我认为在您的案例中-基于您的示例数据- Michał Ziober's answer 可能是最好的,但是如果您需要比普通的数据解包更复杂的处理,您只需要反序列化 不知怎么的,就像我所呈现的那样。