|
@@ -17,23 +17,21 @@ package com.baomidou.mybatisplus.extension.handlers;
|
|
|
|
|
|
import com.baomidou.mybatisplus.annotation.EnumValue;
|
|
import com.baomidou.mybatisplus.annotation.EnumValue;
|
|
import com.baomidou.mybatisplus.core.enums.IEnum;
|
|
import com.baomidou.mybatisplus.core.enums.IEnum;
|
|
-import com.baomidou.mybatisplus.core.toolkit.EnumUtils;
|
|
|
|
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
|
|
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
|
|
-import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
|
|
|
|
-import org.apache.ibatis.logging.Log;
|
|
|
|
-import org.apache.ibatis.logging.LogFactory;
|
|
|
|
|
|
+import org.apache.ibatis.reflection.*;
|
|
|
|
+import org.apache.ibatis.reflection.invoker.Invoker;
|
|
import org.apache.ibatis.type.BaseTypeHandler;
|
|
import org.apache.ibatis.type.BaseTypeHandler;
|
|
import org.apache.ibatis.type.JdbcType;
|
|
import org.apache.ibatis.type.JdbcType;
|
|
|
|
|
|
import java.lang.reflect.Field;
|
|
import java.lang.reflect.Field;
|
|
-import java.lang.reflect.InvocationTargetException;
|
|
|
|
-import java.lang.reflect.Method;
|
|
|
|
|
|
+import java.math.BigDecimal;
|
|
import java.sql.CallableStatement;
|
|
import java.sql.CallableStatement;
|
|
import java.sql.PreparedStatement;
|
|
import java.sql.PreparedStatement;
|
|
import java.sql.ResultSet;
|
|
import java.sql.ResultSet;
|
|
import java.sql.SQLException;
|
|
import java.sql.SQLException;
|
|
import java.util.Arrays;
|
|
import java.util.Arrays;
|
|
import java.util.Map;
|
|
import java.util.Map;
|
|
|
|
+import java.util.Objects;
|
|
import java.util.Optional;
|
|
import java.util.Optional;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
|
|
@@ -45,49 +43,39 @@ import java.util.concurrent.ConcurrentHashMap;
|
|
*/
|
|
*/
|
|
public class MybatisEnumTypeHandler<E extends Enum<?>> extends BaseTypeHandler<Enum<?>> {
|
|
public class MybatisEnumTypeHandler<E extends Enum<?>> extends BaseTypeHandler<Enum<?>> {
|
|
|
|
|
|
- private static final Log LOGGER = LogFactory.getLog(MybatisEnumTypeHandler.class);
|
|
|
|
-
|
|
|
|
- private static final Map<Class<?>, Method> TABLE_METHOD_OF_ENUM_TYPES = new ConcurrentHashMap<>();
|
|
|
|
-
|
|
|
|
|
|
+ private static ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
|
|
|
|
+
|
|
|
|
+ private static final Map<String, String> TABLE_METHOD_OF_ENUM_TYPES = new ConcurrentHashMap<>();
|
|
|
|
+
|
|
private final Class<E> type;
|
|
private final Class<E> type;
|
|
-
|
|
|
|
- private final Method method;
|
|
|
|
|
|
+
|
|
|
|
+ private Invoker invoker;
|
|
|
|
|
|
public MybatisEnumTypeHandler(Class<E> type) {
|
|
public MybatisEnumTypeHandler(Class<E> type) {
|
|
if (type == null) {
|
|
if (type == null) {
|
|
throw new IllegalArgumentException("Type argument cannot be null");
|
|
throw new IllegalArgumentException("Type argument cannot be null");
|
|
}
|
|
}
|
|
this.type = type;
|
|
this.type = type;
|
|
- if (IEnum.class.isAssignableFrom(type)) {
|
|
|
|
- try {
|
|
|
|
- this.method = type.getMethod("getValue");
|
|
|
|
- } catch (NoSuchMethodException e) {
|
|
|
|
- throw new IllegalArgumentException(String.format("NoSuchMethod getValue() in Class: %s.", type.getName()));
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- this.method = TABLE_METHOD_OF_ENUM_TYPES.computeIfAbsent(type, k -> {
|
|
|
|
|
|
+ MetaClass metaClass = MetaClass.forClass(type, reflectorFactory);
|
|
|
|
+ String name = "value";
|
|
|
|
+ if (!IEnum.class.isAssignableFrom(type)) {
|
|
|
|
+ name = TABLE_METHOD_OF_ENUM_TYPES.computeIfAbsent(type.getName(), k -> {
|
|
Field field = dealEnumType(this.type).orElseThrow(() -> new IllegalArgumentException(String.format("Could not find @EnumValue in Class: %s.", type.getName())));
|
|
Field field = dealEnumType(this.type).orElseThrow(() -> new IllegalArgumentException(String.format("Could not find @EnumValue in Class: %s.", type.getName())));
|
|
- return ReflectionKit.getMethod(this.type, field);
|
|
|
|
|
|
+ return field.getName();
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
+ this.invoker = metaClass.getGetInvoker(name);
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
@SuppressWarnings("Duplicates")
|
|
@SuppressWarnings("Duplicates")
|
|
@Override
|
|
@Override
|
|
public void setNonNullParameter(PreparedStatement ps, int i, Enum<?> parameter, JdbcType jdbcType)
|
|
public void setNonNullParameter(PreparedStatement ps, int i, Enum<?> parameter, JdbcType jdbcType)
|
|
throws SQLException {
|
|
throws SQLException {
|
|
- try {
|
|
|
|
- this.method.setAccessible(true);
|
|
|
|
- if (jdbcType == null) {
|
|
|
|
- ps.setObject(i, this.method.invoke(parameter));
|
|
|
|
- } else {
|
|
|
|
- // see r3589
|
|
|
|
- ps.setObject(i, this.method.invoke(parameter), jdbcType.TYPE_CODE);
|
|
|
|
- }
|
|
|
|
- } catch (IllegalAccessException e) {
|
|
|
|
- LOGGER.error("unrecognized jdbcType, failed to set StringValue for type=" + parameter);
|
|
|
|
- } catch (InvocationTargetException e) {
|
|
|
|
- throw ExceptionUtils.mpe("Error: NoSuchMethod in %s. Cause:", e, this.type.getName());
|
|
|
|
|
|
+ if (jdbcType == null) {
|
|
|
|
+ ps.setObject(i, this.getValue(parameter));
|
|
|
|
+ } else {
|
|
|
|
+ // see r3589
|
|
|
|
+ ps.setObject(i, this.getValue(parameter), jdbcType.TYPE_CODE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -96,7 +84,7 @@ public class MybatisEnumTypeHandler<E extends Enum<?>> extends BaseTypeHandler<E
|
|
if (null == rs.getObject(columnName) && rs.wasNull()) {
|
|
if (null == rs.getObject(columnName) && rs.wasNull()) {
|
|
return null;
|
|
return null;
|
|
}
|
|
}
|
|
- return EnumUtils.valueOf(this.type, rs.getObject(columnName), this.method);
|
|
|
|
|
|
+ return this.valueOf(this.type, rs.getObject(columnName));
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
@Override
|
|
@@ -104,7 +92,7 @@ public class MybatisEnumTypeHandler<E extends Enum<?>> extends BaseTypeHandler<E
|
|
if (null == rs.getObject(columnIndex) && rs.wasNull()) {
|
|
if (null == rs.getObject(columnIndex) && rs.wasNull()) {
|
|
return null;
|
|
return null;
|
|
}
|
|
}
|
|
- return EnumUtils.valueOf(this.type, rs.getObject(columnIndex), this.method);
|
|
|
|
|
|
+ return this.valueOf(this.type, rs.getObject(columnIndex));
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
@Override
|
|
@@ -112,10 +100,39 @@ public class MybatisEnumTypeHandler<E extends Enum<?>> extends BaseTypeHandler<E
|
|
if (null == cs.getObject(columnIndex) && cs.wasNull()) {
|
|
if (null == cs.getObject(columnIndex) && cs.wasNull()) {
|
|
return null;
|
|
return null;
|
|
}
|
|
}
|
|
- return EnumUtils.valueOf(this.type, cs.getObject(columnIndex), this.method);
|
|
|
|
|
|
+ return this.valueOf(this.type, cs.getObject(columnIndex));
|
|
}
|
|
}
|
|
|
|
|
|
public static Optional<Field> dealEnumType(Class<?> clazz) {
|
|
public static Optional<Field> dealEnumType(Class<?> clazz) {
|
|
return clazz.isEnum() ? Arrays.stream(clazz.getDeclaredFields()).filter(field -> field.isAnnotationPresent(EnumValue.class)).findFirst() : Optional.empty();
|
|
return clazz.isEnum() ? Arrays.stream(clazz.getDeclaredFields()).filter(field -> field.isAnnotationPresent(EnumValue.class)).findFirst() : Optional.empty();
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ private <E extends Enum<?>> E valueOf(Class<E> enumClass, Object value) {
|
|
|
|
+ E[] es = enumClass.getEnumConstants();
|
|
|
|
+ return Arrays.stream(es).filter((e) -> equalsValue(value, getValue(e))).findAny().orElse(null);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 值比较
|
|
|
|
+ *
|
|
|
|
+ * @param sourceValue 数据库字段值
|
|
|
|
+ * @param targetValue 当前枚举属性值
|
|
|
|
+ * @return 是否匹配
|
|
|
|
+ * @since 3.2.1
|
|
|
|
+ */
|
|
|
|
+ protected boolean equalsValue(Object sourceValue, Object targetValue) {
|
|
|
|
+ if (sourceValue instanceof Number && targetValue instanceof Number
|
|
|
|
+ && new BigDecimal(String.valueOf(sourceValue)).compareTo(new BigDecimal(String.valueOf(targetValue))) == 0) {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ return Objects.equals(sourceValue, targetValue);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private Object getValue(Object object) {
|
|
|
|
+ try {
|
|
|
|
+ return invoker.invoke(object, new Object[0]);
|
|
|
|
+ } catch (ReflectiveOperationException e) {
|
|
|
|
+ throw ExceptionUtils.mpe(e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|