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(AliasToBeanResultTransformer.java:99) ~[hibernate-core-6.1.7.Final.jar!/:6.1.7.Final]
	at org.hibernate.transform.AliasToBeanResultTransformer.transformTuple(AliasToBeanResultTransformer.java:59) ~[hibernate-core-6.1.7.Final.jar!/:6.1.7.Final]
	at org.hibernate.sql.results.internal.RowTransformerTupleTransformerAdapter.transformRow(RowTransformerTupleTransformerAdapter.java:30) ~[hibernate-core-6.1.7.Final.jar!/:6.1.7.Final]
	at org.hibernate.sql.results.internal.StandardRowReader.readRow(StandardRowReader.java:109) ~[hibernate-core-6.1.7.Final.jar!/:6.1.7.Final]
	at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:198) ~[hibernate-core-6.1.7.Final.jar!/:6.1.7.Final]
	at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:33) ~[hibernate-core-6.1.7.Final.jar!/:6.1.7.Final]
	at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.doExecuteQuery(JdbcSelectExecutorStandardImpl.java:443) ~[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,

persistingControl.beginTx(tenant);
final Session session = m_persistingControl.getCurrentSession();
Query query = session.createQuery(QUERY_STRING);
query.setLockMode("e", LockMode.READ);
query.setFirstResult(OFFSET);
query.setMaxResults(SIZE);
query.setTupleTransformer(Transformers.aliasToBean(AInstanceDto.class));
List<T> output = query.list();
persistingControl.commit();

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: net.bytebuddy.renamed.java.util.Date$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(ClassInjector.java:1635) ~[byte-buddy-1.14.7.jar:?]
	at net.bytebuddy.dynamic.loading.ClassInjector$AbstractBase.inject(ClassInjector.java:118) ~[byte-buddy-1.14.7.jar:?]
	at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$UsingLookup.load(ClassLoadingStrategy.java:519) ~[byte-buddy-1.14.7.jar:?]
	at net.bytebuddy.dynamic.TypeResolutionStrategy$Passive.initialize(TypeResolutionStrategy.java:101) ~[byte-buddy-1.14.7.jar:?]
	at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:6325) ~[byte-buddy-1.14.7.jar:?]
	at org.hibernate.bytecode.internal.bytebuddy.ByteBuddyState.load(ByteBuddyState.java:146) ~[hibernate-core-6.3.1.Final.jar:6.3.1.Final]
	at org.hibernate.bytecode.internal.bytebuddy.BytecodeProviderImpl.getReflectionOptimizer(BytecodeProviderImpl.java:214) ~[hibernate-core-6.3.1.Final.jar:6.3.1.Final]
	at org.hibernate.metamodel.internal.EmbeddableRepresentationStrategyPojo.buildReflectionOptimizer(EmbeddableRepresentationStrategyPojo.java:186) ~[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

hi @beikov, not sure if this is a thread to be monitored but we are at hibernate-core:6.5.2.Final and still facing the same issue.

I am wondering;
. Is there a thread-safe implementation of AliasToBeanResultTransformer,
. what should I consider if I try to modify this transformer myself
. if you have any other suggestions instead of these ?

So far, I switched to constructor projections and I assume this fixes the issue. But downside is managing constructors for queries can be a dead-end work.

or maybe @vlad has some suggestions :slight_smile:

  1. AliasToBeanResultTransformer is deprecated, along with the whole ResultTransformer API, since Hibernate 6.0. You should migrate away from it.
  2. It sounds like you’re reusing the same instance of AliasToBeanResultTransformer between multiple Query objects, and that’s not what the tests for this deprecated thingy do. They call Transformers.aliasToBean() to get a new instance for each Query.
  3. It’s highly unlikely that anyone is going to be motivated to spend any time improving this deprecated thing.

thanks for the reply @gavinking and “no” we are not re-using the same AliasToBeanResultTransformer. We exactly do use it as you mention. Transformers.aliasToBean()

What I realize is we are utilizing this transformer through our app in a lot of place and only failings seems to be related to createQuery results. I mean we also use it with createNativeQuery results and no issues happens at all.

Although, I did not gone through the entire source of hibernate, I guess in the end the position transformer applied, should be somehow same. Maybe registration phase applies some HashMap tricks.

Actually I think this could be a result of the caching that happens in QueryInterpretationCache. Please report that in JIRA, with a reproducer, if at all possible. I believe the fix is straightforward.