mybatis-plus3.0.1枚舉返回為null解決辦法
mybatis-plus 3.0.1 枚舉返回為null解決辦法
2020-11-02 14:28:48
今天再次回到代碼裡無意間看到,原來和mybatis-plus沒有關系!發生這個問題的根本原因還是要看是否在對應的Mapper.xml裡指定瞭jdbcType。由於我使用瞭IDEA的代碼生成插件,所以沒有再進一步去研究為什麼返回的數據類型會是以BigDecimal包裝的,就此鬧瞭個笑話。。
結論:枚舉類用EnumValue註解修飾的數據類型,例如是Integer,那麼在Mapper.xml中的jdbcType需要修改為對應類型!
最好的解決辦法就是使用新版的mybatis-plus!
3.1.0版本後改變瞭mybatis原生的默認行為,而3.1.2版本以下的枚舉處理類依然是EnumTypeHandler。推測在3.1.2以上的版本應該是不會出現這個問題的。
項目環境:springboot + oracle + mybatis-plus
實體類引用到的枚舉類,實現 IEnum 接口:
package com.abc.common.model.enums; import com.baomidou.mybatisplus.core.enums.IEnum; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; import lombok.Getter; @Getter public enum FieldType implements IEnum<Integer> { NONE(-1, ""), NORMAL_INPUT(0, "文本"), BIG_INPUT(1, "多文本"), DATETIME(2, "日期時間"), DATE(3, "日期"), TIME(4, "時間"), UPLOAD(5, "文件上傳"), DICT(6, "字典"); private final Integer value; @JsonValue private final String fieldType; private static final FieldType[] values = values(); FieldType(Integer value, String fieldType) { this.value = value; this.fieldType = fieldType; } @JsonCreator public static FieldType valueOf(Integer value) { for (FieldType enu : values) { if (enu.getValue().equals(value)) { return enu; } } return null; } }
mybatis-plus中關於枚舉類的配置:
mybatis-plus: #其它配置... type-enums-package: com.abc.common.model.enums #在3.0.1版本下無法設置默認的枚舉類型處理 #default-enum-type-handler: com.abc.service.handler.CustomizeEnumTypeHandler #其它配置...
前面說過瞭,項目使用的是mybatis-plus 3.0.1,這裡配置default-enum-type-handler是沒有作用的。至於為什麼不更新,項目是多人協同開發的,公司也不允許私自修改依賴包。
調用接口查詢時問題出現瞭:
日志說明這個字段是有一個有效值的,並且查詢出來瞭。(FIELD_TYPE字段是NUMBER(1)類型)
6對應的枚舉值應該是DICT,也就是字典類型才對,但是映射到實體類時卻變成瞭NULL。
在我看瞭一下午的源碼以後發現瞭問題的原因:
EnumTypeHandler.class:
package com.baomidou.mybatisplus.extension.handlers; import com.baomidou.mybatisplus.core.enums.IEnum; import com.baomidou.mybatisplus.core.toolkit.EnumUtils; 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 EnumTypeHandler<E extends Enum<?> & IEnum> extends BaseTypeHandler<IEnum> { private Class<E> type; public EnumTypeHandler(Class<E> type) { if (type == null) { throw new IllegalArgumentException("Type argument cannot be null"); } else { this.type = type; } } public void setNonNullParameter(PreparedStatement ps, int i, IEnum parameter, JdbcType jdbcType) throws SQLException { if (jdbcType == null) { ps.setObject(i, parameter.getValue()); } else { ps.setObject(i, parameter.getValue(), jdbcType.TYPE_CODE); } } public E getNullableResult(ResultSet rs, String columnName) throws SQLException { return null == rs.getString(columnName) && rs.wasNull() ? null : EnumUtils.valueOf(this.type, rs.getObject(columnName)); } public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return null == rs.getString(columnIndex) && rs.wasNull() ? null : EnumUtils.valueOf(this.type, rs.getObject(columnIndex)); } public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return null == cs.getString(columnIndex) && cs.wasNull() ? null : EnumUtils.valueOf(this.type, cs.getObject(columnIndex)); } }
這是mybatis-plus用來處理數值和枚舉類之間關系的處理類(這裡如果枚舉類是用@EnumValue來標註數值的話,處理類是相同包結構下的EnumAnnotationTypeHandler.class,原理相同),可以看到在一些列判空後最後使用EnumUtils工具類來決定返回枚舉類裡的哪個值。
EnumUtils.class
package com.baomidou.mybatisplus.core.toolkit; import com.baomidou.mybatisplus.core.enums.IEnum; import java.lang.reflect.Field; import java.util.Objects; public class EnumUtils { public EnumUtils() { } public static <E extends Enum<?> & IEnum> E valueOf(Class<E> enumClass, Object value) { E[] es = (Enum[])enumClass.getEnumConstants(); Enum[] var3 = es; int var4 = es.length; for(int var5 = 0; var5 < var4; ++var5) { E e = var3[var5]; if (Objects.equals(((IEnum)e).getValue(), value)) { return e; } } return null; } public static <E extends Enum<?>> E valueOf(Class<E> enumClass, Object value, Field enumField) { E[] es = (Enum[])enumClass.getEnumConstants(); Enum[] var4 = es; int var5 = es.length; for(int var6 = 0; var6 < var5; ++var6) { Enum e = var4[var6]; try { if (Objects.equals(enumField.get(e), value)) { return e; } } catch (IllegalAccessException var9) { } } return null; } }
理解瞭源碼就發現瞭問題所在瞭,讓這個EnumUtils返回null值的情況,大概是Objects.equals()判斷值是否相等時,找不到這個枚舉類裡面有任何和查詢出來的值相同的值。
原來oracle的NUMBER類型在這個工具類裡處理的時候,默認是BigDecimal類型,而我們在枚舉類裡定義的是Integer類型。
Objects.equals(Object a, Object b)
public static boolean equals(Object a, Object b) { return (a == b) || (a != null && a.equals(b)); }
所以在判斷是否邏輯一致的時候調用瞭Integer數值的equals方法,也就是
//false log.info(new Integer(6).equals(new BigDecimal(6)));
解決辦法就很簡單瞭,可以寫一個Number的子類,重寫一個業務邏輯一致的equals方法。當然最快速直接的就是把枚舉類裡的Integer改成BigDecimal類型。
修改後的枚舉類:
package com.abc.common.model.enums; import com.baomidou.mybatisplus.core.enums.IEnum; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; import lombok.Getter; import java.math.BigDecimal; /** * 字段類型枚舉 * @author huangsz * @version 1.0 * @date 2020/10/22 11:01 */ @Getter public enum FieldType implements IEnum<BigDecimal> { NONE(new BigDecimal(-1), ""), NORMAL_INPUT(new BigDecimal(0), "文本"), BIG_INPUT(new BigDecimal(1), "多文本"), DATETIME(new BigDecimal(2), "日期時間"), DATE(new BigDecimal(3), "日期"), TIME(new BigDecimal(4), "時間"), UPLOAD(new BigDecimal(5), "文件上傳"), DICT(new BigDecimal(6), "字典"); private final BigDecimal value; @JsonValue private final String fieldType; private static final FieldType[] values = values(); FieldType(BigDecimal value, String fieldType) { this.value = value; this.fieldType = fieldType; } @JsonCreator public static FieldType valueOf(BigDecimal value) { for (FieldType enu : values) { if (enu.getValue().equals(value)) { return enu; } } return null; } }
這回出現瞭,問題解決
到此這篇關於mybatis-plus3.0.1枚舉返回為null解決辦法的文章就介紹到這瞭,更多相關mybatis-plus枚舉返回null內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- mybatis判斷int是否為空的時候,需要註意的3點
- JAVA新手小白學正則表達式、包裝類、自動裝箱/自動拆箱以及BigDecimal
- Java中求Logn/log2 的精度問題
- java開發使用BigDecimal避坑四則
- JAVA biginteger類bigdecimal類的使用示例學習