You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user-java@ibatis.apache.org by Raymond McDermott <ra...@mcdermott.be> on 2007/11/04 21:57:23 UTC
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