[hibernate-dev] Bytecode enhancement and collections

Scott Marlow smarlow at redhat.com
Thu Sep 10 15:30:28 EDT 2015



On 09/10/2015 09:45 AM, Steve Ebersole wrote:
> Wanted to get some opinions.  I am working on HHH-10055 which is basically
> a report of problems with that "lazy loading outside of a
> session/transaction" feature when used in combination with bytecode
> enhancement.  The initial problem was that bytecode interception was not
> accounting for collection attributes properly; it was not building the
> appropriate PersistentCollection to return.  I changed that code to now
> build the PersistentCollection.
>
> But that led to another issue later on that made me question how I was
> building the PersistentCollection during interception.  Essentially I was
> trying to still build an uninitialized PersistentCollection.  The
> interception code immediately tries to read the size of that collection as
> and up-front part of its in-line dirty checking capabilities which
> triggered another interception back in to an inconsistent state.
>
> But what I started thinking about is the assumption that this interception
> ought to prefer to return an uninitialized PersistentCollection.  I now
> think that is not a good assumption.  Why?  Consider code like:
>
>
> Well the idea of an uninitialized PersistentCollection comes from the
> scenario of proxy-based laziness.  In proxy-based laziness, code like:
>
> MyEntity myEntity = session.load( MyEntity.class, 1 );
> System.out.println( myEntity.getName() );
>
> In the case of proxy-based laziness, the second line immediately causes the
> entire proxy to become initialized.  Part of that is to set any of its
> collection attributes.  However, as the collections are not accessed here
> we want to further delay initializing them.  But since the proxy is
> initialized completely that means the only way to achieve that here is
> setting an uninitialized version of the PersistentCollection as state,
> which will initialize itself later when accessed.
>
> For bytecode enhancement, the situation is a little bit different.  There
> we'd not even build the PersistentCollection instance until that attribute
> is accessed.  So in the above code the collection attributes would never be
> built.  So when we are in the interception code I mentioned above, we know
> that something is trying to access that collection attribute specifically.
> This is the difference.
>
> Back to the initial problem... I think the solution is not just to have the
> bytecode interception code build the PersistentCollection, but to also have
> it make sure that the PersistentCollection is initialized.
>
> Going back to the sample code, and adding a line:
>
> MyEntity myEntity = session.load( MyEntity.class, 1 );
> print( myEntity.getName() );
> myEntity.getChildren();
>
> In the proxy-based solution the collection is still uninitialized after
> this.  For bytecode interception I am proposing that the collection would
> be initialized by that 3rd line.  Again we could return the uninitialized
> collection here, and wait for PersistentCollection to initialize itself on
> first "further access" (calling size(), iterating, etc).  I am more think
> through intent; because we know specifically that the collection attribute
> itself was accessed it seems reasonable to go ahead and initialize it.
>
> And if we do not go that route, then we need a different tact as well for
> dealing with the in-line dirty checking aspect of this.
>
> Really the only time this distinction becomes an issue is in code that
> explicitly tries to check whether certain attributes are initialized.  So
> whereas this works for the proxy-based approach:
>
> MyEntity myEntity = session.load( MyEntity.class, 1 );
> if ( !Hibernate.isInitialized( myEntity.getChildren() ) ) {
>      // do something with the uninitialized collection
>      ...
> }
>
> It will fail with the bytecode interception approach I propose, because the
> call to `myEntity.getChildren()` itself causes the initialization.  There
> you'd have to use:
>
> MyEntity myEntity = session.load( MyEntity.class, 1 );
> if ( !Hibernate.isPropertyInitialized( myEntity, "children" ) ) {
>      // do something with the uninitialized collection
>      ...
> }
>
> which has always been the suggested way to deal with questioning bytecode
> initialization state and which matches the JPA call too.
>
> So any thoughts?

What happens if the session is closed after the session.load?  Will the 
collection still be initialized by the time myEntity.getChildren() is 
called?

MyEntity myEntity = session.load( MyEntity.class, 1 );
session.close();
print( myEntity.getName() );
myEntity.getChildren();


> _______________________________________________
> hibernate-dev mailing list
> hibernate-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/hibernate-dev
>


More information about the hibernate-dev mailing list