0

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
  • Type handler is called when setting a parameter of a PreparedStatement. If you use text substitution i.e. ${}, it's not a parameter of the PreparedStatement anymore, so type handler is of no use. As you can use OGNL expression in ${}, you can invoke the method like order by ${searchCriteria.sortBy.getValue()} or order by ${searchCriteria.sortBy.value}. Commented Jun 15, 2021 at 20:36

1 Answer 1

0

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.