Obtaining custom Enum from database ID in MyBatis 3

168 views
Skip to first unread message

Stronkoes

unread,
Oct 8, 2012, 6:26:05 AM10/8/12
to mybati...@googlegroups.com
I have the following MyBatis 3 select statement that selects an ID from the database and should return the enum belonging to that ID:

  <select id="getMyEnum" resultType="MyEnum">
    SELECT DISTINCT enums.id 
    FROM enums    
    WHERE value = #{value}        
  </select>
 
If i use "enums.name" it works. But if i try it with the id of the enum it gives me the following exception:

No enum const class domain.MyEnum.1

I have the following enum:

public enum MyEnum implements ValueEnum<Integer>
{
  RED(1), BLACK(2), BLUE(3);

  private Integer id;

  public Integer getValue()
  {
    return id;
  }

  private MyEnum (Integer id)
  {
    this.id = id;
  }
}
 
With the following type handler:

@MappedJdbcTypes(JdbcType.INTEGER)
@MappedTypes(MyEnum.class)
public class MyEnumTypeHandler extends MyEnumTypeHandlerBase<MyEnum, Integer>
{}

BaseTypeHandler:

public abstract class MyEnumTypeHandlerBase<E extends Enum<E> & ValueEnum<T>, T> extends BaseTypeHandler<E>
{
  private Map<Object, ValueEnum<T>> map = new HashMap<Object, ValueEnum<T>>();
  private JdbcType mappedJdbcType ;

  public MyEnumTypeHandlerBase()
  {
    MappedTypes mappedTypes = this.getClass().getAnnotation(MappedTypes.class);
    MappedJdbcTypes mappedJdbcTypes = this.getClass().getAnnotation(MappedJdbcTypes.class);

    if(mappedJdbcTypes.value().length > 0)
    {
      mappedJdbcType = mappedJdbcTypes.value()[0];
    }
    
    for(Class<?> clazz : mappedTypes.value())
    {
      ValueEnum<T>[] enumConstants = (ValueEnum[]) clazz.getEnumConstants();
      for(ValueEnum<T> enumConstant : enumConstants)
      {
        T value = enumConstant.getValue(); 
        String key = value.toString();
        map.put(key, enumConstant);
      }
    }
  }
  
  /******************* Java to JDBC ************************/
  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException
  {
    if (jdbcType == null && mappedJdbcType == null)
    {
      
      ps.setString(i, parameter.getValue().toString());
    } else
    {
      if(mappedJdbcType != null)
        ps.setObject(i, parameter.getValue(), mappedJdbcType.TYPE_CODE);
      else ps.setObject(i, parameter.getValue(), jdbcType.TYPE_CODE); 
    }
  }

  /******************* JDBC to Java ************************/
  @Override
  public E getNullableResult(ResultSet rs, String columnName) throws SQLException
  {    
    Object s = rs.getObject(columnName);
    E value = s == null ? null : (E) map.get(s.toString());
    return value;
  }

  @Override
  public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException
  {
    Object s = rs.getObject(columnIndex);
    return s == null ? null : (E) map.get(s.toString());
  }

  @Override
  public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException
  {
    Object s = cs.getObject(columnIndex);
    
    return s == null ? null : (E) map.get(s.toString());
  }

}
 
This used to work in MyBatis 2.3.5 but since my migration to MyBatis 3 not anymore.

Could anyone tell me if i am doing something wrong, or how i can make it work?

Thanks in advance!
 

Paul Krause

unread,
Oct 9, 2012, 10:35:46 AM10/9/12
to mybati...@googlegroups.com
MB now has built-in type-handlers for enums, both for names and for values; however, their use is not documented very well.  See

Stronkoes

unread,
Oct 11, 2012, 10:19:04 AM10/11/12
to mybati...@googlegroups.com
Thanks for your reply.

If i am correct the type handler that is discussed there select's the enum in the order that they are written. 
So if i have 
 BLACK(2), BLUE(3),RED(1);
it will return BLACK if the selected Id is 1

I need to obtain the enum from the integer value that it has, not from the order it is in.
 

Op dinsdag 9 oktober 2012 16:35:46 UTC+2 schreef Paul Krause het volgende:

Rob Sonke

unread,
Oct 11, 2012, 2:02:59 PM10/11/12
to mybati...@googlegroups.com
As an addition to this post (I'm a colleague), the problem in this case is not the typehandler itself but the fact that mybatis doesnt pickup the typehandler. In this case the typehandler isnt used for a specific column or a parameter but as the result type itself.

Rob

Paul Krause

unread,
Oct 15, 2012, 1:16:06 PM10/15/12
to mybati...@googlegroups.com
You can still do this.  You just need to extend EnumOrdinalTypeHandler instead of BaseTypeHandler (you'll be overriding all or almost all of its methods, though).
Reply all
Reply to author
Forward
0 new messages