Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate: initialize vs unproxy

Tags:

java

hibernate

I am having an issue with a ManyToMany

@ManyToMany(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY)
@JoinTable(
    name = "PORTFOLIO_USER_PERMS",
    joinColumns = { @JoinColumn(name = "USERNAME") },
    inverseJoinColumns = { @JoinColumn(name = "PORTFOLIO_ID"), }
)
private List<Portfolio> sharedPortfolios = new ArrayList<>();

I have one scenario where one of the of the sharedPortfolios one element is a proxy and another element have an attribute that is a proxy (actulay is the same object because of a one-to-one relationship). This list is normally returned to a Controller method which then is converted to the respective DTO's. As you might suspect, that single attribute with a proxy object is causing a LazyInitializationException.

enter image description here

This means that in the service i need to traverse every element on the list looking for any attributes that might be a proxy and unproxy with the Hibernate Utility: Hibernate.unproxy(...) before it is passed to the controller.

My questions:

1) what is the difference between Hibernate.initialize and Hibernate.unproxy?

Initializing the proxy object does not fix the problem.

2) Why one of the elements is a proxy, but the others not?

3) What is there a better way then manually traverse this list and all the attributes and search for proxy objects?

Thank you so much.

Best Regards.

like image 822
mpssantos Avatar asked Jun 27 '26 02:06

mpssantos


1 Answers

To answer your first question you can look at the implementation of the two methods:

    /**
     * Unproxies a {@link HibernateProxy}. If the proxy is uninitialized, it automatically triggers an initialization.
     * In case the supplied object is null or not a proxy, the object will be returned as-is.
     *
     * @param proxy the {@link HibernateProxy} to be unproxied
     * @return the proxy's underlying implementation object, or the supplied object otherwise
     */
    public static Object unproxy(Object proxy) {
        if ( proxy instanceof HibernateProxy ) {
            HibernateProxy hibernateProxy = (HibernateProxy) proxy;
            LazyInitializer initializer = hibernateProxy.getHibernateLazyInitializer();
            return initializer.getImplementation();
        }
        else {
            return proxy;
        }
    }

and

    /**
     * Force initialization of a proxy or persistent collection.
     * <p/>
     * Note: This only ensures initialization of a proxy object or collection;
     * it is not guaranteed that the elements INSIDE the collection will be initialized/materialized.
     *
     * @param proxy a persistable object, proxy, persistent collection or <tt>null</tt>
     * @throws HibernateException if we can't initialize the proxy at this time, eg. the <tt>Session</tt> was closed
     */
    public static void initialize(Object proxy) throws HibernateException {
        if ( proxy == null ) {
            return;
        }

        if ( proxy instanceof HibernateProxy ) {
            ( (HibernateProxy) proxy ).getHibernateLazyInitializer().initialize();
        }
        else if ( proxy instanceof PersistentCollection ) {
            ( (PersistentCollection) proxy ).forceInitialization();
        }
        else if ( proxy instanceof PersistentAttributeInterceptable ) {
            final PersistentAttributeInterceptable interceptable = (PersistentAttributeInterceptable) proxy;
            final PersistentAttributeInterceptor interceptor = interceptable.$$_hibernate_getInterceptor();
            if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor ) {
                ( (EnhancementAsProxyLazinessInterceptor) interceptor ).forceInitialize( proxy, null );
            }
        }
    }

For instances of entity proxies (HibernateProxy) the two methods do essentially the same, with the only difference that unproxy returnes the unproxied entity. From my testing so far, it should not make a difference whether you work with the return value or the original reference.

initialize also works for persistent collections (PersistentCollection). When you need to initialize a ToMany-Relation, like in your question, you will need to use this method.

Initializing the proxy object does not fix the problem.

You need to initialize the collection sharedPortfolios, not just object that contains the collection:

Hibernate.initialize(entity.sharedPortfolios)

Alternatively, you might want to JOIN FETCH the relation in the query or use an entity graph to avoid having to initialize afterwards and to avoid the extra queries.

like image 75
Dario Seidl Avatar answered Jun 28 '26 15:06

Dario Seidl



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!