You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何利用Jackson注解实现JSON与多Java类的自定义序列化反序列化?

问题背景

原始输入JSON结构:

{"contactPointId": "123","testString": "41277082","address": {"name1": "name1","name2": "name2","street": "street","houseNumber": "123","zipCode": "45567","country": "276","contactPerson": "Bernd","phone1": "1239","phone2": "456"}}

期望序列化后的JSON结构:

{"contactPointId": "123","testString": "41277082","contact": {"name": "Bernd","phone1": "1239","phone2": "456"},"address": {"name1": "name1","name2": "name2","street": "street","houseNumber": "123","zipCode": "45567","country": "276"}}

现有Java类定义如下:

ContactPoint类

public class ContactPoint
{
   private String contactPointId;
   private String testString;
   private Address address;
   private Contact contact;
   public ContactPoint( String contactPointId, String testString, Address address, Contact contact )
   {
      this.contactPointId = contactPointId;
      this.testString = testString;
      this.address = address;
      this.contact = contact;
   }
   public ContactPoint()
   {
   }
   // getter和setter方法
   public String getContactPointId() { return contactPointId; }
   public void setContactPointId(String contactPointId) { this.contactPointId = contactPointId; }
   public String getTestString() { return testString; }
   public void setTestString(String testString) { this.testString = testString; }
   public Address getAddress() { return address; }
   public void setAddress(Address address) { this.address = address; }
   public Contact getContact() { return contact; }
   public void setContact(Contact contact) { this.contact = contact; }
}

Contact类

public class Contact
{
   private String contactPerson;
   private String phone1;
   private String phone2;
   // getter和setter方法
   public String getContactPerson() { return contactPerson; }
   public void setContactPerson(String contactPerson) { this.contactPerson = contactPerson; }
   public String getPhone1() { return phone1; }
   public void setPhone1(String phone1) { this.phone1 = phone1; }
   public String getPhone2() { return phone2; }
   public void setPhone2(String phone2) { this.phone2 = phone2; }
}

Address类

public class Address
{
   private String name1;
   private String name2;
   private String street;
   private String houseNumber;
   private String zipCode;
   private String country;
   // getter和setter方法
   public String getName1() { return name1; }
   public void setName1(String name1) { this.name1 = name1; }
   public String getName2() { return name2; }
   public void setName2(String name2) { this.name2 = name2; }
   public String getStreet() { return street; }
   public void setStreet(String street) { this.street = street; }
   public String getHouseNumber() { return houseNumber; }
   public void setHouseNumber(String houseNumber) { this.houseNumber = houseNumber; }
   public String getZipCode() { return zipCode; }
   public void setZipCode(String zipCode) { this.zipCode = zipCode; }
   public String getCountry() { return country; }
   public void setCountry(String country) { this.country = country; }
}

需求:通过注解告知Jackson的ObjectMapper从原始JSON的address节点中提取contactPerson、phone1、phone2字段初始化Contact对象,同时序列化时输出目标结构,且不修改现有类的核心结构。


解决方案

方法一:构造器结合@JsonProperty提取嵌套字段

Jackson支持在构造器参数上用@JsonProperty指定嵌套JSON路径,反序列化时直接从address节点提取字段构造Contact对象,序列化时保持现有结构输出:

修改ContactPoint的构造器:

public class ContactPoint
{
   private String contactPointId;
   private String testString;
   private Address address;
   private Contact contact;

   @JsonCreator
   public ContactPoint(
           @JsonProperty("contactPointId") String contactPointId,
           @JsonProperty("testString") String testString,
           @JsonProperty("address") Address address,
           @JsonProperty("address.contactPerson") String contactPerson,
           @JsonProperty("address.phone1") String phone1,
           @JsonProperty("address.phone2") String phone2
   ) {
      this.contactPointId = contactPointId;
      this.testString = testString;
      this.address = address;
      // 手动构造Contact对象
      this.contact = new Contact();
      this.contact.setContactPerson(contactPerson);
      this.contact.setPhone1(phone1);
      this.contact.setPhone2(phone2);
   }

   // 保留原无参构造器和getter/setter
   public ContactPoint() {}

   // ... 原有的getter和setter方法不变
}

此方法无需修改Address和Contact类,仅通过构造器注解完成字段提取,序列化自动输出目标格式。

方法二:自定义@JsonSetter处理字段映射

若不想修改构造器,可在ContactPoint的address字段的setter中,手动从Address提取字段构造Contact:

public class ContactPoint
{
   private String contactPointId;
   private String testString;
   private Address address;
   private Contact contact;

   // ... 原有的构造器和getter方法不变

   // 自定义setter,反序列化时从address中提取contact字段
   @JsonSetter
   public void setAddress(Address address) {
      this.address = address;
      // 同时构造Contact对象
      if (address != null) {
         this.contact = new Contact();
         this.contact.setContactPerson(address.getContactPerson());
         this.contact.setPhone1(address.getPhone1());
         this.contact.setPhone2(address.getPhone2());
      }
   }

   // 序列化时隐藏address中的contact相关字段
   @JsonIgnoreProperties({"contactPerson", "phone1", "phone2"})
   public Address getAddress() {
      return address;
   }

   // ... 其他getter/setter不变
}

注意:需给Address临时添加contactPerson、phone1、phone2的字段及getter/setter,仅用于反序列化接收字段,序列化时会被忽略。

方法三:自定义反序列化器

若上述方法不满足需求,可编写自定义反序列化器手动处理解析逻辑:

public class ContactPointDeserializer extends StdDeserializer<ContactPoint> {

   public ContactPointDeserializer() {
      super(ContactPoint.class);
   }

   @Override
   public ContactPoint deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
      JsonNode node = p.getCodec().readTree(p);
      ContactPoint contactPoint = new ContactPoint();
      contactPoint.setContactPointId(node.get("contactPointId").asText());
      contactPoint.setTestString(node.get("testString").asText());

      // 解析Address
      JsonNode addressNode = node.get("address");
      Address address = new Address();
      address.setName1(addressNode.get("name1").asText());
      address.setName2(addressNode.get("name2").asText());
      address.setStreet(addressNode.get("street").asText());
      address.setHouseNumber(addressNode.get("houseNumber").asText());
      address.setZipCode(addressNode.get("zipCode").asText());
      address.setCountry(addressNode.get("country").asText());
      contactPoint.setAddress(address);

      // 从addressNode中解析Contact
      Contact contact = new Contact();
      contact.setContactPerson(addressNode.get("contactPerson").asText());
      contact.setPhone1(addressNode.get("phone1").asText());
      contact.setPhone2(addressNode.get("phone2").asText());
      contactPoint.setContact(contact);

      return contactPoint;
   }
}

在ContactPoint类上指定反序列化器:

@JsonDeserialize(using = ContactPointDeserializer.class)
public class ContactPoint {
   // ... 原有类内容不变
}

此方法完全不修改现有类结构,所有解析逻辑集中在反序列化器中,灵活性最高。


内容的提问来源于stack exchange,提问作者Beanssss

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 17:55:57