Copier优化

This commit is contained in:
redkale
2023-08-10 15:30:14 +08:00
parent e5d31344b9
commit 52a1fa9f3a
5 changed files with 306 additions and 82 deletions

View File

@@ -180,30 +180,30 @@ public interface DataSqlSource extends DataSource {
//----------------------------- JavaBean ----------------------------- //----------------------------- JavaBean -----------------------------
default int nativeUpdate(String sql, Serializable bean) { default int nativeUpdate(String sql, Serializable bean) {
return nativeUpdate(sql, (Map<String, Object>) Copier.copyToMap(bean, false)); return nativeUpdate(sql, (Map<String, Object>) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE));
} }
default <V> V nativeQuery(String sql, Function<DataResultSet, V> handler, Serializable bean) { default <V> V nativeQuery(String sql, Function<DataResultSet, V> handler, Serializable bean) {
return nativeQuery(sql, null, handler, (Map<String, Object>) Copier.copyToMap(bean, false)); return nativeQuery(sql, null, handler, (Map<String, Object>) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE));
} }
default <V> V nativeQueryOne(Class<V> type, String sql, Serializable bean) { default <V> V nativeQueryOne(Class<V> type, String sql, Serializable bean) {
return nativeQueryOne(type, sql, (Map<String, Object>) Copier.copyToMap(bean, false)); return nativeQueryOne(type, sql, (Map<String, Object>) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE));
} }
default <V> List<V> nativeQueryList(Class<V> type, String sql, Serializable bean) { default <V> List<V> nativeQueryList(Class<V> type, String sql, Serializable bean) {
return nativeQueryList(type, sql, (Map<String, Object>) Copier.copyToMap(bean, false)); return nativeQueryList(type, sql, (Map<String, Object>) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE));
} }
default <K, V> Map<K, V> nativeQueryMap(Class<K> keyType, Class<V> valType, String sql, Serializable bean) { default <K, V> Map<K, V> nativeQueryMap(Class<K> keyType, Class<V> valType, String sql, Serializable bean) {
return nativeQueryMap(keyType, valType, sql, (Map<String, Object>) Copier.copyToMap(bean, false)); return nativeQueryMap(keyType, valType, sql, (Map<String, Object>) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE));
} }
default Map<String, String> nativeQueryStrStrMap(String sql, Serializable bean) { default Map<String, String> nativeQueryStrStrMap(String sql, Serializable bean) {
return nativeQueryMap(String.class, String.class, sql, (Map<String, Object>) Copier.copyToMap(bean, false)); return nativeQueryMap(String.class, String.class, sql, (Map<String, Object>) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE));
} }
default Map<Integer, String> nativeQueryIntStrMap(String sql, Serializable bean) { default Map<Integer, String> nativeQueryIntStrMap(String sql, Serializable bean) {
return nativeQueryMap(Integer.class, String.class, sql, (Map<String, Object>) Copier.copyToMap(bean, false)); return nativeQueryMap(Integer.class, String.class, sql, (Map<String, Object>) Copier.copyToMap(bean, Copier.OPTION_SKIP_NULL_VALUE));
} }
} }

View File

@@ -24,6 +24,16 @@ import org.redkale.asm.Type;
*/ */
public interface Copier<S, D> extends BiFunction<S, D, D> { public interface Copier<S, D> extends BiFunction<S, D, D> {
/**
* 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<S, D> extends BiFunction<S, D, D> {
* @return 目标对象 * @return 目标对象
*/ */
public static <S, D> D copy(final S src, final D dest) { public static <S, D> D copy(final S src, final D dest) {
return copy(src, dest, 0);
}
/**
* 将源对象字段复制到目标对象
*
* @param <D> 目标类泛型
* @param <S> 源类泛型
* @param dest 目标对象
* @param src 源对象
* @param options 可配项
*
* @return 目标对象
*/
public static <S, D> D copy(final S src, final D dest, final int options) {
if (src == null || dest == null) { if (src == null || dest == null) {
return null; return null;
} }
Class<D> destClass = (Class<D>) dest.getClass(); return load((Class<S>) src.getClass(), (Class<D>) dest.getClass(), options).apply(src, dest);
Creator<D> creator = Creator.load(destClass);
return load((Class<S>) src.getClass(), destClass).apply(src, creator.create());
} }
/** /**
@@ -65,28 +88,43 @@ public interface Copier<S, D> extends BiFunction<S, D, D> {
* @return 目标对象 * @return 目标对象
*/ */
public static <S, D> D copy(final S src, final Class<D> destClass) { public static <S, D> D copy(final S src, final Class<D> destClass) {
if (src == null) { return copy(src, destClass, 0);
return null;
}
Creator<D> creator = Creator.load(destClass);
return load((Class<S>) src.getClass(), destClass).apply(src, creator.create());
} }
/** /**
* 将源对象字段复制到目标对象 * 将源对象字段复制到目标对象
* *
* @param <S> 类泛型 * @param <D> 目标类泛型
* @param src 源对象 * @param <S> 源类泛型
* @param allowMapNullVal 是否允许复制value为null的键值对 * @param destClass 目标类名
* @param src 源对象
* @param options 可配项
* *
* @return 目标对象 * @return 目标对象
*/ */
public static <S> Map copyToMap(final S src, final boolean allowMapNullVal) { public static <S, D> D copy(final S src, final Class<D> destClass, final int options) {
if (src == null) {
return null;
}
Creator<D> creator = Creator.load(destClass);
return load((Class<S>) src.getClass(), destClass, options).apply(src, creator.create());
}
/**
* 将源对象字段复制到目标对象
*
* @param <S> 源类泛型
* @param src 源对象
* @param options 可配项
*
* @return 目标对象
*/
public static <S> Map copyToMap(final S src, final int options) {
if (src == null) { if (src == null) {
return null; return null;
} }
HashMap dest = new HashMap(); HashMap dest = new HashMap();
return load((Class<S>) src.getClass(), HashMap.class, allowMapNullVal).apply(src, dest); return load((Class<S>) src.getClass(), HashMap.class, options).apply(src, dest);
} }
/** /**
@@ -100,35 +138,30 @@ public interface Copier<S, D> extends BiFunction<S, D, D> {
* @return 复制器 * @return 复制器
*/ */
public static <S, D> Copier<S, D> load(final Class<S> srcClass, final Class<D> destClass) { public static <S, D> Copier<S, D> load(final Class<S> srcClass, final Class<D> destClass) {
if (destClass == srcClass) { return load(srcClass, destClass, 0);
return CopierInner.copierOneCaches
.computeIfAbsent(srcClass, v -> create(srcClass, destClass));
} else {
return CopierInner.copierTwoCaches
.computeIfAbsent(srcClass, t -> new ConcurrentHashMap<>())
.computeIfAbsent(destClass, v -> create(srcClass, destClass));
}
} }
/** /**
* 创建源类到目标类的复制器并缓存 * 创建源类到目标类的复制器并缓存
* *
* @param <D> 目标类泛型 * @param <D> 目标类泛型
* @param <S> 源类泛型 * @param <S> 源类泛型
* @param destClass 目标类名 * @param destClass 目标类名
* @param srcClass 源类名 * @param srcClass 源类名
* @param allowMapNullVal 是否允许复制value为null的键值对 * @param options 可配项
* *
* @return 复制器 * @return 复制器
*/ */
public static <S, D extends Map> Copier<S, D> load(final Class<S> srcClass, final Class<D> destClass, final boolean allowMapNullVal) { public static <S, D> Copier<S, D> load(final Class<S> srcClass, final Class<D> destClass, final int options) {
if (destClass == srcClass) { if (destClass == srcClass) {
return CopierInner.copierOneCaches return CopierInner.copierOneCaches
.computeIfAbsent(srcClass, v -> create(srcClass, destClass, allowMapNullVal, (BiPredicate) null, (Map<String, String>) null)); .computeIfAbsent(options, t -> new ConcurrentHashMap<>())
.computeIfAbsent(srcClass, v -> create(srcClass, destClass, options));
} else { } else {
return CopierInner.copierTwoCaches return CopierInner.copierTwoCaches
.computeIfAbsent(options, t -> new ConcurrentHashMap<>())
.computeIfAbsent(srcClass, t -> new ConcurrentHashMap<>()) .computeIfAbsent(srcClass, t -> new ConcurrentHashMap<>())
.computeIfAbsent(destClass, v -> create(srcClass, destClass, allowMapNullVal, (BiPredicate) null, (Map<String, String>) null)); .computeIfAbsent(destClass, v -> create(srcClass, destClass, options));
} }
} }
@@ -190,7 +223,8 @@ public interface Copier<S, D> extends BiFunction<S, D, D> {
* @return 复制器 * @return 复制器
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <S, D> Copier<S, D> create(final Class<S> srcClass, final Class<D> destClass, final Predicate<String> srcColumnPredicate, final Map<String, String> names) { public static <S, D> Copier<S, D> create(final Class<S> srcClass, final Class<D> destClass,
final Predicate<String> srcColumnPredicate, final Map<String, String> names) {
return create(srcClass, destClass, (sc, m) -> srcColumnPredicate.test(m), names); return create(srcClass, destClass, (sc, m) -> srcColumnPredicate.test(m), names);
} }
@@ -206,7 +240,8 @@ public interface Copier<S, D> extends BiFunction<S, D, D> {
* @return 复制器 * @return 复制器
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <S, D> Copier<S, D> create(final Class<S> srcClass, final Class<D> destClass, final BiPredicate<java.lang.reflect.AccessibleObject, String> srcColumnPredicate) { public static <S, D> Copier<S, D> create(final Class<S> srcClass, final Class<D> destClass,
final BiPredicate<java.lang.reflect.AccessibleObject, String> srcColumnPredicate) {
return create(srcClass, destClass, srcColumnPredicate, (Map<String, String>) null); return create(srcClass, destClass, srcColumnPredicate, (Map<String, String>) null);
} }
@@ -223,8 +258,25 @@ public interface Copier<S, D> extends BiFunction<S, D, D> {
* @return 复制器 * @return 复制器
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <S, D> Copier<S, D> create(final Class<S> srcClass, final Class<D> destClass, final BiPredicate<java.lang.reflect.AccessibleObject, String> srcColumnPredicate, final Map<String, String> names) { public static <S, D> Copier<S, D> create(final Class<S> srcClass, final Class<D> destClass,
return create(srcClass, destClass, false, srcColumnPredicate, names); final BiPredicate<java.lang.reflect.AccessibleObject, String> srcColumnPredicate, final Map<String, String> names) {
return create(srcClass, destClass, 0, srcColumnPredicate, names);
}
/**
* 创建源类到目标类的复制器
*
* @param <D> 目标类泛型
* @param <S> 源类泛型
* @param destClass 目标类名
* @param srcClass 源类名
* @param options 可配项
*
* @return 复制器
*/
@SuppressWarnings("unchecked")
public static <S, D> Copier<S, D> create(final Class<S> srcClass, final Class<D> destClass, final int options) {
return create(srcClass, destClass, options, (BiPredicate) null, (Map<String, String>) null);
} }
/** /**
@@ -234,15 +286,20 @@ public interface Copier<S, D> extends BiFunction<S, D, D> {
* @param <S> 源类泛型 * @param <S> 源类泛型
* @param destClass 目标类名 * @param destClass 目标类名
* @param srcClass 源类名 * @param srcClass 源类名
* @param allowMapNullVal 目标类是Map子类时是否允许复制value为null的键值对 * @param options 可配项
* @param srcColumnPredicate 需复制的字段名判断期 * @param srcColumnPredicate 需复制的字段名判断期
* @param names 源字段名与目标字段名的映射关系 * @param names 源字段名与目标字段名的映射关系
* *
* @return 复制器 * @return 复制器
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <S, D> Copier<S, D> create(final Class<S> srcClass, final Class<D> destClass, final boolean allowMapNullVal, final BiPredicate<java.lang.reflect.AccessibleObject, String> srcColumnPredicate, final Map<String, String> names) { public static <S, D> Copier<S, D> create(final Class<S> srcClass, final Class<D> destClass, final int options,
final boolean allowMapNull = allowMapNullVal && !ConcurrentHashMap.class.isAssignableFrom(destClass); final BiPredicate<java.lang.reflect.AccessibleObject, String> srcColumnPredicate, final Map<String, String> 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<Object> valPredicate = v -> !(skipNullValue && v == null)
&& !(skipEmptyString && v instanceof CharSequence && ((CharSequence) v).length() == 0);
if (Map.class.isAssignableFrom(destClass) && Map.class.isAssignableFrom(srcClass)) { if (Map.class.isAssignableFrom(destClass) && Map.class.isAssignableFrom(srcClass)) {
final Map names0 = names; final Map names0 = names;
if (srcColumnPredicate != null) { if (srcColumnPredicate != null) {
@@ -250,7 +307,7 @@ public interface Copier<S, D> extends BiFunction<S, D, D> {
return (S src, D dest) -> { return (S src, D dest) -> {
Map d = (Map) dest; Map d = (Map) dest;
((Map) src).forEach((k, v) -> { ((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); d.put(names0.getOrDefault(k, k), v);
} }
}); });
@@ -260,7 +317,7 @@ public interface Copier<S, D> extends BiFunction<S, D, D> {
return (S src, D dest) -> { return (S src, D dest) -> {
Map d = (Map) dest; Map d = (Map) dest;
((Map) src).forEach((k, v) -> { ((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); d.put(k, v);
} }
}); });
@@ -271,7 +328,7 @@ public interface Copier<S, D> extends BiFunction<S, D, D> {
return (S src, D dest) -> { return (S src, D dest) -> {
Map d = (Map) dest; Map d = (Map) dest;
((Map) src).forEach((k, v) -> { ((Map) src).forEach((k, v) -> {
if (allowMapNull || v != null) { if (valPredicate.test(v)) {
d.put(names0.getOrDefault(k, k), v); d.put(names0.getOrDefault(k, k), v);
} }
}); });
@@ -281,12 +338,12 @@ public interface Copier<S, D> extends BiFunction<S, D, D> {
return new Copier<S, D>() { return new Copier<S, D>() {
@Override @Override
public D apply(S src, D dest) { public D apply(S src, D dest) {
if (allowMapNull) { if (options == 0) {
((Map) dest).putAll((Map) src); ((Map) dest).putAll((Map) src);
} else { } else {
Map d = (Map) dest; Map d = (Map) dest;
((Map) src).forEach((k, v) -> { ((Map) src).forEach((k, v) -> {
if (v != null) { if (valPredicate.test(v)) {
d.put(k, v); d.put(k, v);
} }
}); });
@@ -305,7 +362,7 @@ public interface Copier<S, D> extends BiFunction<S, D, D> {
final String srcDesc = Type.getDescriptor(srcClass); final String srcDesc = Type.getDescriptor(srcClass);
final ClassLoader loader = Thread.currentThread().getContextClassLoader(); final ClassLoader loader = Thread.currentThread().getContextClassLoader();
final String utilClassName = Utility.class.getName().replace('.', '/'); 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('$', '_') + "__" + srcClass.getName().replace('.', '_').replace('$', '_')
+ "__" + destClass.getName().replace('.', '_').replace('$', '_'); + "__" + destClass.getName().replace('.', '_').replace('$', '_');
try { try {
@@ -403,18 +460,29 @@ public interface Copier<S, D> extends BiFunction<S, D, D> {
? ((Field) en.getValue()).getType() ? ((Field) en.getValue()).getType()
: ((Method) en.getValue()).getParameterTypes()[0]; : ((Method) en.getValue()).getParameterTypes()[0];
final boolean primitive = fieldClass.isPrimitive(); final boolean primitive = fieldClass.isPrimitive();
final boolean charstr = CharSequence.class.isAssignableFrom(fieldClass);
mv.visitLdcInsn(en.getKey()); mv.visitLdcInsn(en.getKey());
mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false);
Label ifeq = index == elements.size() ? goLabel : new Label(); Label ifeq = index == elements.size() ? goLabel : new Label();
mv.visitJumpInsn(IFEQ, ifeq); mv.visitJumpInsn(IFEQ, ifeq);
if (primitive) { if (skipNullValue || primitive) {
mv.visitVarInsn(ALOAD, 2); mv.visitVarInsn(ALOAD, 2);
mv.visitJumpInsn(IFNULL, ifeq); 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) { if (fieldClass == boolean.class) {
mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;"); mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;");
} else if (fieldClass == byte.class) { } else if (fieldClass == byte.class) {
@@ -484,7 +552,7 @@ public interface Copier<S, D> extends BiFunction<S, D, D> {
mv.visitMaxs(3, 3); mv.visitMaxs(3, 3);
mv.visitEnd(); mv.visitEnd();
} }
} else { } else { //srcClass是JavaBean
mv = (cw.visitMethod(ACC_PUBLIC, "apply", "(" + srcDesc + destDesc + ")" + destDesc, null, null)); mv = (cw.visitMethod(ACC_PUBLIC, "apply", "(" + srcDesc + destDesc + ")" + destDesc, null, null));
//mv.setDebug(true); //mv.setDebug(true);
@@ -504,10 +572,11 @@ public interface Copier<S, D> extends BiFunction<S, D, D> {
} }
final String dfname = names == null ? sfname : names.getOrDefault(sfname, sfname); final String dfname = names == null ? sfname : names.getOrDefault(sfname, sfname);
if (destIsMap) { final Class st = field.getType();
Class st = field.getType(); final boolean charstr = CharSequence.class.isAssignableFrom(st);
if (destIsMap) { //srcClass是JavaBean
String td = Type.getDescriptor(st); String td = Type.getDescriptor(st);
if (allowMapNull || st.isPrimitive()) { if ((!skipNullValue && !(skipEmptyString && charstr)) || st.isPrimitive()) {
mv.visitVarInsn(ALOAD, 2); mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(dfname); mv.visitLdcInsn(dfname);
mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ALOAD, 1);
@@ -531,17 +600,23 @@ public interface Copier<S, D> extends BiFunction<S, D, D> {
} }
mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", destClass.isInterface()); mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", destClass.isInterface());
mv.visitInsn(POP); mv.visitInsn(POP);
} else { } else { // skipNullValue OR (skipEmptyString && charstr)
mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ALOAD, 1);
mv.visitFieldInsn(GETFIELD, srcClassName, sfname, td); mv.visitFieldInsn(GETFIELD, srcClassName, sfname, td);
mv.visitVarInsn(ASTORE, 3); mv.visitVarInsn(ASTORE, 3);
mv.visitVarInsn(ALOAD, 3); mv.visitVarInsn(ALOAD, 3);
Label ifLabel = new Label(); Label ifLabel = new Label();
mv.visitJumpInsn(IFNULL, ifLabel); 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, 2);
mv.visitLdcInsn(dfname); mv.visitLdcInsn(dfname);
mv.visitVarInsn(ALOAD, 3); 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.visitInsn(POP);
mv.visitLabel(ifLabel); mv.visitLabel(ifLabel);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
@@ -562,14 +637,39 @@ public interface Copier<S, D> extends BiFunction<S, D, D> {
continue; continue;
} }
} }
mv.visitVarInsn(ALOAD, 2); String td = Type.getDescriptor(st);
mv.visitVarInsn(ALOAD, 1); if ((!skipNullValue && !(skipEmptyString && charstr)) || st.isPrimitive()) {
String td = Type.getDescriptor(field.getType()); mv.visitVarInsn(ALOAD, 2);
mv.visitFieldInsn(GETFIELD, srcClassName, sfname, td); mv.visitVarInsn(ALOAD, 1);
if (setter == null) { mv.visitFieldInsn(GETFIELD, srcClassName, sfname, td);
mv.visitFieldInsn(PUTFIELD, destClassName, dfname, td); if (setter == null) {
} else { mv.visitFieldInsn(PUTFIELD, destClassName, dfname, td);
mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, setter.getName(), Type.getMethodDescriptor(setter), destClass.isInterface()); } 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<S, D> extends BiFunction<S, D, D> {
} }
final String dfname = names == null ? sfname : names.getOrDefault(sfname, sfname); final String dfname = names == null ? sfname : names.getOrDefault(sfname, sfname);
if (destIsMap) { final Class st = getter.getReturnType();
Class st = getter.getReturnType(); final boolean charstr = CharSequence.class.isAssignableFrom(st);
if (allowMapNull || st.isPrimitive()) { if (destIsMap) { //srcClass是JavaBean
if ((!skipNullValue && !(skipEmptyString && charstr)) || st.isPrimitive()) {
mv.visitVarInsn(ALOAD, 2); mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(dfname); mv.visitLdcInsn(dfname);
mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ALOAD, 1);
@@ -625,20 +726,25 @@ public interface Copier<S, D> extends BiFunction<S, D, D> {
} }
mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", destClass.isInterface()); mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", destClass.isInterface());
mv.visitInsn(POP); mv.visitInsn(POP);
} else { } else { // skipNullValue OR (skipEmptyString && charstr)
mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(srcClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, srcClassName, getter.getName(), Type.getMethodDescriptor(getter), srcClass.isInterface()); mv.visitMethodInsn(srcClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, srcClassName, getter.getName(), Type.getMethodDescriptor(getter), srcClass.isInterface());
mv.visitVarInsn(ASTORE, 3); mv.visitVarInsn(ASTORE, 3);
mv.visitVarInsn(ALOAD, 3); mv.visitVarInsn(ALOAD, 3);
Label ifLabel = new Label(); Label ifLabel = new Label();
mv.visitJumpInsn(IFNULL, ifLabel); 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, 2);
mv.visitLdcInsn(dfname); mv.visitLdcInsn(dfname);
mv.visitVarInsn(ALOAD, 3); mv.visitVarInsn(ALOAD, 3);
mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", destClass.isInterface()); mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", destClass.isInterface());
mv.visitInsn(POP); mv.visitInsn(POP);
mv.visitLabel(ifLabel); mv.visitLabel(ifLabel);
mv.visitLineNumber(47, ifLabel);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
} }
} else { } else {
@@ -662,13 +768,38 @@ public interface Copier<S, D> extends BiFunction<S, D, D> {
continue; continue;
} }
} }
mv.visitVarInsn(ALOAD, 2); if ((!skipNullValue && !(skipEmptyString && charstr)) || st.isPrimitive()) {
mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(srcClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, srcClassName, getter.getName(), Type.getMethodDescriptor(getter), srcClass.isInterface()); mv.visitVarInsn(ALOAD, 1);
if (srcField == null) { mv.visitMethodInsn(srcClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, srcClassName, getter.getName(), Type.getMethodDescriptor(getter), srcClass.isInterface());
mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, setter.getName(), Type.getMethodDescriptor(setter), destClass.isInterface()); if (srcField == null) {
} else { mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, setter.getName(), Type.getMethodDescriptor(setter), destClass.isInterface());
mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(getter.getReturnType())); } 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<S, D> extends BiFunction<S, D, D> {
static class CopierInner { static class CopierInner {
static final ConcurrentHashMap<Class, Copier> copierOneCaches = new ConcurrentHashMap(); static final ConcurrentHashMap<Integer, ConcurrentHashMap<Class, Copier>> copierOneCaches = new ConcurrentHashMap();
static final ConcurrentHashMap<Class, ConcurrentHashMap<Class, Copier>> copierTwoCaches = new ConcurrentHashMap(); static final ConcurrentHashMap<Integer, ConcurrentHashMap<Class, ConcurrentHashMap<Class, Copier>>> copierTwoCaches = new ConcurrentHashMap();
} }

View File

@@ -24,6 +24,11 @@ public class CopierTest {
test.run5(); test.run5();
test.run6(); test.run6();
test.run7(); test.run7();
test.run8();
test.run9();
test.run10();
test.run11();
test.run12();
} }
@Test @Test
@@ -36,6 +41,7 @@ public class CopierTest {
Map map = new TreeMap(Copier.copy(bean, Map.class)); Map map = new TreeMap(Copier.copy(bean, Map.class));
System.out.println(JsonConvert.root().convertTo(map)); System.out.println(JsonConvert.root().convertTo(map));
TreeMap rs = Copier.copy(bean, TreeMap.class); TreeMap rs = Copier.copy(bean, TreeMap.class);
rs.remove("remark");
Assertions.assertEquals(bean.toString(), JsonConvert.root().convertTo(rs)); Assertions.assertEquals(bean.toString(), JsonConvert.root().convertTo(rs));
} }
@@ -113,5 +119,91 @@ public class CopierTest {
map.put("map", Utility.ofMap("aa", "bbb")); map.put("map", Utility.ofMap("aa", "bbb"));
Copier.load(Map.class, TestBean.class).apply(map, bean); Copier.load(Map.class, TestBean.class).apply(map, bean);
System.out.println(JsonConvert.root().convertTo(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);
} }
} }

View File

@@ -20,6 +20,8 @@ public class TestBean extends TestABean implements TestInterface {
private Map<String, String> map; private Map<String, String> map;
public String remark;
public String getName() { public String getName() {
return name; return name;
} }

View File

@@ -3,13 +3,12 @@
* To change this template file, choose Tools | Templates * To change this template file, choose Tools | Templates
* and open the template in the editor. * and open the template in the editor.
*/ */
package org.redkale.test.util; package org.redkale.test.util;
/** /**
* *
* @author zhangjx * @author zhangjx
*/ */
public class TestXBean extends TestBean{ public class TestXBean extends TestBean {
} }