Search code examples
javaibatis

How to Return NULL-values in iBatis?


Let's say I have an Oracle database and an interface like this:

public interface DaoMapper {

  @Select({
      "SELECT col1, col2, col3",
        "FROM my_table" })
  List<Map<String, Object>> getUntyped();

}

If I call getUntyped() and all columns have a value the map contains three entries. However, if col2 is NULL, the map has only two entries. In many cases this isn't a problem, but in a generic part of our code I actually want to call .values() on that map and want a list consisting of three entries. Any entry may be null (or an empty string as that's the same in Oracle).

Actually, what I would be really happy about is something like this where each outer list consists of lists with three entries:

  @Select({
      "SELECT col1, col2, col3",
        "FROM my_table" })
  List<List<Object>> getUntypedList();

However, iBatis tells me that this is an unsupported operation.

Therefore, I'm here to ask how I can tell iBatis to include columns that are NULL or an empty string.


Solution

  • Thanks to Giovanni's answer I noticed the example for type handlers and went from there:

    public class EmptyStringTypeHandler extends StringTypeHandler {
    
      @Override
      public String getResult(ResultSet rs, String columnName) throws SQLException {
        return unnulledString(super.getResult(rs, columnName));
      }
    
      @Override
      public String getResult(ResultSet rs, int columnIndex) throws SQLException {
        return unnulledString(super.getResult(rs, columnIndex));
      }
    
      @Override
      public String getResult(CallableStatement cs, int columnIndex) throws SQLException {
        return unnulledString(super.getResult(cs, columnIndex));
      }
    
      private String unnulledString(String value) {
        return StringUtils.defaultString(value, "");
      }
    
    }
    

    The interface is now:

    public interface DaoMapper {
    
      @Select({
          "SELECT col1, col2, col3",
            "FROM my_table" })
      @Results(value = {
          @Result(column = "col1", property = "col1", typeHandler = EmptyStringTypeHandler.class),
          @Result(column = "col2", property = "col2", typeHandler = EmptyStringTypeHandler.class),
          @Result(column = "col3", property = "col3", typeHandler = EmptyStringTypeHandler.class)
      })
      List<LinkedHashMap<String, ?>> getUntyped();
    
    }
    

    I should add that the big advantage is that I can specify this per column per statement. For more generic use it would be better to specify this per statement. Maybe in some future version?