In the web project I use hiberante and jersey which in turn goes together with Jackson. For work with hiberante I have 3 entity-classes which reflect structure of tables of a database and have "one to many" and "many to one" relations. Binding fields are annotated as @OneToMany
and @ManyToOne
. Objects of these classes have to be serialized in json. For avoidance of mistakes during serialization binding fields were also annotated as @JsonManagedReference
and @JsonBackReference
.
As a result of serialization of object of the Shops
class such line turned out:
{
"id": 2,
"name": "Shop #2",
"category": "auto",
"distance": 120,
"discounts": [
{
"id": 9,
"title": "-50%",
"startDate": 1425679200000,
"endDate": 1425679200000
}
]
}
It didn't suit me and I decided to write the custom serializer. As a result I wanted to see the following json:
{
"id": 2,
"name": "Shop #2",
"category": "auto",
"distance": 120,
"locality_id": 10,
}
For this purpose I created 3 classes serializers for each of entity and cleaned annotations @JsonManagedReference
and @JsonBackReference
which were earlier and added @JsonSerialize
about the indication of a class serializer.
As a result in start attempt I receive the following mistake:
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)
How I can correct this error?
Entity-classes and classes serializers are given below.
Entity-classes:
Localities
@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
}
Shops
@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
}
Discount
@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
}
Serializers:
LocalitiesSerializer
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();
}
}
DiscountsSerializer
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();
}
}
P.S. Annotation @JsonIgnore
in this case doesn't approach as further I plan to clean annotations @JsonSerialize
and to use classes serializers as follows:
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(Item.class, new ShopsSerializer());
mapper.registerModule(module);
String serialized = mapper.writeValueAsString(shop);
Thus there is an opportunity to use different serializers.