-->
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.  [ 12 posts ] 
Author Message
 Post subject: IllegalArgumentException from CharBooleanType sub-class
PostPosted: Tue May 10, 2005 6:47 am 
Beginner
Beginner

Joined: Tue May 10, 2005 6:25 am
Posts: 20
Location: London
I'm having a bit of a problem with a custom user type. in my legacy database, one column can contain either a 'C', or a blank. I'd like to map these to true and false respectivly. This is very nearly the same as the true_false type, so I used TrueFalseType as a template:

Code:
package uk.co.trisystems.morph.user_type;

import java.sql.ResultSet;
import java.sql.SQLException;

import net.sf.hibernate.type.CharBooleanType;

public class BooleanCBlankType extends CharBooleanType {

    protected final String getTrueString() {
        return "C";
    }

    protected final String getFalseString() {
        return " ";
    }

}

My mapping document looks like so:

Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>

    <class name="uk.co.trisystems.morph.currency.CurrencyDAO" table="MACPFCC0">

...
       
        <property name="cancelled" column="CCCYCF" not-null="true" type="uk.co.trisystems.morph.user_type.BooleanCBlankType">
            <meta attribute="field-description">Currency Cancelled</meta>
        </property>

...

    </class>   
</hibernate-mapping>

I used hbm2java to generate my CurrencyDAO.java file. The cancelled property is an instance of BooleanCBlankType, and eberything generates and compiles OK. When I try to pull data from by database, though, I get an exception:

Code:
ERROR 11:40:41 net.sf.hibernate.property.BasicPropertyAccessor$BasicSetter.set():60 - IllegalArgumentException in class: uk.co.trisystems.morph.currency.CurrencyDAO, setter method of property: cancelled
ERROR 11:40:41 net.sf.hibernate.property.BasicPropertyAccessor$BasicSetter.set():64 - expected type: uk.co.trisystems.morph.user_type.BooleanCBlankType, actual value: java.lang.Boolean

Exception in thread "main" net.sf.hibernate.PropertyAccessException: IllegalArgumentException occurred while calling setter of uk.co.trisystems.morph.currency.CurrencyDAO.cancelled
   at net.sf.hibernate.property.BasicPropertyAccessor$BasicSetter.set(BasicPropertyAccessor.java:68)
   at net.sf.hibernate.persister.AbstractEntityPersister.setPropertyValues(AbstractEntityPersister.java:229)
   at net.sf.hibernate.impl.SessionImpl.initializeEntity(SessionImpl.java:2224)
   at net.sf.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:319)
   at net.sf.hibernate.loader.Loader.doQuery(Loader.java:309)
   at net.sf.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:138)
   at net.sf.hibernate.loader.Loader.doList(Loader.java:1063)
   at net.sf.hibernate.loader.Loader.list(Loader.java:1054)
   at net.sf.hibernate.hql.QueryTranslator.list(QueryTranslator.java:854)
   at net.sf.hibernate.impl.SessionImpl.find(SessionImpl.java:1554)
   at net.sf.hibernate.impl.QueryImpl.list(QueryImpl.java:49)
   at uk.co.trisystems.morph.currency.CurrencyDAOTest.allCurrencies(CurrencyDAOTest.java:23)
   at uk.co.trisystems.morph.currency.CurrencyDAOTest.main(CurrencyDAOTest.java:54)
Caused by: java.lang.IllegalArgumentException: argument type mismatch
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
   at java.lang.reflect.Method.invoke(Unknown Source)
   at net.sf.hibernate.property.BasicPropertyAccessor$BasicSetter.set(BasicPropertyAccessor.java:38)
   ... 12 more

I included what looks like some revevant logging info in there, too. I've searched this forum and googled about a bit, but I can't find a solution to this. So, what am I doing stupid?

I'm using Hibernate 2.8.1, running against an AS/400 (iSeries).

_________________
Cheers,
Simon B,
simon@brunningonline.net,
http://www.brunningonline.net/simon/blog/


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 10, 2005 8:07 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
your type should be a UserType not a Hibernate Type.

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject: Subclassing net.sf.hibernate.type classes OK?
PostPosted: Tue May 10, 2005 8:22 am 
Beginner
Beginner

Joined: Tue May 10, 2005 6:25 am
Posts: 20
Location: London
max wrote:
your type should be a UserType not a Hibernate Type.


Are you saying that I can't sub-class anything from the net.sf.hibernate.type package, but must instead write my own from scratch, impementing UserType?

_________________
Cheers,
Simon B,
simon@brunningonline.net,
http://www.brunningonline.net/simon/blog/


Top
 Profile  
 
 Post subject: New implementation, same problem.
PostPosted: Tue May 10, 2005 8:30 am 
Beginner
Beginner

Joined: Tue May 10, 2005 6:25 am
Posts: 20
Location: London
Thanks for your time, Max.

OK, so I've written my own class. I've now got:

Code:
package uk.co.trisystems.morph.user_type;

public class BooleanCBlankType extends AbstractBooleanType {

    public final String getTrueString() {
        return "C";
    }

    public final String getFalseString() {
        return " ";
    }

}

and:

Code:
package uk.co.trisystems.morph.user_type;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

import org.apache.log4j.Logger;

import net.sf.hibernate.Hibernate;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.UserType;

public abstract class AbstractBooleanType implements UserType {
    protected final Logger logger = Logger.getLogger(this.getClass());

    public Object deepCopy(Object value) throws HibernateException {
        return value;
    }

    public boolean equals(Object x, Object y) throws HibernateException {
        return x == null ? y == null : x.equals(y);
    }

    public abstract String getFalseString();

    public abstract String getTrueString();

    public boolean isMutable() {
        return false;
    }

    public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
            throws HibernateException, SQLException {
        final Object nullSafeGet = Hibernate.CHARACTER
                .nullSafeGet(rs, names[0]);
        String databaseValue = String.valueOf(nullSafeGet);
        if (databaseValue == this.getTrueString()) {
            return Boolean.TRUE;
        } else {
            return Boolean.FALSE;
        }
    }

    public void nullSafeSet(PreparedStatement st, Object value, int index)
            throws HibernateException, SQLException {
        final boolean pojoValue = ((Boolean) value).booleanValue();
        if (pojoValue) {
            Hibernate.CHARACTER.nullSafeSet(st, this.getTrueString(), index);
        } else {
            Hibernate.CHARACTER.nullSafeSet(st, this.getFalseString(), index);
        }
    }

    public Class returnedClass() {
        return Boolean.class;
    }

    public int[] sqlTypes() {
        int[] typeList = { Types.CHAR };
        return typeList;
    }

}

I'm still getting exactly the same error messages. Clearly I didn't understand you, Max.

_________________
Cheers,
Simon B,
simon@brunningonline.net,
http://www.brunningonline.net/simon/blog/


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 10, 2005 8:32 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
what is the signature of your cancellable property ?

your returnedclass is saying it should take and return a Boolean - maybe yours are a boolean ?

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject: What should my property be?
PostPosted: Tue May 10, 2005 8:54 am 
Beginner
Beginner

Joined: Tue May 10, 2005 6:25 am
Posts: 20
Location: London
max wrote:
what is the signature of your cancellable property ?

your returnedclass is saying it should take and return a Boolean - maybe yours are a boolean ?


I don't think I've really got the hang of these user types yet. ;-) In my CurrencyDAO.hbm.xml file, I've got a property declared as so:

Code:
<property name="cancelled" column="CCCYCF" not-null="true" type="uk.co.trisystems.morph.user_type.BooleanCBlankType">
    <meta attribute="field-description">Currency Cancelled</meta>
</property>

CurrencyDAO.java is generated for me by hbm2java. I've not touched the code by hand at all. Its cancelled property is an instance of BooleanCBlankType, not boolean or Boolean. (Is this as it should be, or have I declared the property incorrectly in my hbm.xml file?) Here it is:

Code:
    /** persistent field */
    private BooleanCBlankType cancelled;

    /**
     * Currency Cancelled
     */
    public BooleanCBlankType getCancelled() {
        return this.cancelled;
    }

    public void setCancelled(BooleanCBlankType cancelled) {
        this.cancelled = cancelled;
    }

The BooleanCBlankType.java class that I've written returns Boolean.class from its returnedClass() method, and int[] typeList = {Types.CHAR} from its sqlTypes() method, indicating (I think) that the column on the database side is a CHAR field (and that only one column is involved), and that the java side value is a Boolean.

My nullSafeGet and nullSafeSet methods are responsible for performing the conversions. But I don't think that the problem lies with them, since they don't turn up in the traceback. Or is this an unwarrented assumption?

The problem that I can see is that in net.sf.hibernate.property.BasicPropertyAccessor$BasicSetter.set(), it's trying to call the CurrencyDAO.setCancelled() method with a Boolean, but it wants a BooleanCBlankType instead. So, either the CurrencyDAO.cancelled property ought to be a Boolean, or CurrencyDAO.setCancelled() should be passed a BooleanCBlankType. I am new to Hibernate, and I don't know which of these is the case.

I suspect that the problem lies in my CurrencyDAO.hbm.xml file somewhere, rather than in my UserType code, but I'm far from sure. ;-)

Your help is very much appreciated, Max.

_________________
Cheers,
Simon B,
simon@brunningonline.net,
http://www.brunningonline.net/simon/blog/


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 10, 2005 8:56 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
if you use hbm2java you need to have the UserType class in the classpath so hbm2java can actually load it and ask what class it should use.

/max

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject: Classpath
PostPosted: Tue May 10, 2005 8:59 am 
Beginner
Beginner

Joined: Tue May 10, 2005 6:25 am
Posts: 20
Location: London
max wrote:
if you use hbm2java you need to have the UserType class in the classpath so hbm2java can actually load it and ask what class it should use.

/max


hibernate2.jar is in the classpath. Is that OK?

_________________
Cheers,
Simon B,
simon@brunningonline.net,
http://www.brunningonline.net/simon/blog/


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 10, 2005 9:04 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
your usertype is not inside hibernate2.jar is it ? ;)

/max

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject: A dropping penny?
PostPosted: Tue May 10, 2005 9:09 am 
Beginner
Beginner

Joined: Tue May 10, 2005 6:25 am
Posts: 20
Location: London
max wrote:
your usertype is not inside hibernate2.jar is it ? ;)

/max


Nope, hibernate2.jar is as shipped.

Ah, are you saying that my type has to be in the classpath when hbm2java runs? My class is in the classpath at runtime, but it won't yet have compiled when hbm2java runs.

If I were to compile my user types prior to running hbm2java, would the generated CurrencyDAO.java file have the cancelled property as a Boolean rather than as a BooleanCBlankType?

_________________
Cheers,
Simon B,
simon@brunningonline.net,
http://www.brunningonline.net/simon/blog/


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 10, 2005 9:11 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
yes - how else did you expect hbm2java to discover what return type your type has ? ;)

/max

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject: Thanks!
PostPosted: Tue May 10, 2005 10:32 am 
Beginner
Beginner

Joined: Tue May 10, 2005 6:25 am
Posts: 20
Location: London
Thanks, Max. After a rather unseemly wrestling match with Ant, I have my my user types before hbm2java, and the hbm2java target has the correct classpath. All is now working beautifully.

Thanks very much, Max. I appreciate the help.

_________________
Cheers,
Simon B,
simon@brunningonline.net,
http://www.brunningonline.net/simon/blog/


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 12 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.