From 745c89683ee86a8448d97abb41deb5fd62aab321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=80=E6=BA=90=E6=B5=B7=E5=93=A5?= Date: Sun, 16 Apr 2023 13:23:47 +0800 Subject: [PATCH] =?UTF-8?q?feature:=20=E4=B8=BA=20entity=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E6=9E=9A=E4=B8=BE=E5=B1=9E=E6=80=A7=E7=9A=84=E6=94=AF?= =?UTF-8?q?=E6=8C=81=20close=20#I6W15K?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/mybatisflex/annotation/EnumValue.java | 25 ++++ .../handler/CompositeEnumTypeHandler.java | 63 ++++++++++ .../core/handler/FlexEnumTypeHandler.java | 113 ++++++++++++++++++ .../mybatisflex/core/table/ColumnInfo.java | 12 +- .../core/table/TableInfoFactory.java | 1 + .../com/mybatisflex/core/util/ClassUtil.java | 25 ++-- 6 files changed, 226 insertions(+), 13 deletions(-) create mode 100644 mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/EnumValue.java create mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/handler/CompositeEnumTypeHandler.java create mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/handler/FlexEnumTypeHandler.java diff --git a/mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/EnumValue.java b/mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/EnumValue.java new file mode 100644 index 00000000..342e8e27 --- /dev/null +++ b/mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/EnumValue.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mybatisflex.annotation; + +import java.lang.annotation.*; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +public @interface EnumValue { + +} \ No newline at end of file diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/handler/CompositeEnumTypeHandler.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/handler/CompositeEnumTypeHandler.java new file mode 100644 index 00000000..9695009b --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/handler/CompositeEnumTypeHandler.java @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mybatisflex.core.handler; + +import com.mybatisflex.annotation.EnumValue; +import com.mybatisflex.core.util.ClassUtil; +import org.apache.ibatis.type.EnumTypeHandler; +import org.apache.ibatis.type.JdbcType; +import org.apache.ibatis.type.TypeHandler; + +import java.lang.reflect.Field; +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +public class CompositeEnumTypeHandler> implements TypeHandler { + + private final TypeHandler delegate; + + public CompositeEnumTypeHandler(Class enumClass) { + List enumDbValueFields = ClassUtil.getAllFields(enumClass, f -> f.getAnnotation(EnumValue.class) != null); + if (enumDbValueFields.isEmpty()) { + delegate = new EnumTypeHandler<>(enumClass); + } else { + delegate = new FlexEnumTypeHandler<>(enumClass); + } + } + + @Override + public void setParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException { + delegate.setParameter(ps, i, parameter, jdbcType); + } + + @Override + public E getResult(ResultSet rs, String columnName) throws SQLException { + return delegate.getResult(rs, columnName); + } + + @Override + public E getResult(ResultSet rs, int columnIndex) throws SQLException { + return delegate.getResult(rs, columnIndex); + } + + @Override + public E getResult(CallableStatement cs, int columnIndex) throws SQLException { + return delegate.getResult(cs, columnIndex); + } +} diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/handler/FlexEnumTypeHandler.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/handler/FlexEnumTypeHandler.java new file mode 100644 index 00000000..1d11eeb8 --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/handler/FlexEnumTypeHandler.java @@ -0,0 +1,113 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mybatisflex.core.handler; + +import com.mybatisflex.annotation.EnumValue; +import com.mybatisflex.core.exception.FlexExceptions; +import com.mybatisflex.core.util.ClassUtil; +import com.mybatisflex.core.util.StringUtil; +import org.apache.ibatis.type.BaseTypeHandler; +import org.apache.ibatis.type.JdbcType; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +public class FlexEnumTypeHandler> extends BaseTypeHandler { + + private Class enumPropertyType; + private E[] enums; + private Method getter; + + public FlexEnumTypeHandler(Class enumClass) { + + List allFields = ClassUtil.getAllFields(enumClass, field -> field.getAnnotation(EnumValue.class) != null); + Field field = allFields.get(0); + + List allMethods = ClassUtil.getAllMethods(enumClass, method -> { + String methodName = method.getName(); + return methodName.equals("get" + StringUtil.firstCharToUpperCase(field.getName())); + }); + + enumPropertyType = field.getType(); + enums = enumClass.getEnumConstants(); + getter = allMethods.get(0); + } + + + @Override + public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException { + Object value = getValue(parameter); + if (jdbcType == null) { + ps.setObject(i, value); + } else { + ps.setObject(i, value, jdbcType.TYPE_CODE); + } + } + + + private Object getValue(Object object) { + try { + return this.getter.invoke(object); + } catch (Exception e) { + throw FlexExceptions.wrap(e); + } + } + + + @Override + public E getNullableResult(ResultSet rs, String columnName) throws SQLException { + Object value = rs.getObject(columnName, this.enumPropertyType); + if (null == value && rs.wasNull()) { + return null; + } + return convertToEnum(value); + } + + + @Override + public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException { + Object value = rs.getObject(columnIndex, this.enumPropertyType); + if (null == value && rs.wasNull()) { + return null; + } + return convertToEnum(value); + } + + + @Override + public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { + Object value = cs.getObject(columnIndex, this.enumPropertyType); + if (null == value && cs.wasNull()) { + return null; + } + return convertToEnum(value); + } + + + private E convertToEnum(Object value) { + for (E e : enums) { + if (value.equals(getValue(e))) { + return e; + } + } + return null; + } +} diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/table/ColumnInfo.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/table/ColumnInfo.java index f039172d..8378e646 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/table/ColumnInfo.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/table/ColumnInfo.java @@ -15,6 +15,7 @@ */ package com.mybatisflex.core.table; +import com.mybatisflex.core.handler.CompositeEnumTypeHandler; import com.mybatisflex.core.mask.MaskTypeHandler; import com.mybatisflex.core.util.StringUtil; import org.apache.ibatis.type.JdbcType; @@ -51,7 +52,6 @@ public class ColumnInfo { protected String maskType; - public String getColumn() { return column; } @@ -87,12 +87,16 @@ public class ColumnInfo { public TypeHandler buildTypeHandler() { //优先使用自定义的 typeHandler - if (typeHandler != null){ + if (typeHandler != null) { return typeHandler; } + //枚举 + else if (propertyType.isEnum()) { + typeHandler = new CompositeEnumTypeHandler(propertyType); + } //若用户未定义 typeHandler,而配置了数据脱敏,则使用脱敏的 handler 处理 - else if (StringUtil.isNotBlank(maskType)){ - typeHandler = new MaskTypeHandler(maskType); + else if (StringUtil.isNotBlank(maskType)) { + typeHandler = new MaskTypeHandler(maskType); } return typeHandler; diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/table/TableInfoFactory.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/table/TableInfoFactory.java index 4094d8b7..3459b7f2 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/table/TableInfoFactory.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/table/TableInfoFactory.java @@ -173,6 +173,7 @@ public class TableInfoFactory { //未配置 typeHandler 的情况下,只支持基本数据类型,不支持比如 list set 或者自定义的类等 if ((column == null || column.typeHandler() == UnknownTypeHandler.class) + && !field.getType().isEnum() && !defaultSupportColumnTypes.contains(field.getType())) { continue; } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/ClassUtil.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/ClassUtil.java index 675bd76a..23fad6a7 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/ClassUtil.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/ClassUtil.java @@ -144,22 +144,29 @@ public class ClassUtil { public static List getAllFields(Class cl) { List fields = new ArrayList<>(); - doGetFields(cl, fields); + doGetFields(cl, fields, null); return fields; } + public static List getAllFields(Class cl, Predicate predicate) { + List fields = new ArrayList<>(); + doGetFields(cl, fields, predicate); + return fields; + } - private static void doGetFields(Class cl, List fields) { + private static void doGetFields(Class cl, List fields, Predicate predicate) { if (cl == null || cl == Object.class) { return; } Field[] declaredFields = cl.getDeclaredFields(); for (Field declaredField : declaredFields) { - fields.add(declaredField); + if (predicate == null || predicate.test(declaredField)) { + fields.add(declaredField); + } } - doGetFields(cl.getSuperclass(), fields); + doGetFields(cl.getSuperclass(), fields, predicate); } public static List getAllMethods(Class cl) { @@ -168,26 +175,26 @@ public class ClassUtil { return methods; } - public static List getAllMethods(Class cl, Predicate tester) { + public static List getAllMethods(Class cl, Predicate predicate) { List methods = new ArrayList<>(); - doGetMethods(cl, methods, tester); + doGetMethods(cl, methods, predicate); return methods; } - private static void doGetMethods(Class cl, List methods, Predicate tester) { + private static void doGetMethods(Class cl, List methods, Predicate predicate) { if (cl == null || cl == Object.class) { return; } Method[] declaredMethods = cl.getDeclaredMethods(); for (Method method : declaredMethods) { - if (tester == null || tester.test(method)) { + if (predicate == null || predicate.test(method)) { methods.add(method); } } - doGetMethods(cl.getSuperclass(), methods, tester); + doGetMethods(cl.getSuperclass(), methods, predicate); } }