Java MyBatis Enum String Value

I feel like this is a simple problem, but none of the things I've tried work for me. I have an enum, the reason why I have a string constructor is because Java does not allow an enum to be numeric. I've tried AA, AB, 2C directly without a string constructor but it gives an error. Note that for the existing enum, I am adding C ("2C").

public enum TestEnum{
      AA("AA"), AB("AB"), C("2C");
      private String display;
    private TestEnum( String display ) {
          this.display = display;
       }
    public String toString() {
          return display;
       }
    public String getDisplay() {
          return display;
       }
    public void setDisplay( String display ) {
          this.display = display;
       }
     public String getName() {
          return display;
       }

      

Now I have mybatis mapper doing the merge, this already exists and one of the parameters for the transformer is TestEnum. This has worked fine so far as the enum and string are the same, but I added C ("2C"). Now I want to insert 2C into the table using mybaits, but it always inserts C.

merge into text t
        using (select #{id} as id from dual) d on (d.id = t.id)
        when matched then
        update set
        appId = #{applId},
        src = #{testEnum}

      

testEnum inserts C, so I changed that to # {testEnum.toString ()}, which gave me no name for the toString () property name. I tried # {testEnum.display} and # {testEnum.name}, both of which still insert C, whereas I want it to insert 2C. Do you guys know an easier way to handle this?

I don't want to modify the model object to pass a String and not a TestEnum because this object is used in many places. Is there a way to do this in mybatis mapper without modifying the model object?

Thank you for your help:)

+3


source to share


3 answers


You need a TypeHandler

First add a static method to yours TestEnum

to return a TestEnum

given the display string:

public static TestEnum fromDisplay(String display){
    for (TestEnum v : TestEnum.values()){
        if (v.getDisplay().equals(display)){
            return v;
        }
    }
    return null;
}

      

Then use it to create a TypeHandler:



import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

public class TestEnumTypeHandler extends BaseTypeHandler<TestEnum> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, TestEnum parameter, JdbcType jdbcType)
            throws SQLException {
        ps.setString(i, parameter.getDisplay());
    }

    @Override
    public TestEnum getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return TestEnum.fromDisplay(rs.getString(columnName));
    }

    @Override
    public TestEnum getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return TestEnum.fromDisplay(rs.getString(columnIndex));
    }

    @Override
    public TestEnum getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return TestEnum.fromDisplay(cs.getString(columnIndex));
    }
}

      

Finally, register your TypeHandler in mybatis xml:

<typeHandlers>
  <typeHandler handler="blah.blah.TestEnumTypeHandler "/>
</typeHandlers>

      

+3


source


In addition to @Malt's answer:

The reason you are trying is not working, MyBatis EnumTypeHandler

defaults to the name()

method value and is flagged final

, so you cannot override it:

EnumTypeHandler.class (lines 38 to 44):

  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
    if (jdbcType == null) {
      ps.setString(i, parameter.name());
    } else {
      ps.setObject(i, parameter.name(), jdbcType.TYPE_CODE); // see r3589
    }
  }

      



Otherwise, the enumeration is generated from a method valueOf(type, name)

that also uses the enumeration name.

@Override
  public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
    String s = rs.getString(columnIndex);
    return s == null ? null : Enum.valueOf(type, s);
  }

  @Override
  public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
    String s = cs.getString(columnIndex);
    return s == null ? null : Enum.valueOf(type, s);
  }

      

So definitely you need to use a Handler type specific to handle your enum which has certain behavior, but I would extends

directly EnumTypeHandler

in certain handlers of enumeration types instead of BaseTypeHandler

(malt's answer) because you might reuse some functionality (not in your case, but, perhaps in others), so it handles the general behavior of the enum.

+2


source


You don't need to write any custom ones TypeHandler

if you want to insert the value of your Enum.

The only thing you need to do is provide the name of the getter method in your MyBatis insert.

Example:

SQL:

CREATE TABLE demo
(
    id BIGINT,
    value VARCHAR(10),
    status CHAR(1)
);

      

MyBatis mapper:

@Update("UPDATE demo SET status = #{status.value} WHERE id= #{uuid}")
    long updateStatus(@Param("status") Status status, @Param("uuid") String uuid);

      

And Java enum:

public enum Status {
    ACTIVE("A"),
    INACTIVE("I");

    Status(final String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}

      

In your case, you can use src = #{testEnum.display}

in your SQL.

0


source







All Articles