简体   繁体   中英

iBatis (version 2.0) with Java 1.5 code throwing : No type handler could be found to map the property 'codec' to the column 'codec'

I'm working on a legacy application using Java 1.5, PostgreSQL 8.4.20 and iBatis version < 2.3.4.726 (as I've to use two jars for iBatis namely ibatis-common-2.jar & ibatis-sqlmap-2.jar). I've to use codec as Java Enum and corresponding column in db is varchar. While trying to get data from backend db and displaying on screen I get the following error:

[root@cent610-server iBatis-jdk18-work]# javac15 -cp .:jars-old-postgre/ibatis-sqlmap-2.jar:jars-old-postgre/ibatis-common-2.jar:jars-old-postgre/postgresql.jdbc3.jar:jars-old-postgre/commons-logging-1.1.1.jar com/dummy/iBatis/*.java
[root@cent610-server iBatis-jdk18-work]#
[root@cent610-server iBatis-jdk18-work]# java15 -cp .:jars-old-postgre/ibatis-sqlmap-2.jar:jars-old-postgre/ibatis-common-2.jar:jars-old-postgre/postgresql.jdbc3.jar:jars-old-postgre/commons-logging-1.1.1.jar com/dummy/iBatis/EnumMain5
Going to read record.....
Exception in thread "main" com.ibatis.common.jdbc.exception.NestedSQLException:   
--- The error occurred in SqlMapPostgre.xml.  
--- The error occurred while applying a result map.  
--- Check the codec-dscp-result.  
--- Check the result mapping for the 'codec' property.  
--- Cause: com.ibatis.sqlmap.client.SqlMapException: No type handler could be found to map the property 'codec' to the column 'codec'.  One or both of the types, or the combination of types is not supported.
Caused by: com.ibatis.sqlmap.client.SqlMapException: No type handler could be found to map the property 'codec' to the column 'codec'.  One or both of the types, or the combination of types is not supported.
    at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWithCallback(GeneralStatement.java:183)
    at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryForObject(GeneralStatement.java:99)
    at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForObject(SqlMapExecutorDelegate.java:561)
    at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForObject(SqlMapExecutorDelegate.java:536)
    at com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForObject(SqlMapSessionImpl.java:97)
    at com.ibatis.sqlmap.engine.impl.SqlMapClientImpl.queryForObject(SqlMapClientImpl.java:69)
    at com.dummy.iBatis.EnumMain5.main(EnumMain5.java:28)
Caused by: com.ibatis.sqlmap.client.SqlMapException: No type handler could be found to map the property 'codec' to the column 'codec'.  One or both of the types, or the combination of types is not supported.
    at com.ibatis.sqlmap.engine.mapping.result.BasicResultMap.getPrimitiveResultMappingValue(BasicResultMap.java:521)
    at com.ibatis.sqlmap.engine.mapping.result.BasicResultMap.getResults(BasicResultMap.java:274)
    at com.ibatis.sqlmap.engine.execution.SqlExecutor.handleResults(SqlExecutor.java:354)
    at com.ibatis.sqlmap.engine.execution.SqlExecutor.executeQuery(SqlExecutor.java:179)
    at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.sqlExecuteQuery(GeneralStatement.java:200)
    at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWithCallback(GeneralStatement.java:168)
    ... 6 more

Caused by: 
com.ibatis.sqlmap.client.SqlMapException: No type handler could be found to map the property 'codec' to the column 'codec'.  One or both of the types, or the combination of types is not supported.
    at com.ibatis.sqlmap.engine.mapping.result.BasicResultMap.getPrimitiveResultMappingValue(BasicResultMap.java:521)
    at com.ibatis.sqlmap.engine.mapping.result.BasicResultMap.getResults(BasicResultMap.java:274)
    at com.ibatis.sqlmap.engine.execution.SqlExecutor.handleResults(SqlExecutor.java:354)
    at com.ibatis.sqlmap.engine.execution.SqlExecutor.executeQuery(SqlExecutor.java:179)
    at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.sqlExecuteQuery(GeneralStatement.java:200)
    at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWithCallback(GeneralStatement.java:168)
    at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryForObject(GeneralStatement.java:99)
    at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForObject(SqlMapExecutorDelegate.java:561)
    at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForObject(SqlMapExecutorDelegate.java:536)
    at com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForObject(SqlMapSessionImpl.java:97)
    at com.ibatis.sqlmap.engine.impl.SqlMapClientImpl.queryForObject(SqlMapClientImpl.java:69)
    at com.dummy.iBatis.EnumMain5.main(EnumMain5.java:28)
[root@cent610-server iBatis-jdk18-work]# 

Note that, using the single iBatis 2.3.4.726 jar with JDK1.5 codebase without any custom typehandler works smoothly, but on my legacy application I've to use older iBatis version.

Here is the db schema:

          Table "public.enumtest"
 Column |         Type          | Modifiers 
--------+-----------------------+-----------
 id     | integer               | not null
 codec  | character varying(10) | not null
 dscp   | integer               | not null
Indexes:
    "enumtest_pkey" PRIMARY KEY, btree (id)

This is the class with main:EnumMain5.java, it is used for pulling the data from backend db and displaying:

package com.dummy.iBatis;


import java.io.Reader;
import java.util.List;

import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;

/**
 * @author geek
 *
 */
public class EnumMain5 {

        /**
         * @param args
         */
        public static void main(String[] args) throws Exception {
                // TODO Auto-generated method stub
                String resource = "SqlMapConfigPostgre.xml";
                Reader reader = Resources.getResourceAsReader(resource);
                SqlMapClient smc = SqlMapClientBuilder.buildSqlMapClient(reader);

                int id = 4;
              System.out.println("Going to read record.....");
              EnumiBatisTest e = (EnumiBatisTest)smc.queryForObject ("getCodecDscpPairValues", id);

              System.out.println("dscp:  " + e.getDscp());
              System.out.println("codec:  " + e.getCodec());
              System.out.println("Record read Successfully ");
        }
}

Other Java class files are as below EnumiBatisTest:

package com.dummy.iBatis;


/**
 * @author geek
 *
 */
public class EnumiBatisTest {

        /* codec value for a pair */
        private Codec codec;

        /* dscp value for a pair */
        private Integer dscp;

        /**
         * @return the codec
         */
        public Codec getCodec() {
                return codec;
        }

        /**
         * @param codec the codec to set
         */
        public void setCodec(Codec codec) {
                this.codec = codec;
        }
       /**
         * @return the dscp
         */
        public Integer getDscp() {
                return dscp;
        }

        /**
         * @param dscp the dscp to set
         */
        public void setDscp(Integer dscp) {
                this.dscp = dscp;
        }

}

SqlMapConfigPostgre.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMapConfig
    PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"
    "http://www.ibatis.com/dtd/sql-map-config-2.dtd">

<sqlMapConfig>

  <settings
    lazyLoadingEnabled="false"
    cacheModelsEnabled="true"
    enhancementEnabled="true"
    errorTracingEnabled="false"
    maxRequests="512"
    maxSessions="128"
    maxTransactions="32"
    />

<typeHandler callback="com.dummy.iBatis.CodecTypeHandlerCallback" javaType="com.dummy.iBatis.Codec" jdbcType="VARCHAR"/>

<transactionManager type="JDBC">
    <dataSource type="SIMPLE">
        <property name="JDBC.Driver" value="org.postgresql.Driver"/>
        <property name="JDBC.ConnectionURL" value="jdbc:postgresql://localhost:7654/mydb"/>
        <property name="JDBC.Username" value="dbuser"/>
        <property name="JDBC.Password" value="nano123"/>
    </dataSource>
  </transactionManager>

  <sqlMap resource="SqlMapPostgre.xml" />

</sqlMapConfig>

Codec.java:

package com.dummy.iBatis;

public enum Codec {
              G711, G729, UNDEFINED;
              }

Custom typehandler callback class CodecTypeHandlerCallback is:

package com.dummy.iBatis;
/**
 * 
 */

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;

/**
 * @author geek
 *
 */
public class CodecTypeHandlerCallback implements TypeHandlerCallback {

    private static final String G711 = "G711";
    private static final String G729 = "G729";
    private static final String UNDEFINED = null;

    public void setParameter(
                  ParameterSetter setter, Object parameter
                ) throws SQLException {
                    setter.setString(enumToString((Enum) parameter));
                }

    private String enumToString(Enum b) {
          if (b == null) {
                  return UNDEFINED;
          } else if (b==Codec.G711) {
            return G711;
          } else if (b==Codec.G729) {
            return G729;
          } else
                  return UNDEFINED;
    }
private Enum stringToEnum(String str) {
        if (str == null) return Codec.UNDEFINED;
        if (str.toUpperCase().indexOf("G711") >= 0) return Codec.G711;
        if (str.toUpperCase().indexOf("G729") >= 0) return Codec.G729;
        return Codec.UNDEFINED;
        }


    public Object getResult(ResultGetter getter)
            throws SQLException {
          return stringToEnum(getter.getString());
        }

    public Object valueOf(String s) {
        return stringToEnum(s);
    }

}

SqlMapPostgre.xml is as below:

<?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>
    <resultMap id="codec-dscp-result" 
               class="com.dummy.iBatis.EnumiBatisTest">
            <result property="dscp" column="dscp"/>
            <result property="codec" column="codec"/>
    </resultMap>
    
    <select id="getCodecDscpPairValues"  
            resultMap="codec-dscp-result"
            parameterClass="int">
            SELECT codec, dscp
              FROM enumtest
                where id=#id#
    </select>
</sqlMap>

What is missing here? How to properly use the custom typehandler mentioned here? I also checked the custom type handler example(YesNo one) from iBatis docs: https://livebook.manning.com/book/ibatis-in-action/chapter-12/ and created my custom type handler. Anything wrong with iBatis configuration xml files? Appreciate your time.

After trying lot many things and searching the web tutorials, found a quick solution(there could be many other ways as well, this is just one approach): In SqlMapConfigPostgre.xml file, remove this part jdbcType="VARCHAR" from typehandler statement.

In short update this line:
<typeHandler callback="com.dummy.iBatis.CodecTypeHandlerCallback" javaType="com.dummy.iBatis.Codec" jdbcType="VARCHAR"/>
to this:
<typeHandler callback="com.dummy.iBatis.CodecTypeHandlerCallback" javaType="com.dummy.iBatis.Codec"/>

Compile and run the code, it should work without any issue.
Hope this helps someone dealing with similar problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM