From 52a1fa9f3a91e10438ed3d818db017a598db2638 Mon Sep 17 00:00:00 2001 From: redkale Date: Thu, 10 Aug 2023 15:30:14 +0800 Subject: [PATCH] =?UTF-8?q?Copier=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/redkale/source/DataSqlSource.java | 14 +- src/main/java/org/redkale/util/Copier.java | 275 +++++++++++++----- .../org/redkale/test/util/CopierTest.java | 92 ++++++ .../java/org/redkale/test/util/TestBean.java | 2 + .../java/org/redkale/test/util/TestXBean.java | 5 +- 5 files changed, 306 insertions(+), 82 deletions(-) diff --git a/src/main/java/org/redkale/source/DataSqlSource.java b/src/main/java/org/redkale/source/DataSqlSource.java index 0fef1b55f..ba8ff194f 100644 --- a/src/main/java/org/redkale/source/DataSqlSource.java +++ b/src/main/java/org/redkale/source/DataSqlSource.java @@ -180,30 +180,30 @@ public interface DataSqlSource extends DataSource { //----------------------------- JavaBean ----------------------------- default int nativeUpdate(String sql, Serializable bean) { - return nativeUpdate(sql, (Map) Copier.copyToMap(bean, false)); + return nativeUpdate(sql, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); } default V nativeQuery(String sql, Function handler, Serializable bean) { - return nativeQuery(sql, null, handler, (Map) Copier.copyToMap(bean, false)); + return nativeQuery(sql, null, handler, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); } default V nativeQueryOne(Class type, String sql, Serializable bean) { - return nativeQueryOne(type, sql, (Map) Copier.copyToMap(bean, false)); + return nativeQueryOne(type, sql, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); } default List nativeQueryList(Class type, String sql, Serializable bean) { - return nativeQueryList(type, sql, (Map) Copier.copyToMap(bean, false)); + return nativeQueryList(type, sql, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); } default Map nativeQueryMap(Class keyType, Class valType, String sql, Serializable bean) { - return nativeQueryMap(keyType, valType, sql, (Map) Copier.copyToMap(bean, false)); + return nativeQueryMap(keyType, valType, sql, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); } default Map nativeQueryStrStrMap(String sql, Serializable bean) { - return nativeQueryMap(String.class, String.class, sql, (Map) Copier.copyToMap(bean, false)); + return nativeQueryMap(String.class, String.class, sql, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); } default Map nativeQueryIntStrMap(String sql, Serializable bean) { - return nativeQueryMap(Integer.class, String.class, sql, (Map) Copier.copyToMap(bean, false)); + return nativeQueryMap(Integer.class, String.class, sql, (Map) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE)); } } diff --git a/src/main/java/org/redkale/util/Copier.java b/src/main/java/org/redkale/util/Copier.java index e696f45fe..55543881f 100644 --- a/src/main/java/org/redkale/util/Copier.java +++ b/src/main/java/org/redkale/util/Copier.java @@ -24,6 +24,16 @@ import org.redkale.asm.Type; */ public interface Copier extends BiFunction { + /** + * bean复制到map时,是否跳过值为null的字段 + */ + public static final int OPTION_SKIP_NULL_VALUE = 1 << 1; //2 + + /** + * bean复制到map时,是否跳过值为空字符串的字段 + */ + public static final int OPTION_SKIP_RMPTY_STRING = 1 << 2; //4 + /** * 将源对象字段复制到目标对象 * @@ -46,12 +56,25 @@ public interface Copier extends BiFunction { * @return 目标对象 */ public static D copy(final S src, final D dest) { + return copy(src, dest, 0); + } + + /** + * 将源对象字段复制到目标对象 + * + * @param 目标类泛型 + * @param 源类泛型 + * @param dest 目标对象 + * @param src 源对象 + * @param options 可配项 + * + * @return 目标对象 + */ + public static D copy(final S src, final D dest, final int options) { if (src == null || dest == null) { return null; } - Class destClass = (Class) dest.getClass(); - Creator creator = Creator.load(destClass); - return load((Class) src.getClass(), destClass).apply(src, creator.create()); + return load((Class) src.getClass(), (Class) dest.getClass(), options).apply(src, dest); } /** @@ -65,28 +88,43 @@ public interface Copier extends BiFunction { * @return 目标对象 */ public static D copy(final S src, final Class destClass) { - if (src == null) { - return null; - } - Creator creator = Creator.load(destClass); - return load((Class) src.getClass(), destClass).apply(src, creator.create()); + return copy(src, destClass, 0); } /** * 将源对象字段复制到目标对象 * - * @param 源类泛型 - * @param src 源对象 - * @param allowMapNullVal 是否允许复制value为null的键值对 + * @param 目标类泛型 + * @param 源类泛型 + * @param destClass 目标类名 + * @param src 源对象 + * @param options 可配项 * * @return 目标对象 */ - public static Map copyToMap(final S src, final boolean allowMapNullVal) { + public static D copy(final S src, final Class destClass, final int options) { + if (src == null) { + return null; + } + Creator creator = Creator.load(destClass); + return load((Class) src.getClass(), destClass, options).apply(src, creator.create()); + } + + /** + * 将源对象字段复制到目标对象 + * + * @param 源类泛型 + * @param src 源对象 + * @param options 可配项 + * + * @return 目标对象 + */ + public static Map copyToMap(final S src, final int options) { if (src == null) { return null; } HashMap dest = new HashMap(); - return load((Class) src.getClass(), HashMap.class, allowMapNullVal).apply(src, dest); + return load((Class) src.getClass(), HashMap.class, options).apply(src, dest); } /** @@ -100,35 +138,30 @@ public interface Copier extends BiFunction { * @return 复制器 */ public static Copier load(final Class srcClass, final Class destClass) { - if (destClass == srcClass) { - return CopierInner.copierOneCaches - .computeIfAbsent(srcClass, v -> create(srcClass, destClass)); - } else { - return CopierInner.copierTwoCaches - .computeIfAbsent(srcClass, t -> new ConcurrentHashMap<>()) - .computeIfAbsent(destClass, v -> create(srcClass, destClass)); - } + return load(srcClass, destClass, 0); } /** * 创建源类到目标类的复制器并缓存 * - * @param 目标类泛型 - * @param 源类泛型 - * @param destClass 目标类名 - * @param srcClass 源类名 - * @param allowMapNullVal 是否允许复制value为null的键值对 + * @param 目标类泛型 + * @param 源类泛型 + * @param destClass 目标类名 + * @param srcClass 源类名 + * @param options 可配项 * * @return 复制器 */ - public static Copier load(final Class srcClass, final Class destClass, final boolean allowMapNullVal) { + public static Copier load(final Class srcClass, final Class destClass, final int options) { if (destClass == srcClass) { return CopierInner.copierOneCaches - .computeIfAbsent(srcClass, v -> create(srcClass, destClass, allowMapNullVal, (BiPredicate) null, (Map) null)); + .computeIfAbsent(options, t -> new ConcurrentHashMap<>()) + .computeIfAbsent(srcClass, v -> create(srcClass, destClass, options)); } else { return CopierInner.copierTwoCaches + .computeIfAbsent(options, t -> new ConcurrentHashMap<>()) .computeIfAbsent(srcClass, t -> new ConcurrentHashMap<>()) - .computeIfAbsent(destClass, v -> create(srcClass, destClass, allowMapNullVal, (BiPredicate) null, (Map) null)); + .computeIfAbsent(destClass, v -> create(srcClass, destClass, options)); } } @@ -190,7 +223,8 @@ public interface Copier extends BiFunction { * @return 复制器 */ @SuppressWarnings("unchecked") - public static Copier create(final Class srcClass, final Class destClass, final Predicate srcColumnPredicate, final Map names) { + public static Copier create(final Class srcClass, final Class destClass, + final Predicate srcColumnPredicate, final Map names) { return create(srcClass, destClass, (sc, m) -> srcColumnPredicate.test(m), names); } @@ -206,7 +240,8 @@ public interface Copier extends BiFunction { * @return 复制器 */ @SuppressWarnings("unchecked") - public static Copier create(final Class srcClass, final Class destClass, final BiPredicate srcColumnPredicate) { + public static Copier create(final Class srcClass, final Class destClass, + final BiPredicate srcColumnPredicate) { return create(srcClass, destClass, srcColumnPredicate, (Map) null); } @@ -223,8 +258,25 @@ public interface Copier extends BiFunction { * @return 复制器 */ @SuppressWarnings("unchecked") - public static Copier create(final Class srcClass, final Class destClass, final BiPredicate srcColumnPredicate, final Map names) { - return create(srcClass, destClass, false, srcColumnPredicate, names); + public static Copier create(final Class srcClass, final Class destClass, + final BiPredicate srcColumnPredicate, final Map names) { + return create(srcClass, destClass, 0, srcColumnPredicate, names); + } + + /** + * 创建源类到目标类的复制器 + * + * @param 目标类泛型 + * @param 源类泛型 + * @param destClass 目标类名 + * @param srcClass 源类名 + * @param options 可配项 + * + * @return 复制器 + */ + @SuppressWarnings("unchecked") + public static Copier create(final Class srcClass, final Class destClass, final int options) { + return create(srcClass, destClass, options, (BiPredicate) null, (Map) null); } /** @@ -234,15 +286,20 @@ public interface Copier extends BiFunction { * @param 源类泛型 * @param destClass 目标类名 * @param srcClass 源类名 - * @param allowMapNullVal 目标类是Map子类时是否允许复制value为null的键值对 + * @param options 可配项 * @param srcColumnPredicate 需复制的字段名判断期 * @param names 源字段名与目标字段名的映射关系 * * @return 复制器 */ @SuppressWarnings("unchecked") - public static Copier create(final Class srcClass, final Class destClass, final boolean allowMapNullVal, final BiPredicate srcColumnPredicate, final Map names) { - final boolean allowMapNull = allowMapNullVal && !ConcurrentHashMap.class.isAssignableFrom(destClass); + public static Copier create(final Class srcClass, final Class destClass, final int options, + final BiPredicate srcColumnPredicate, final Map names) { + final boolean skipNullValue = (options & OPTION_SKIP_NULL_VALUE) > 0 || ConcurrentHashMap.class.isAssignableFrom(destClass); + final boolean skipEmptyString = (options & OPTION_SKIP_RMPTY_STRING) > 0; + final Predicate valPredicate = v -> !(skipNullValue && v == null) + && !(skipEmptyString && v instanceof CharSequence && ((CharSequence) v).length() == 0); + if (Map.class.isAssignableFrom(destClass) && Map.class.isAssignableFrom(srcClass)) { final Map names0 = names; if (srcColumnPredicate != null) { @@ -250,7 +307,7 @@ public interface Copier extends BiFunction { return (S src, D dest) -> { Map d = (Map) dest; ((Map) src).forEach((k, v) -> { - if (srcColumnPredicate.test(null, k.toString()) && (allowMapNull || v != null)) { + if (srcColumnPredicate.test(null, k.toString()) && valPredicate.test(v)) { d.put(names0.getOrDefault(k, k), v); } }); @@ -260,7 +317,7 @@ public interface Copier extends BiFunction { return (S src, D dest) -> { Map d = (Map) dest; ((Map) src).forEach((k, v) -> { - if (srcColumnPredicate.test(null, k.toString()) && (allowMapNull || v != null)) { + if (srcColumnPredicate.test(null, k.toString()) && valPredicate.test(v)) { d.put(k, v); } }); @@ -271,7 +328,7 @@ public interface Copier extends BiFunction { return (S src, D dest) -> { Map d = (Map) dest; ((Map) src).forEach((k, v) -> { - if (allowMapNull || v != null) { + if (valPredicate.test(v)) { d.put(names0.getOrDefault(k, k), v); } }); @@ -281,12 +338,12 @@ public interface Copier extends BiFunction { return new Copier() { @Override public D apply(S src, D dest) { - if (allowMapNull) { + if (options == 0) { ((Map) dest).putAll((Map) src); } else { Map d = (Map) dest; ((Map) src).forEach((k, v) -> { - if (v != null) { + if (valPredicate.test(v)) { d.put(k, v); } }); @@ -305,7 +362,7 @@ public interface Copier extends BiFunction { final String srcDesc = Type.getDescriptor(srcClass); final ClassLoader loader = Thread.currentThread().getContextClassLoader(); final String utilClassName = Utility.class.getName().replace('.', '/'); - final String newDynName = "org/redkaledyn/copier/_Dyn" + Copier.class.getSimpleName() + final String newDynName = "org/redkaledyn/copier/_Dyn" + Copier.class.getSimpleName() + "_" + options + "__" + srcClass.getName().replace('.', '_').replace('$', '_') + "__" + destClass.getName().replace('.', '_').replace('$', '_'); try { @@ -403,18 +460,29 @@ public interface Copier extends BiFunction { ? ((Field) en.getValue()).getType() : ((Method) en.getValue()).getParameterTypes()[0]; final boolean primitive = fieldClass.isPrimitive(); + final boolean charstr = CharSequence.class.isAssignableFrom(fieldClass); mv.visitLdcInsn(en.getKey()); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false); Label ifeq = index == elements.size() ? goLabel : new Label(); mv.visitJumpInsn(IFEQ, ifeq); - if (primitive) { + if (skipNullValue || primitive) { mv.visitVarInsn(ALOAD, 2); mv.visitJumpInsn(IFNULL, ifeq); + } else if (skipEmptyString && charstr) { + mv.visitVarInsn(ALOAD, 2); + mv.visitJumpInsn(IFNULL, ifeq); + mv.visitVarInsn(ALOAD, 2); + mv.visitTypeInsn(INSTANCEOF, "java/lang/CharSequence"); + mv.visitJumpInsn(IFEQ, ifeq); + mv.visitVarInsn(ALOAD, 2); + mv.visitTypeInsn(CHECKCAST, "java/lang/CharSequence"); + mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "length", "()I", true); + mv.visitJumpInsn(IFLE, ifeq); } - mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 0); if (fieldClass == boolean.class) { mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;"); } else if (fieldClass == byte.class) { @@ -484,7 +552,7 @@ public interface Copier extends BiFunction { mv.visitMaxs(3, 3); mv.visitEnd(); } - } else { + } else { //srcClass是JavaBean mv = (cw.visitMethod(ACC_PUBLIC, "apply", "(" + srcDesc + destDesc + ")" + destDesc, null, null)); //mv.setDebug(true); @@ -504,10 +572,11 @@ public interface Copier extends BiFunction { } final String dfname = names == null ? sfname : names.getOrDefault(sfname, sfname); - if (destIsMap) { - Class st = field.getType(); + final Class st = field.getType(); + final boolean charstr = CharSequence.class.isAssignableFrom(st); + if (destIsMap) { //srcClass是JavaBean String td = Type.getDescriptor(st); - if (allowMapNull || st.isPrimitive()) { + if ((!skipNullValue && !(skipEmptyString && charstr)) || st.isPrimitive()) { mv.visitVarInsn(ALOAD, 2); mv.visitLdcInsn(dfname); mv.visitVarInsn(ALOAD, 1); @@ -531,17 +600,23 @@ public interface Copier extends BiFunction { } mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", destClass.isInterface()); mv.visitInsn(POP); - } else { + } else { // skipNullValue OR (skipEmptyString && charstr) mv.visitVarInsn(ALOAD, 1); mv.visitFieldInsn(GETFIELD, srcClassName, sfname, td); mv.visitVarInsn(ASTORE, 3); mv.visitVarInsn(ALOAD, 3); Label ifLabel = new Label(); mv.visitJumpInsn(IFNULL, ifLabel); + if (skipEmptyString && charstr) { + mv.visitVarInsn(ALOAD, 3); + mv.visitTypeInsn(CHECKCAST, "java/lang/CharSequence"); + mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "length", "()I", true); + mv.visitJumpInsn(IFLE, ifLabel); + } mv.visitVarInsn(ALOAD, 2); mv.visitLdcInsn(dfname); mv.visitVarInsn(ALOAD, 3); - mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", true); + mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", destClass.isInterface()); mv.visitInsn(POP); mv.visitLabel(ifLabel); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); @@ -562,14 +637,39 @@ public interface Copier extends BiFunction { continue; } } - mv.visitVarInsn(ALOAD, 2); - mv.visitVarInsn(ALOAD, 1); - String td = Type.getDescriptor(field.getType()); - mv.visitFieldInsn(GETFIELD, srcClassName, sfname, td); - if (setter == null) { - mv.visitFieldInsn(PUTFIELD, destClassName, dfname, td); - } else { - mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, setter.getName(), Type.getMethodDescriptor(setter), destClass.isInterface()); + String td = Type.getDescriptor(st); + if ((!skipNullValue && !(skipEmptyString && charstr)) || st.isPrimitive()) { + mv.visitVarInsn(ALOAD, 2); + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn(GETFIELD, srcClassName, sfname, td); + if (setter == null) { + mv.visitFieldInsn(PUTFIELD, destClassName, dfname, td); + } else { + mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, setter.getName(), Type.getMethodDescriptor(setter), destClass.isInterface()); + } + } else { // skipNullValue OR (skipEmptyString && charstr) + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn(GETFIELD, srcClassName, sfname, td); + mv.visitVarInsn(ASTORE, 3); + mv.visitVarInsn(ALOAD, 3); + Label ifLabel = new Label(); + mv.visitJumpInsn(IFNULL, ifLabel); + if (skipEmptyString && charstr) { + mv.visitVarInsn(ALOAD, 3); + mv.visitTypeInsn(CHECKCAST, "java/lang/CharSequence"); + mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "length", "()I", true); + mv.visitJumpInsn(IFLE, ifLabel); + } + mv.visitVarInsn(ALOAD, 2); + mv.visitVarInsn(ALOAD, 3); + mv.visitTypeInsn(CHECKCAST, st.getName().replace('.', '/')); + if (setter == null) { + mv.visitFieldInsn(PUTFIELD, destClassName, dfname, td); + } else { + mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, setter.getName(), Type.getMethodDescriptor(setter), destClass.isInterface()); + } + mv.visitLabel(ifLabel); + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); } } } @@ -599,9 +699,10 @@ public interface Copier extends BiFunction { } final String dfname = names == null ? sfname : names.getOrDefault(sfname, sfname); - if (destIsMap) { - Class st = getter.getReturnType(); - if (allowMapNull || st.isPrimitive()) { + final Class st = getter.getReturnType(); + final boolean charstr = CharSequence.class.isAssignableFrom(st); + if (destIsMap) { //srcClass是JavaBean + if ((!skipNullValue && !(skipEmptyString && charstr)) || st.isPrimitive()) { mv.visitVarInsn(ALOAD, 2); mv.visitLdcInsn(dfname); mv.visitVarInsn(ALOAD, 1); @@ -625,20 +726,25 @@ public interface Copier extends BiFunction { } mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", destClass.isInterface()); mv.visitInsn(POP); - } else { + } else { // skipNullValue OR (skipEmptyString && charstr) mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(srcClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, srcClassName, getter.getName(), Type.getMethodDescriptor(getter), srcClass.isInterface()); mv.visitVarInsn(ASTORE, 3); mv.visitVarInsn(ALOAD, 3); Label ifLabel = new Label(); mv.visitJumpInsn(IFNULL, ifLabel); + if (skipEmptyString && charstr) { + mv.visitVarInsn(ALOAD, 3); + mv.visitTypeInsn(CHECKCAST, "java/lang/CharSequence"); + mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "length", "()I", true); + mv.visitJumpInsn(IFLE, ifLabel); + } mv.visitVarInsn(ALOAD, 2); mv.visitLdcInsn(dfname); mv.visitVarInsn(ALOAD, 3); mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", destClass.isInterface()); mv.visitInsn(POP); mv.visitLabel(ifLabel); - mv.visitLineNumber(47, ifLabel); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); } } else { @@ -662,13 +768,38 @@ public interface Copier extends BiFunction { continue; } } - mv.visitVarInsn(ALOAD, 2); - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn(srcClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, srcClassName, getter.getName(), Type.getMethodDescriptor(getter), srcClass.isInterface()); - if (srcField == null) { - mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, setter.getName(), Type.getMethodDescriptor(setter), destClass.isInterface()); - } else { - mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(getter.getReturnType())); + if ((!skipNullValue && !(skipEmptyString && charstr)) || st.isPrimitive()) { + mv.visitVarInsn(ALOAD, 2); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(srcClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, srcClassName, getter.getName(), Type.getMethodDescriptor(getter), srcClass.isInterface()); + if (srcField == null) { + mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, setter.getName(), Type.getMethodDescriptor(setter), destClass.isInterface()); + } else { + mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(getter.getReturnType())); + } + } else { // skipNullValue OR (skipEmptyString && charstr) + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(srcClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, srcClassName, getter.getName(), Type.getMethodDescriptor(getter), srcClass.isInterface()); + mv.visitVarInsn(ASTORE, 3); + mv.visitVarInsn(ALOAD, 3); + Label ifLabel = new Label(); + mv.visitJumpInsn(IFNULL, ifLabel); + if (skipEmptyString && charstr) { + mv.visitVarInsn(ALOAD, 3); + mv.visitTypeInsn(CHECKCAST, "java/lang/CharSequence"); + mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "length", "()I", true); + mv.visitJumpInsn(IFLE, ifLabel); + } + mv.visitVarInsn(ALOAD, 2); + mv.visitVarInsn(ALOAD, 3); + mv.visitTypeInsn(CHECKCAST, st.getName().replace('.', '/')); + if (srcField == null) { + mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, setter.getName(), Type.getMethodDescriptor(setter), destClass.isInterface()); + } else { + mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(getter.getReturnType())); + } + mv.visitLabel(ifLabel); + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); } } } @@ -709,9 +840,9 @@ public interface Copier extends BiFunction { static class CopierInner { - static final ConcurrentHashMap copierOneCaches = new ConcurrentHashMap(); + static final ConcurrentHashMap> copierOneCaches = new ConcurrentHashMap(); - static final ConcurrentHashMap> copierTwoCaches = new ConcurrentHashMap(); + static final ConcurrentHashMap>> copierTwoCaches = new ConcurrentHashMap(); } diff --git a/src/test/java/org/redkale/test/util/CopierTest.java b/src/test/java/org/redkale/test/util/CopierTest.java index 5b363e9a3..e2c0df24b 100644 --- a/src/test/java/org/redkale/test/util/CopierTest.java +++ b/src/test/java/org/redkale/test/util/CopierTest.java @@ -24,6 +24,11 @@ public class CopierTest { test.run5(); test.run6(); test.run7(); + test.run8(); + test.run9(); + test.run10(); + test.run11(); + test.run12(); } @Test @@ -36,6 +41,7 @@ public class CopierTest { Map map = new TreeMap(Copier.copy(bean, Map.class)); System.out.println(JsonConvert.root().convertTo(map)); TreeMap rs = Copier.copy(bean, TreeMap.class); + rs.remove("remark"); Assertions.assertEquals(bean.toString(), JsonConvert.root().convertTo(rs)); } @@ -113,5 +119,91 @@ public class CopierTest { map.put("map", Utility.ofMap("aa", "bbb")); Copier.load(Map.class, TestBean.class).apply(map, bean); System.out.println(JsonConvert.root().convertTo(bean)); + System.out.println("------------------------------------------"); + } + + @Test + public void run8() throws Exception { + TestBean bean = new TestBean(); + Map map = new TreeMap(); + map.put("name", ""); + map.put("time", "55555"); + map.put("id", null); + map.put("map", Utility.ofMap("aa", "bbb")); + Copier.load(Map.class, TestBean.class, Copier.OPTION_SKIP_RMPTY_STRING).apply(map, bean); + System.out.println(JsonConvert.root().convertTo(bean)); + Assertions.assertTrue(bean.getName() == null); + } + + @Test + public void run9() throws Exception { + TestBean bean = new TestBean(); + bean.remark = "hehehoho"; + Map map = new TreeMap(); + map.put("name", ""); + map.put("time", "55555"); + map.put("id", null); + map.put("remark", null); + map.put("map", Utility.ofMap("aa", "bbb")); + Copier.load(Map.class, TestBean.class).apply(map, bean); + System.out.println(JsonConvert.root().convertTo(bean)); + Assertions.assertTrue(bean.remark == null); + + bean.remark = "hehehoho"; + Copier.load(Map.class, TestBean.class, Copier.OPTION_SKIP_NULL_VALUE).apply(map, bean); + System.out.println(JsonConvert.root().convertTo(bean)); + Assertions.assertTrue(bean.remark != null); + } + + @Test + public void run10() throws Exception { + TestBean bean = new TestBean(); + bean.remark = "hehehoho"; + TestXBean srcBean = new TestXBean(); + srcBean.setName(""); + srcBean.time = 55555; + srcBean.remark = null; + srcBean.setMap(Utility.ofMap("aa", "bbb")); + Copier.load(TestXBean.class, TestBean.class).apply(srcBean, bean); + System.out.println(JsonConvert.root().convertTo(bean)); + Assertions.assertTrue(bean.remark == null); + + bean.remark = "hehehoho"; + Copier.load(TestXBean.class, TestBean.class, Copier.OPTION_SKIP_NULL_VALUE).apply(srcBean, bean); + System.out.println(JsonConvert.root().convertTo(bean)); + Assertions.assertTrue(bean.remark != null); + } + + @Test + public void run11() throws Exception { + TestBean bean = new TestBean(); + TestXBean srcBean = new TestXBean(); + srcBean.setName(""); + srcBean.time = 55555; + srcBean.remark = null; + srcBean.setMap(Utility.ofMap("aa", "bbb")); + Copier.load(TestXBean.class, TestBean.class, Copier.OPTION_SKIP_RMPTY_STRING).apply(srcBean, bean); + System.out.println(JsonConvert.root().convertTo(bean)); + Assertions.assertTrue(bean.getName() == null); + } + + @Test + public void run12() throws Exception { + TestBean bean = new TestBean(); + bean.remark = "hehehoho"; + TestXBean srcBean = new TestXBean(); + srcBean.setName(""); + srcBean.time = 55555; + srcBean.remark = null; + srcBean.setMap(Utility.ofMap("aa", "bbb")); + Copier.load(TestXBean.class, TestBean.class).apply(srcBean, bean); + System.out.println(JsonConvert.root().convertTo(bean)); + Assertions.assertTrue(bean.remark == null); + + bean.setName(null); + bean.remark = "hehehoho"; + Copier.load(TestXBean.class, TestBean.class, Copier.OPTION_SKIP_NULL_VALUE | Copier.OPTION_SKIP_RMPTY_STRING).apply(srcBean, bean); + System.out.println(JsonConvert.root().convertTo(bean)); + Assertions.assertTrue(bean.getName() == null); } } diff --git a/src/test/java/org/redkale/test/util/TestBean.java b/src/test/java/org/redkale/test/util/TestBean.java index 7bb3b6ae3..8a9a6b37f 100644 --- a/src/test/java/org/redkale/test/util/TestBean.java +++ b/src/test/java/org/redkale/test/util/TestBean.java @@ -20,6 +20,8 @@ public class TestBean extends TestABean implements TestInterface { private Map map; + public String remark; + public String getName() { return name; } diff --git a/src/test/java/org/redkale/test/util/TestXBean.java b/src/test/java/org/redkale/test/util/TestXBean.java index eddd61f86..e4fe9fa80 100644 --- a/src/test/java/org/redkale/test/util/TestXBean.java +++ b/src/test/java/org/redkale/test/util/TestXBean.java @@ -3,13 +3,12 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ - package org.redkale.test.util; /** * * @author zhangjx */ -public class TestXBean extends TestBean{ - +public class TestXBean extends TestBean { + }