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:[EMAIL PROTECTED] Sent: maandag 5 november 2007 16:25 To: [email protected]; [EMAIL PROTECTED] 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 < [EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]> > 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 <[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+u se+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 <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
