We have lot of hibernate entity classes with nested relationships. I\'m trying to find best way to convert given entity to equivalent json format.
I know about JsonI
What I usually do is map Entities to DTOs manually, or with the help of tools such as MapStruct.
This will give you maximum flexibility, with a bit of overhead at the beginning, unfortunately.
Over time however, you'll see it was worth it.
Jackson, GSON, and other serialization tools are obviously limited in what they can do out-of-the-box, and this kind of customization requires a bit too much work, imho, while also being difficult to understand and maintain.
Keep it simple.
If you do not want to create new POJO
model for representing JSON
on REST API
level you need to prepare ORM
model before passing to Jackson
layer.
You should start from enabling Hibernate module which fits the best to your Hibernate
version. It solves many problem with lazy-loadings
and internal data types.
Read about options which Jackson
have for solving cycles problem during serialisation. Main annotations are:
You can define global visibility on ObjectMapper
, how to specify jackson to only use fields - preferably globally and customise it if needed for given class using JsonAutoDetect annotation.
POJO
modelProbably for most cases you will be able to reuse POJO
model created for ORM
. In cases where customising JSON
output with annotation will be to hard you can always create custom class and map ORM
model to this one manually in extra mapping/business layer.
In case you need to handle some custom annotations or some fields in general way you can use BeanSerializerModifier and BeanPropertyWriter. It is not easy to implement but it is very powerful. See example usage here: Jackson custom serialization and deserialization.
Simple example how it could be done for bidirectional relations and visibility configuration:
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.util.Arrays;
import java.util.List;
public class JsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
Item item0 = new Item();
item0.setId(1);
item0.setItemName("Item 0");
Item item1 = new Item();
item1.setId(2);
item1.setItemName("Item 1");
List<Item> items = Arrays.asList(item0, item1);
User user = new User();
user.setId(123);
user.setName("Rick");
user.setUserItems(items);
items.forEach(item -> item.setOwner(user));
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(mapper.getSerializationConfig().getDefaultVisibilityChecker()
.withFieldVisibility(JsonAutoDetect.Visibility.ANY)
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withSetterVisibility(JsonAutoDetect.Visibility.NONE)
.withCreatorVisibility(JsonAutoDetect.Visibility.NONE));
System.out.println(mapper.writeValueAsString(user));
}
}
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
class User {
private int id;
private String name;
private List<Item> userItems;
// getters, setters
}
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
class Item {
private int id;
private String itemName;
private User owner;
// getters, setters
}
Above code prints:
{"id":123,"name":"Rick","userItems":[{"id":1,"itemName":"Item 0","owner":123},{"id":2,"itemName":"Item 1","owner":123}]}