Pretty simple question, hard to find an answer:
I want to Serialize in JSON my POJO JPA entities with references being Dojo-like to use it with dojox.data.JsonRestStore.
The server part is made with Spring MVC and HttpConverters to make it a RESTfull web-app. I’m using JacksonJson to convert JPA entities to JSON.
As a lot of people have, I do have problems with multiple references. @JsonBackReference and @JsonManagedReference do not do the trick!
Considering this basic example:
public class A {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(nullable=false)
private String field;
@OneToMany(mappedBy = "b")
private List<B> bs;
}
public class B {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne
private A a;
}
With the basic Jackson Json converter you obtain something like this (considering you have put the @JsonBackReference and @JsonManagedReference):
{ id:1, fieldB:"bbbbb", a: { id:1, fieldA: "aaaaaa" }}
In a concrete application, having the list of bs from the A objects is pointless in most cases. But having knowing what kind of A object is in the B.a field is important (at least to me).
Now, the problem lies in the references which are copied and you can end up having some serious big JSON with not much data in it.
The Dojo Framework provides a reference standard explained in here : http://www.sitepen.com/blog/2008/06/17/json-referencing-in-dojo/ and
http://dojotoolkit.org/reference-guide/dojox/data/JsonRestStore.html.
So what I’m searching is a way to define this as the following:
{ id:1, fieldB:"bbbbb", a: { $ref: "getA/1"}}
First problem: Jackson obviously can’t know what url you will use for the Reference.
To resolve that problem I made very simple interface like this:
public interface EntityWithId {
public Long getId();
public void setId(Long id);
}
This interface in then implemented by all my entities and I made this very very simple JsonSerializer:
public class EntityIdSerializer extends JsonSerializer<EntityWithId> {
@Override
public void serialize(EntityWithId value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
jgen.writeStartObject();
jgen.writeStringField("$ref", "db/" + value.getClass().getSimpleName() + "/" + value.getId().toString());
jgen.writeEndObject();
}
}
With those two I got the desired JSON, adding @JsonSerialize(using = EntityIdSerializer.class) to the @ManyToOne fields.
Is there no more standard approach? The Dojo dojox.data.JsonRestStore sounds really promising as you can combine it with lots of Dijits widgets, but is it really a nice thing to do and try? Won’t my REST app be to much Dojo-restrictive?
Thanks for your answers!
Dojo approach sounds like it requires dealing with a complete logical tree, to be able to use location-based references. This will not work well with Jackson, which supports fully incremental data-binding, i.e. only subset of the logical being available at the point where data is read or written.
So Jackson does not support it by default; nor is that approach considered much of a standard in general (AFAIK). At least I havent seen it supported by Java libraries.