Batch Fetch for field having subtypes…Error: could not re-associate uninitialized transient collection

Description

I have this problem running within a single Spring transaction.

I load objects of type PointerClass (See the “model” below), which contains two fields of type AbstractSuperClass.
At that point, 2 proxies of type AbstractSuperClass are are created.

I try to unproxy one of those AbstractSuperClass proxies like this:

  1. Get a PointerClass field_1 by reflection

  2. Call Hibernate.unproxy with that field value

  3. Hibernate does a batch fetch for objects of type ConcreteClass_1 and ConcreteClass_2 (both extending AbstractSuperClass, which is also abstract).

The prefetching generates a query to preload a few objects of ConcreteClass_1 and ConcreteClass_2.

The returned object of type ConcreteClass_1 is perfectly fine. I can see that the ConcreteClass_2 object is also fine.

I have this in the context: An AbstractSuperClass object pointing to one of those ConcreteClass_2 objects.

But I merge that same AbstractSuperClass object with that relation nullified.

I can see that during the merge ConcreteClass_2.field_1 changes from initialized = true to false.

At a later stage I unproxy that ConcreteClass_2 objects, and set a reference to it without modifying it.
Actually, unproxying this object does nothing but returning the already loaded object. However, from my Eclipse IDE I can’t see the 2 collection fields from the super classes (field_1 and field_2 below). These fields should be empty sets (according to the database):

  • proxy of type PointerClass$HibernateProxy$?????? ->

    • $$_hibernate_interceptor of type ByteBuddyInterceptor

      • target of type ConcreteClass_2

        • field_1 of type Set

          • com.sun.jdi.InvocationException: Exception occurred in target VM occurred invoking method.

    • field_1 = empty HashSet

At flush time hibernate thinks that the ConcreteClass_2 object above is dirty (which is not true) and tries to load its fields. There is an exception trying to load the set declared in an upper class: field_1

  • org.hibernate.HibernateException: could not re-associate uninitialized transient collection

Putting a breakpoint in ProxyVisitor.reattachCollection before throwing the Exception:

  • throw new HibernateException( "could not re-associate uninitialized transient collection" );

I can see that the reason is:

  • PersistentSet.key == null && PersistentSet.role == null
    I can also see that PersistetSet.session says closed == false

I could avoid the exception detaching the referenced object after the merge:

  1. entityManager.detach(class_2_Instance);

  2. class_2_Instance = getReference(class_2_Instance);

Now I can make a reference from a PointerClass object to that class_2_Instance .

Model:

@MappedSuperClass
PersistentObject
{
@OneToMany
Set<> field_1

@Inheritance(strategy = InheritanceType.JOINED)
public abstract class DomainObject extends PersistentObject
{
@OneToMany
Set<> field_2

@MappedSuperclass
public abstract class ValueObject extends DomainObject
{

public abstract class AbstractSuperClass extends ValueObject
{

public class ConcreteClass_1 extends AbstractSuperClass
{

public class PointerClass extends ??? which in turn extends DomainObject Q: Why not make it extend DomainObject directly?
{
@OneToOne(fetch = FetchType.LAZY)
private AbstractSuperClassfield_1;

@OneToOne(fetch = FetchType.LAZY)
private AbstractSuperClassfield_2;

<property name="hibernate.default_batch_fetch_size" value="20"/>
<property name="hibernate.jdbc.fetch_size" value="20"/>
<property name="hibernate.jdbc.batch_size" value="20"/>
<property name="hibernate.jdbc.batch_versioned_data" value="true"/>

Environment

None

Assignee

Unassigned

Reporter

Mario Martin Santana