JsonIgnoreProperties [2017 Update]:
You can now use JsonIgnoreProperties to suppress serialization of properties (during serialization), or ignore processing of JSON properties read (during deserialization). If this is not what you're looking for, please keep reading below.
(Thanks to As Zammel AlaaEddine for pointing this out).
JsonManagedReference and JsonBackReference
Since Jackson 1.6 you can use two annotations to solve the infinite recursion problem without ignoring the getters/setters during serialization: @JsonManagedReference
and @JsonBackReference
.
Explanation
For Jackson to work well, one of the two sides of the relationship should not be serialized, in order to avoid the infite loop that causes your stackoverflow error.
So, Jackson takes the forward part of the reference (your Set<BodyStat> bodyStats
in Trainee class), and converts it in a json-like storage format; this is the so-called marshalling process. Then, Jackson looks for the back part of the reference (i.e. Trainee trainee
in BodyStat class) and leaves it as it is, not serializing it. This part of the relationship will be re-constructed during the deserialization (unmarshalling) of the forward reference.
You can change your code like this (I skip the useless parts):
Business Object 1:
@Entity
@Table(name = "ta_trainee", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
public class Trainee extends BusinessObject {
@OneToMany(mappedBy = "trainee", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@Column(nullable = true)
@JsonManagedReference
private Set<BodyStat> bodyStats;
Business Object 2:
@Entity
@Table(name = "ta_bodystat", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
public class BodyStat extends BusinessObject {
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name="trainee_fk")
@JsonBackReference
private Trainee trainee;
Now it all should work properly.
If you want more informations, I wrote an article about Json and Jackson Stackoverflow issues on Keenformatics, my blog.
EDIT:
Another useful annotation you could check is @JsonIdentityInfo: using it, everytime Jackson serializes your object, it will add an ID (or another attribute of your choose) to it, so that it won't entirely "scan" it again everytime. This can be useful when you've got a chain loop between more interrelated objects (for example: Order -> OrderLine -> User -> Order and over again).
In this case you've got to be careful, since you could need to read your object's attributes more than once (for example in a products list with more products that share the same seller), and this annotation prevents you to do so. I suggest to always take a look at firebug logs to check the Json response and see what's going on in your code.
Sources:
Both approaches serve different purposes:
The first approach that you have outlined is to customize Jackson ObjectMapper - say for eg, to show the date in a different format in the json or to register a custom serializer to handle mapping a class to a json a little differently.
The second approach is to register converters - to transform one object to another, say for eg, to convert a String request parameter from the UI to an object or say if you get the entity id of a field and want to convert it to an entity.
So both have their place, to customize Jackson you would use the first approach, to create custom converters you would use the second approach.
Update:
Based on the new information that you have provided, I think what you are looking for is actually a HttpMessageConverter not a Converter.
When you say you want to return an object of type A to your client, you would serialize it some way over the wire - json or xml typically, but potentially other formats also - if you are going to convert it to json then you essentially customize ObjectMapper underlying MappingJacksonHttpMessageConverter(with Jackson 1.x) or MappingJackson2HttpMessageConverter(with Jackson2.x) you would typically do this:
<mvc:annotation-driven conversion-service="conversionService">
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.bk.lmt.web.spring.CustomObjectMapper"/>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
and in the Custom Object Mapper, register the appropriate serializers/deserializers IF you want to customize the Json representation.
Similarly with XML, you would typically not write your own converter(Jaxb2RootElementHttpMessageConverter), but use XmlJavaAdapters to customize how some of the elements are serialized.
If you have some new serialization format (not xml, json), then yes, you can attempt writing a HttpMessageConverter from scratch.
Best Answer
You should annotate corresponding model field with @JsonSerialize annontation. In your case it may be:
But in my opinion, it should better don't use entity models as VOs. Better way is to have different models and map between them. You can find my example project here (I used date serialization with Spring 3 and Jackson 2 as example).