Json and Java - Circular Reference - java

I'm having and issue with the Circular reference.
I have Rest Webservices which returns objects to the front end, the issue is when I try to return objects that have several references so as the result I get an infinite response, which generate
java.lang.IllegalStateException:
Cannot call sendError() after the response has been committed
The objects are generated automatically by Hibernate Code Generation and I need to have the circular reference in the backend, I've just need to remove it before send the information to the frontend using Jackson.
The controller method header is:
#RequestMapping(value="/list", method=RequestMethod.POST)
public #ResponseBody eventResponse list(#RequestBody String sessionID) {
I'm not doing anything explicite to convert to Json, I'm a newby with this and I think that jackson resolved this automatically.

There are two ways you can go about this. If you must expose your entity to the outside world, I recommend adding #JsonIgnore on the property that is causing the circular reference. This will tell Jackson not to serialize that property.
Another way is to use the bidirectional features provided by Jackson. You can either use #JsonManagedReference or #JsonBackReference. #JsonManagedReference is the "forward" part of the property and it will get serialized normally. #JsonBackReference is the "back" part of the reference; it will not be serialized, but will be reconstructed when the "forward" type is deserialized.
You can check out the examples here.
This addresses your comment: I think what you might want to do in this case is use a DTO that is visible to the outside world. I like this approach because I don't want to expose my entities to the outside. This means that the Jackson annotations would be on the DTO and not on the enity. You would need some sort of mapper or converter that converts the entity to the DTO. Now when you make changes to your entity, they won't get propagated to the DTO unless you modify your mapper/converter. I think this is ok, because when you make a change to your entity you can decide if you want that change to be exposed or not.
UPDATE
There is a good blog post here that goes into detail about the various ways you can handle bidirectional relationships in Jackson. It describes solutions that use #JsonIgnore, #JsonManagedReference and #JsonBackReference, #JsonIdentityInfo, #JsonView and a custom serializer as well. It's a pretty comprehensive writeup of the various techniques that you can use.

A single annotation #JsonIdentityInfo solves the problem. It handles circular references also.Reference

A #JsonbTransient solved my problem to handel circular references:
#JsonbTransient // javax.json.bind.annotation.JsonbTransient
#ManyToOne
#JoinColumn(name = "userId", referencedColumnName = "id", nullable = false)
public AContainedEntity getAContainedEntity() {
return aContainedEntity;
}

Related

Conflicting types of serialization/deserialization and annotations

I've just started to learn about serialization/deserialization and I'm a bit confused about which type is used where and when... let me explain:
I have an object containing many fields some of which are full of "useless" info.
Now, when I log the contents of such object for debugging purposes I would like the output to be in a nice json format.
So in the toString() method of this object I do the following:
import com.fasterxml.jackson.databind.ObjectMapper;
...
...
#Override
public String toString() {
ObjectMapper objectMapper = new ObjectMapper();
String s = "";
try{
s = objectMapper.writeValueAsString(this);
} catch (Exception e) {
}
return s;
}
but this also logs all the useless fields.
So I've looked around and found the #JsonIgnore annotation from com.fasterxml.jackson.annotation.JsonIgnore which I can put on top of the useless fields so as not to log them.
But from what I've understood serialization is a process of transforming a java object into a bytestream so that it can be written to file, saved in session, sent across the internet. So my noob question is: is it possible that using the #JsonIgnore annotation on top of certain fields will result in those fields not being saved into session (I use an hazelcast map), or not being sent in the http responses I send, or not being written to a file If I ever decide to do that?
If the answer to the previous question is NO, then is that because those types of actions (saving in session, writing to file, sending as http response) use different types of serialization than objectMapper.writeValueAsString(this); so they don't conflict?
In your case, you're using Jackson's ObjectMapper to convert your object to a string representation (in JSON format). The #JsonIgnore annotation is part of Jackson's annotations and will prevent fields annotated with it from being included in the JSON representation of your object.
However, this only affects the string representation created by the ObjectMapper, not other forms of serialization/deserialization. If you want to persist the object in a specific way, you may need to use a different form of serialization (such as binary serialization) or create a custom representation that excludes the fields you don't want to save.
So to answer your questions:
No, using #JsonIgnore will not affect the object saved in a session or sent as an HTTP response.
Yes, that's correct. Different forms of serialization/deserialization may handle fields differently, even if they are part of the same object.

Hibernate Bidirectional Mapping Results in Cycle when using converter for DTO

I've mapped the classes as follows:
#ManyToOne(fetch = FetchType.LAZY,cascade = CascadeType.ALL)
#JoinColumn(name = "CATEGORY_ITEMS_ID")
private CategoryItem categoryItem;
#OneToMany(mappedBy="categoryItem",cascade = CascadeType.ALL, orphanRemoval = true)
private List<CategoryRating> categoryRatingList;
But when I need to convert the table models to dto's I'm caught in a cycle as:
target.setCategoryRatingDtoList(categoryRatingConverter.convert(source.getCategoryRatingList()));
target.setCategoryItemDto(categoryItemConverter.convertToDto(source.getCategoryItem()));
both converters end up calling each other.
I need the result as:
List of CategoryItems, in which every CategoryItems object contains a list of associated CategoryRatings
How should I solve this problem? Maybe I'm using bidirectional mapping in the wrong sense. Anyhow, kindly provide your opinion and possible solutions for this problem
You have 3 options.
You could introduce a context and register objects to that context in their constructors. When another object is then in it's constructor it can receive an inflight list/object through that context and thus resolve the cycle this way.
Another option is to make the DTOs mutable and first instantiate the objects as well as register them into a context, before setting the state on the objects. This is similar to the first solution with the slight difference that the DTO class doesn't need to know about the context.
The third solution is that you avoid the cycle by using a simpler converter for e.g. CategoryRating within the CategoryItemConverter that only converts some data, but not the categoryRatings list.

Disable enhancement for Play Framework model classes

Is there a way to disable enhancement for play framework model classes?
The reason why I'm asking this is because I want to serialize the model objects to JSON but as soon as json serializer touches any non initialized model,
that model will be initialized causing an extra database hit and the resulting json will be bloated with unnecessary model objects. I tried excluding the models.* from the application.conf and using a ServerConfigStartup with this call serverConfig.addClass(Model.class) or that call serverConfig.addPackage("models") but neither of them worked for me.
Ebean requires that model classes be enhanced. You can't use a model class with ebean if it's not enhanced.
So, your options are, don't use ebean, or don't serialise your model objects to JSON. The latter is considered best practice, tying your REST API data objects to your database models is not a good idea, for the reason of the problem that you are experiencing now - the two models usually are conceptually different - the database model has references to other models, while the JSON model doesn't. So use different classes to represent the different models.
There is another option, use Jackson annotations like #JsonIgnore to ignore these properties. But really, that's a slippery slope, as your codebase evolves it becomes next to impossible to reason about what your JSON will look like as you start to use more of these annotations on your classes, and maintaining the models, ensuring you don't break your public REST API, becomes a nightmare.
I found a way around the loading of models that are not needed during the json serialization.
First I had to modify the way Jackson serializes the model objects by using this:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.PUBLIC_ONLY);
This forces Jackson to use the field directly but your model fields have to be public. This is still not enough because uninitialized model sets will still be loaded during the serialization.
To get around this, I had to null the sets before the serialization process by using reflection as follows:
for (Field field : model.getClass().getFields())
{
Object fieldObject = field.get(model);
if (fieldObject instanceof BeanSet)
{
BeanSet beanSet = (BeanSet) fieldObject;
//checks if the set is loaded or not
if (beanSet.isReference())
{
field.set(model, null);
}
}
}
Now your model is safe to pass to the Jackson serializer without uninitialized model objects loaded during the serialization.
String jsonString = objectMapper.writeValueAsString(model);
JsonNode jsonNode = Json.parse(jsonString);
Using #JsonIgnore will also work but it is not reliable in the long run as James mentioned because you may have a need for the model object that you are ignoring later.

Java/Hibernate: How to detect, if field is lazy-loaded proxy and not actual data?

I'm converting my entity to DTO and I want to set NULL as DTO value for all fields, which are lazy-loaded and not initialized (because I do not want to transfer all the data all the time).
I've tried:
if (!(entity.getNationality() instanceof HibernateProxy))
this.setNationalityFromEntity(entity.getNationality());
But it did not seemed to help.
Any suggestions are welcome!
Thank you!
They way we do this in our Entities is we have boolean methods which do the check in a way that will not trigger the lazy loading. For example, if our Entity had an associated entity called 'associatedSomething', then the method to check if that associated Entity has been lazy loaded would be:
public boolean isAssociatedSomethingLoaded() {
if (associatedSomething instanceof HibernateProxy) {
if (((HibernateProxy)associatedSomething).getHibernateLazyInitializer().isUninitialized()) {
return false;
}
}
return (getAssociatedSomething() != null);
}
NOTE: It's important not to use getAssociatedSomething() in the check, as this makes sure that the associated Entity does not get lazy-loaded during the check.
The class is always a proxy, whether it's initialized or not, so you're going to exclude it every time if you just check for instances of proxy. The Lazy Load does not cause the Proxy reference on the entity to be replaced with a reference to a new object, it just populates the fields.
To find out if it's actually initialized you need to ask it!
if (HibernateProxy.class.isInstance(entity.getNationality())) {
HibernateProxy proxy = HibernateProxy.class.cast(entity.getNationality());
if (!proxy.getHibernateLazyInitializer().isUninitialized()) {
this.setNationalityFromEntity(entity.getNationality());
}
}
The mere possibility of being able to invoke a getter for some state that shouldn't be available for a use case is problematic in my opinion, but that's a different story. I would suggest you implement a proper DTO approach instead to avoid accidental errors.
I created Blaze-Persistence Entity Views for exactly that use case. You essentially define DTOs for JPA entities as interfaces and apply them on a query. It supports mapping nested DTOs, collection etc., essentially everything you'd expect and on top of that, it will improve your query performance as it will generate queries fetching just the data that you actually require for the DTOs.
The entity views for your example could look like this
#EntityView(Person.class)
interface PersonDto {
String getNationality();
}
Querying could look like this
List<PersonDto> dtos = entityViewManager.applySetting(
EntityViewSetting.create(PersonDto.class),
criteriaBuilderFactory.create(em, Person.class)
).getResultList();

Grails. Hibernate lazy loading multiple objects

I'm having difficulties with proxied objects in Grails.
Assuming I've got the following
class Order {
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name="xxx", joinColumns = {#JoinColumn(name = "xxx")}, inverseJoinColumns = {#JoinColumn(name = "yyy")})
#OrderBy("id")
#Fetch(FetchMode.SUBSELECT)
private List<OrderItem> items;
}
class Customer {
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = true)
#JoinColumn(name = "xxx",insertable = false, nullable = false)
private OrderItem lastItem;
private Long lastOrderId;
}
And inside some controller class
//this all happens during one hibernate session.
def currentCustomer = Customer.findById(id)
//at this point currentCustomer.lastItem is a javassist proxy
def lastOrder = Order.findById(current.lastOrderId)
//lastOrder.items is a proxy
//Some sample actions to initialise collections
lastOrder.items.each { println "${it.id}"}
After the iteration lastOrder.items still contains a proxy of currentCustomer.lastItem. For example if there are 4 items in the lastOrder.items collection, it looks like this:
object
object
javassist proxy (all fields are null including id field). This is the same object as in currentCustomer.lastItem.
object
Furthermore, this proxy object has all properties set to null and it's not initialized when getters are invoked. I have to manually call GrailsHibernateUtils.unwrapIdProxy() on every single element inside lastOrder.items to ensure that there are no proxies inside (which basically leads to EAGER fetching).
This one proxy object leads to some really weird Exceptions, which are difficult to track on testing phase.
Interesting fact: if I change the ordering of the operations (load the order first and the customer second) every element inside lastOrder.items is initialized.
The question is: Is there a way to tell Hibernate that it should initialize the collections when they are touched, no matter if any elements from the collection is already proxied in the session?
I think what's happening here is an interesting interaction between the first level cache (stored in Hibernate's Session instance) and having different FetchType on related objects.
When you load Customer, it gets put in to the Session cache, along with any objects that are loaded with it. This includes a proxy object for the OrderItem object, because you've got FetchType.LAZY. Hibernate only allows one instance to be associated with any particular ID, so any further operations that would be acting on the OrderItem with that ID would always be using that proxy. If you asked the same Session to get that particular OrderItem in another way, as you are by loading an Order containing it, that Order would have the proxy, because of Session-level identity rules.
That's why it 'works' when you reverse the order. Load the Order first, it's collection is FetchType.EAGER, and so it (and the first level cache) have fully realized instances of OrderItem. Now load a Customer which has it's lastItem set to one of the already-loaded OrderItem instances and presto, you have a real OrderItem, not a proxy.
You can see the identity rules documented in the Hibernate manual:
For objects attached to a particular Session... JVM identity for database identity is guaranteed by Hibernate.
All that said, even if you get an OrderItem proxy, it should work fine as long as the associated Session is still active. I wouldn't necessarily expect the proxy ID field to show up as populated in the debugger or similar, simply because the proxy handles things in a 'special' way (ie, it's not a POJO). But it should respond to method calls the same way it's base class would. So if you have an OrderItem.getId() method, it should certainly return the ID when called, and similarly on any other method. Because it's lazily initialized though, some of those calls may require a database query.
It's possible that the only real problem here is simply that it's confusing to have it so that any particular OrderItem could be a proxy or not. Maybe you want to simply change the relationships so that they're either both lazy, or both eager?
For what it's worth, it's a bit odd that you've got the ManyToMany relationship as EAGER and the ManyToOne as LAZY. That's exactly the reverse of the usual settings, so I would at least think about changing it (although I obviously don't know your entire use case). One way to think about it: If an OrderItem is so expensive to fetch completely that it's a problem when querying for Customer, surely it's also too expensive to load all of them at once? Or conversely, if it's cheap enough to load all of them, surely it's cheap enough to just grab it when you get a Customer?
I think you can force eager loading this way or using
def lastOrder = Order.withCriteria(uniqueResult: true) {
eq('id', current.lastOrderId)
items{}
}
or using HQL query with 'fetch all'

Categories

Resources