I know the answer will probably be "not for the Spring 1.0 release", but I thought I'd ask anyway. Will there be support for IBATIS SqlMaps 2.0 soon? Specifically, I'm having trouble with Spring's SqlMapFactoryBean (et al.) parsing the new IBATIS XML config files appropriately.
If not, does anyone have suggestions as to which classes of Spring I should override or extend to provide support? I'm thinking those in the org.springframework.orm.ibatis.
Thanks.
-Darren
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
On the occasion, I've just taken the time to add SQL Maps 2 support classes :-) There's SqlMapClientFactoryBean/Template/Callback/Operastions now, plus SqlMapClientDaoSupport.
Note that you can just use either SQL Maps 1.x or SQL Maps 2 in the same application. Simply choose the corresponding Spring support classes when working with Spring.
It's already in CVS, and will be part of the upcoming RC2!
Juergen
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I'm getting an exception when using complex properties in my SqlMap 2 result maps. Simple result maps work fine, though, as does going against IBATIS directly. It's only through Spring that the problem occurs. I tested against a 2/28 snapshot from CVS for Spring and IBATIS 2-beta3. I'm including minimal info here, but I can email a complete test case if you wish. Thanks.
Cheers,
Darren
org.springframework.jdbc.UncategorizedSQLException: (SqlMapTemplate): encountered SQLException [
--- The error occurred in examples/User.map.xml.
--- The error occurred while applying a result map.
--- Check the complex-user-result-map.
--- Check the result mapping for the 'address' property.
--- Cause: java.lang.NullPointerException]; nested exception is com.ibatis.common.jdbc.exception.NestedSQLException:
--- The error occurred in examples/User.map.xml.
--- The error occurred while applying a result map.
--- Check the complex-user-result-map.
--- Check the result mapping for the 'address' property.
--- Cause: java.lang.NullPointerException
com.ibatis.common.jdbc.exception.NestedSQLException:
--- The error occurred in examples/User.map.xml.
--- The error occurred while applying a result map.
--- Check the complex-user-result-map.
--- Check the result mapping for the 'address' property.
--- Cause: java.lang.NullPointerException
Caused by: java.lang.NullPointerException
at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWithCallback(GeneralStatement.java:151)
at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryForObject(GeneralStatement.java:78)
at com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate.queryForObject(SqlMapClientDelegate.java:218)
at com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate.queryForObject(SqlMapClientDelegate.java:203)
at com.ibatis.sqlmap.engine.impl.SingleThreadSqlMapClient.queryForObject(SingleThreadSqlMapClient.java:43)
at org.springframework.orm.ibatis.SqlMapClientTemplate.doInSqlMapSession(SqlMapClientTemplate.java:84)
at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:62)
at org.springframework.orm.ibatis.SqlMapClientTemplate.queryForObject(SqlMapClientTemplate.java:82)
at examples.UserMapDao.getComplexUserById(UserMapDao.java:9)
at examples.UserServiceImpl.getComplexUserById(UserServiceImpl.java:12)
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:324)
at org.springframework.aop.framework.AopProxyUtils.invokeJoinpointUsingReflection(AopProxyUtils.java:59)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:201)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:176)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:158)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:196)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:135)
Caused by: java.lang.NullPointerException
at com.ibatis.sqlmap.engine.mapping.result.BasicResultMap.getNestedResultMappingValue(BasicResultMap.java:137)
at com.ibatis.sqlmap.engine.mapping.result.BasicResultMap.getResults(BasicResultMap.java:118)
at com.ibatis.sqlmap.engine.execution.SqlExecutor.handleResults(SqlExecutor.java:238)
at com.ibatis.sqlmap.engine.execution.SqlExecutor.executeQuery(SqlExecutor.java:110)
at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.sqlExecuteQuery(GeneralStatement.java:168)
at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWithCallback(GeneralStatement.java:137)
----- IBATIS SQL MAP 2 CONFIG -----
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN"
"http://www.ibatis.com/dtd/sql-map-2.dtd">
<sqlMap>
<resultMap id="complex-user-result-map" class="examples.User">
<result property="id" column="id"/>
<result property="name" column="name"/>
<result property="address" column="address_id" select="getAddressById"/>
</resultMap>
<resultMap id="addressResultMap" class="examples.Address">
<result property="id" column="id"/>
<result property="street" column="street"/>
<result property="city" column="city"/>
<result property="state" column="state"/>
<result property="zip" column="zip"/>
</resultMap>
<select id="getComplexUserById" parameterClass="int" resultMap="complex-user-result-map">
select *
from user
where id = #value#
</select>
<select id="getAddressById" parameterClass="int" resultMap="addressResultMap">
select *
from address
where id = #value#
</select>
</sqlMap>
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
That seems awkward; I'm not sure how Spring could cause this. Could you double-check that it works in a plain SqlMapClient and not via SqlMapClientTemplate? Possibly also via a custom SqlMapClientCallback implementation?
The only notable difference is that a plain SqlMapClient uses its own connection pool configuration while Spring creates a SqlMapSession via SqlMapClient.getSession and invokes setUserConnection on it.
So you could also try to write your plain SqlMapClient code with such a SqlMapSession and a user connection; it's virtually the same as with a SqlMapClientTemplate then. I strongly suspect that iBATIS has a bug in that mode of usage.
Juergen
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
BTW, if you respond *very* quickly, possibly with a complete test case, I'll be able to still merge a potential fix into Spring 1.0 RC2 (although I doubt that it's a Spring bug).
The RC2 release is ready, but I'm gonna take an hour or two off now before uploading it to SourceForge - so there is a chance :-)
Juergen
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I modified my DAO to use the SqlMapClient instead of the SqlMapClientTemplate as you first suggested. It seems to work (i.e., returns expected result without exception), but only if I define the connection in the SqlMap configuration--without it, no go. So, in my class UserMapDao, I have:
public User getComplexUserById(Integer id) throws DataAccessException {
SqlMapClient sqlMap = getSqlMapClient();
User user = null;
try {
user = (User) sqlMap.queryForObject("getComplexUserById", id);
} catch (SQLException e) {
// handle something
}
return user;
// OLD IMPLEMENTATION
//return (User) getSqlMapClientTemplate().queryForObject("getComplexUserById", id);
}
When inspecting IBATIS' com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate and com.ibatis.sqlmap.engine.scope.SessionScope classes, it appears the session's connection is not set properly under Spring. I'm not convinced this is Spring's problem though as the session in question exists in IBATIS.
I did not try a custom SqlMapClientCallback, though. Now, I'm at a loss, because I'm not quite sure how to verify what's happening in the SqlMapClientTemplate. I don't immediately see anything that would make me doubt how it's handling IBATIS calls. The only potential issue, as you mentioned, may be the SqlMapSession.
Cheers,
Darren
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I've browsed through the iBATIS SQL Maps 2 beta 3 source code for quite some time now...
Frankly, the LocalSession stuff that the SqlMapClient implementations are using for each and every call seems to be severely broken: endSession (which closes the underlying SessionScope) is just invoked from endTransaction; so if you're not using SQL Maps native transaction management, it will *never* be called. This certainly can't be correct behavior.
Of course, we're talking about a SQL Maps 2 beta here. So please report this issue to Clinton; if there's something we can do differently on the Spring side of things (setUserConnection calls etc), it's just not obvious at this point of time. Would be good to clarify that promptly, before Spring 1.0 final. I guess it's Clinton's turn now :-)
For the time being, I'm afraid that the only option is to use the SqlMapClient directly, configuring the connection pool within sql-map-config.xml. I have to say that working with SQL Maps 1.x was signficantly simpler: In particular, passing-in user connections was absolutely straightforward, without any hard-to-understand magic behind the scenes...
Juergen
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
This indeed is my bug/omission. :-) I need to implement some sort of "close" method for the session, but I need to make sure it works the way I intend. The client interfaces need a bit of shuffling first.
Admittedly, user connection and getSession stuff took a back seat to the SQLMaps native transaction support.
I'll try to have a fix in the next release (Tue or Wed).
Cheers,
Clinton
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
PS: Consider limiting access to SqlMapClient and SqlMapSession to avoid messing around with the transaction (start, commit, setConnection etc.). You might be better off only providing an SqlExecutor instance (both SqlMapClient and SqlMapSession implement it).
Cheers,
Clinton
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I grabbed the latest source from CVS this morning and ran it with SqlMaps 2 beta 4 against my test case. It passed with flying colors. Granted it's a simple case, but at least I'm over the hurdle I faced with mapping complex properties.
Thanks to both of you for your gracious diligence and support!
Cheers,
Darren
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Good to hear that it works now! :-) Makes me feel confident about SQL Maps 2 support for Spring 1.0 final.
BTW, Clinton, when do you plan to release a SQL Maps 2.0 RC? It would be excellent to have one within the Spring 1.0 final timeframe: However, that's around mid March, so I can understand if a SQL Maps 2.0 RC is not possible in time.
Juergen
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Funny you should ask, I put a note up last night about this.
The Beta goals of stability and compatibility have been met, and I've been out of "bugs" for weeks. The only think keeping it from RC now is better error messages, improved XML validation and some additional documentation (for DAO 2.0 and all the session stuff).
Once that's done, I'm going to put up RC1.
Unfortunately March is going to be a crazy month for me. So RC1 will either come within the next 2 weeks, or it will be mid April.
Cheers,
Clinton
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
In fact, I'm mainly concerned about further API changes. I don't want to ship Spring 1.0 final with iBATIS SQL Maps 2 support that only works with a certain beta version of SQL Maps 2.0.
As long as the SqlMapClient API is considered stable, I'm happy with shipping the most current beta for the time being. People can always update the SQL Maps jar themselves when a further release is available.
BTW, thanks for your efforts, Clinton :-)
Juergen
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I know the answer will probably be "not for the Spring 1.0 release", but I thought I'd ask anyway. Will there be support for IBATIS SqlMaps 2.0 soon? Specifically, I'm having trouble with Spring's SqlMapFactoryBean (et al.) parsing the new IBATIS XML config files appropriately.
If not, does anyone have suggestions as to which classes of Spring I should override or extend to provide support? I'm thinking those in the org.springframework.orm.ibatis.
Thanks.
-Darren
On the occasion, I've just taken the time to add SQL Maps 2 support classes :-) There's SqlMapClientFactoryBean/Template/Callback/Operastions now, plus SqlMapClientDaoSupport.
Note that you can just use either SQL Maps 1.x or SQL Maps 2 in the same application. Simply choose the corresponding Spring support classes when working with Spring.
It's already in CVS, and will be part of the upcoming RC2!
Juergen
Wow, Juergen! I was all prepared to be disappointed, but there you go and remind me just why I like you Spring fellas so much.
Thanks! I look forward to RC2.
Cheers,
Darren
I'm getting an exception when using complex properties in my SqlMap 2 result maps. Simple result maps work fine, though, as does going against IBATIS directly. It's only through Spring that the problem occurs. I tested against a 2/28 snapshot from CVS for Spring and IBATIS 2-beta3. I'm including minimal info here, but I can email a complete test case if you wish. Thanks.
Cheers,
Darren
org.springframework.jdbc.UncategorizedSQLException: (SqlMapTemplate): encountered SQLException [
--- The error occurred in examples/User.map.xml.
--- The error occurred while applying a result map.
--- Check the complex-user-result-map.
--- Check the result mapping for the 'address' property.
--- Cause: java.lang.NullPointerException]; nested exception is com.ibatis.common.jdbc.exception.NestedSQLException:
--- The error occurred in examples/User.map.xml.
--- The error occurred while applying a result map.
--- Check the complex-user-result-map.
--- Check the result mapping for the 'address' property.
--- Cause: java.lang.NullPointerException
com.ibatis.common.jdbc.exception.NestedSQLException:
--- The error occurred in examples/User.map.xml.
--- The error occurred while applying a result map.
--- Check the complex-user-result-map.
--- Check the result mapping for the 'address' property.
--- Cause: java.lang.NullPointerException
Caused by: java.lang.NullPointerException
at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWithCallback(GeneralStatement.java:151)
at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryForObject(GeneralStatement.java:78)
at com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate.queryForObject(SqlMapClientDelegate.java:218)
at com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate.queryForObject(SqlMapClientDelegate.java:203)
at com.ibatis.sqlmap.engine.impl.SingleThreadSqlMapClient.queryForObject(SingleThreadSqlMapClient.java:43)
at org.springframework.orm.ibatis.SqlMapClientTemplate.doInSqlMapSession(SqlMapClientTemplate.java:84)
at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:62)
at org.springframework.orm.ibatis.SqlMapClientTemplate.queryForObject(SqlMapClientTemplate.java:82)
at examples.UserMapDao.getComplexUserById(UserMapDao.java:9)
at examples.UserServiceImpl.getComplexUserById(UserServiceImpl.java:12)
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:324)
at org.springframework.aop.framework.AopProxyUtils.invokeJoinpointUsingReflection(AopProxyUtils.java:59)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:201)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:176)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:158)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:196)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:135)
Caused by: java.lang.NullPointerException
at com.ibatis.sqlmap.engine.mapping.result.BasicResultMap.getNestedResultMappingValue(BasicResultMap.java:137)
at com.ibatis.sqlmap.engine.mapping.result.BasicResultMap.getResults(BasicResultMap.java:118)
at com.ibatis.sqlmap.engine.execution.SqlExecutor.handleResults(SqlExecutor.java:238)
at com.ibatis.sqlmap.engine.execution.SqlExecutor.executeQuery(SqlExecutor.java:110)
at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.sqlExecuteQuery(GeneralStatement.java:168)
at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWithCallback(GeneralStatement.java:137)
----- IBATIS SQL MAP 2 CONFIG -----
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN"
"http://www.ibatis.com/dtd/sql-map-2.dtd">
<sqlMap>
<resultMap id="complex-user-result-map" class="examples.User">
<result property="id" column="id"/>
<result property="name" column="name"/>
<result property="address" column="address_id" select="getAddressById"/>
</resultMap>
<resultMap id="addressResultMap" class="examples.Address">
<result property="id" column="id"/>
<result property="street" column="street"/>
<result property="city" column="city"/>
<result property="state" column="state"/>
<result property="zip" column="zip"/>
</resultMap>
<select id="getComplexUserById" parameterClass="int" resultMap="complex-user-result-map">
select *
from user
where id = #value#
</select>
<select id="getAddressById" parameterClass="int" resultMap="addressResultMap">
select *
from address
where id = #value#
</select>
</sqlMap>
That seems awkward; I'm not sure how Spring could cause this. Could you double-check that it works in a plain SqlMapClient and not via SqlMapClientTemplate? Possibly also via a custom SqlMapClientCallback implementation?
The only notable difference is that a plain SqlMapClient uses its own connection pool configuration while Spring creates a SqlMapSession via SqlMapClient.getSession and invokes setUserConnection on it.
So you could also try to write your plain SqlMapClient code with such a SqlMapSession and a user connection; it's virtually the same as with a SqlMapClientTemplate then. I strongly suspect that iBATIS has a bug in that mode of usage.
Juergen
BTW, if you respond *very* quickly, possibly with a complete test case, I'll be able to still merge a potential fix into Spring 1.0 RC2 (although I doubt that it's a Spring bug).
The RC2 release is ready, but I'm gonna take an hour or two off now before uploading it to SourceForge - so there is a chance :-)
Juergen
I modified my DAO to use the SqlMapClient instead of the SqlMapClientTemplate as you first suggested. It seems to work (i.e., returns expected result without exception), but only if I define the connection in the SqlMap configuration--without it, no go. So, in my class UserMapDao, I have:
public User getComplexUserById(Integer id) throws DataAccessException {
SqlMapClient sqlMap = getSqlMapClient();
User user = null;
try {
user = (User) sqlMap.queryForObject("getComplexUserById", id);
} catch (SQLException e) {
// handle something
}
return user;
// OLD IMPLEMENTATION
//return (User) getSqlMapClientTemplate().queryForObject("getComplexUserById", id);
}
When inspecting IBATIS' com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate and com.ibatis.sqlmap.engine.scope.SessionScope classes, it appears the session's connection is not set properly under Spring. I'm not convinced this is Spring's problem though as the session in question exists in IBATIS.
I did not try a custom SqlMapClientCallback, though. Now, I'm at a loss, because I'm not quite sure how to verify what's happening in the SqlMapClientTemplate. I don't immediately see anything that would make me doubt how it's handling IBATIS calls. The only potential issue, as you mentioned, may be the SqlMapSession.
Cheers,
Darren
I've browsed through the iBATIS SQL Maps 2 beta 3 source code for quite some time now...
Frankly, the LocalSession stuff that the SqlMapClient implementations are using for each and every call seems to be severely broken: endSession (which closes the underlying SessionScope) is just invoked from endTransaction; so if you're not using SQL Maps native transaction management, it will *never* be called. This certainly can't be correct behavior.
Of course, we're talking about a SQL Maps 2 beta here. So please report this issue to Clinton; if there's something we can do differently on the Spring side of things (setUserConnection calls etc), it's just not obvious at this point of time. Would be good to clarify that promptly, before Spring 1.0 final. I guess it's Clinton's turn now :-)
For the time being, I'm afraid that the only option is to use the SqlMapClient directly, configuring the connection pool within sql-map-config.xml. I have to say that working with SQL Maps 1.x was signficantly simpler: In particular, passing-in user connections was absolutely straightforward, without any hard-to-understand magic behind the scenes...
Juergen
Hi guys,
This indeed is my bug/omission. :-) I need to implement some sort of "close" method for the session, but I need to make sure it works the way I intend. The client interfaces need a bit of shuffling first.
Admittedly, user connection and getSession stuff took a back seat to the SQLMaps native transaction support.
I'll try to have a fix in the next release (Tue or Wed).
Cheers,
Clinton
Hi guys,
I've released Beta 4 with a SqlMapSession fully implemented. Please try it out and let me know if it improves your situation. Some notes:
sqlMapClient.getSession() has been deprecated and replaced by .openSession();
SqlMapSession now has a .close() method.
SqlMapClient no longer extends SqlMapSession (both now extend SqlMapExecutor and SqlMapTransactionManager).
Cheers,
Clinton
PS: Consider limiting access to SqlMapClient and SqlMapSession to avoid messing around with the transaction (start, commit, setConnection etc.). You might be better off only providing an SqlExecutor instance (both SqlMapClient and SqlMapSession implement it).
Cheers,
Clinton
Thanks, Clinton!
I've just adapted Spring's SQL Maps 2 support accordingly; already committed to CVS. Early adopters, feel free to check out CVS head :-)
Juergen
Juergen, Clinton-
This is one such early adopter! ;)
I grabbed the latest source from CVS this morning and ran it with SqlMaps 2 beta 4 against my test case. It passed with flying colors. Granted it's a simple case, but at least I'm over the hurdle I faced with mapping complex properties.
Thanks to both of you for your gracious diligence and support!
Cheers,
Darren
Good to hear that it works now! :-) Makes me feel confident about SQL Maps 2 support for Spring 1.0 final.
BTW, Clinton, when do you plan to release a SQL Maps 2.0 RC? It would be excellent to have one within the Spring 1.0 final timeframe: However, that's around mid March, so I can understand if a SQL Maps 2.0 RC is not possible in time.
Juergen
Hi Juergen,
Funny you should ask, I put a note up last night about this.
The Beta goals of stability and compatibility have been met, and I've been out of "bugs" for weeks. The only think keeping it from RC now is better error messages, improved XML validation and some additional documentation (for DAO 2.0 and all the session stuff).
Once that's done, I'm going to put up RC1.
Unfortunately March is going to be a crazy month for me. So RC1 will either come within the next 2 weeks, or it will be mid April.
Cheers,
Clinton
In fact, I'm mainly concerned about further API changes. I don't want to ship Spring 1.0 final with iBATIS SQL Maps 2 support that only works with a certain beta version of SQL Maps 2.0.
As long as the SqlMapClient API is considered stable, I'm happy with shipping the most current beta for the time being. People can always update the SQL Maps jar themselves when a further release is available.
BTW, thanks for your efforts, Clinton :-)
Juergen