Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to serialize lazy loaded Hibernate collections (like PersistentSet) outside a DB session

I am developing a Spring MVC facade to access to a number of services. There are no DTOs implemented, and due to the magnitude, it is currently not an option to do so.

Serialization is done by Jackson directly to entities returned to the controllers as a result of transactional invocations to methods in the services, which fetch the entities from DB through the ORM (Hibernate).

The problem comes with entities that have collection attributes (such as Sets) from one-to-many or many-to-many relations, that Hibernate returns as PersistentCollections (like PersistentSet), and are lazy loaded, due to which, can't be read outside the scope of the DB session (which is when Jackson is attempting to serialize the response from the Controller).

Ideally, I would like Hibernate to return Java collections of proxies (HibernateProxy) that do maintain a reference (identifier) to the entity they wrap. Could also work to keep using specialized data structures (like PersistentCollection) but keeping references to the items wrapped, since once wrapped, they can only be retrieved from within a map that lives in the BD session, and without it, the key to the collection is completely useless (why do it like that? what if we don't want the whole item, and just it's identifier to be serialized as a reference? sigh).

I wonder...

Is it possible to force Hibernate to return Java collections of proxies wrapping entities?

If not, is it possible to extend Hibernate collections (like PersistentCollection) to maintain references to the entities wrapped, in order to read them in a specialized Jackson-Hibernate serializer?

If not, is it possible to convert Hibernate collections to Java collections before closing the BD session, without using additional data structures, besides the entity itself (i.e. convert the collection back to a Java type)?

like image 244
Jose Bosca Avatar asked Oct 28 '25 06:10

Jose Bosca


1 Answers

Well, you can just join fetch the collection with e.g. HQL select u from User u join fetch u.groups and annotate the groups property in the User entity with @JsonView(ReferenceJsonView.class) with interface ReferenceJsonView { Integer getId(); }, but that would fetch more state than necessary. I would recommend you look into implementing proper DTOs which can be done quite easily with Blaze-Persistence Entity Views.

Blaze-Persistence is a query builder on top of JPA which supports many of the advanced DBMS features on top of the JPA model. I created Entity Views on top of it to allow easy mapping between JPA models and custom interface defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure the way you like and map attributes(getters) via JPQL expressions to the entity model. Since the attribute name is used as default mapping, you mostly don't need explicit mappings as 80% of the use cases is to have DTOs that are a subset of the entity model.

Assuming you have an entity model like this

@Entity
public class User {
    @Id
    Integer id;
    String username;
    @ONeToMany
    Set<Group> groups;
}

@Entity
public class Group {
    @Id
    Integer id;
    String name;
}

A DTO mapping for your model could look as simple as the following

@EntityView(User.class)
interface UserDto {
    Integer getId();
    String getUsername();
    Set<GroupDto> getGroups();
}
@EntityView(Group.class)
interface GroupDto {
    Integer getId();
}

Querying is a matter of applying the entity view to a query, the simplest being just a query by id.

UserDto dto = entityViewManager.find(entityManager, UserDto.class, id);

But the Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features

It will only fetch the mappings that you tell it to fetch and all mappings are validated at boot time so nothing can go wrong at runtime.

like image 77
Christian Beikov Avatar answered Oct 29 '25 19:10

Christian Beikov