【问题标题】:Jackson, serialize one attribute of a referenceJackson,序列化引用的一个属性
【发布时间】:2013-10-07 17:21:49
【问题描述】:

当序列化一个有其他对象引用的Java对象时,我只需要序列化嵌套对象的一个​​属性(通常是外键,所以序列化对象引用的“id”属性)。英戈尔其他一切。

例如,我有两个类需要序列化为 JSON 和 XML(为了清楚起见,删除了 JPA 注释):

关系:用户->(一对多)地址信息; 另外:AddressInformation ->(一对一)用户

@XmlRootElement
public class User {
    private String id;
    private String firstName;
    private String lastName;
    private String email;
    private AddressInformation defaultAddress;
    private Set<AddressInformation> addressInformation;

    public User() {
    }

    @JsonProperty(value = "id")
    @XmlAttribute(name = "id")
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @JsonProperty(value = "firstname")
    @XmlAttribute(name = "firstname")
    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    @JsonProperty(value = "lastname")
    @XmlAttribute(name = "lastname")
    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    @JsonProperty(value = "email")
    @XmlAttribute(name = "email")
    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @JsonIgnore
    public Set<AddressInformation> getAddressInformation() {
        return addressInformation;
    }

    public void setAddressInformation(Set<AddressInformation> addressInformation) {
        this.addressInformation = addressInformation;
    }

    @JsonProperty(value = "defaultaddress")
    @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
    public AddressInformation getDefaultAddress() {
        return defaultAddress;
    }

    public void setDefaultAddress(AddressInformation defaultAddress) {
        this.defaultAddress = defaultAddress;
    }
}

地址信息:

@XmlRootElement
public class AddressInformation  {
    private String id;
    private String address;
    private String details;
    private User user;

    @JsonProperty(value = "id")
    @XmlAttribute(name = "id")
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @JsonProperty(value = "details")
    @XmlAttribute(name = "details")
    public String getDetails() {
        return details;
    }

    public void setDetails(String details) {
        this.details = details;
    }

    @JsonProperty(value = "address")
    @XmlAttribute(name = "address")
    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public AddressInformation() {
        super();
    }
}
enter code here

例如在序列化用户时,我需要:

{
  "id" : "idofuser01",
  "email" : "some.email@gmail.com",
  "status" : "OK",
  "firstname" : "Filan",
  "lastname" : "Ovni",
  "defaultaddressid" : "idofaddress01",
}
enter code here

序列化地址信息时:

{
  "id" : "idofaddress01",
  "address" : "R.8. adn",
  "details" : "blah blah",
  "userid" : "idofuser01",
}

我试过@JsonManageReference & @JsonBackReference 没有成功。如您所见,我也尝试过@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")

【问题讨论】:

    标签: java json spring serialization jackson


    【解决方案1】:

    刚刚找到了使用 Jackson 2.1+ 的方法。

    用注释对象引用(这将只选择AddressInformationid 属性):

    @JsonProperty(value = "defaultaddressid")
    @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
    @JsonIdentityReference(alwaysAsId = true) 
    public AddressInformation getDefaultAddress() {
        return defaultAddress;
    }
    

    序列化效果很好。

    【讨论】:

    • 这行得通,但我不明白它在做什么。能详细点吗?
    • 是的,任何人都可以详细说明为什么上述方法有效吗?谢谢。
    • 我通常将@JsonIdentityInfo 放在类级别,将@JsonIdentityReference 放在属性级别(引用其他类的那个)。 @JsonIdentityInfo 在序列化时避免无限递归(如 User1->Address1->User1->Address1 ->...)写入引用实体的“id”字段,而不是尝试序列化完整的 POJO。但主要行为是完全序列化第一次出现的 POJO,进一步的引用只写 'id'。 @JsonIdentityReference 将行为重新配置为始终写入引用的 id,而不是序列化完整的 POJO;所以:地址1->“约翰”。
    【解决方案2】:

    您可以为此类实现自定义反序列化器并在User 类中使用它。示例实现:

    class AddressInformationIdJsonSerializer extends JsonSerializer<AddressInformation> {
        @Override
        public void serialize(AddressInformation value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
            jgen.writeString(value.getId());
        }
    }
    

    以及User类中的配置:

    @JsonProperty(value = "defaultaddress")
    @JsonSerialize(using = AddressInformationIdJsonSerializer.class)
    public AddressInformation getDefaultAddress() {
        return defaultAddress;
    }
    

    ### 实现一个接口的所有类的通用解决方案###
    您可以创建包含String getId() 方法的接口:

    interface Identifiable {
        String getId();
    }
    

    此接口的序列化器可能如下所示:

    class IdentifiableJsonSerializer extends JsonSerializer<Identifiable> {
        @Override
        public void serialize(Identifiable value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
            jgen.writeString(value.getId());
        }
    }
    

    现在,您可以将此序列化程序用于所有 Identifiable 实现。例如:

    @JsonProperty(value = "defaultaddress")
    @JsonSerialize(using = IdentifiableJsonSerializer.class)
    public AddressInformation getDefaultAddress() {
        return defaultAddress;
    }
    

    当然:AddressInformation 必须实现这个接口:

    class AddressInformation implements Identifiable {
        ....
    }
    

    【讨论】:

    • 谢谢。是否可以编写这样的通用序列化程序(不使用反射)以在我需要该功能的地方使用?
    • 您想对所有具有“私有字符串 id”属性的 POJO 类使用此序列化程序,是吗?你能确认一下吗?
    • 我解决了这个问题,但是是的,有一个适用于所有 POJO 的通用序列化程序会很有趣。
    • 是的,我看到了您的解决方案 - 不错。请在编辑后查看我的答案。也许你将来会用它来解决类似的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-19
    • 1970-01-01
    • 2018-10-31
    • 1970-01-01
    • 1970-01-01
    • 2013-04-09
    • 1970-01-01
    相关资源
    最近更新 更多