I think I found a bug, but per instructions on Jira I'm posting it here first for comments. I haven't found any references to this issue in Jira or on the web, but I could be missing them.
I have an abstract class that looks like this:
Code:
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Table(schema = "control")
public abstract class BaseFoo {
private boolean needsAction;
...
public void setNeedsAction(boolean needsAction) {
this.needsAction = needsAction;
}
public boolean isNeedsAction() {
return this.needsAction;
}
}
Then I have a child class that looks like this:
Code:
@Entity
@Table(schema="control")
public class OneParticularFoo extends BaseFoo {
...
public void setNeedsAction(Priority priority) {
...
setNeedsAction(true);
}
}
You'll see the child class has a "setter" (not actually a bean-style setter) with the same name as the parent class' setter, but a different argument. There is no getNeedsAction method which returns a Priority, there is only the getter on the parent class.
With this setup, I get the following exception:
Code:
org.springframework.orm.hibernate3.HibernateSystemException: IllegalArgumentException occurred while calling setter of com.mycompany.domain.OneParticularFoo.needsAction; nested exception is org.hibernate.PropertyAccessException: IllegalArgumentException occurred while calling setter of com.mycompany.domain.OneParticularFoo.needsAction
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:676)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:95)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:212)
at org.springframework.orm.jpa.JpaAccessor.translateIfNecessary(JpaAccessor.java:152)
at org.springframework.orm.jpa.JpaTemplate.execute(JpaTemplate.java:189)
at org.springframework.orm.jpa.JpaTemplate.executeFind(JpaTemplate.java:151)
at org.springframework.orm.jpa.JpaTemplate.find(JpaTemplate.java:311)
...
Caused by: java.lang.IllegalArgumentException: argument type mismatch
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$BasicSetter.set(BasicPropertyAccessor.java:42)
The problem seems to be that Hibernate is calling the method on the child class which has the correct name but the wrong argument, instead of the actual setter on the parent class. My successful workaround was to create a setNeedsAction(boolean) method on the child class which simply delegates to the parent class. Leaving aside the issue of whether it's good design to have my transient child class method named "setNeedsAction" - it's probably not - shouldn't Hibernate be looking for a setter based on the complete method signature, not just the name?
As you can see I'm using annotation-based configuration, but here is my persistence.xml:
Code:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
<persistence-unit name="Bar" transaction-type="RESOURCE_LOCAL">
<class>com.mycompany.domain.OneParticularFoo</class>
...
<properties>
<property name="hibernate.archive.autodetection" value="class, hbm" />
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.use_sql_comments" value="false" />
<property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.SingletonEhCacheProvider" />
<property name="net.sf.ehcache.configurationResourceName" value="/ehcache.xml" />
<property name="hibernate.cache.use_query_cache" value="true" />
<property name="hibernate.cache.use_second_level_cache" value="true" />
<property name="hibernate.generate_statistics" value="true" />
<!-- RepeatableRead -->
<property name="hibernate.connection.isolation" value="4" />
</properties>
</persistence-unit>
</persistence>
I'm using Hibernate 3.2.6.