当前位置: 首页 > 知识库问答 >
问题:

自定义Jackson序列化具有一对多关系的实体

东方河
2023-03-14

在这个网络项目中,我使用了Hibernate和jersey,这两个元素与Jackson一起使用。对于Hibernate,我有3个实体类,它们反映了数据库表的结构,并且具有“一对多”和“多对一”关系。绑定字段被注释为@OneToMany@ManyToOne。这些类的对象必须用json序列化。为了避免序列化过程中出现错误,绑定字段还被注释为@JsonManagedReference@JsonBackReference。由于Shops类对象的序列化,结果如下:

{
      "id": 2,
      "name": "Shop #2",
      "category": "auto",
      "distance": 120,
      "discounts": [
          {
              "id": 9,
              "title": "-50%",
              "startDate": 1425679200000,
              "endDate": 1425679200000
          }
      ]
 }

它不适合我,我决定编写自定义序列化程序。因此,我希望看到以下json:

{
      "id": 2,
      "name": "Shop #2",
      "category": "auto",
      "distance": 120,
      "locality_id": 10,
}

为此,我为每个实体创建了3个类序列化器,并清理了注释@JsonManaged参考@JsonBack参考,它们在前面并添加了@JsonSerializ关于类序列化器的指示。

由于尝试启动,我收到以下错误:

com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: java.util.ArrayList[0])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:210)
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:189)
at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:216)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:117)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:73)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:19)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:129)
at com.fasterxml.jackson.databind.ObjectWriter._configAndWriteValue(ObjectWriter.java:1052)

我怎样才能纠正这个错误
下面给出了实体类和类序列化程序。

实体类:

地区

@XmlRootElement
@Entity
@JsonSerialize(using = LocalitiesSerializer.class)
@Table(name = "localities")
public class Localities {
    @Id
    @GeneratedValue
    @Column(name="id", unique=true, nullable=false)
    private Integer id;

    @Column(name="name",nullable=false, length=57)
    private String name;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "locality")
    private Set<Shops> shops = new HashSet<Shops>(0);

    //constructors, getters & setters
}

商店

@XmlRootElement
@Entity
@JsonSerialize(using = ShopsSerializer.class)
@Table(name = "shops")
public class Shops {
    @Id
    @GeneratedValue
    @Column(name="id", unique=true, nullable=false)
    protected Integer id;

    @Column(name="name", length=45, nullable=false)
    protected String name;

    @Column(name="category", columnDefinition="ENUM('undefined','auto','children_prod','food','game','book','electronics','beuty_and_health','fashion','footwear','clothing','sports','homewere','pet_prod','services','gift_and_flowers')",
            nullable=false)
    @Enumerated(EnumType.STRING)
    protected Categories category;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "locality_id", nullable = false)
    protected Localities locality;

    @Transient
    private Double distance;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "shop")
    private Set<Discounts> discounts = new HashSet<Discounts>(0);

    //constructors, getters & setters    
}

折扣

@XmlRootElement
@Entity
@JsonSerialize(using = DiscountsSerializer.class)
@Table(name="discounts")
public class Discounts {

    @Id
    @GeneratedValue
    @Column(name="id")
    private Integer id;

    @Column(name="title")
    private String title;

    @Column(name="start_date")
    @Temporal(TemporalType.DATE) 
    private Calendar startDate;

    @Column(name="end_date")
    @Temporal(TemporalType.DATE) 
    private Calendar endDate;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "shop_id", nullable = false)
    private Shops shop;

    //constructors, getters & setters

}

序列化程序:

本地化序列化程序

public class LocalitiesSerializer extends JsonSerializer<Localities> {
    @Override
    public void serialize(Localities locality, JsonGenerator jsonGen,
            SerializerProvider serProv) throws IOException,
            JsonProcessingException {
        jsonGen.writeStartObject();
        jsonGen.writeNumberField("id", locality.getId());
        jsonGen.writeStringField("name", locality.getName());
        jsonGen.writeEndObject();

    }
}

ShopsSerializer

public class ShopsSerializer extends JsonSerializer<Shops> {

    @Override
    public void serialize(Shops shop, JsonGenerator jsonGen,
            SerializerProvider serProv) throws IOException,
            JsonProcessingException {
        jsonGen.writeStartObject();
        jsonGen.writeNumberField("id", shop.getId());
        jsonGen.writeStringField("name", shop.getName());
        jsonGen.writeStringField("category", shop.getCategory().toString());
        jsonGen.writeNumberField("distance", shop.getDistance());
        jsonGen.writeNumberField("locality_id", shop.getLocality().getId());
        jsonGen.writeEndObject();

    }

}

折扣序列化器

public class DiscountsSerializer extends JsonSerializer<Discounts> {
    @Override
    public void serialize(Discounts discount, JsonGenerator jsonGen,
            SerializerProvider serProv) throws IOException,
            JsonProcessingException {

        jsonGen.writeStartObject();
        jsonGen.writeNumberField("id", discount.getId());
        jsonGen.writeStringField("title", discount.getTitle());
        jsonGen.writeStringField("start_date", discount.getStartDate().toString());
        jsonGen.writeStringField("end_date", discount.getEndDate().toString());
        jsonGen.writeNumberField("shop_id", discount.getShop().getId());
        jsonGen.writeEndObject();

    }
}

注:注释@JsonIgnore在本例中,由于我计划进一步清理注释@JsonSerialize,并使用类序列化器,如下所示:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(Item.class, new ShopsSerializer());
mapper.registerModule(module);
String serialized = mapper.writeValueAsString(shop);

因此,有机会使用不同的序列化程序。

共有1个答案

充普松
2023-03-14

仅供参考(因为这是我一直在寻找的,但最终在这里):Jackson——具有双向关系的实体序列化(避免循环)

 类似资料:
  • 我有下面的JSON,我正试图使用Jackson API反序列化它 我基本上需要一个附件类,它有一个AttachmentFile对象列表,如下所示: 如何使用自定义反序列化器实现这一点? 谢谢

  • 问题内容: 我有两个实体: 我知道和。如果我要序列化的实例,那么它们很好。 但是我还需要传输的实例,并且我想填充该字段。 换一种说法: 在序列化时应该有,但是其父字段可能为空(可以通过使用json参考注释解决)。 在序列化时,它应该带有它们(但不必填充。) 有没有一种使用标准Jackson功能来解决它​​的方法? 即跳过已经序列化的实体的序列化,而不是标记符合或不符合序列化条件的字段。 问题答案:

  • 我有两个实体: 我知道和。如果我序列化的实例,那么它们是很好的。 但是我还需要传输的实例,并且我希望填充字段。 换句话说: null

  • 我试图创建会影响序列化值的自定义jackson注释。 意思是: 现在序列化对象X(10)将导致: 我怎样才能做到这一点?

  • 如何基于json中指定的类类型,在Jackson中实现从json到Java对象的转换。 Java类型示例:

  • 我想将包含另一个空值POJO的POJO序列化为JSON。 例如,给定: 连载之后,它看起来会是这样的 如果类的所有字段也为空,是否可以排除空对象?理想情况下,全局适用于每个对象,而无需编写自定义代码。