AliasToBeanResultTransformer is not threadsafe

Hi, we have migrated our application to Hibernate 6 and we are in version 6.1.7.Final now. We have used the AliasToBeanResultTransformer in a couple of places to bind the resultset to a DTO object. We started to see some weird behavior in the transformation. First, we saw the resultant DTO object had only a few fields populated and most of the fields were left empty though the data was available in the database. It also happens only sporadically and also when there are multiple invocations of the same query in a short span of time. Secondly, we saw a few error messages that the cached aliases were different, but the compared array of aliases had the same values printed in the logs. The error was like below,

aliases are different from what is cached; aliases=[id, modificationTime, variable, instanceState, revision, value] cached=[id, modificationTime, variable, instanceState, revision, value]
java.lang.IllegalStateException: aliases are different from what is cached; aliases=[id, modificationTime, variable, instanceState, revision, value] cached=[id, modificationTime, variable, instanceState, revision, value]
	at org.hibernate.transform.AliasToBeanResultTransformer.check( ~[hibernate-core-6.1.7.Final.jar!/:6.1.7.Final]
	at org.hibernate.transform.AliasToBeanResultTransformer.transformTuple( ~[hibernate-core-6.1.7.Final.jar!/:6.1.7.Final]
	at org.hibernate.sql.results.internal.RowTransformerTupleTransformerAdapter.transformRow( ~[hibernate-core-6.1.7.Final.jar!/:6.1.7.Final]
	at org.hibernate.sql.results.internal.StandardRowReader.readRow( ~[hibernate-core-6.1.7.Final.jar!/:6.1.7.Final]
	at org.hibernate.sql.results.spi.ListResultsConsumer.consume( ~[hibernate-core-6.1.7.Final.jar!/:6.1.7.Final]
	at org.hibernate.sql.results.spi.ListResultsConsumer.consume( ~[hibernate-core-6.1.7.Final.jar!/:6.1.7.Final]
	at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.doExecuteQuery( ~[hibernate-core-6.1.7.Final.jar!/:6.1.7.Final]

This was quite puzzling but when I debugged the AliasToBeanResultTransformer I was able to see the Setter[] is maintained globally and populated only when the first row of the resultset is populated. The place where the setters are populated is not protected by a synchronous block. So when multiple threads access the transformTuple() method for the first time the first thread populates the Setter[] and then proceeds with setting the tuple values to the resultant object referring to the Setter[] and in the meanwhile the second thread clears and repopulated the Setter[] which caused some of the field of the resultant object not being populated by the first thread.

Below is how the AliasToBeanResultTransformer is used,

final Session session = m_persistingControl.getCurrentSession();
Query query = session.createQuery(QUERY_STRING);
query.setLockMode("e", LockMode.READ);
List<T> output = query.list();

Is this already a known issue with Hibernate 6?
Because of the fact that a new instance of the AliasToBeanResultTransformer is always supplied to the query should it be really shared by multiple threads?
If there is a possibility that the transformer object can be accessed by multiple threads at a time shouldn’t it be either made stateless or the state is made thread-safe?

Hibernate ORM 6.1 is not supported anymore. Update to 6.3.1.Final or 6.4.0.CR1

Thanks for the reply. Do you have any idea whether the problematic situation is taken care of in 6.3.1.Final version?

Most likely it is, yes. Try it out.

When I tried to upgrade the hibernate version to 6.3.1.Final the application failed to start with the below exception,

Caused by: java.lang.IllegalArgumentException:$HibernateInstantiator$zOd3MagU must be defined in the same package as java.util.Date/org.hibernate.bytecode.internal.bytebuddy.ByteBuddyState
	at net.bytebuddy.dynamic.loading.ClassInjector$UsingLookup.injectRaw( ~[byte-buddy-1.14.7.jar:?]
	at net.bytebuddy.dynamic.loading.ClassInjector$AbstractBase.inject( ~[byte-buddy-1.14.7.jar:?]
	at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$UsingLookup.load( ~[byte-buddy-1.14.7.jar:?]
	at net.bytebuddy.dynamic.TypeResolutionStrategy$Passive.initialize( ~[byte-buddy-1.14.7.jar:?]
	at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load( ~[byte-buddy-1.14.7.jar:?]
	at org.hibernate.bytecode.internal.bytebuddy.ByteBuddyState.load( ~[hibernate-core-6.3.1.Final.jar:6.3.1.Final]
	at org.hibernate.bytecode.internal.bytebuddy.BytecodeProviderImpl.getReflectionOptimizer( ~[hibernate-core-6.3.1.Final.jar:6.3.1.Final]
	at org.hibernate.metamodel.internal.EmbeddableRepresentationStrategyPojo.buildReflectionOptimizer( ~[hibernate-core-6.3.1.Final.jar:6.3.1.Final]

I checked the migration guide and there is nothing specially mentioned related to java.util.Date except the fact they are deprecated and I believe deprecated capabilities should still work.

Do you see anything obvious that is causing this problem?

No idea what is happening there. Could you please try to create a reproducer for this problem based on our test case template and attach that to a new Jira ticket?

1 Like