-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 
Author Message
 Post subject: Problem with hibernate proxy object and ClassMetaData
PostPosted: Wed Apr 12, 2006 1:42 am 
Newbie

Joined: Sat Nov 22, 2003 9:21 pm
Posts: 18
Location: Malaysia
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 );
}


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 27, 2007 11:11 am 
Newbie

Joined: Thu Sep 27, 2007 10:48 am
Posts: 5
I'm generally against code generation. I don't like bloat, duplication and many other evils caused by it.

For a long time, I've been annoyed by all the code that must be written and/or generated to simply read and display raw data from the database. Although many properties of a POJO are required for proper processing of business rules, workflow, and general domain model design, most properties are just shuttled from the database to the view and are never referenced by the business logic.

When I look at code for PHP or Ruby I get very jealous. In some codebases, they use metadata to determine the properties of classes at runtime. I look at similar Java projects and I cringe.

While some have asserted that getters and setters are evil, I'm not quite that militant about it. I just think that if you aren't going to access a property in your hand-written business logic, it shouldn't exist.

I've been thinking about trying something new. I was thinking about making my data objects publish a Map, or something similar, to allow dyamic access to data properties. I know some of you may be thinking I've lost my mind, and I wouldn't blame you if I intended to do this for all properties. I am just thinking of doing this for properties that come from the database and are read by the view. Another exception might be if they are only read by a rules engine. I could get hibernate to play nicely by implementing my own PropertyAccessor. It's also possible to tell BeanInfo how to properly access the properties. The biggest technical issue would be protecting the dynamic values from being accessed by a programmer.

I believe this will greatly reduce the total KLOC, decrease compile times, promote a simpler domain model, and improve the maintainability of the code base. I could add new columns to the database without having to recompile or possibly even redeploy. User-defined fields would be a snap. Am I crazy or is this a good idea?


----

“Change the changeable, accept the unchangeable, and remove yourself from the unacceptable.” ~ Denis Waitley
forsalebyowner


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.