Note: This bug is displayed in read-only format because the product is no longer active in Red Hat Bugzilla.

Bug 1152329

Summary: [HHH-9476] Query with Composite Primary Key parameter receives "org.hibernate.PropertyAccessException: could not get a field value by reflection getter of xxx" if using javassit instrument.
Product: [JBoss] JBoss Enterprise Application Platform 6 Reporter: Gary Hu <ghu>
Component: HibernateAssignee: Gail Badner <gbadner>
Status: CLOSED WONTFIX QA Contact: Martin Simka <msimka>
Severity: high Docs Contact:
Priority: high    
Version: 6.3.2CC: msimka, smarlow
Target Milestone: ---   
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2015-09-24 18:12:35 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Attachments:
Description Flags
sample test project none

Description Gary Hu 2014-10-13 22:11:23 UTC
Created attachment 946611 [details]
sample test project

The issue is related
  - composite primary key
  - javassist instrument

When a composite primary key is instrumented by using javassit, it throws the following error:

 Tests run: 2, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 13.261 sec <<< FAILURE!
test01225809(com.redhat.gss.hibernate.test.EntityManagerTest)  Time elapsed: 4.075 sec  <<< ERROR!
javax.persistence.PersistenceException: org.hibernate.PropertyAccessException: could not get a field value by reflection getter of com.michaelrice.data.PrimaryKey.id
	at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1387)
	at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1310)
	at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:277)
	at com.redhat.gss.hibernate.test.EntityManagerTest.test01225809(EntityManagerTest.java:136)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at junit.framework.TestCase.runTest(TestCase.java:176)
	at junit.framework.TestCase.runBare(TestCase.java:141)
	at junit.framework.TestResult$1.protect(TestResult.java:122)
	at junit.framework.TestResult.runProtected(TestResult.java:142)
	at junit.framework.TestResult.run(TestResult.java:125)
	at junit.framework.TestCase.run(TestCase.java:129)
	at junit.framework.TestSuite.runTest(TestSuite.java:255)
	at junit.framework.TestSuite.run(TestSuite.java:250)
	at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:84)
	at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62)
	at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
	at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)
	at org.apache.maven.surefire.Surefire.run(Surefire.java:177)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:345)
	at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1009)
Caused by: org.hibernate.PropertyAccessException: could not get a field value by reflection getter of com.michaelrice.data.PrimaryKey.id
	at org.hibernate.property.DirectPropertyAccessor$DirectGetter.get(DirectPropertyAccessor.java:62)
	at org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValue(AbstractComponentTuplizer.java:76)
	at org.hibernate.type.ComponentType.getPropertyValue(ComponentType.java:413)
	at org.hibernate.type.ComponentType.getHashCode(ComponentType.java:254)
	at org.hibernate.engine.spi.EntityUniqueKey.generateHashCode(EntityUniqueKey.java:85)
	at org.hibernate.engine.spi.EntityUniqueKey.<init>(EntityUniqueKey.java:66)
	at org.hibernate.loader.Loader.loadFromResultSet(Loader.java:1719)
	at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1627)
	at org.hibernate.loader.Loader.getRow(Loader.java:1509)
	at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:719)
	at org.hibernate.loader.Loader.processResultSet(Loader.java:949)
	at org.hibernate.loader.Loader.doQuery(Loader.java:917)
	at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:348)
	at org.hibernate.loader.Loader.doList(Loader.java:2550)
	at org.hibernate.loader.Loader.doList(Loader.java:2536)
	at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2366)
	at org.hibernate.loader.Loader.list(Loader.java:2361)
	at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:495)
	at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:357)
	at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:198)
	at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1194)
	at org.hibernate.internal.QueryImpl.list(QueryImpl.java:101)
	at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:268)
	... 24 more
Caused by: java.lang.IllegalArgumentException: Can not set java.lang.Long field com.michaelrice.data.PrimaryKey.id to org.hibernate.bytecode.instrumentation.spi.LazyPropertyInitializer$1
	at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:164)
	at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:168)
	at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:55)
	at sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:36)
	at java.lang.reflect.Field.get(Field.java:379)
	at org.hibernate.property.DirectPropertyAccessor$DirectGetter.get(DirectPropertyAccessor.java:59)
	... 46 more


The org.hibernate.tool.instrument.javassist.InstrumentTask is used to instument the entity classes. Here is what's used in the pom.xml:
        <plugin>
                <artifactId>maven-antrun-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>process-classes</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <tasks>
                        <taskdef name="instrument" classname="org.hibernate.tool.instrument.javassist.InstrumentTask">
                            <classpath>
                                <path refid="maven.runtime.classpath" />
                                <path refid="maven.plugin.classpath" />
                            </classpath>
                        </taskdef>
                        <instrument verbose="false">
                            <fileset dir="${project.build.outputDirectory}">
                                <include name="*my_entity_classes.class" />
                            </fileset>
                        </instrument>
                    </tasks>
                </configuration>
            </plugin> 
  
I've attached a sample project that uses EAP 6.3.0(Hibernate 4.2.14.SP1-redhat-1) to demonstrate the issue.

The EntityManagerTest class contains two test methods, test01225809 and test01225809_2. The method test01225809 shows the issue and the method test01225809_2 shows that if the composite primary key is not used the issue is gone. 

It seems that when Hibernate loads the data from database and tries to bind them with the entity class, it needs to generates an unique hashCode. It has its own algorithm to create such hashCode.

         public int getHashCode(Object x, EntityMode entityMode, SessionFactoryImplementor factory) {
		int result = 17;
		Object[] values = getPropertyValues( x, entityMode );
		for ( int i = 0; i < propertySpan; i++ ) {
			Object y = values[i];
			result *= 37;
			if ( y != null ) {
				result += propertyTypes[i].getHashCode( y, entityMode, factory );
			}
		}
		return result;
          }


For the composite primary key, it needs to access each field and use its value to generate the hashCode.  Consequently, it calls the filed's getter method to obtain the value. However, the javassist instrument modifies the getter method and causes error.

Comment 1 Gail Badner 2014-10-16 19:27:42 UTC
I have verified this issue. I've asked Steve Ebersole to look into this. He can do that later tonight or tomorrow.