Search code examples
javamybatisibatis

How to specify IN param type with annotation-configured MyBatis


It seems I need to explicitly tell MyBatis what db-type to use for java.util.Date IN parameters if I want to able to pass null values. But I can't find a way of doing that.

I tried different variations of following with no luck:

@Select("<script>SELECT ... WHERE ... " +
    "<if test='#{dateFrom,jdbcType=TIMESTAMP} != null'>" +
    "  AND date &gt; #{dateFrom,jdbcType=TIMESTAMP}" + 
    "</if></script>")
List<MyType> getRecords(@Param("dateFrom") dateFrom)

How does one specify a parameter type when using annotations?


Solution

  • Other developers already commented about this kind of problem.

    I quote from GitHub comments:

    @nglsatheesh MyBatis cannot cast/convert those types unless you tell it how. All you need is a simple custom type handler.

    public class StrToIntTypeHandler implements TypeHandler<String> {
      @Override
      public void setParameter(PreparedStatement ps, int i,
          String parameter, JdbcType jdbcType) throws SQLException {
        ps.setInt(i, Integer.parseInt(parameter));
      }
      // other methods are for binding query results.
    }
    

    select * from table_name where id = #{value,typeHandler=StrToIntTypeHandler}

    So now, if you will create such a custom typehandler:

    public class Null2DateTypeHandler implements TypeHandler<Date> {
    
        @Override
        public void setParameter(PreparedStatement ps, int i, java.util.Date parameter, JdbcType jdbcType) throws SQLException {
            System.err.println(String.format("ps: %s, i: %d, param: %s, type: %s", ps.toString(), i, parameter, jdbcType.toString()));
    
            if (parameter == null) {
                ps.setDate(i, null); // ??? I'm not sure. But it works.
            } else {
                ps.setDate(i, new java.sql.Date(parameter.getTime()));
            }
        }
    }
    

    And, mapper side:

    @Select({
        "<script>"
        , "SELECT * FROM `employees` WHERE `hire_date` "
        , "  BETWEEN
        , "  #{dateFrom,typeHandler=*.*.*.Null2DateTypeHandler}"
        , "  AND"
        , "  #{dateTo,typeHandler=*.*.*.Null2DateTypeHandler}"      
        ,"</script>"
    })
    @Results({
          @Result(property = "empNo", column = "emp_no"),
          @Result(property = "birthDate", column = "birth_date"),
          @Result(property = "firstName", column = "first_name"),
          @Result(property = "lastName",  column = "last_name"),
          @Result(property = "gender",    column = "gender"),
          @Result(property = "hireDate",  column = "hire_date")          
    })  
    List<Employees> selectBetweenTypeHandler(@Param("dateFrom") Date dateFrom, @Param("dateTo") Date dateTo);
    

    My logging, it looks working fine.

    DEBUG [main] - ==>  Preparing: SELECT * FROM `employees` WHERE `hire_date` BETWEEN ? AND ? 
    ps: org.apache.ibatis.logging.jdbc.PreparedStatementLogger@369f73a2, i: 1, param: null, type: OTHER
    DEBUG [main] - ==> Parameters: null, null
    ps: org.apache.ibatis.logging.jdbc.PreparedStatementLogger@369f73a2, i: 2, param: null, type: OTHER
    DEBUG [main] - <==      Total: 0