I am having a strange issue when using Criteria queries and FetchMode with an @EmbeddedId entity.
The entity in question has a PK field from the embedded ID class also mapped as a FK join column in a @ManyToOne association (with insertable=false, updatable=false), which may have something to do with the problem.
When BasicPropertyAccessor tries to invoke the getter for this field in the embedded ID class, the actual target object being passed for the method invocation is the entity class not the ID class. Thus, an IllegalArgumentException results.
The issue only occurs when using FetchMode to join a child collection. Querying with no FetchMode works OK.
Any ideas or pointers on what I may have screwed up appreciated.
The Criteria query that causes the problem:
Code:
Criteria crit = session.createCriteria(AttributeValueSet.class).setFetchMode("attributeValues", FetchMode.JOIN);
The relevant pieces of the entity class:
Code:
@Entity
@Table(name="AttributeValueSet")
@Immutable
@Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class AttributeValueSet extends AbstractSurrogateIdObject implements Serializable, CompositeIdObject<AttributeValueSetId>{
protected AttributeDefinitionSet attributeDefinitionSet;
protected List<AttributeValue> attributeValues = new ArrayList<AttributeValue>();
private AttributeValueSetId compositeId;
@EmbeddedId
public AttributeValueSetId getCompositeId() {
return compositeId;
}
public void setCompositeId(AttributeValueSetId id) {
this.compositeId = id;
}
@ManyToOne(optional=false)
@JoinColumn(name="attributeDefinitionSetId", referencedColumnName="SurrogateId", insertable=false, updatable=false)
public AttributeDefinitionSet getAttributeDefinitionSet() {
return attributeDefinitionSet;
}
public void setAttributeDefinitionSet(
AttributeDefinitionSet attributeDefinitionSet) {
this.attributeDefinitionSet = attributeDefinitionSet;
}
@OneToMany(cascade={CascadeType.ALL}, mappedBy="attributeValueSet")
public List<AttributeValue> getAttributeValues() {
return attributeValues;
}
public void setAttributeValues(List<AttributeValue> attributeValues) {
this.attributeValues = attributeValues;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((getCompositeId() == null) ? 0 : getCompositeId().hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
AttributeValueSet other = (AttributeValueSet) obj;
if (getCompositeId() == null) {
if (other.getCompositeId() != null)
return false;
} else if (!getCompositeId().equals(other.getCompositeId()))
return false;
return true;
}
}
The composite ID class:
Code:
@Embeddable
public class AttributeValueSetId implements Serializable{
private String attributeDefinitionSetId;
private String attributeValueSetKey;
@Basic
public String getAttributeDefinitionSetId() {
return attributeDefinitionSetId;
}
public void setAttributeDefinitionSetId(String attributeDefinitionSetId) {
this.attributeDefinitionSetId = attributeDefinitionSetId;
}
@Basic
public String getAttributeValueSetKey() {
return attributeValueSetKey;
}
public void setAttributeValueSetKey(String attributeValueSetId) {
this.attributeValueSetKey = attributeValueSetId;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime
* result
+ ((attributeDefinitionSetId == null) ? 0
: attributeDefinitionSetId.hashCode());
result = prime
* result
+ ((attributeValueSetKey == null) ? 0 : attributeValueSetKey
.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
AttributeValueSetId other = (AttributeValueSetId) obj;
if (attributeDefinitionSetId == null) {
if (other.attributeDefinitionSetId != null)
return false;
} else if (!attributeDefinitionSetId
.equals(other.attributeDefinitionSetId))
return false;
if (attributeValueSetKey == null) {
if (other.attributeValueSetKey != null)
return false;
} else if (!attributeValueSetKey.equals(other.attributeValueSetKey))
return false;
return true;
}
public AttributeValueSetId(String attributeDefinitionSetKey,
String attributeValueSetKey) {
super();
this.attributeDefinitionSetId = attributeDefinitionSetKey;
this.attributeValueSetKey = attributeValueSetKey;
}
public AttributeValueSetId() {
super();
}
}
The error:
Code:
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:308)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:321)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:220)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:301)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:303)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityCachePreloaderBean' defined in class path resource [persistence-bean-context.xml]: Invocation of init method failed; nested exception is org.hibernate.PropertyAccessException: IllegalArgumentException occurred calling getter of com.etse.model.derivation.AttributeValueSetId.attributeDefinitionSetId
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1420)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:580)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:84)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:1)
at org.springframework.test.context.TestContext.loadApplicationContext(TestContext.java:280)
at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:304)
... 24 more
Caused by: org.hibernate.PropertyAccessException: IllegalArgumentException occurred calling getter of com.etse.model.derivation.AttributeValueSetId.attributeDefinitionSetId
at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:198)
at org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValue(AbstractComponentTuplizer.java:77)
at org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValues(AbstractComponentTuplizer.java:83)
at org.hibernate.tuple.component.PojoComponentTuplizer.getPropertyValues(PojoComponentTuplizer.java:108)
at org.hibernate.type.ComponentType.getPropertyValues(ComponentType.java:382)
at org.hibernate.type.ComponentType.getHashCode(ComponentType.java:213)
at org.hibernate.engine.EntityKey.generateHashCode(EntityKey.java:126)
at org.hibernate.engine.EntityKey.<init>(EntityKey.java:70)
at org.hibernate.engine.StatefulPersistenceContext.getCollectionOwner(StatefulPersistenceContext.java:734)
at org.hibernate.engine.loading.CollectionLoadContext.getLoadingCollection(CollectionLoadContext.java:130)
at org.hibernate.loader.Loader.readCollectionElement(Loader.java:1151)
at org.hibernate.loader.Loader.readCollectionElements(Loader.java:774)
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:622)
at org.hibernate.loader.Loader.doQuery(Loader.java:829)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:274)
at org.hibernate.loader.Loader.doList(Loader.java:2533)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2276)
at org.hibernate.loader.Loader.list(Loader.java:2271)
at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:119)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1716)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:347)
at com.etse.persistence.cache.EntityCachePreloaderImpl.populateAttributeValueSets(EntityCachePreloaderImpl.java:26)
at com.etse.persistence.cache.EntityCachePreloaderImpl.populatePreloadEntities(EntityCachePreloaderImpl.java:20)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:42)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:161)
at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:55)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:161)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:50)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:161)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy48.populatePreloadEntities(Unknown Source)
at com.etse.persistence.cache.EntityCachePreloaderBean.afterPropertiesSet(EntityCachePreloaderBean.java:12)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1477)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1417)
... 37 more
Caused by: java.lang.IllegalArgumentException: object is not an instance of declaring class
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:172)
... 79 more