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+use+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 <[EMAIL PROTECTED]> 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 <[EMAIL PROTECTED]> 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:[EMAIL PROTECTED] > > Sent: maandag 5 november 2007 10:45 > > To: [email protected] > > 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 < [EMAIL PROTECTED]> 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+use+a+Custom+Type+Handler+with+complex+property+or+Type+Safe+Enumeration > > > > > > > > Hth, > > > > > > > > Niels > > > > ________________________________ > > > > > From: Raymond McDermott [mailto: [EMAIL PROTECTED] > > Sent: zondag 4 november 2007 21:57 > > To: [email protected] > > 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.FrequencyTypeHandler"/> > > > > <typeHandler > javaType="com.opengrail.circles365.domain.MeasurementType" > > jdbcType="VARCHAR" > > > callback="com.opengrail.circles365.config.ibatis.typehandlers.MeasurementTypeTypeHandler > "/> > > > > > > <!-- 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.executeUpdate(GeneralStatement.java:94) > > at > com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.update(SqlMapExecutorDelegate.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(SqlMapClientTemplate.java:381) > > at > com.opengrail.circles365.data.impl.MeasurementItemDaoImpl.createMeasurementItem > (MeasurementItemDaoImpl.java:13) > > at > com.opengrail.circles365.service.impl.MeasurementItemManagementImpl.createMeasurementItem(MeasurementItemManagementImpl.java:25) > > at > com.opengrail.circles365.tests.ServiceImplementationTests.testGoodMeasurementItem > (ServiceImplementationTests.java:56) > > 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 > 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.java:38) > > at > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460) > > at > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673) > > at > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run > (RemoteTestRunner.java:386) > > at > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196) > > Caused by: java.lang.NullPointerException > > at > com.ibatis.sqlmap.engine.mapping.parameter.BasicParameterMap.setParameter > (BasicParameterMap.java:165) > > at > com.ibatis.sqlmap.engine.mapping.parameter.BasicParameterMap.setParameters(BasicParameterMap.java:125) > > at > com.ibatis.sqlmap.engine.execution.SqlExecutor.executeUpdate(SqlExecutor.java > :79) > > at > com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.sqlExecuteUpdate(GeneralStatement.java:200) > > at > com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeUpdate(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
