Hi there,
I noticed that after upgrading to newer version of iBatis, some of the
functionality that used to work with iBatis 2.0.9 stopped working.
Namely, the problem occurred in case when there is complex property in
result map.
Here is the simple test case:
- Sql map:
<resultMap id="resultA" class="A">
<result property="id" column="ID"/>
<result property="description" column="DESCRIPTION"/>
</resultMap>
<resultMap id="resultB" class="B">
<result property="id" column="ID"/>
<result property="a_id" column="A_ID"/>
<result property="a" column="A_ID" select="getA"/>
</resultMap>
<select id="getAllB" resultMap="resultB">
select * from TABLE_B
</select>
<select id="getA" resultMap="resultA">
select * from TABLE_A
where id=#value#
</select>
- class A(id, description); class B (id, a_id, object A)
- TABLE_A(id, description){(1, rec 1), (2, rec 2)}
- TABLE_B(id, a_id){(1, 1), (1, null)}
As you can see, a_id field in TABLE_B is nullable.
When you invoke queryForList("getAllB"), iBatis breaks with following
exception:
com.ibatis.common.jdbc.exception.NestedSQLException:
--- The error occurred in Test.xml.
--- The error occurred while applying a result map.
--- Check the Test.resultB.
--- Check the result mapping for the 'a' property.
--- Cause: java.lang.NullPointerException
at
com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.executeQueryW
ithCallback(MappedStatement.java:204)
at
com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.executeQueryF
orList(MappedStatement.java:139)
at
com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMap
ExecutorDelegate.java:567)
at
com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMap
ExecutorDelegate.java:541)
at
com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForList(SqlMapSessi
onImpl.java:118)
at
com.ibatis.sqlmap.engine.impl.SqlMapClientImpl.queryForList(SqlMapClient
Impl.java:94)
at TestIbatis.main(TestIbatis.java:28)
Caused by: java.lang.NullPointerException
at java.lang.Class.isAssignableFrom(Native Method)
at
com.ibatis.sqlmap.engine.type.TypeHandlerFactory.getTypeHandler(TypeHand
lerFactory.java:143)
at
com.ibatis.sqlmap.engine.type.TypeHandlerFactory.getTypeHandler(TypeHand
lerFactory.java:123)
at
com.ibatis.sqlmap.engine.mapping.result.ResultMap.prepareBeanParameterOb
ject(ResultMap.java:591)
at
com.ibatis.sqlmap.engine.mapping.result.ResultMap.getNestedSelectMapping
Value(ResultMap.java:475)
at
com.ibatis.sqlmap.engine.mapping.result.ResultMap.getResults(ResultMap.j
ava:341)
at
com.ibatis.sqlmap.engine.execution.SqlExecutor.handleResults(SqlExecutor
.java:384)
at
com.ibatis.sqlmap.engine.execution.SqlExecutor.handleMultipleResults(Sql
Executor.java:300)
at
com.ibatis.sqlmap.engine.execution.SqlExecutor.executeQuery(SqlExecutor.
java:189)
at
com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.sqlExecuteQue
ry(MappedStatement.java:221)
at
com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.executeQueryW
ithCallback(MappedStatement.java:189)
... 6 more
What I would expect is that for those null values in database, null
value of property A in class B to be set.
This used to work in version 2.0.9, and was broken after version 2.2 I
think. I tried with latest 2.3.3 as well with the same result.
Is this a known issue, or maybe a feature? Is there some simple
workaround for the problem? I am aware that above solution is not
perfect (problem of N+1 selects), but we already implemented a lot of
queries this way and it would be time consuming to rewrite them all.
Dragan