【问题标题】:Wrapping Json fields into instance variable of a pojo将 Json 字段包装到 pojo 的实例变量中
【发布时间】:2019-06-19 14:30:57
【问题描述】:

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

我的示例 Person 类如下所示:

public class Person {
   private String name;
   private Address address;

   //many more fields 

   //getters and setters
}

示例 Address 类是:

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反序列化为地址字段也正确映射的Person pojo?

我使用了一个自定义地址反序列化器,正如这里很多帖子中提到的那样。但是,它没有被调用,因为 Json 对象不包含“地址”字段。

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

有没有使用杰克逊解决此类问题的方法? 另外,如果之前有人问过这个问题,那么代表我道歉,因为我已经深入寻找解决方案并且可能还没有看到它。 .

【问题讨论】:

  • 你可以创建这个不包含地址的超类并使用转换器。避免手动锻炼。
  • 是作业还是什么?有一个几乎相同的问题,asked just a few hours ago

标签: java json spring jackson jackson2


【解决方案1】:

@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

【讨论】:

  • 投反对票是我的错。它偶然发生,因为我想赞成它。现在,只要@Michał Ziober 不编辑它,我就不能投票。我收到的消息是“除非编辑此答案,否则您的投票现在已锁定。”我的错。一旦它被编辑,我会改变它
  • 我又添加了一个额外的 URL。你现在可以投票了。谢谢!
【解决方案2】:

我理解您的问题,因此它与所有 Address 字段与 Person 处于同一级别的平面 Json 有关。即使不完全如此,这也可能对您有所帮助。 JsonDeserializer 可以,但您需要将其应用于 Person,因为它是所有字段所在的级别。

像这样:

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;
    }

}

当然,这不是唯一的方法,也可能没有最好的性能,但这只是关于您如何在自定义反序列化器中进行反序列化。如果您的 PersonAddress 对象有 10 个字段,每个使用这应该不是问题。

更新

我认为在您的情况下-基于您的示例数据-Michał Ziober's answer 可能是最好的,但如果您需要比简单展开数据更复杂的处理,您只需要像我介绍的那样以某种方式反序列化 Person 类.

【讨论】:

    【解决方案3】:

    我不认为您在这里真的有反序列化问题,而是一般的 Java 问题:如何确保 address 字段始终包含一个值。您需要做的就是在Person 构造函数中将address 分配一个默认值,或者在Person.getAddress 方法中为address 生成并分配一个默认值。

    【讨论】:

      猜你喜欢
      • 2021-08-22
      • 2021-08-22
      • 2016-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多