Problem with hibernate proxy object and ClassMetaData

Description

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?

2 postings have been made in regard to this on hibernate forum:

http://forum.hibernate.org/viewtopic.php?t=955828
http://forum.hibernate.org/viewtopic.php?t=958029

========================================================================================================================

THE TEST 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

passwordClassMetaData.getPropertyValue( itspassword, "TsRecStat", EntityMode.POJO );

The exception:

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:

<?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:

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:

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 );
}

Environment

Tested environment:

  • Hibernate 3.1.2

  • Hibernate 3.1.3

  • Postgresql 8.1

  • Jdk 1.5.0_06

  • Windows XP SP2 and Linux

Assignee

Unassigned

Reporter

DavidD

Fix versions

None

Labels

None

backPortable

None

Suitable for new contributors

None

Requires Release Note

None

Pull Request

None

backportDecision

None

Affects versions

Priority

Critical
Configure