From e60e869fe919b61e024ea67a2b92b8f3fc728548 Mon Sep 17 00:00:00 2001 From: redkale Date: Thu, 21 Sep 2023 17:25:36 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96Copier?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/javax/annotation/Priority.java | 3 +- src/main/java/javax/annotation/Resource.java | 2 +- .../java/javax/persistence/Cacheable.java | 4 +- src/main/java/javax/persistence/Column.java | 4 +- src/main/java/javax/persistence/Entity.java | 4 +- src/main/java/javax/persistence/Id.java | 4 +- src/main/java/javax/persistence/Index.java | 4 +- src/main/java/javax/persistence/Table.java | 4 +- .../java/javax/persistence/Transient.java | 4 +- .../javax/persistence/UniqueConstraint.java | 4 +- .../java/org/redkale/source/EntityCache.java | 22 +- src/main/java/org/redkale/util/Copier.java | 247 +++++++++++------- 12 files changed, 176 insertions(+), 130 deletions(-) diff --git a/src/main/java/javax/annotation/Priority.java b/src/main/java/javax/annotation/Priority.java index 32758523f..f501c4090 100644 --- a/src/main/java/javax/annotation/Priority.java +++ b/src/main/java/javax/annotation/Priority.java @@ -25,7 +25,8 @@ import java.lang.annotation.*; * * @since Common Annotations 1.2 * - * @deprecated replace by org.redkale.annotation.Priority + * @deprecated replace by {@link org.redkale.annotation.Priority} + * */ @Deprecated(since = "2.8.0") @Target({ElementType.TYPE}) diff --git a/src/main/java/javax/annotation/Resource.java b/src/main/java/javax/annotation/Resource.java index 461066414..6d3366ef7 100644 --- a/src/main/java/javax/annotation/Resource.java +++ b/src/main/java/javax/annotation/Resource.java @@ -12,7 +12,7 @@ import java.lang.annotation.*; * * @see org.redkale.annotation.Resource * - * @deprecated replace by org.redkale.annotation.Resource + * @deprecated replace by {@link org.redkale.annotation.Resource} */ @Deprecated(since = "2.8.0") @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) diff --git a/src/main/java/javax/persistence/Cacheable.java b/src/main/java/javax/persistence/Cacheable.java index c1b553177..44b13a7fa 100644 --- a/src/main/java/javax/persistence/Cacheable.java +++ b/src/main/java/javax/persistence/Cacheable.java @@ -15,9 +15,9 @@ ***************************************************************************** */ package javax.persistence; +import java.lang.annotation.*; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import java.lang.annotation.*; /** * Specifies whether an entity should be cached if caching is enabled @@ -33,7 +33,7 @@ import java.lang.annotation.*; * * @since Java Persistence 2.0 * - * @deprecated replace by org.redkale.persistence.Cacheable + * @deprecated replace by {@link org.redkale.persistence.Cacheable} * @see org.redkale.persistence.Cacheable */ @Deprecated(since = "2.8.0") diff --git a/src/main/java/javax/persistence/Column.java b/src/main/java/javax/persistence/Column.java index 46e5a6437..f9d817365 100644 --- a/src/main/java/javax/persistence/Column.java +++ b/src/main/java/javax/persistence/Column.java @@ -15,9 +15,9 @@ ***************************************************************************** */ package javax.persistence; -import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.*; import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * Specifies the mapped column for a persistent property or field. @@ -47,7 +47,7 @@ import static java.lang.annotation.ElementType.*; * * @since Java Persistence 1.0 * - * @deprecated replace by org.redkale.persistence.Column + * @deprecated replace by {@link org.redkale.persistence.Column} * * @see org.redkale.persistence.Column */ diff --git a/src/main/java/javax/persistence/Entity.java b/src/main/java/javax/persistence/Entity.java index 638bbe06e..0976a4eee 100644 --- a/src/main/java/javax/persistence/Entity.java +++ b/src/main/java/javax/persistence/Entity.java @@ -15,9 +15,9 @@ ******************************************************************************/ package javax.persistence; +import java.lang.annotation.*; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import java.lang.annotation.*; /** * Specifies that the class is an entity. This annotation is applied to the @@ -25,7 +25,7 @@ import java.lang.annotation.*; * * @since Java Persistence 1.0 * - * @deprecated replace by org.redkale.persistence.Entity + * @deprecated replace by {@link org.redkale.persistence.Entity} * * @see org.redkale.persistence.Entity */ diff --git a/src/main/java/javax/persistence/Id.java b/src/main/java/javax/persistence/Id.java index 49aa62a01..e27430c60 100644 --- a/src/main/java/javax/persistence/Id.java +++ b/src/main/java/javax/persistence/Id.java @@ -15,9 +15,9 @@ ******************************************************************************/ package javax.persistence; -import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.*; import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * Specifies the primary key of an entity. @@ -47,7 +47,7 @@ import static java.lang.annotation.ElementType.*; * * @since Java Persistence 1.0 * - * @deprecated replace by org.redkale.persistence.Id + * @deprecated replace by {@link org.redkale.persistence.Id} * * @see org.redkale.persistence.Id */ diff --git a/src/main/java/javax/persistence/Index.java b/src/main/java/javax/persistence/Index.java index 767dcbedf..bf1f58b48 100644 --- a/src/main/java/javax/persistence/Index.java +++ b/src/main/java/javax/persistence/Index.java @@ -14,8 +14,8 @@ ***************************************************************************** */ package javax.persistence; -import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * Used in schema generation to specify creation of an index. @@ -38,7 +38,7 @@ import java.lang.annotation.*; * * @since Java Persistence 2.1 * - * @deprecated replace by org.redkale.persistence.Index + * @deprecated replace by {@link org.redkale.persistence.Index} * * @see org.redkale.persistence.Index * diff --git a/src/main/java/javax/persistence/Table.java b/src/main/java/javax/persistence/Table.java index 857fbf1c9..310f65369 100644 --- a/src/main/java/javax/persistence/Table.java +++ b/src/main/java/javax/persistence/Table.java @@ -15,9 +15,9 @@ ***************************************************************************** */ package javax.persistence; +import java.lang.annotation.*; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import java.lang.annotation.*; /** * Specifies the primary table for the annotated entity. Additional @@ -37,7 +37,7 @@ import java.lang.annotation.*; * * @since Java Persistence 1.0 * - * @deprecated replace by org.redkale.persistence.Table + * @deprecated replace by {@link org.redkale.persistence.Table} * * @see org.redkale.persistence.Table */ diff --git a/src/main/java/javax/persistence/Transient.java b/src/main/java/javax/persistence/Transient.java index 635f79df0..3eaee2225 100644 --- a/src/main/java/javax/persistence/Transient.java +++ b/src/main/java/javax/persistence/Transient.java @@ -15,9 +15,9 @@ ******************************************************************************/ package javax.persistence; -import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.*; import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * Specifies that the property or field is not persistent. It is used @@ -37,7 +37,7 @@ import static java.lang.annotation.ElementType.*; * * @since Java Persistence 1.0 * - * @deprecated replace by org.redkale.persistence.Transient + * @deprecated replace by {@link org.redkale.persistence.Transient} * * @see org.redkale.persistence.Transient */ diff --git a/src/main/java/javax/persistence/UniqueConstraint.java b/src/main/java/javax/persistence/UniqueConstraint.java index b3af5986c..d04667c08 100644 --- a/src/main/java/javax/persistence/UniqueConstraint.java +++ b/src/main/java/javax/persistence/UniqueConstraint.java @@ -15,8 +15,8 @@ ***************************************************************************** */ package javax.persistence; -import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * Specifies that a unique constraint is to be included in @@ -35,7 +35,7 @@ import java.lang.annotation.*; * * @since Java Persistence 1.0 * - * @deprecated replace by org.redkale.persistence.UniqueConstraint + * @deprecated replace by {@link org.redkale.persistence.UniqueConstraint} * * @see org.redkale.persistence.UniqueConstraint * diff --git a/src/main/java/org/redkale/source/EntityCache.java b/src/main/java/org/redkale/source/EntityCache.java index ae6cef65e..5e640213d 100644 --- a/src/main/java/org/redkale/source/EntityCache.java +++ b/src/main/java/org/redkale/source/EntityCache.java @@ -65,7 +65,7 @@ public final class EntityCache { private final Copier newCopier; //修改时的复制器, 排除了标记为@Transient或@Column(updatable=false)的字段 - private final Copier chgCopier; + private final Copier uptCopier; //是否已经全量加载过 private volatile boolean fullloaded; @@ -110,26 +110,24 @@ public final class EntityCache { } } this.needCopy = !direct; - this.newCopier = Copier.create(type, type, (m) -> { + this.newCopier = Copier.create(type, type, (e, c) -> { try { - java.lang.reflect.Field field = type.getDeclaredField(m); - return field.getAnnotation(Transient.class) == null && field.getAnnotation(javax.persistence.Transient.class) == null; - } catch (Exception e) { + return e.getAnnotation(Transient.class) == null && e.getAnnotation(javax.persistence.Transient.class) == null; + } catch (Exception ex) { return true; } }); - this.chgCopier = Copier.create(type, type, (m) -> { + this.uptCopier = Copier.create(type, type, (e, c) -> { try { - java.lang.reflect.Field field = type.getDeclaredField(m); - if (field.getAnnotation(Transient.class) != null) { + if (e.getAnnotation(Transient.class) != null) { return false; } - if (field.getAnnotation(javax.persistence.Transient.class) != null) { + if (e.getAnnotation(javax.persistence.Transient.class) != null) { return false; } - Column column = field.getAnnotation(Column.class); + Column column = e.getAnnotation(Column.class); return (column == null || column.updatable()); - } catch (Exception e) { + } catch (Exception ex) { return true; } }); @@ -874,7 +872,7 @@ public final class EntityCache { } tableLock.lock(); //表锁, 可优化成行锁 try { - this.chgCopier.apply(rs, entity); + this.uptCopier.apply(rs, entity); } finally { tableLock.unlock(); } diff --git a/src/main/java/org/redkale/util/Copier.java b/src/main/java/org/redkale/util/Copier.java index 8e5a7a19c..64c809055 100644 --- a/src/main/java/org/redkale/util/Copier.java +++ b/src/main/java/org/redkale/util/Copier.java @@ -7,6 +7,7 @@ import java.lang.reflect.*; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.function.*; +import java.util.stream.Collectors; import org.redkale.asm.*; import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; import static org.redkale.asm.Opcodes.*; @@ -392,7 +393,7 @@ public interface Copier extends BiFunction { * @param 源类泛型 * @param destClass 目标类名 * @param srcClass 源类名 - * @param srcColumnPredicate 需复制的字段名判断期 + * @param srcColumnPredicate 需复制源类的字段名判断器 * * @return 复制器 */ @@ -408,7 +409,7 @@ public interface Copier extends BiFunction { * @param 源类泛型 * @param destClass 目标类名 * @param srcClass 源类名 - * @param srcColumnPredicate 需复制的字段名判断期 + * @param srcColumnPredicate 需复制源类的字段名判断器 * @param names 源字段名与目标字段名的映射关系 * * @return 复制器 @@ -426,7 +427,7 @@ public interface Copier extends BiFunction { * @param 源类泛型 * @param destClass 目标类名 * @param srcClass 源类名 - * @param srcColumnPredicate 需复制的字段名判断期 + * @param srcColumnPredicate 需复制源类的字段名判断器 * * @return 复制器 */ @@ -443,7 +444,7 @@ public interface Copier extends BiFunction { * @param 源类泛型 * @param destClass 目标类名 * @param srcClass 源类名 - * @param srcColumnPredicate 需复制的字段名判断期 + * @param srcColumnPredicate 需复制源类的字段名判断器 * @param names 源字段名与目标字段名的映射关系 * * @return 复制器 @@ -478,7 +479,7 @@ public interface Copier extends BiFunction { * @param destClass 目标类名 * @param srcClass 源类名 * @param options 可配项 - * @param srcColumnPredicate 需复制的字段名判断期 + * @param srcColumnPredicate 需复制源类的字段名判断器 * @param nameAlias 源字段名与目标字段名的映射关系 * * @return 复制器 @@ -559,6 +560,126 @@ public interface Copier extends BiFunction { // ------------------------------------------------------------------------------ final boolean destIsMap = Map.class.isAssignableFrom(destClass); final boolean srcIsMap = Map.class.isAssignableFrom(srcClass); + final Predicate> throwPredicate = e -> !RuntimeException.class.isAssignableFrom(e); + final Map elements = new TreeMap<>(); + final Map destNewNames = new TreeMap<>(); + int ingoreCount = 0; + if (srcIsMap) { //Map -> JavaBean + for (java.lang.reflect.Field field : destClass.getFields()) { + if (Modifier.isStatic(field.getModifiers())) { + continue; + } + if (Modifier.isFinal(field.getModifiers())) { + continue; + } + if (!Modifier.isPublic(field.getModifiers())) { + continue; + } + final String sfname = field.getName(); + if (srcColumnPredicate != null && !srcColumnPredicate.test(field, sfname)) { + ingoreCount++; + continue; + } + final String dfname = nameAlias == null ? sfname : nameAlias.getOrDefault(sfname, sfname); + if (!Objects.equals(sfname, dfname)) { + destNewNames.put(sfname, dfname); + } + elements.put(dfname, field); + } + + for (java.lang.reflect.Method setter : destClass.getMethods()) { + if (Modifier.isStatic(setter.getModifiers())) { + continue; + } + if (setter.getParameterTypes().length != 1) { + continue; + } + if (Utility.contains(setter.getExceptionTypes(), throwPredicate)) { + continue; //setter方法带有非RuntimeException异常 + } + if (!setter.getName().startsWith("set")) { + continue; + } + String sfname = Utility.readFieldName(setter.getName()); + if (sfname.isEmpty()) { + continue; + } + if (srcColumnPredicate != null && !srcColumnPredicate.test(setter, sfname)) { + ingoreCount++; + continue; + } + final String dfname = nameAlias == null ? sfname : nameAlias.getOrDefault(sfname, sfname); + if (!Objects.equals(sfname, dfname)) { + destNewNames.put(sfname, dfname); + } + elements.put(dfname, setter); + } + } else { //JavaBean -> Map/JavaBean + for (java.lang.reflect.Field field : srcClass.getFields()) { + if (Modifier.isStatic(field.getModifiers())) { + continue; + } + if (Modifier.isFinal(field.getModifiers())) { + continue; + } + if (!Modifier.isPublic(field.getModifiers())) { + continue; + } + final String sfname = field.getName(); + if (srcColumnPredicate != null && !srcColumnPredicate.test(field, sfname)) { + ingoreCount++; + continue; + } + final String dfname = nameAlias == null ? sfname : nameAlias.getOrDefault(sfname, sfname); + if (!Objects.equals(sfname, dfname)) { + destNewNames.put(sfname, dfname); + } + elements.put(sfname, field); + } + for (java.lang.reflect.Method getter : srcClass.getMethods()) { + if (Modifier.isStatic(getter.getModifiers())) { + continue; + } + if (getter.getParameterTypes().length > 0) { + continue; + } + if ("getClass".equals(getter.getName())) { + continue; + } + if (Utility.contains(getter.getExceptionTypes(), throwPredicate)) { + continue; //setter方法带有非RuntimeException异常 + } + if (!getter.getName().startsWith("get") && !getter.getName().startsWith("is")) { + continue; + } + final String sfname = Utility.readFieldName(getter.getName()); + if (sfname.isEmpty()) { + continue; + } + if (srcColumnPredicate != null && !srcColumnPredicate.test(getter, sfname)) { + ingoreCount++; + continue; + } + final String dfname = nameAlias == null ? sfname : nameAlias.getOrDefault(sfname, sfname); + if (!Objects.equals(sfname, dfname)) { + destNewNames.put(sfname, dfname); + } + elements.put(sfname, getter); + } + } + StringBuilder extendInfo = new StringBuilder(); + if (ingoreCount > 0 || nameAlias != null) { + if (ingoreCount > 0) { + extendInfo.append(elements.keySet().stream().collect(Collectors.joining(","))); + } + if (nameAlias != null) { + if (extendInfo.length() > 0) { + extendInfo.append(";"); + } + destNewNames.forEach((k, v) -> extendInfo.append(k).append(':').append(v)); + } + } + // ------------------------------------------------------------------------------ final String supDynName = Copier.class.getName().replace('.', '/'); final String destClassName = destClass.getName().replace('.', '/'); final String srcClassName = srcClass.getName().replace('.', '/'); @@ -568,16 +689,14 @@ public interface Copier extends BiFunction { final String utilClassName = Utility.class.getName().replace('.', '/'); final String newDynName = "org/redkaledyn/copier/_Dyn" + Copier.class.getSimpleName() + "_" + options + "__" + srcClass.getName().replace('.', '_').replace('$', '_') - + "__" + destClass.getName().replace('.', '_').replace('$', '_'); - if (srcColumnPredicate == null && nameAlias == null) { - try { - Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); - return (Copier) (clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz).getDeclaredConstructor().newInstance(); - } catch (Throwable ex) { - } + + "__" + destClass.getName().replace('.', '_').replace('$', '_') + + (extendInfo.length() == 0 ? "" : Utility.md5Hex(extendInfo.toString())); + try { + Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + return (Copier) (clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz).getDeclaredConstructor().newInstance(); + } catch (Throwable ex) { } - final Predicate> throwPredicate = e -> !RuntimeException.class.isAssignableFrom(e); // ------------------------------------------------------------------------------ ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); FieldVisitor fv; @@ -623,49 +742,6 @@ public interface Copier extends BiFunction { mv.visitEnd(); } { - final Map elements = new LinkedHashMap<>(); - for (java.lang.reflect.Field field : destClass.getFields()) { - if (Modifier.isStatic(field.getModifiers())) { - continue; - } - if (Modifier.isFinal(field.getModifiers())) { - continue; - } - if (!Modifier.isPublic(field.getModifiers())) { - continue; - } - final String sfname = field.getName(); - if (srcColumnPredicate != null && !srcColumnPredicate.test(field, sfname)) { - continue; - } - final String dfname = nameAlias == null ? sfname : nameAlias.getOrDefault(sfname, sfname); - elements.put(dfname, field); - } - - for (java.lang.reflect.Method setter : destClass.getMethods()) { - if (Modifier.isStatic(setter.getModifiers())) { - continue; - } - if (setter.getParameterTypes().length != 1) { - continue; - } - if (Utility.contains(setter.getExceptionTypes(), throwPredicate)) { - continue; //setter方法带有非RuntimeException异常 - } - if (!setter.getName().startsWith("set")) { - continue; - } - String sfname = Utility.readFieldName(setter.getName()); - if (sfname.isEmpty()) { - continue; - } - if (srcColumnPredicate != null && !srcColumnPredicate.test(setter, sfname)) { - continue; - } - final String dfname = nameAlias == null ? sfname : nameAlias.getOrDefault(sfname, sfname); - elements.put(dfname, setter); - } - mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "lambda$0", "(" + destDesc + "Ljava/lang/Object;Ljava/lang/Object;)V", null, null); Label goLabel = new Label(); int i = 0; @@ -741,23 +817,14 @@ public interface Copier extends BiFunction { } Predicate simpler = t -> t.isPrimitive() || t == String.class || Number.class.isAssignableFrom(t); + for (Map.Entry en : elements.entrySet()) { + if (!(en.getValue() instanceof java.lang.reflect.Field)) { + continue; + } + java.lang.reflect.Field field = (java.lang.reflect.Field) en.getValue(); + final String sfname = en.getKey(); - for (java.lang.reflect.Field field : srcClass.getFields()) { - if (Modifier.isStatic(field.getModifiers())) { - continue; - } - if (Modifier.isFinal(field.getModifiers())) { - continue; - } - if (!Modifier.isPublic(field.getModifiers())) { - continue; - } - final String sfname = field.getName(); - if (srcColumnPredicate != null && !srcColumnPredicate.test(field, sfname)) { - continue; - } - - final String dfname = nameAlias == null ? sfname : nameAlias.getOrDefault(sfname, sfname); + final String dfname = destNewNames.getOrDefault(sfname, sfname); final Class srcFieldType = field.getType(); final boolean charstr = CharSequence.class.isAssignableFrom(srcFieldType); if (destIsMap) { //JavaBean -> Map @@ -914,32 +981,14 @@ public interface Copier extends BiFunction { } } } + for (Map.Entry en : elements.entrySet()) { + if (!(en.getValue() instanceof java.lang.reflect.Method)) { + continue; + } + java.lang.reflect.Method getter = (java.lang.reflect.Method) en.getValue(); + final String sfname = en.getKey(); - for (java.lang.reflect.Method getter : srcClass.getMethods()) { - if (Modifier.isStatic(getter.getModifiers())) { - continue; - } - if (getter.getParameterTypes().length > 0) { - continue; - } - if ("getClass".equals(getter.getName())) { - continue; - } - if (Utility.contains(getter.getExceptionTypes(), throwPredicate)) { - continue; //setter方法带有非RuntimeException异常 - } - if (!getter.getName().startsWith("get") && !getter.getName().startsWith("is")) { - continue; - } - final String sfname = Utility.readFieldName(getter.getName()); - if (sfname.isEmpty()) { - continue; - } - if (srcColumnPredicate != null && !srcColumnPredicate.test(getter, sfname)) { - continue; - } - - final String dfname = nameAlias == null ? sfname : nameAlias.getOrDefault(sfname, sfname); + final String dfname = destNewNames.getOrDefault(sfname, sfname); final Class srcFieldType = getter.getReturnType(); final boolean charstr = CharSequence.class.isAssignableFrom(srcFieldType); if (destIsMap) { //srcClass是JavaBean @@ -1113,9 +1162,7 @@ public interface Copier extends BiFunction { return defineClass(name, b, 0, b.length); } }.loadClass(newDynName.replace('/', '.'), bytes); - if (srcColumnPredicate == null && nameAlias == null) { - RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); - } + RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.')); try { return (Copier) newClazz.getDeclaredConstructor().newInstance();