I think this is a bug. After adding some extra debugging to the hibernate code, Hibernate is passing in an array of of the properties and trying to call the getter on the array instead of the containing object. Hopefully, I can show this with the stack trace:
Code:
[00:07:27.864] [WARN ] BasicPropertyAccessor - ON instance class FlightKey
ON instance class FlightKey
Property [0] is airlineCode
Property [1] is airportCode
Property [2] is flightNumber
Property [3] is departureDate
[00:07:27.864] [WARN ] BasicPropertyAccessor - Invoking method public java.lang.String FlightKey.getAirlineCode()
[00:07:27.864] [WARN ] BasicPropertyAccessor - from class class FlightKey
[00:07:27.864] [WARN ] BasicPropertyAccessor - and property airlineCode
[00:07:27.864] [WARN ] BasicPropertyAccessor - ON instance class java.lang.String
[00:07:27.865] [WARN ] BasicPropertyAccessor - ON instance class java.lang.String
[00:07:27.865] [WARN ] BasicPropertyAccessor - ON instance class java.lang.Integer
[00:07:27.865] [WARN ] BasicPropertyAccessor - ON instance class java.sql.Timestamp
[00:07:27.865] [ERROR] BasicPropertyAccessor - IllegalArgumentException in class: FlightKey, getter method of property: airlineCode
[00:07:27.867] [DEBUG] JDBCTransaction - rollback
[00:07:27.873] [DEBUG] JDBCTransaction - re-enabling autocommit
[00:07:27.873] [DEBUG] JDBCTransaction - rolled back JDBC Connection
[00:07:27.873] [DEBUG] JDBCContext - after transaction completion
[00:07:27.873] [DEBUG] ConnectionManager - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
[00:07:27.874] [DEBUG] ConnectionManager - performing cleanup
[00:07:27.874] [DEBUG] ConnectionManager - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
[00:07:27.874] [DEBUG] JDBCContext - after transaction completion
[00:07:27.874] [DEBUG] ConnectionManager - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
[00:07:27.876] [ERROR] UpdateRequestProcessorChain - Error processing request
org.springframework.orm.hibernate3.HibernateSystemException: IllegalArgumentException occurred calling getter of FlightKey.airlineCode; nested exception is org.hibernate.PropertyAccessExce
Caused by:
org.hibernate.PropertyAccessException: IllegalArgumentException occurred calling getter of FlightKey.airlineCode
at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:187)
at org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValue(AbstractComponentTuplizer.java:66)
at org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValues(AbstractComponentTuplizer.java:79)
at org.hibernate.tuple.component.PojoComponentTuplizer.getPropertyValues(PojoComponentTuplizer.java:86)
at org.hibernate.type.ComponentType.getPropertyValues(ComponentType.java:353)
at org.hibernate.type.ComponentType.isEqual(ComponentType.java:123)
at org.hibernate.event.def.DefaultFlushEntityEventListener.checkNaturalId(DefaultFlushEntityEventListener.java:93)
at org.hibernate.event.def.DefaultFlushEntityEventListener.getValues(DefaultFlushEntityEventListener.java:169)
at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:120)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:196)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:76)
at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:35)
at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:969)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1562)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:283)
at org.springframework.orm.hibernate3.HibernateTemplate$35.doInHibernate(HibernateTemplate.java:984)
at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:372)
at org.springframework.orm.hibernate3.HibernateTemplate.findByCriteria(HibernateTemplate.java:974)
at org.springframework.orm.hibernate3.HibernateTemplate.findByCriteria(HibernateTemplate.java:967)
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:585)
at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:161)
... 57 more
The debugging code is this (pardon the lack of niceness):
BasicPropertyAccessor
Code:
public Object get(Object target) throws HibernateException {
try {
log.warn("Invoking method " + method);
log.warn("from class " + clazz);
log.warn("and property " + propertyName);
if (target.getClass().isArray()) {
for (Object targetx : (Object[])target) {
log.warn("ON instance " + targetx.getClass());
}
} else {
log.warn("ON instance " + target.getClass());
}
return method.invoke(target, null);
}
catch (InvocationTargetException ite) {
throw new PropertyAccessException(
ite,
"Exception occurred inside",
false,
clazz,
propertyName
);
}
catch (IllegalAccessException iae) {
throw new PropertyAccessException(
iae,
"IllegalAccessException occurred while calling",
false,
clazz,
propertyName
);
//cannot occur
}
catch (IllegalArgumentException iae) {
log.error(
"IllegalArgumentException in class: " + clazz.getName() +
", getter method of property: " + propertyName
);
throw new PropertyAccessException(
iae,
"IllegalArgumentException occurred calling",
false,
clazz,
propertyName
);
}
}
AbstractComponentTuplizer:
Code:
protected Component component;
protected AbstractComponentTuplizer(Component component) {
this.component = component;
propertySpan = component.getPropertySpan();
getters = new Getter[propertySpan];
setters = new Setter[propertySpan];
Iterator iter = component.getPropertyIterator();
boolean foundCustomAccessor=false;
int i = 0;
while ( iter.hasNext() ) {
Property prop = ( Property ) iter.next();
getters[i] = buildGetter( component, prop );
setters[i] = buildSetter( component, prop );
if ( !prop.isBasicPropertyAccessor() ) {
foundCustomAccessor = true;
}
i++;
}
hasCustomAccessors = foundCustomAccessor;
String[] getterNames = new String[propertySpan];
String[] setterNames = new String[propertySpan];
Class[] propTypes = new Class[propertySpan];
for ( int j = 0; j < propertySpan; j++ ) {
getterNames[j] = getters[j].getMethodName();
setterNames[j] = setters[j].getMethodName();
propTypes[j] = getters[j].getReturnType();
}
instantiator = buildInstantiator( component );
}
public Object[] getPropertyValues(Object component) throws HibernateException {
Iterator iter = this.component.getPropertyIterator();
int j = 0;
while ( iter.hasNext() ) {
Property prop = ( Property ) iter.next();
System.err.println("Property [" + j++ + "] is " + prop.getName());
}
Object[] values = new Object[propertySpan];
for ( int i = 0; i < propertySpan; i++ ) {
values[i] = getPropertyValue( component, i );
}
return values;
}