Hi,
The problem can be summarised as follow:
- If an hibernate entity object has proxy attribute is defined inside class node of hbm.xml file, ClassMetaData.getPropertyValue() of any property will throw IllegalArgumentException;
- Regardless whether Reflection API is used or hibernate.cglib.use_reflection_optimizer is either set to true or false;
- If the proxy attribute is not defined, ClassMetaData::getPropertyValue() / ClassMetaData::getPropertyValues() returns the values successfully; and
- Accessing the TsRecStat property by invoking TsPassword::getTsRecStat() does not cause exception to be thrown in any of the case.
My question:
- If reflection API should not be used to access the property value, shouldn't hibernate ClassMetaData API be used to access the property value?
Tested environment:
- Hibernate 3.1.2
- Hibernate 3.1.3
- Postgresql 8.1
- Jdk 1.5.0_06
- Windows XP SP2
The test code:
Code:
public void testAccessingTsPasswordProxyWithClassMetaDataAPI()
{
Session currentSession = null;
Transaction transaction = null;
try
{
ClassMetadata passwordClassMetaData = m_sessionFactory.getClassMetadata( TsPassword.class );
currentSession = m_sessionFactory.openSession();
transaction = currentSession.beginTransaction();
Query query = currentSession.createQuery( "FROM TsPassword AS p" );
Iterator it = query.iterate();
while( it.hasNext() )
{
Object obj = it.next();
ITsPassword itspassword = (ITsPassword) obj;
Date tsExpiryTimestamp = itspassword.getTsExpiryTimestamp();
passwordClassMetaData.getPropertyValue( itspassword, "TsRecStat", EntityMode.POJO );
Object expiryFromPasswordInterface = passwordClassMetaData.getPropertyValue(
itspassword, "TsExpiryTimestamp", EntityMode.POJO
);
assertEquals( "Expiry timestamp from interface", tsExpiryTimestamp, expiryFromPasswordInterface );
Object propertyValue = passwordClassMetaData.getPropertyValue(
obj, "TsExpiryTimestamp", EntityMode.POJO
);
assertEquals( "Expiry timestamp from raw object", tsExpiryTimestamp, propertyValue );
}
transaction.commit();
} catch( HibernateException he )
{
he.printStackTrace();
fail( "Hibernate exception occurred." );
if( transaction != null )
{
transaction.rollback();
}
} catch( Exception e )
{
e.printStackTrace();
fail( "Something else exception occured." );
if( transaction != null )
{
transaction.rollback();
}
}
finally
{
if( currentSession != null )
{
currentSession.close();
}
}
}
Line 78 is
Code:
passwordClassMetaData.getPropertyValue( itspassword, "TsRecStat", EntityMode.POJO );
The exception:
Code:
IllegalArgumentException in class: com.tokuii.baseapp.conf.redbull.v1.data.TsPassword, getter method of property: TsRecStat
org.hibernate.PropertyAccessException: IllegalArgumentException occurred calling getter of com.tokuii.baseapp.conf.redbull.v1.data.TsPassword.TsRecStat
at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:171)
at org.hibernate.tuple.AbstractEntityTuplizer.getPropertyValue(AbstractEntityTuplizer.java:270)
at org.hibernate.tuple.AbstractEntityTuplizer.getPropertyValue(AbstractEntityTuplizer.java:280)
at org.hibernate.persister.entity.AbstractEntityPersister.getPropertyValue(AbstractEntityPersister.java:3252)
at com.tokuii.tests.component.hibernate.HibernateProxyTest.testAccessingTsPasswordProxyWithClassMetaDataAPI(Hibe
rnateProxyTest.java:78)
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:145)
... 50 more
Hbm.xml:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.tokuii.baseapp.conf.redbull.v1.data.TsPassword" table="TsPassword" proxy="com.tokuii.system.ITsPassword">
<id name="Id" type="long" unsaved-value="0">
<generator class="native"/>
</id>
<version column="TsVersion" name="TsVersion"/>
<many-to-one name="TsCreateUser" class="com.tokuii.baseapp.conf.redbull.v1.data.TsUser"/>
<many-to-one name="TsModifyUser" class="com.tokuii.baseapp.conf.redbull.v1.data.TsUser"/>
<property name="TsCreateTimestamp" type="timestamp" column="TsCreateTimestamp" not-null="false"/>
<property name="TsModifyTimestamp" type="timestamp" column="TsModifyTimestamp" not-null="false"/>
<property name="TsRecStat" type="java.lang.String" column="TsRecStat" not-null="false"/>
<property name="TsSysRowState" type="java.lang.String" column="TsSysRowState" not-null="false"/>
<property name="TsExpiryTimestamp" type="timestamp" column="TsExpiryTimestamp" not-null="false"/>
<property name="TsPassword" type="java.lang.String" column="TsPassword" not-null="false" length="50"/>
<property name="TsPwChangeRestriction" type="java.lang.Boolean" column="TsPwChangeRestriction" not-null="false"/>
<property name="TsPwValidity" type="java.lang.String" column="TsPwValidity" not-null="false"/>
</class>
</hibernate-mapping>
The TsPassword.java:
Code:
public class TsPassword implements com.tokuii.system.ITsPassword {
private java.lang.Long m_Id;
private int m_TsVersion = 1;
private com.tokuii.system.ITsUser m_TsCreateUser;
private com.tokuii.system.ITsUser m_TsModifyUser;
private java.util.Date m_TsCreateTimestamp;
private java.util.Date m_TsModifyTimestamp;
private java.lang.String m_TsRecStat = "A";
private java.lang.String m_TsSysRowState = "P";
private java.util.Date m_TsExpiryTimestamp;
private java.lang.String m_TsPassword; // Natural Identifier
private java.lang.Boolean m_TsPwChangeRestriction;
private java.lang.String m_TsPwValidity;
private com.tokuii.system.ITsUser m_TsUserId; // Natural Identifier
private java.util.Set m_TsPasswordIdTsUser;
/** Non-persistent field. */
private java.util.Map m_NonDBFields;
public TsPassword() {
}
public java.lang.Long getId() {
return m_Id;
}
public void setId(java.lang.Long newId) {
m_Id = newId;
}
public int getTsVersion() {
return m_TsVersion;
}
public void setTsVersion(int newTsVersion) {
m_TsVersion = newTsVersion;
}
public Object getNonDBField(String fieldName) {
synchronized (this) {
if (m_NonDBFields == null) {
return null;
}
return m_NonDBFields.get(fieldName);
}
}
public void setNonDBField(String fieldName, Object value) {
synchronized (this) {
if (m_NonDBFields == null) {
m_NonDBFields = new java.util.HashMap();
}
m_NonDBFields.put(fieldName, value);
}
}
public com.tokuii.system.ITsUser getTsCreateUser() {
return m_TsCreateUser;
}
public void setTsCreateUser(com.tokuii.system.ITsUser newTsCreateUser) {
m_TsCreateUser = newTsCreateUser;
}
public com.tokuii.system.ITsUser getTsModifyUser() {
return m_TsModifyUser;
}
public void setTsModifyUser(com.tokuii.system.ITsUser newTsModifyUser) {
m_TsModifyUser = newTsModifyUser;
}
public java.util.Date getTsCreateTimestamp() {
return m_TsCreateTimestamp;
}
public void setTsCreateTimestamp(java.util.Date newTsCreateTimestamp) {
m_TsCreateTimestamp = newTsCreateTimestamp;
}
public java.util.Date getTsModifyTimestamp() {
return m_TsModifyTimestamp;
}
public void setTsModifyTimestamp(java.util.Date newTsModifyTimestamp) {
m_TsModifyTimestamp = newTsModifyTimestamp;
}
public java.lang.String getTsRecStat() {
return m_TsRecStat;
}
public void setTsRecStat(java.lang.String newTsRecStat) {
m_TsRecStat = newTsRecStat;
}
public java.lang.String getTsSysRowState() {
return m_TsSysRowState;
}
public void setTsSysRowState(java.lang.String newTsSysRowState) {
m_TsSysRowState = newTsSysRowState;
}
public java.util.Date getTsExpiryTimestamp() {
return m_TsExpiryTimestamp;
}
public void setTsExpiryTimestamp(java.util.Date newTsExpiryTimestamp) {
m_TsExpiryTimestamp = newTsExpiryTimestamp;
}
public java.lang.String getTsPassword() {
return m_TsPassword;
}
public void setTsPassword(java.lang.String newTsPassword) {
m_TsPassword = newTsPassword;
}
public java.lang.Boolean getTsPwChangeRestriction() {
return m_TsPwChangeRestriction;
}
public void setTsPwChangeRestriction(java.lang.Boolean newTsPwChangeRestriction) {
m_TsPwChangeRestriction = newTsPwChangeRestriction;
}
public java.lang.String getTsPwValidity() {
return m_TsPwValidity;
}
public void setTsPwValidity(java.lang.String newTsPwValidity) {
m_TsPwValidity = newTsPwValidity;
}
public com.tokuii.system.ITsUser getTsUserId() {
return m_TsUserId;
}
public void setTsUserId(com.tokuii.system.ITsUser newTsUserId) {
m_TsUserId = newTsUserId;
}
public java.util.Set getTsPasswordIdTsUser() {
synchronized (this) {
if (m_TsPasswordIdTsUser == null) {
m_TsPasswordIdTsUser = new java.util.HashSet();
}
}
return m_TsPasswordIdTsUser;
}
public void setTsPasswordIdTsUser(java.util.Set newTsPasswordIdTsUser) {
m_TsPasswordIdTsUser = newTsPasswordIdTsUser;
}
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final TsPassword that = (TsPassword) o;
if (m_TsPassword != null ? !m_TsPassword.equals(that.m_TsPassword) : that.m_TsPassword != null) {
return false;
}
Object thisId = m_TsUserId != null ? m_TsUserId.getId() : null;
Object thatId = that.m_TsUserId != null ? that.m_TsUserId.getId() : null;
if (thisId != null ? !thisId.equals(thatId) : thatId != null) {
return false;
}
return true;
}
public int hashCode() {
int result = 0;
result = 29 * result + (m_TsPassword != null ? m_TsPassword.hashCode() : 0);
result = 29 * result + (m_TsUserId != null && m_TsUserId.getId() != null ? m_TsUserId.getId().hashCode() : 0);
return result;
}
}
The interface:
Code:
public interface ITsPassword extends java.io.Serializable
{
java.lang.Long getId();
void setId( java.lang.Long aLong );
int getTsVersion();
void setTsVersion( int index );
java.lang.Object getNonDBField( java.lang.String elementLinkName );
void setNonDBField( java.lang.String elementLinkName, java.lang.Object object );
com.tokuii.system.ITsUser getTsCreateUser();
void setTsCreateUser( com.tokuii.system.ITsUser iTsUser );
java.util.Date getTsCreateTimestamp();
void setTsCreateTimestamp( java.util.Date date );
com.tokuii.system.ITsUser getTsModifyUser();
void setTsModifyUser( com.tokuii.system.ITsUser iTsUser );
java.util.Date getTsModifyTimestamp();
void setTsModifyTimestamp( java.util.Date date );
java.lang.String getTsRecStat();
void setTsRecStat( java.lang.String elementLinkName );
java.lang.String getTsSysRowState();
void setTsSysRowState( java.lang.String elementLinkName );
java.util.Date getTsExpiryTimestamp();
void setTsExpiryTimestamp( java.util.Date date );
java.lang.String getTsPassword();
void setTsPassword( java.lang.String elementLinkName );
java.lang.Boolean getTsPwChangeRestriction();
void setTsPwChangeRestriction( java.lang.Boolean aBoolean );
java.lang.String getTsPwValidity();
void setTsPwValidity( java.lang.String elementLinkName );
com.tokuii.system.ITsUser getTsUserId();
void setTsUserId( com.tokuii.system.ITsUser iTsUser );
java.util.Set getTsPasswordIdTsUser();
void setTsPasswordIdTsUser( java.util.Set set );
}