[hibernate-dev] Bytecode enhancement and collections
Steve Ebersole
steve at hibernate.org
Thu Sep 10 18:34:18 EDT 2015
That depends on the "allow lazy loading outside transaction" setting, much
like how the outcome of `myEntity.getChildren().size()` depends on same in
the proxy solution.
If that is allowed, then the call will build the collection (from a
"temporary Session", just like the proxy solution works) and return that.
If not allowed, the the call will throw an exception
(LazyInitializationException to be precise). I had thought of returning an
uninitialized PersistentCollection here, but no matter what you try to do
with that collection afterwards will fail.
On Thu, Sep 10, 2015 at 2:30 PM Scott Marlow <smarlow at redhat.com> wrote:
>
>
> 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