Răsfoiți Sursa

修复json类型处理器自动绑定异常问题

woody 1 an în urmă
părinte
comite
9daab99ca0

+ 8 - 13
framework-common/src/main/java/com/chelvc/framework/common/util/ObjectUtils.java

@@ -444,21 +444,13 @@ public final class ObjectUtils {
      * @return 字段实例
      */
     public static Field lookupField(@NonNull Class<?> clazz, @NonNull String name) {
-        Field field = null;
-        NoSuchFieldException undefined = null;
         do {
             try {
-                field = clazz.getDeclaredField(name);
-            } catch (NoSuchFieldException e) {
-                if (undefined == null) {
-                    undefined = e;
-                }
+                return clazz.getDeclaredField(name);
+            } catch (NoSuchFieldException ignored) {
             }
-        } while (field == null && (clazz = clazz.getSuperclass()) != Object.class);
-        if (field == null) {
-            throw new RuntimeException(undefined);
-        }
-        return field;
+        } while ((clazz = clazz.getSuperclass()) != Object.class);
+        return null;
     }
 
     /**
@@ -548,7 +540,10 @@ public final class ObjectUtils {
         int index = 0;
         boolean continuing = true;
         do {
-            for (Field field : CLASS_FIELD_MAPPING.computeIfAbsent(clazz, Class::getDeclaredFields)) {
+            Field[] fields = CLASS_FIELD_MAPPING.computeIfAbsent(
+                    clazz, c -> ObjectUtils.ifNull(c.getDeclaredFields(), () -> new Field[0])
+            );
+            for (Field field : fields) {
                 if (!Modifier.isStatic(field.getModifiers()) && !field.getName().startsWith("this$")) {
                     if (!(continuing = Boolean.TRUE.equals(function.apply(index++, field)))) {
                         break;

+ 53 - 25
framework-database/src/main/java/com/chelvc/framework/database/interceptor/JsonHandlerConfigureInterceptor.java

@@ -3,6 +3,7 @@ package com.chelvc.framework.database.interceptor;
 import java.lang.reflect.Field;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicLong;
@@ -41,6 +42,7 @@ import com.google.common.collect.Maps;
 import javassist.ClassPool;
 import javassist.CtClass;
 import javassist.CtConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.ibatis.parsing.XNode;
 import org.apache.ibatis.type.UnknownTypeHandler;
 import org.w3c.dom.Document;
@@ -52,6 +54,7 @@ import org.w3c.dom.Element;
  * @author Woody
  * @date 2024/4/6
  */
+@Slf4j
 public class JsonHandlerConfigureInterceptor extends MybatisConfigureInterceptor {
     /**
      * JSON类型处理器计数器
@@ -63,6 +66,17 @@ public class JsonHandlerConfigureInterceptor extends MybatisConfigureInterceptor
      */
     private final Map<Type, Class<?>> handlers = Maps.newConcurrentMap();
 
+    /**
+     * 判断是否是元类型
+     *
+     * @param clazz 对象类型
+     * @return true/false
+     */
+    private boolean isMetaType(Class<?> clazz) {
+        return DatabaseContextHolder.isTypeHandlerRegistered(clazz) || Map.class.isAssignableFrom(clazz)
+                || Collection.class.isAssignableFrom(clazz);
+    }
+
     /**
      * 绑定字段JSON类型处理器
      *
@@ -174,6 +188,9 @@ public class JsonHandlerConfigureInterceptor extends MybatisConfigureInterceptor
      * @return true/false
      */
     private boolean isJsonHandlerConfigurable(Class<?> clazz) {
+        if (this.isMetaType(clazz)) {
+            return false;
+        }
         Reference<Boolean> configurable = new Reference<>();
         ObjectUtils.iterateFields(clazz, (i, field) -> {
             if (this.isJsonHandlerConfigurable(field)) {
@@ -204,14 +221,14 @@ public class JsonHandlerConfigureInterceptor extends MybatisConfigureInterceptor
      */
     private Class<?> getSelectResultType(XNode node) {
         String type = node.getStringAttribute("resultType");
-        if (StringUtils.isEmpty(type)) {
-            return null;
-        }
-        try {
-            return Class.forName(type);
-        } catch (ClassNotFoundException e) {
-            throw new RuntimeException(e);
+        if (StringUtils.notEmpty(type)) {
+            try {
+                return Class.forName(type);
+            } catch (ClassNotFoundException e) {
+                log.warn("Result type class load failed: {}", e.getMessage());
+            }
         }
+        return null;
     }
 
     /**
@@ -221,11 +238,15 @@ public class JsonHandlerConfigureInterceptor extends MybatisConfigureInterceptor
      * @return 对象类型
      */
     private Class<?> getResultMappingType(XNode node) {
-        try {
-            return Class.forName(node.getStringAttribute("type"));
-        } catch (ClassNotFoundException e) {
-            throw new RuntimeException(e);
+        String type = node.getStringAttribute("type");
+        if (StringUtils.notEmpty(type)) {
+            try {
+                return Class.forName(type);
+            } catch (ClassNotFoundException e) {
+                log.warn("Result map class load failed: {}", e.getMessage());
+            }
         }
+        return null;
     }
 
     /**
@@ -267,20 +288,23 @@ public class JsonHandlerConfigureInterceptor extends MybatisConfigureInterceptor
         // 设置已有resultMap的json类型处理器
         List<XNode> maps = mapper.evalNodes("resultMap");
         if (ObjectUtils.notEmpty(maps)) {
-            maps.forEach(map -> {
+            for (XNode map : maps) {
                 Class<?> clazz = this.getResultMappingType(map);
+                if (clazz == null || this.isMetaType(clazz)) {
+                    continue;
+                }
                 for (XNode child : map.getChildren()) {
                     // 判断当前是有存在typeHandler,如果不存在且字段满足配置json类型处理器条件,则自动绑定json类型处理器
                     if (StringUtils.isEmpty(child.getStringAttribute("typeHandler"))) {
                         String property = child.getStringAttribute("property");
-                        Field field = ObjectUtils.getField(clazz, property);
-                        if (this.isJsonHandlerConfigurable(field)) {
+                        Field field = ObjectUtils.lookupField(clazz, property);
+                        if (field != null && this.isJsonHandlerConfigurable(field)) {
                             Class<?> handler = this.lookupJsonHandlerClass(field);
                             ((Element) child.getNode()).setAttribute("typeHandler", handler.getName());
                         }
                     }
                 }
-            });
+            }
         }
 
         // 设置resultType对应的resultMap,并将原来的resultType替换成resultMap
@@ -288,20 +312,24 @@ public class JsonHandlerConfigureInterceptor extends MybatisConfigureInterceptor
         List<XNode> selects = mapper.evalNodes("select");
         if (ObjectUtils.notEmpty(selects)) {
             Map<Class<?>, Element> cache = Maps.newHashMap();
-            selects.forEach(select -> {
+            for (XNode select : selects) {
                 // 判断resultType是否可配置json类型处理器
                 Class<?> clazz = this.getSelectResultType(select);
-                if (clazz != null && this.isJsonHandlerConfigurable(clazz)) {
-                    // 构建并注册resultMap
-                    Element map = cache.computeIfAbsent(clazz, c -> this.initializeResultMapping(document, clazz));
-                    mapper.getNode().appendChild(map);
+                try {
+                    if (clazz != null && this.isJsonHandlerConfigurable(clazz)) {
+                        // 构建并注册resultMap
+                        Element map = cache.computeIfAbsent(clazz, c -> this.initializeResultMapping(document, clazz));
+                        mapper.getNode().appendChild(map);
 
-                    // 用户新生成的resultMap替换resultType
-                    Element element = (Element) select.getNode();
-                    element.removeAttribute("resultType");
-                    element.setAttribute("resultMap", map.getAttribute("id"));
+                        // 用户新生成的resultMap替换resultType
+                        Element element = (Element) select.getNode();
+                        element.removeAttribute("resultType");
+                        element.setAttribute("resultMap", map.getAttribute("id"));
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
                 }
-            });
+            }
         }
     }