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 Mon, 05 Nov 2007 15:42:48 GMT
It seems that the ValueEnum interface is only needed when you want to
persist the enum using customized names, instead of just the enum
constant name itself. It still doesn't explain why you get a NPE when
you have verified that iBATIS calls your typehandler. Can you try
debugging some more, you should be able to find it...

 

Niels

________________________________

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

 

I saw that option but, to be honest rather than critical, I made it the
option of 'last resort'.  

If I understand it correctly, the design directly adds features to enums
to allow them to work with iBATIS.

For me it is a little inelegant and unnatural to have all my enums
implement an interface for the sake of iBATIS.  

However at this point perhaps elegance is no longer so important ;-)

Thanks for the post.

Ray



On 05/11/2007, Larry Meadors < lmeadors@apache.org
<mailto:lmeadors@apache.org> > wrote:

Hey Ray,

Did you see the other way to do this on the Wiki? 

http://opensource.atlassian.com/confluence/oss/display/IBATIS/How+do+I+u
se+Enums+with+annotations

That is http://tinyurl.com/2mgqd3 if that gets buggered up by gmail.

I do it a bit different and it's very little code - essentially, you
tell a base type handler the enum class and the jdbc type, and the 
rest is done for you:

@EnumTypeHandler(
  enumClass = EmploymentTermReason.class,
  jdbcType = Types.VARCHAR)
public class EmploymentTermReasonTypeHandler extends EnumTypeHandlerImpl
{
}

After that, you register some type aliases and the handler in your 
sqlmap config:

<typeAlias
  alias="EmploymentTermReason"
  type="com.blah.EmploymentTermReason" />
<typeAlias
  alias="EmploymentTermReasonTypeHandler"
  type=" com.blah.EmploymentTermReasonTypeHandler" />
<typeHandler
  javaType="EmploymentTermReason"
  callback="EmploymentTermReasonTypeHandler" />

BTW, the type aliases are optional, but save some typing and make 
refactoring easier.

Larry


On 11/5/07, 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> 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 > 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
<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">
> >
> > <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
(JUnit3TestReference.java:130)
> >     at
>
org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.ja
va:38)
> >     at
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests
(RemoteTestRunner.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 


Mime
View raw message