MyBatis Typehandler with String Substitution Instead of Prepared Statement

655 Views Asked by At

Does MyBatis support specifying type handlers with string substitution ${​}​ instead of prepared statement substitution #{​}​?  

I am trying to populate an order by clause with an enum value so I am using a TypeHandler for this but I can't get it to work.

EnumTypeHandler

public class EnumTypeHandler implements TypeHandler<MyEnum> {

  @Override
  public void setParameter(PreparedStatement ps, int i, MyEnum parameter,
      JdbcType jdbcType) throws SQLException {
    ps.setString(i, parameter.getValue());
  }

  @Override
  public MyEnum getResult(ResultSet rs, String columnName) throws SQLException {
    // Not implemented
    return null;
  }

  @Override
  public MyEnum getResult(ResultSet rs, int columnIndex) throws SQLException {
    // Not implemented
    return null;
  }

  @Override
  public MyEnum getResult(CallableStatement cs, int columnIndex) throws SQLException {
    // Not implemented
    return null;
  }
}

MyBatis XML

order by ${searchCriteria.sortBy, typeHandler=com.example.EnumTypeHandler}

Error

org.apache.ibatis.binding.BindingException: Parameter 'com' not found. Available parameters are [offset, searchCriteria, limit, param3, param1, param2]
1

There are 1 best solutions below

0
On

I believe the string substitution just calls toString() from my experience with it. Though if you just want to specify a column to sort by using an enum, you don't actually need a type handler. Having the enum names match the possible column names should work. Or if you want more readable names in your code, you can override the enum's toString() to return the actual column names.

A while back I wanted to use an enum for sorting, and since ${} just calls toString(), I just overrode the method to return the column name and put the enum in the substitution without any type handler.

It's super simple, but for completeness' sake, here is essentially what I did.

public class Constants {
  public enum SortFields {
    REQUEST_DATE("REQ_DT"), ID_NUMBER("ID"), MEMBER_NAME("MEM_NM");

    private final String columnName;

    SortFields(String columnName) {
      this.columnName = columnName;
    }

    public String getColumnName() {
      return columnName;
    }

    public boolean equalsColumnName(String comparedColumnName) {
      return columnName.equals(comparedColumnName);
    }

    @Override
    public String toString() {
      return columnName;
    }
  }
}

And just passed the enum into a ${}. If the enum names had just been the column names instead of being spelled out, overriding toString() probably would not have been necessary.