ibatis-user-java mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Niels Beekman" <n.beek...@wis.nl>
Subject RE: JAVA 1.5 enum > typehandler woes
Date Tue, 06 Nov 2007 00:36:39 GMT
Since it's likely you are referring to the Javadocs, let me paste them
here:

 

* Returns the name of this enum constant, exactly as declared in its
enum declaration.

* 

* <b>Most programmers should use the {@link #toString} method in

* preference to this one, as the toString method may return

* a more user-friendly name.</b>  This method is designed primarily for

* use in specialized situations where correctness depends on getting the

* exact name, which will not vary from release to release.

 

If I'm reading this right, you would want to use name(), since we are
interested in a non-varying exact name.

 

Niels

________________________________

From: Raymond McDermott [mailto:ray@mcdermott.be] 
Sent: dinsdag 6 november 2007 0:32
To: user-java@ibatis.apache.org
Subject: Re: JAVA 1.5 enum > typehandler woes

 

One further (perhaps obvious) follow-up point was that after I had
specified the typehandlers properly I no longer needed to map them
explicitly on the SELECT statement.

Finally I have one small update to the generic enum handler code (use
Enum.toString() rather than Enum.name() ):

import java.sql.SQLException;

import com.ibatis.sqlmap.client.extensions.ParameterSetter;
import com.ibatis.sqlmap.client.extensions.ResultGetter;
import com.ibatis.sqlmap.client.extensions.TypeHandlerCallback; 

public abstract class EnumTypeHandler<E extends Enum> implements
TypeHandlerCallback 
{
    private Class<E> enumClass_; 
    
    public EnumTypeHandler(Class<E> enumClass) 
    {
        enumClass_ = enumClass; 
    }

    @SuppressWarnings("unchecked")
    public void setParameter(ParameterSetter setter, Object parameter) 
            throws SQLException
    {
        // use toString rather than name -- as suggested by the 1.5
official documentation
        setter.setString(((E) parameter).toString());
    }

    public Object getResult(ResultGetter getter) throws SQLException 
    {
        return valueOf( getter.getString());
    }

    @SuppressWarnings("unchecked")
    public Object valueOf(String s) 
    {
        return Enum.valueOf(enumClass_, s);
    }
}

On 06/11/2007, Raymond McDermott <ray@mcdermott.be> wrote:

I followed your advice on the typehandler properties on the select
statement and it started to work.  Great!

I also have to rescind one of my earlier statements.  I did some more
debugging on the INSERT statement and although the property values are
all being set nicely, there was no typehandler :( 

So I looked again at the manual and at the typeHandler definitions.  The
reason that it does not associate the typehandler with the correct types
is that I have incorrectly specced the type handler thus:

<typeHandler javaType=" domain.Frequency"
                    jdbcType="VARCHAR"
                    callback="typehandlers.FrequencyTypeHandler"/> 

Once I removed the jdbcType it all started to work nicely :)

<typeHandler javaType="domain.Frequency"
                    callback="typehandlers.FrequencyTypeHandler"/>

So all is well that ends well.

Thanks for the pointers and the support.

Best regards

Ray





On 05/11/2007, Raymond McDermott <ray@mcdermott.be> wrote:

I have not tried it on the select.  Good idea.  I will do that and post
back any new information. 

I don't know how I would be more explicit for the INSERT.  Do I have to
decompose the definition of the parameter class?  Given that I know from
the debugger that the typehandler is definitely called on the INSERT,
what benefit would that bring? 





On 05/11/2007, Niels Beekman < n.beekman@wis.nl
<mailto:n.beekman@wis.nl> > wrote:

Have you tried to define the typehandler explicitly on the resultmap or
insert statement? Do both select and insert blow up?

 

Niels

________________________________

From: Raymond McDermott [mailto:ray@mcdermott.be] 
Sent: maandag 5 november 2007 10:45
To: user-java@ibatis.apache.org
Subject: Re: JAVA 1.5 enum > typehandler woes

 

Thanks for the comments Niels.  I read the FAQ entry completely before
posting and used it to drive the coded solution.

In terms of the stacktrace, it is the complete stacktrace from Eclipse.
I think it gives enough to show that there is genuinely a problem with
the typehandler. 

I have debugged it all the way line by line, including adding the iBATIS
source code to the project.  The data is good and it should return a
valid value - this is shown in the debugger - but somehow between the
typehandler returning a value from the ENUM and coming back into iBATIS,
the value goes null. 

That is why I wondered if there is something that I needed to do with
the enum itself?

Thanks for the continued support.

Ray

On 05/11/2007, Niels Beekman < n.beekman@wis.nl
<mailto:n.beekman@wis.nl> > wrote:

Hi,

 

Are you sure this is the complete stacktrace? Did you try debugging?

This error can be caused by numerous things, for example the property
frequency can be null in your bean, ensure that you are handling the
null-case in your typehandler, for a comprehensive explanation, see:

http://opensource.atlassian.com/confluence/oss/display/IBATIS/How+do+I+u
se+a+Custom+Type+Handler+with+complex+property+or+Type+Safe+Enumeration

 

Hth,

 

Niels

________________________________

From: Raymond McDermott [mailto: ray@mcdermott.be] 
Sent: zondag 4 november 2007 21:57
To: user-java@ibatis.apache.org
Subject: JAVA 1.5 enum > typehandler woes

 

I am having some, ahem, fun trying to get enums persisting as varchars
using iBatis 2.3 for Java

Can I just check something... is there are a 'proper' way for iBATIS to
persist enums or do we really have to write a typehandler?  Is this is
something that the developer group will patch in 2.x or is there
something more fundamental in the architecture that makes it a 3.0
feature?

Also, I wonder if i have to do something extra in the definition of an
ENUM to support access by the typehandler framework? 

Anyway, for the moment it seems that we are stuck with the, IMHO overly
complex, task of scripting support for our enum types.  I am getting
null pointers despite debugging the code and seeing that the typehandler
is being properly registered and invoked. 

I have a simple enum class 'frequency':

---> ENUM START

/**
 * The frequency over which measurements are made
 */

public enum Frequency {
    DAILY, 
    WEEKLY, 
    MONTHLY, 
    YEARLY
}


---> ENUM END

I used the generic enum typehandler from the FAQ:

---> GENERIC TYPEHANDLER START

import java.sql.SQLException;

import com.ibatis.sqlmap.client.extensions.ParameterSetter;
import com.ibatis.sqlmap.client.extensions.ResultGetter;
import com.ibatis.sqlmap.client.extensions.TypeHandlerCallback ;

public abstract class EnumTypeHandler<E extends Enum> implements
TypeHandlerCallback
{
    private Class<E> enumClass_;
    
    public EnumTypeHandler(Class<E> enumClass)
    {
        enumClass_ = enumClass;
    }

    @SuppressWarnings("unchecked")
    public void setParameter(ParameterSetter setter, Object parameter)
            throws SQLException
    {
        setter.setString(((E) parameter).name());
    }

    public Object getResult(ResultGetter getter) throws SQLException
    {
        return valueOf(getter.getString());
    }

    @SuppressWarnings("unchecked") 
    public Object valueOf(String s)
    {
        return Enum.valueOf(enumClass_, s);
    }
}

---> GENERIC TYPEHANDLER END

Then I have the simple implementation as proposed in the FAQ:

---> SPECIFIC TYPEHANDLER START

public class FrequencyTypeHandler extends EnumTypeHandler<Frequency> {
    
    public FrequencyTypeHandler() {
    super(Frequency.class);
    }

}

---> SPECIFIC TYPEHANDLER END

---> IBATIS CONFIGURATION FILE START

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE sqlMapConfig      
    PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"      
    "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">

<sqlMapConfig>

    <typeHandler     javaType="
com.opengrail.circles365.domain.Frequency"
                    jdbcType="VARCHAR"
 
callback="com.opengrail.circles365.config.ibatis.typehandlers.FrequencyT
ypeHandler"/> 

    <typeHandler
javaType="com.opengrail.circles365.domain.MeasurementType"
                    jdbcType="VARCHAR"
 
callback="com.opengrail.circles365.config.ibatis.typehandlers.Measuremen
tTypeTypeHandler "/>


    <!-- List the SQL Map XML files. They can be loaded from the 
         classpath, as they are here (com.domain.data...) -->

    <sqlMap resource="com/opengrail/circles365/config/iBatis-
User.xml"/>
    <sqlMap
resource="com/opengrail/circles365/config/iBatis-MeasurementItem.xml"/>

</sqlMapConfig>

---> IBATIS CONFIGURATION FILE END

---> IBATIS SQLMAP FILE START

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE sqlMap 
    PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
    " http://ibatis.apache.org/dtd/sql-map-2.dtd
<http://ibatis.apache.org/dtd/sql-map-2.dtd> ">

<sqlMap namespace="MeasurementItem">

    <resultMap id="result"
class="com.opengrail.circles365.domain.impl.MeasurementItemImpl ">
        <result property="frequency" column="FREQUENCY"/>
        <result property="measurementType" column="MEASUREMENTTYPE"/>
        <result property="name" column="ITEMNAME"/> 
        <result property="derived" column="ISDERIVED"/>
    </resultMap>

    <select id="findMeasurementItemsByUserId" resultMap="result">
        select     FREQUENCY, MEASURETYPE, ITEMNAME, ISDERIVED 
        from     C365MEASUREMENTITEM MI, C365USER U
        where    U.USERID = #value#
        and        MI.USERID = U.ID
    </select>

    <insert id="createMeasurementItem" parameterClass="
com.opengrail.circles365.domain.MeasurementItem">
        insert 
        into C365MEASUREMENTITEM (frequency, measuretype, itemname,
isderived, userid)
            select     #frequency#, #measurementType#, #name#,
#derived#, u.id
            from     c365user u
            where     u.userid = #userId#
    </insert>

</sqlMap>

---> IBATIS SQLMAP FILE END

Unit test trace ON INSERT: 

org.springframework.jdbc.UncategorizedSQLException: SqlMapClient
operation; uncategorized SQLException for SQL []; SQL state [null];
error code [0];   
--- The error occurred in com/opengrail/circles365/config/iBatis-
MeasurementItem.xml.  
--- The error occurred while applying a parameter map.  
--- Check the createMeasurementItem-InlineParameterMap.  
--- Check the parameter mapping for the 'frequency' property.  
--- Cause: java.lang.NullPointerException; nested exception is
com.ibatis.common.jdbc.exception.NestedSQLException:   
--- The error occurred in
com/opengrail/circles365/config/iBatis-MeasurementItem.xml.  
--- The error occurred while applying a parameter map.  
--- Check the createMeasurementItem-InlineParameterMap.  
--- Check the parameter mapping for the 'frequency' property.  
--- Cause: java.lang.NullPointerException
Caused by: com.ibatis.common.jdbc.exception.NestedSQLException:   
--- The error occurred in
com/opengrail/circles365/config/iBatis-MeasurementItem.xml .  
--- The error occurred while applying a parameter map.  
--- Check the createMeasurementItem-InlineParameterMap.  
--- Check the parameter mapping for the 'frequency' property.  
--- Cause: java.lang.NullPointerException 
    at
com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeUpdat
e(GeneralStatement.java:94)
    at
com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.update(SqlMapExecut
orDelegate.java:505)
    at
com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.update(SqlMapSessionImpl
.java:90)
    at
org.springframework.orm.ibatis.SqlMapClientTemplate$10.doInSqlMapClient(
SqlMapClientTemplate.java:383)
    at org.springframework.orm.ibatis.SqlMapClientTemplate.execute
(SqlMapClientTemplate.java:193)
    at
org.springframework.orm.ibatis.SqlMapClientTemplate.update(SqlMapClientT
emplate.java:381)
    at
com.opengrail.circles365.data.impl.MeasurementItemDaoImpl.createMeasurem
entItem (MeasurementItemDaoImpl.java:13)
    at
com.opengrail.circles365.service.impl.MeasurementItemManagementImpl.crea
teMeasurementItem(MeasurementItemManagementImpl.java:25)
    at
com.opengrail.circles365.tests.ServiceImplementationTests.testGoodMeasur
ementItem (ServiceImplementationTests.java:56)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.jav
a:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke
(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at junit.framework.TestCase.runTest(TestCase.java:154)
    at junit.framework.TestCase.runBare(TestCase.java:127) 
    at
org.springframework.test.ConditionalTestCase.runBare(ConditionalTestCase
.java:69)
    at junit.framework.TestResult$1.protect(TestResult.java:106)
    at junit.framework.TestResult.runProtected(TestResult.java :124)
    at junit.framework.TestResult.run(TestResult.java:109)
    at junit.framework.TestCase.run(TestCase.java:118)
    at junit.framework.TestSuite.runTest(TestSuite.java:208)
    at junit.framework.TestSuite.run (TestSuite.java:203)
    at
org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUn
it3TestReference.java:130)
    at
org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.ja
va:38)
    at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTe
stRunner.java:460)
    at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTe
stRunner.java:673)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run
(RemoteTestRunner.java:386)
    at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRu
nner.java:196)
Caused by: java.lang.NullPointerException
    at
com.ibatis.sqlmap.engine.mapping.parameter.BasicParameterMap.setParamete
r (BasicParameterMap.java:165)
    at
com.ibatis.sqlmap.engine.mapping.parameter.BasicParameterMap.setParamete
rs(BasicParameterMap.java:125)
    at
com.ibatis.sqlmap.engine.execution.SqlExecutor.executeUpdate(SqlExecutor
.java :79)
    at
com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.sqlExecuteUp
date(GeneralStatement.java:200)
    at
com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeUpdat
e(GeneralStatement.java :78)
    ... 27 more

Do any of you folks have any ideas?

Thanks in advance for your support.

Ray




-- 
Ray McDermott
GSM 047/32.53.854 




-- 
Ray McDermott
GSM 047/32.53.854 




-- 
Ray McDermott
GSM 047/32.53.854 




-- 
Ray McDermott
GSM 047/32.53.854 


Mime
View raw message