Question

I have a REST project which uses the Gson library to produce and consume my entities.

But I'm having a problem with that. My entities with collections mapped via LAZY fetch are generating the LazyInitializationException when serialized by Gson.

I know that the exception is raised because a collection was accessed when the hibernate session has been closed. But like a form of Gson ignore uninitialized lazy collections, its possible?

The App class is one of the affected, where when your appUsers property is serialized generates the error in question:

App.java:

@Entity
@Table(name = "tb_app")
public class App implements Serializable {

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "id.app", cascade = CascadeType.ALL)
    private Set<AppUser> appUsers;
}

AppUser.java:

@Entity
@Table(name = "tb_app_user")
@AssociationOverrides({
    @AssociationOverride(name = "id.app", 
        joinColumns = @JoinColumn(name = "id_app", nullable = false)),
    @AssociationOverride(name = "id.user", 
        joinColumns = @JoinColumn(name = "id_user", nullable = false)) })
public class AppUser implements Serializable {

    @EmbeddedId
    private AppUserId id;
}

AppUserId.java:

@Embeddable
public class AppUserId implements Serializable {

    @ManyToOne
    private App app;

    @ManyToOne
    private User user;
}

Already, thanks!

Was it helpful?

Solution

That means that when your JSON serialization happens your Hibernate session is closed. Adding this to your web.xml might help (this is for JPA, if you are using pure Hibernate, there is a Hibernate filter for that too):

<filter>
    <filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
    <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
    <async-supported>true</async-supported>
</filter>



<filter-mapping>
    <filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

If that doesn't help, you might need to override Gson's mapper to account for uninitialized persistent collections, here is some code for that:

import org.hibernate.collection.internal.AbstractPersistentCollection;

public class PersistentCollectionUtils {
    public boolean isAbstractPersistentCollection(Object object) {
        return object instanceof AbstractPersistentCollection;
    }

    public boolean wasAbstractPersistentCollectionInitialized(Object collection) {
        return ((AbstractPersistentCollection) collection).wasInitialized();
    }

    public boolean isObjectSafeToUse(Object object) {
        return isAbstractPersistentCollection(object) ? 
                wasAbstractPersistentCollectionInitialized(object) :
                    true;
    }

    public boolean tryToInitializeCollection(Collection<?> collection) {
        if(collection != null) {
            try {
                collection.iterator().hasNext();
                return true;
            } catch (Exception t) {}
        }
        return false;
    }
}

Below is sample code used (this particular implementation is for Dozer, but you can easily translate it into Gson's mapper/adapter version).

public class PersistentSetMapper implements CustomFieldMapper {

    private PersistentCollectionUtils mapperUtils = new PersistentCollectionUtils();

    @Override
    public boolean mapField(Object source, Object destination, Object sourceFieldValue, ClassMap classMap, FieldMap fieldMapping) {
        // return true => the field has been mapped, no need to map it further
        // return false => the field was not mapped, use downstream mappers

        // check if field is derived from Persistent Collection
        if (!mapperUtils.isAbstractPersistentCollection(sourceFieldValue)) {
            return false;
        }

        // check if field is already initialized
        if (mapperUtils.wasAbstractPersistentCollectionInitialized(sourceFieldValue)) {
            return false;
        } else {
            // if not initialized, try to initialize it
            boolean wasInitialized = mapperUtils.tryToInitializeCollection((Collection<?>) sourceFieldValue);
            if(wasInitialized) {
                return false;
            } else {
                destination = null;
                return true;
            }
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top