Menu

Support for IBATIS SqlMaps 2

2004-02-24
2004-03-04
  • Darren Spurgeon

    Darren Spurgeon - 2004-02-24

    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

     
    • Juergen Hoeller

      Juergen Hoeller - 2004-02-25

      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

       
      • Darren Spurgeon

        Darren Spurgeon - 2004-02-25

        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

         
    • Darren Spurgeon

      Darren Spurgeon - 2004-03-01

      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>

       
      • Juergen Hoeller

        Juergen Hoeller - 2004-03-01

        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

         
        • Juergen Hoeller

          Juergen Hoeller - 2004-03-01

          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

           
          • Darren Spurgeon

            Darren Spurgeon - 2004-03-01

            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

             
            • Juergen Hoeller

              Juergen Hoeller - 2004-03-01

              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

               
              • Clinton Begin

                Clinton Begin - 2004-03-02

                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

                 
                • Clinton Begin

                  Clinton Begin - 2004-03-03

                  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

                   
                  • Clinton Begin

                    Clinton Begin - 2004-03-03

                    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

                     
                  • Juergen Hoeller

                    Juergen Hoeller - 2004-03-03

                    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

                     
                    • Darren Spurgeon

                      Darren Spurgeon - 2004-03-03

                      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

                       
                      • Juergen Hoeller

                        Juergen Hoeller - 2004-03-03

                        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

                         
                        • Clinton Begin

                          Clinton Begin - 2004-03-03

                          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

                           
                          • Juergen Hoeller

                            Juergen Hoeller - 2004-03-04

                            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

                             

Log in to post a comment.

MongoDB Logo MongoDB