1177 lines
56 KiB
Java
1177 lines
56 KiB
Java
/*
|
||
*
|
||
*/
|
||
package org.redkale.util;
|
||
|
||
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.*;
|
||
import org.redkale.asm.Type;
|
||
|
||
/**
|
||
* JavaBean类对象的拷贝,相同的字段名会被拷贝 <br>
|
||
*
|
||
* <p>
|
||
* 详情见: https://redkale.org
|
||
*
|
||
* @author zhangjx
|
||
* @param <D> 目标对象的数据类型
|
||
* @param <S> 源对象的数据类型
|
||
*
|
||
* @since 2.8.0
|
||
*/
|
||
public interface Copier<S, D> extends BiFunction<S, D, D> {
|
||
|
||
/**
|
||
* 是否跳过值为null的字段
|
||
*/
|
||
public static final int OPTION_SKIP_NULL_VALUE = 1 << 1; //2
|
||
|
||
/**
|
||
* 是否跳过值为空字符串的字段
|
||
*/
|
||
public static final int OPTION_SKIP_EMPTY_STRING = 1 << 2; //4
|
||
|
||
/**
|
||
* 同名字段类型强制转换
|
||
*/
|
||
public static final int OPTION_ALLOW_TYPE_CAST = 1 << 3; //8
|
||
|
||
/**
|
||
* 将源对象字段复制到目标对象
|
||
*
|
||
* @param dest 目标对象
|
||
* @param src 源对象
|
||
*
|
||
* @return 目标对象
|
||
*/
|
||
@Override
|
||
public D apply(S src, D dest);
|
||
|
||
/**
|
||
* 将源对象字段复制到目标对象
|
||
*
|
||
* @param <D> 目标类泛型
|
||
* @param <S> 源类泛型
|
||
* @param dest 目标对象
|
||
* @param src 源对象
|
||
*
|
||
* @return 目标对象
|
||
*/
|
||
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) {
|
||
return dest;
|
||
}
|
||
return load((Class<S>) src.getClass(), (Class<D>) dest.getClass(), options).apply(src, dest);
|
||
}
|
||
|
||
/**
|
||
* 将源对象字段复制到目标对象
|
||
*
|
||
* @param <D> 目标类泛型
|
||
* @param <S> 源类泛型
|
||
* @param destClass 目标类名
|
||
* @param src 源对象
|
||
*
|
||
* @return 目标对象
|
||
*/
|
||
public static <S, D> D copy(final S src, final Class<D> destClass) {
|
||
return copy(src, destClass, 0);
|
||
}
|
||
|
||
/**
|
||
* 将源对象字段复制到目标对象
|
||
*
|
||
* @param <D> 目标类泛型
|
||
* @param <S> 源类泛型
|
||
* @param destClass 目标类名
|
||
* @param src 源对象
|
||
* @param options 可配项
|
||
*
|
||
* @return 目标对象
|
||
*/
|
||
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) {
|
||
return null;
|
||
}
|
||
HashMap dest = new HashMap();
|
||
return load((Class<S>) src.getClass(), HashMap.class, options).apply(src, dest);
|
||
}
|
||
|
||
/**
|
||
* 创建源类到目标类的复制器并缓存
|
||
*
|
||
* @param <D> 目标类泛型
|
||
* @param <S> 源类泛型
|
||
* @param destClass 目标类名
|
||
* @param srcClass 源类名
|
||
*
|
||
* @return 复制器
|
||
*/
|
||
public static <S, D> Function<S, D> func(final Class<S> srcClass, final Class<D> destClass) {
|
||
return func(srcClass, destClass, 0);
|
||
}
|
||
|
||
/**
|
||
* 创建源类到目标类的复制器并缓存
|
||
*
|
||
* @param <D> 目标类泛型
|
||
* @param <S> 源类泛型
|
||
* @param destClass 目标类名
|
||
* @param srcClass 源类名
|
||
*
|
||
* @return 复制器
|
||
*/
|
||
public static <S, D> Function<Collection<S>, Set<D>> funcSet(final Class<S> srcClass, final Class<D> destClass) {
|
||
return funcSet(srcClass, destClass, 0);
|
||
}
|
||
|
||
/**
|
||
* 创建源类到目标类的复制器并缓存
|
||
*
|
||
* @param <D> 目标类泛型
|
||
* @param <S> 源类泛型
|
||
* @param destClass 目标类名
|
||
* @param srcClass 源类名
|
||
*
|
||
* @return 复制器
|
||
*/
|
||
public static <S, D> Function<Collection<S>, List<D>> funcList(final Class<S> srcClass, final Class<D> destClass) {
|
||
return funcList(srcClass, destClass, 0);
|
||
}
|
||
|
||
/**
|
||
* 创建源类到目标类的复制器并缓存
|
||
*
|
||
* @param <D> 目标类泛型
|
||
* @param <S> 源类泛型
|
||
* @param <C> 集合泛型
|
||
* @param destClass 目标类名
|
||
* @param srcClass 源类名
|
||
* @param collectionClass 集合类名
|
||
*
|
||
* @return 复制器
|
||
*/
|
||
public static <S, D, C extends Collection> Function<Collection<S>, Collection<D>> funcCollection(final Class<S> srcClass,
|
||
final Class<D> destClass, final Class<C> collectionClass) {
|
||
return funcCollection(srcClass, destClass, 0, collectionClass);
|
||
}
|
||
|
||
/**
|
||
* 创建源类到目标类的复制器并缓存
|
||
*
|
||
* @param <D> 目标类泛型
|
||
* @param <S> 源类泛型
|
||
* @param destClass 目标类名
|
||
* @param srcClass 源类名
|
||
*
|
||
* @return 复制器
|
||
*/
|
||
public static <S, D> Copier<S, D> load(final Class<S> srcClass, final Class<D> destClass) {
|
||
return load(srcClass, destClass, 0);
|
||
}
|
||
|
||
/**
|
||
* 创建源类到目标类的复制器并缓存
|
||
*
|
||
* @param <D> 目标类泛型
|
||
* @param <S> 源类泛型
|
||
* @param destClass 目标类名
|
||
* @param srcClass 源类名
|
||
* @param options 可配项
|
||
*
|
||
* @return 复制器
|
||
*/
|
||
public static <S, D> Function<Collection<S>, Set<D>> funcSet(final Class<S> srcClass, final Class<D> destClass, final int options) {
|
||
return (Function) funcCollection(srcClass, destClass, options, LinkedHashSet.class);
|
||
}
|
||
|
||
/**
|
||
* 创建源类到目标类的复制器并缓存
|
||
*
|
||
* @param <D> 目标类泛型
|
||
* @param <S> 源类泛型
|
||
* @param destClass 目标类名
|
||
* @param srcClass 源类名
|
||
* @param options 可配项
|
||
*
|
||
* @return 复制器
|
||
*/
|
||
public static <S, D> Function<Collection<S>, List<D>> funcList(final Class<S> srcClass, final Class<D> destClass, final int options) {
|
||
return (Function) funcCollection(srcClass, destClass, options, ArrayList.class);
|
||
}
|
||
|
||
/**
|
||
* 创建源类到目标类的复制器并缓存
|
||
*
|
||
* @param <D> 目标类泛型
|
||
* @param <S> 源类泛型
|
||
* @param <C> 集合泛型
|
||
* @param destClass 目标类名
|
||
* @param srcClass 源类名
|
||
* @param options 可配项
|
||
* @param collectionClass 集合类名
|
||
*
|
||
* @return 复制器
|
||
*/
|
||
public static <S, D, C extends Collection> Function<Collection<S>, Collection<D>> funcCollection(final Class<S> srcClass, final Class<D> destClass,
|
||
final int options, final Class<C> collectionClass) {
|
||
if (destClass == srcClass) {
|
||
return Inners.CopierInner.copierFuncListOneCaches
|
||
.computeIfAbsent(collectionClass, t -> new ConcurrentHashMap<>())
|
||
.computeIfAbsent(options, t -> new ConcurrentHashMap<>())
|
||
.computeIfAbsent(srcClass, v -> {
|
||
Creator<C> creator = Creator.create(collectionClass);
|
||
Function<S, D> func = func(srcClass, destClass, options);
|
||
Function<Collection<S>, Collection<D>> funcList = srcs -> {
|
||
if (srcs == null) {
|
||
return null;
|
||
} else if (srcs.isEmpty()) {
|
||
return creator.create();
|
||
} else {
|
||
C list = creator.create();
|
||
for (S s : srcs) {
|
||
list.add(func.apply(s));
|
||
}
|
||
return list;
|
||
}
|
||
};
|
||
return funcList;
|
||
});
|
||
} else {
|
||
return Inners.CopierInner.copierFuncListTwoCaches
|
||
.computeIfAbsent(collectionClass, t -> new ConcurrentHashMap<>())
|
||
.computeIfAbsent(options, t -> new ConcurrentHashMap<>())
|
||
.computeIfAbsent(srcClass, t -> new ConcurrentHashMap<>())
|
||
.computeIfAbsent(destClass, v -> {
|
||
Creator<C> creator = Creator.create(collectionClass);
|
||
Function<S, D> func = func(srcClass, destClass, options);
|
||
Function<Collection<S>, Collection<D>> funcList = srcs -> {
|
||
if (srcs == null) {
|
||
return null;
|
||
} else if (srcs.isEmpty()) {
|
||
return (C) creator.create();
|
||
} else {
|
||
C list = creator.create();
|
||
for (S s : srcs) {
|
||
list.add(func.apply(s));
|
||
}
|
||
return list;
|
||
}
|
||
};
|
||
return funcList;
|
||
});
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 创建源类到目标类的复制器并缓存
|
||
*
|
||
* @param <D> 目标类泛型
|
||
* @param <S> 源类泛型
|
||
* @param destClass 目标类名
|
||
* @param srcClass 源类名
|
||
* @param options 可配项
|
||
*
|
||
* @return 复制器
|
||
*/
|
||
public static <S, D> Function<S, D> func(final Class<S> srcClass, final Class<D> destClass, final int options) {
|
||
if (destClass == srcClass) {
|
||
return Inners.CopierInner.copierFuncOneCaches
|
||
.computeIfAbsent(options, t -> new ConcurrentHashMap<>())
|
||
.computeIfAbsent(srcClass, v -> {
|
||
Copier<S, D> copier = load(srcClass, destClass, options);
|
||
Creator<D> creator = Creator.load(destClass);
|
||
Function<S, D> func = src -> src == null ? null : copier.apply(src, creator.create());
|
||
return func;
|
||
});
|
||
} else {
|
||
return Inners.CopierInner.copierFuncTwoCaches
|
||
.computeIfAbsent(options, t -> new ConcurrentHashMap<>())
|
||
.computeIfAbsent(srcClass, t -> new ConcurrentHashMap<>())
|
||
.computeIfAbsent(destClass, v -> {
|
||
Copier<S, D> copier = load(srcClass, destClass, options);
|
||
Creator<D> creator = Creator.load(destClass);
|
||
Function<S, D> func = src -> src == null ? null : copier.apply(src, creator.create());
|
||
return func;
|
||
});
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 创建源类到目标类的复制器并缓存
|
||
*
|
||
* @param <D> 目标类泛型
|
||
* @param <S> 源类泛型
|
||
* @param destClass 目标类名
|
||
* @param srcClass 源类名
|
||
* @param options 可配项
|
||
*
|
||
* @return 复制器
|
||
*/
|
||
public static <S, D> Copier<S, D> load(final Class<S> srcClass, final Class<D> destClass, final int options) {
|
||
if (destClass == srcClass) {
|
||
return Inners.CopierInner.copierOneCaches
|
||
.computeIfAbsent(options, t -> new ConcurrentHashMap<>())
|
||
.computeIfAbsent(srcClass, v -> create(srcClass, destClass, options));
|
||
} else {
|
||
return Inners.CopierInner.copierTwoCaches
|
||
.computeIfAbsent(options, t -> new ConcurrentHashMap<>())
|
||
.computeIfAbsent(srcClass, t -> new ConcurrentHashMap<>())
|
||
.computeIfAbsent(destClass, v -> create(srcClass, destClass, options));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 创建源类到目标类的复制器
|
||
*
|
||
* @param <D> 目标类泛型
|
||
* @param <S> 源类泛型
|
||
* @param destClass 目标类名
|
||
* @param srcClass 源类名
|
||
*
|
||
* @return 复制器
|
||
*/
|
||
public static <S, D> Copier<S, D> create(final Class<S> srcClass, final Class<D> destClass) {
|
||
return create(srcClass, destClass, (BiPredicate) null, (Map<String, String>) null);
|
||
}
|
||
|
||
/**
|
||
* 创建源类到目标类的复制器
|
||
*
|
||
* @param <D> 目标类泛型
|
||
* @param <S> 源类泛型
|
||
* @param destClass 目标类名
|
||
* @param srcClass 源类名
|
||
* @param names 源字段名与目标字段名的映射关系
|
||
*
|
||
* @return 复制器
|
||
*/
|
||
public static <S, D> Copier<S, D> create(final Class<S> srcClass, final Class<D> destClass, final Map<String, String> names) {
|
||
return create(srcClass, destClass, (BiPredicate) null, names);
|
||
}
|
||
|
||
/**
|
||
* 创建源类到目标类的复制器
|
||
*
|
||
* @param <D> 目标类泛型
|
||
* @param <S> 源类泛型
|
||
* @param destClass 目标类名
|
||
* @param srcClass 源类名
|
||
* @param srcColumnPredicate 需复制源类的字段名判断器
|
||
*
|
||
* @return 复制器
|
||
*/
|
||
@SuppressWarnings("unchecked")
|
||
public static <S, D> Copier<S, D> create(final Class<S> srcClass, final Class<D> destClass, final Predicate<String> srcColumnPredicate) {
|
||
return create(srcClass, destClass, (sc, m) -> srcColumnPredicate.test(m), (Map<String, String>) null);
|
||
}
|
||
|
||
/**
|
||
* 创建源类到目标类的复制器
|
||
*
|
||
* @param <D> 目标类泛型
|
||
* @param <S> 源类泛型
|
||
* @param destClass 目标类名
|
||
* @param srcClass 源类名
|
||
* @param srcColumnPredicate 需复制源类的字段名判断器
|
||
* @param names 源字段名与目标字段名的映射关系
|
||
*
|
||
* @return 复制器
|
||
*/
|
||
@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) {
|
||
return create(srcClass, destClass, (sc, m) -> srcColumnPredicate.test(m), names);
|
||
}
|
||
|
||
/**
|
||
* 创建源类到目标类的复制器
|
||
*
|
||
* @param <D> 目标类泛型
|
||
* @param <S> 源类泛型
|
||
* @param destClass 目标类名
|
||
* @param srcClass 源类名
|
||
* @param srcColumnPredicate 需复制源类的字段名判断器
|
||
*
|
||
* @return 复制器
|
||
*/
|
||
@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) {
|
||
return create(srcClass, destClass, srcColumnPredicate, (Map<String, String>) null);
|
||
}
|
||
|
||
/**
|
||
* 创建源类到目标类的复制器
|
||
*
|
||
* @param <D> 目标类泛型
|
||
* @param <S> 源类泛型
|
||
* @param destClass 目标类名
|
||
* @param srcClass 源类名
|
||
* @param srcColumnPredicate 需复制源类的字段名判断器
|
||
* @param names 源字段名与目标字段名的映射关系
|
||
*
|
||
* @return 复制器
|
||
*/
|
||
@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) {
|
||
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);
|
||
}
|
||
|
||
/**
|
||
* 创建源类到目标类的复制器
|
||
*
|
||
* @param <D> 目标类泛型
|
||
* @param <S> 源类泛型
|
||
* @param destClass 目标类名
|
||
* @param srcClass 源类名
|
||
* @param options 可配项
|
||
* @param srcColumnPredicate 需复制源类的字段名判断器
|
||
* @param nameAlias 源字段名与目标字段名的映射关系
|
||
*
|
||
* @return 复制器
|
||
*/
|
||
@SuppressWarnings("unchecked")
|
||
public static <S, D> Copier<S, D> create(final Class<S> srcClass, final Class<D> destClass, final int options,
|
||
final BiPredicate<java.lang.reflect.AccessibleObject, String> srcColumnPredicate, final Map<String, String> nameAlias) {
|
||
final boolean skipNullValue = (options & OPTION_SKIP_NULL_VALUE) > 0 || ConcurrentHashMap.class.isAssignableFrom(destClass);
|
||
final boolean skipEmptyString = (options & OPTION_SKIP_EMPTY_STRING) > 0;
|
||
final boolean allowTypeCast = (options & OPTION_ALLOW_TYPE_CAST) > 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)) {
|
||
final Map names0 = nameAlias;
|
||
if (srcColumnPredicate != null) {
|
||
if (nameAlias != null) {
|
||
return (S src, D dest) -> {
|
||
if (src == null) {
|
||
return dest;
|
||
}
|
||
Map d = (Map) dest;
|
||
((Map) src).forEach((k, v) -> {
|
||
if (srcColumnPredicate.test(null, k.toString()) && valPredicate.test(v)) {
|
||
d.put(names0.getOrDefault(k, k), v);
|
||
}
|
||
});
|
||
return dest;
|
||
};
|
||
} else {
|
||
return (S src, D dest) -> {
|
||
if (src == null) {
|
||
return dest;
|
||
}
|
||
Map d = (Map) dest;
|
||
((Map) src).forEach((k, v) -> {
|
||
if (srcColumnPredicate.test(null, k.toString()) && valPredicate.test(v)) {
|
||
d.put(k, v);
|
||
}
|
||
});
|
||
return dest;
|
||
};
|
||
}
|
||
} else if (nameAlias != null) {
|
||
return (S src, D dest) -> {
|
||
if (src == null) {
|
||
return dest;
|
||
}
|
||
Map d = (Map) dest;
|
||
((Map) src).forEach((k, v) -> {
|
||
if (valPredicate.test(v)) {
|
||
d.put(names0.getOrDefault(k, k), v);
|
||
}
|
||
});
|
||
return dest;
|
||
};
|
||
}
|
||
return new Copier<S, D>() {
|
||
@Override
|
||
public D apply(S src, D dest) {
|
||
if (src == null) {
|
||
return dest;
|
||
}
|
||
if (options == 0) {
|
||
((Map) dest).putAll((Map) src);
|
||
} else {
|
||
Map d = (Map) dest;
|
||
((Map) src).forEach((k, v) -> {
|
||
if (valPredicate.test(v)) {
|
||
d.put(k, v);
|
||
}
|
||
});
|
||
}
|
||
return dest;
|
||
}
|
||
};
|
||
}
|
||
// ------------------------------------------------------------------------------
|
||
final boolean destIsMap = Map.class.isAssignableFrom(destClass);
|
||
final boolean srcIsMap = Map.class.isAssignableFrom(srcClass);
|
||
final Predicate<Class<?>> throwPredicate = e -> !RuntimeException.class.isAssignableFrom(e);
|
||
final Map<String, AccessibleObject> elements = new TreeMap<>();
|
||
final Map<String, String> 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('.', '/');
|
||
final String destDesc = Type.getDescriptor(destClass);
|
||
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() + "_" + options
|
||
+ "__" + srcClass.getName().replace('.', '_').replace('$', '_')
|
||
+ (srcClass == destClass ? "" : ("__" + 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) {
|
||
}
|
||
|
||
// ------------------------------------------------------------------------------
|
||
ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
|
||
FieldVisitor fv;
|
||
MethodVisitor mv;
|
||
AnnotationVisitor av0;
|
||
|
||
cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, "Ljava/lang/Object;L" + supDynName + "<" + srcDesc + destDesc + ">;", "java/lang/Object", new String[]{supDynName});
|
||
|
||
{ // 构造函数
|
||
mv = (cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
|
||
//mv.setDebug(true);
|
||
mv.visitVarInsn(ALOAD, 0);
|
||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
||
mv.visitInsn(RETURN);
|
||
mv.visitMaxs(1, 1);
|
||
mv.visitEnd();
|
||
}
|
||
if (srcIsMap) { //Map -> JavaBean
|
||
{
|
||
mv = (cw.visitMethod(ACC_PUBLIC, "apply", "(" + srcDesc + destDesc + ")" + destDesc, null, null));
|
||
//mv.setDebug(true);
|
||
{
|
||
//if(src == null) return null;
|
||
mv.visitVarInsn(ALOAD, 1);
|
||
Label ifLabel = new Label();
|
||
mv.visitJumpInsn(IFNONNULL, ifLabel);
|
||
mv.visitVarInsn(ALOAD, 2);
|
||
mv.visitInsn(ARETURN);
|
||
mv.visitLabel(ifLabel);
|
||
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||
}
|
||
|
||
mv.visitVarInsn(ALOAD, 1);
|
||
mv.visitVarInsn(ALOAD, 2);
|
||
mv.visitInvokeDynamicInsn("accept",
|
||
"(" + destDesc + ")Ljava/util/function/BiConsumer;",
|
||
new Handle(Opcodes.H_INVOKESTATIC, "java/lang/invoke/LambdaMetafactory", "metafactory", "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;", false),
|
||
new Object[]{Type.getType("(Ljava/lang/Object;Ljava/lang/Object;)V"), new Handle(Opcodes.H_INVOKESTATIC, newDynName, "lambda$0", "(" + destDesc + "Ljava/lang/Object;Ljava/lang/Object;)V", false), Type.getType("(Ljava/lang/Object;Ljava/lang/Object;)V")});
|
||
mv.visitMethodInsn(srcClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, srcClassName, "forEach", "(Ljava/util/function/BiConsumer;)V", srcClass.isInterface());
|
||
mv.visitVarInsn(ALOAD, 2);
|
||
mv.visitInsn(ARETURN);
|
||
mv.visitMaxs(2, 3);
|
||
mv.visitEnd();
|
||
}
|
||
{
|
||
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;
|
||
for (Map.Entry<String, AccessibleObject> en : elements.entrySet()) {
|
||
final int index = ++i;
|
||
final java.lang.reflect.Type fieldType = en.getValue() instanceof Field
|
||
? ((Field) en.getValue()).getGenericType()
|
||
: ((Method) en.getValue()).getGenericParameterTypes()[0];
|
||
final Class fieldClass = en.getValue() instanceof Field
|
||
? ((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 (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);
|
||
Asms.visitFieldInsn(mv, fieldClass);
|
||
|
||
mv.visitVarInsn(ALOAD, 2);
|
||
mv.visitMethodInsn(INVOKESTATIC, utilClassName, "convertValue", "(Ljava/lang/reflect/Type;Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||
Asms.visitCheckCast(mv, fieldClass);
|
||
|
||
if (en.getValue() instanceof Field) {
|
||
mv.visitFieldInsn(PUTFIELD, destClassName, en.getKey(), Type.getDescriptor(fieldClass));
|
||
} else {
|
||
Method setter = (Method) en.getValue();
|
||
mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, setter.getName(), Type.getMethodDescriptor(setter), destClass.isInterface());
|
||
}
|
||
if (index == elements.size()) {
|
||
mv.visitLabel(goLabel);
|
||
} else {
|
||
mv.visitJumpInsn(GOTO, goLabel);
|
||
mv.visitLabel(ifeq);
|
||
}
|
||
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||
}
|
||
|
||
mv.visitInsn(RETURN);
|
||
mv.visitMaxs(3, 3);
|
||
mv.visitEnd();
|
||
}
|
||
} else { //JavaBean -> Map/JavaBean
|
||
mv = (cw.visitMethod(ACC_PUBLIC, "apply", "(" + srcDesc + destDesc + ")" + destDesc, null, null));
|
||
//mv.setDebug(true);
|
||
{
|
||
//if(src == null) return null;
|
||
mv.visitVarInsn(ALOAD, 1);
|
||
Label ifLabel = new Label();
|
||
mv.visitJumpInsn(IFNONNULL, ifLabel);
|
||
mv.visitVarInsn(ALOAD, 2);
|
||
mv.visitInsn(ARETURN);
|
||
mv.visitLabel(ifLabel);
|
||
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||
}
|
||
|
||
Predicate<Class> simpler = t -> t.isPrimitive() || t == String.class || Number.class.isAssignableFrom(t);
|
||
for (Map.Entry<String, AccessibleObject> 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();
|
||
|
||
final String dfname = destNewNames.getOrDefault(sfname, sfname);
|
||
final Class srcFieldType = field.getType();
|
||
final boolean charstr = CharSequence.class.isAssignableFrom(srcFieldType);
|
||
if (destIsMap) { //JavaBean -> Map
|
||
String td = Type.getDescriptor(srcFieldType);
|
||
if ((!skipNullValue && !(skipEmptyString && charstr)) || srcFieldType.isPrimitive()) {
|
||
mv.visitVarInsn(ALOAD, 2);
|
||
mv.visitLdcInsn(dfname);
|
||
mv.visitVarInsn(ALOAD, 1);
|
||
mv.visitFieldInsn(GETFIELD, srcClassName, sfname, td);
|
||
Asms.visitPrimitiveValueOf(mv, srcFieldType);
|
||
mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", destClass.isInterface());
|
||
mv.visitInsn(POP);
|
||
} 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(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);
|
||
}
|
||
} else { //JavaBean -> JavaBean
|
||
boolean needTypeCast = false;
|
||
java.lang.reflect.Method setter = null;
|
||
java.lang.reflect.Field setField = null;
|
||
try {
|
||
setField = destClass.getField(dfname);
|
||
if (field.getType() == setField.getType()) {
|
||
needTypeCast = false;
|
||
} else if (simpler.test(field.getType()) && simpler.test(setField.getType())) {
|
||
needTypeCast = true;
|
||
} else if (!field.getType().equals(setField.getType())) {
|
||
if (allowTypeCast) {
|
||
needTypeCast = true;
|
||
} else {
|
||
continue;
|
||
}
|
||
}
|
||
} catch (Exception e) {
|
||
String setterMethodName = "set" + Utility.firstCharUpperCase(dfname);
|
||
try {
|
||
setter = destClass.getMethod(setterMethodName, field.getType());
|
||
if (Utility.contains(setter.getExceptionTypes(), throwPredicate)) {
|
||
continue; //setter方法带有非RuntimeException异常
|
||
}
|
||
} catch (Exception e2) {
|
||
try {
|
||
for (java.lang.reflect.Method m : destClass.getMethods()) {
|
||
if (Modifier.isStatic(m.getModifiers())) {
|
||
continue;
|
||
}
|
||
if (Utility.contains(m.getExceptionTypes(), throwPredicate)) {
|
||
continue; //setter方法带有非RuntimeException异常
|
||
}
|
||
if (m.getParameterTypes().length != 1) {
|
||
continue;
|
||
}
|
||
if (m.getName().equals(setterMethodName)) {
|
||
if (simpler.test(field.getType()) && simpler.test(setField.getType())) {
|
||
setter = m;
|
||
needTypeCast = true;
|
||
} else if (!allowTypeCast) {
|
||
setter = null;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
if (setter == null) {
|
||
continue;
|
||
}
|
||
} catch (Exception e3) {
|
||
continue;
|
||
}
|
||
}
|
||
}
|
||
String srcFieldDesc = Type.getDescriptor(srcFieldType);
|
||
final Class destFieldType = setter == null ? setField.getType() : setter.getParameterTypes()[0];
|
||
boolean localSkipNull = skipNullValue || (!srcFieldType.isPrimitive() && destFieldType.isPrimitive());
|
||
if ((!localSkipNull && !(skipEmptyString && charstr))
|
||
|| (srcFieldType.isPrimitive() && !allowTypeCast)
|
||
|| (srcFieldType.isPrimitive() && destFieldType.isPrimitive())) {
|
||
if (needTypeCast) {
|
||
mv.visitVarInsn(ALOAD, 2);
|
||
Asms.visitFieldInsn(mv, destFieldType);
|
||
mv.visitVarInsn(ALOAD, 1);
|
||
mv.visitFieldInsn(GETFIELD, srcClassName, sfname, srcFieldDesc);
|
||
Asms.visitPrimitiveValueOf(mv, srcFieldType);
|
||
mv.visitMethodInsn(INVOKESTATIC, utilClassName, "convertValue", "(Ljava/lang/reflect/Type;Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||
Asms.visitCheckCast(mv, destFieldType);
|
||
if (setter == null) { //src: field, dest:field
|
||
mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(destFieldType));
|
||
} else { //src: field, dest:method
|
||
mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, setter.getName(), Type.getMethodDescriptor(setter), destClass.isInterface());
|
||
}
|
||
} else {
|
||
mv.visitVarInsn(ALOAD, 2);
|
||
mv.visitVarInsn(ALOAD, 1);
|
||
mv.visitFieldInsn(GETFIELD, srcClassName, sfname, srcFieldDesc);
|
||
if (setter == null) { //src: field, dest:field
|
||
mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(destFieldType));
|
||
} else { //src: field, dest:method
|
||
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, srcFieldDesc);
|
||
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);
|
||
}
|
||
if (needTypeCast) {
|
||
mv.visitVarInsn(ALOAD, 2);
|
||
Asms.visitFieldInsn(mv, destFieldType);
|
||
mv.visitVarInsn(ALOAD, 3);
|
||
Asms.visitPrimitiveValueOf(mv, srcFieldType);
|
||
mv.visitMethodInsn(INVOKESTATIC, utilClassName, "convertValue", "(Ljava/lang/reflect/Type;Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||
Asms.visitCheckCast(mv, destFieldType);
|
||
if (setter == null) { //src: field, dest:field
|
||
mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(destFieldType));
|
||
} else { //src: field, dest:method
|
||
mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, setter.getName(), Type.getMethodDescriptor(setter), destClass.isInterface());
|
||
}
|
||
} else {
|
||
mv.visitVarInsn(ALOAD, 2);
|
||
mv.visitVarInsn(ALOAD, 3);
|
||
mv.visitTypeInsn(CHECKCAST, srcFieldType.getName().replace('.', '/'));
|
||
if (setter == null) { //src: field, dest:field
|
||
mv.visitFieldInsn(PUTFIELD, destClassName, dfname, srcFieldDesc);
|
||
} else { //src: field, dest:method
|
||
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);
|
||
}
|
||
}
|
||
}
|
||
for (Map.Entry<String, AccessibleObject> 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();
|
||
|
||
final String dfname = destNewNames.getOrDefault(sfname, sfname);
|
||
final Class srcFieldType = getter.getReturnType();
|
||
final boolean charstr = CharSequence.class.isAssignableFrom(srcFieldType);
|
||
if (destIsMap) { //srcClass是JavaBean
|
||
if ((!skipNullValue && !(skipEmptyString && charstr)) || srcFieldType.isPrimitive()) {
|
||
mv.visitVarInsn(ALOAD, 2);
|
||
mv.visitLdcInsn(dfname);
|
||
mv.visitVarInsn(ALOAD, 1);
|
||
mv.visitMethodInsn(srcClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, srcClassName, getter.getName(), Type.getMethodDescriptor(getter), srcClass.isInterface());
|
||
Asms.visitPrimitiveValueOf(mv, srcFieldType);
|
||
mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", destClass.isInterface());
|
||
mv.visitInsn(POP);
|
||
} 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.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||
}
|
||
} else { //srcClass、destClass是JavaBean
|
||
boolean needTypeCast = false;
|
||
java.lang.reflect.Method setter = null;
|
||
java.lang.reflect.Field setField = null;
|
||
String setterMethodName = "set" + Utility.firstCharUpperCase(dfname);
|
||
try {
|
||
setter = destClass.getMethod(setterMethodName, getter.getReturnType());
|
||
if (Utility.contains(setter.getExceptionTypes(), throwPredicate)) {
|
||
continue; //setter方法带有非RuntimeException异常
|
||
}
|
||
} catch (Exception e) {
|
||
if (allowTypeCast) {
|
||
try {
|
||
for (java.lang.reflect.Method m : destClass.getMethods()) {
|
||
if (Modifier.isStatic(m.getModifiers())) {
|
||
continue;
|
||
}
|
||
if (Utility.contains(m.getExceptionTypes(), throwPredicate)) {
|
||
continue; //setter方法带有非RuntimeException异常
|
||
}
|
||
if (m.getParameterTypes().length != 1) {
|
||
continue;
|
||
}
|
||
if (m.getName().equals(setterMethodName)) {
|
||
setter = m;
|
||
needTypeCast = true;
|
||
break;
|
||
}
|
||
}
|
||
} catch (Exception e2) {
|
||
}
|
||
}
|
||
if (setter == null) {
|
||
try {
|
||
setField = destClass.getField(dfname);
|
||
if (!getter.getReturnType().equals(setField.getType())) {
|
||
if (allowTypeCast) {
|
||
needTypeCast = true;
|
||
} else {
|
||
continue;
|
||
}
|
||
}
|
||
} catch (Exception e3) {
|
||
continue;
|
||
}
|
||
}
|
||
}
|
||
final Class destFieldType = setter == null ? setField.getType() : setter.getParameterTypes()[0];
|
||
boolean localSkipNull = skipNullValue || (!srcFieldType.isPrimitive() && destFieldType.isPrimitive());
|
||
if ((!localSkipNull && !(skipEmptyString && charstr))
|
||
|| (srcFieldType.isPrimitive() && !allowTypeCast)
|
||
|| (srcFieldType.isPrimitive() && destFieldType.isPrimitive())) {
|
||
if (needTypeCast) {
|
||
mv.visitVarInsn(ALOAD, 2);
|
||
Asms.visitFieldInsn(mv, destFieldType);
|
||
mv.visitVarInsn(ALOAD, 1);
|
||
mv.visitMethodInsn(srcClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, srcClassName, getter.getName(), Type.getMethodDescriptor(getter), srcClass.isInterface());
|
||
Asms.visitPrimitiveValueOf(mv, srcFieldType);
|
||
mv.visitMethodInsn(INVOKESTATIC, utilClassName, "convertValue", "(Ljava/lang/reflect/Type;Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||
Asms.visitCheckCast(mv, destFieldType);
|
||
if (setter == null) { //src: method, dest: field
|
||
mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(destFieldType));
|
||
} else { //src: method, dest: method
|
||
mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, setter.getName(), Type.getMethodDescriptor(setter), destClass.isInterface());
|
||
}
|
||
} else {
|
||
mv.visitVarInsn(ALOAD, 2);
|
||
mv.visitVarInsn(ALOAD, 1);
|
||
mv.visitMethodInsn(srcClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, srcClassName, getter.getName(), Type.getMethodDescriptor(getter), srcClass.isInterface());
|
||
if (setter == null) { //src: method, dest: field
|
||
mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(destFieldType));
|
||
} else { //src: method, dest: method
|
||
mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, setter.getName(), Type.getMethodDescriptor(setter), destClass.isInterface());
|
||
}
|
||
}
|
||
} 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);
|
||
}
|
||
if (needTypeCast) {
|
||
mv.visitVarInsn(ALOAD, 2);
|
||
Asms.visitFieldInsn(mv, destFieldType);
|
||
mv.visitVarInsn(ALOAD, 3);
|
||
Asms.visitPrimitiveValueOf(mv, srcFieldType);
|
||
mv.visitMethodInsn(INVOKESTATIC, utilClassName, "convertValue", "(Ljava/lang/reflect/Type;Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||
Asms.visitCheckCast(mv, destFieldType);
|
||
if (setter == null) { //src: method, dest: field
|
||
mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(destFieldType));
|
||
} else { //src: method, dest: method
|
||
mv.visitMethodInsn(destClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, destClassName, setter.getName(), Type.getMethodDescriptor(setter), destClass.isInterface());
|
||
}
|
||
} else {
|
||
mv.visitVarInsn(ALOAD, 2);
|
||
mv.visitVarInsn(ALOAD, 3);
|
||
mv.visitTypeInsn(CHECKCAST, srcFieldType.getName().replace('.', '/'));
|
||
if (setter == null) { //src: method, dest: field
|
||
mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(getter.getReturnType()));
|
||
} else { //src: method, dest: method
|
||
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);
|
||
}
|
||
}
|
||
}
|
||
mv.visitVarInsn(ALOAD, 2);
|
||
mv.visitInsn(ARETURN);
|
||
mv.visitMaxs(3, 3);
|
||
mv.visitEnd();
|
||
}
|
||
{
|
||
mv = (cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "apply", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", null, null));
|
||
//mv.setDebug(true);
|
||
mv.visitVarInsn(ALOAD, 0);
|
||
mv.visitVarInsn(ALOAD, 1);
|
||
mv.visitTypeInsn(CHECKCAST, srcClassName);
|
||
mv.visitVarInsn(ALOAD, 2);
|
||
mv.visitTypeInsn(CHECKCAST, destClassName);
|
||
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "apply", "(" + srcDesc + destDesc + ")" + destDesc, false);
|
||
mv.visitInsn(ARETURN);
|
||
mv.visitMaxs(3, 3);
|
||
mv.visitEnd();
|
||
}
|
||
cw.visitEnd();
|
||
// ------------------------------------------------------------------------------
|
||
byte[] bytes = cw.toByteArray();
|
||
Class<?> newClazz = new ClassLoader(loader) {
|
||
public final Class<?> loadClass(String name, byte[] b) {
|
||
return defineClass(name, b, 0, b.length);
|
||
}
|
||
}.loadClass(newDynName.replace('/', '.'), bytes);
|
||
RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz);
|
||
RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.'));
|
||
try {
|
||
return (Copier) newClazz.getDeclaredConstructor().newInstance();
|
||
} catch (Exception ex) {
|
||
throw new RedkaleException(ex);
|
||
}
|
||
}
|
||
|
||
}
|