有时候不想复制整个类的所有属性,只需要一部分属性,为了避免大量get/set,采用反射方式做复制处理.
1.方法类: CopyBeanValueUtil
/**
* @author wangfuxu
* @date: 2021/11/19
* @description: 使用前提:两个类属性字段一样,不一样需要自己添加适配器
* 在复制某两个类某些属性时,可使用此方法,前提两个类有相同字段属性名
* 只需要在目标类和字段上加注@CopyValue注解
* 两种:
* 类上默认CONTAIN,字段必须标注了才复制
* 类上标注EXCLUDE,字段标注EXCLUDE的不复制,剩下全部复制
* 调用copyValue方法即可
* //todo 采用适配器+责任链模式
*/
@Slf4j
public class CopyBeanValueUtil {
private static CopyBeanValue copyBeanValue = new CopyBeanValue();
/**
* 复制字段值
*
* @param source 源字段
* @param supplier 目标字段
* @return 目标类
*/
public static <Source, Target> Target copyValue(Source source, Supplier<Target> supplier) {
return (Target) copyBeanValue.copyValue(source, supplier);
}
/**
* 复制字段值
*
* @param source 源字段
* @param target 目标字段
* @return
*/
public static <Source, Target> void copyValue(Source source, Target target) {
copyBeanValue.copyValue(source, target);
}
private static class CopyBeanValue<Source, Target> {
/**
* 获得所有字段数组
*
* @param t
* @return 字段数组
*/
public Field[] getSourceFields(@NotNull Source t) {
Class clazz = t.getClass();
if (clazz == null) {
return null;
}
Field[] declaredFields = clazz.getDeclaredFields();
return declaredFields;
}
/**
* 获得所有字段数组Map
*
* @param t
* @return 字段数组
*/
public Map<String, Field> getTargetFields(@NotNull Target t) {
Class clazz = t.getClass();
if (clazz == null) {
return null;
}
Field[] declaredFields = clazz.getDeclaredFields();
Map<String, Field> map = MapUtil.createMap(HashMap.class);
for (Field field : declaredFields) {
map.put(field.getName(), field);
}
return map;
}
public Target copyValue(@NotNull Source source, @NotNull Supplier<Target> supplier) {
Target target = supplier.get();
copyValue(source, target);
return target;
}
public void copyValue(@NotNull Source source, @NotNull Target target) {
try {
CopyValue clazzCopyValue = target.getClass().getAnnotation(CopyValue.class);
Field[] fields = getSourceFields(source);
Map<String, Field> targetFields = getTargetFields(target);
for (Field sourceField : fields) {
sourceField.setAccessible(true);
if (null != sourceField.get(source) && targetFields.containsKey(sourceField.getName())) {
CopyValue copyValue = targetFields.get(sourceField.getName()).getAnnotation(CopyValue.class);
//(类为准)类标注为包含 & 字段添加标注
Boolean conditionOne = CONTAIN.equals(clazzCopyValue.type()) && null != copyValue;
// 类标注为排除 & 字段添加标注
Boolean conditionTwo = EXCLUDE.equals(clazzCopyValue.type()) && (copyValue == null || !EXCLUDE.equals(copyValue.type()));
if (conditionOne || conditionTwo) {
Field targetField = targetFields.get(sourceField.getName());
setTargetValue(targetField, sourceField, target, source);
}
}
}
} catch (Exception e) {
log.error("CopyBeanValueUtil#copyValue have error:", e);
}
}
/**
* 简单转换器
*
* @param targetField
* @param sourceField
*/
private void setTargetValue(Field targetField, Field sourceField, Target target, Source source) throws IllegalAccessException {
Type targetFiledType = targetField.getGenericType();
if (targetFiledType.getTypeName().equals(sourceField.getGenericType().getTypeName())) {
targetField.setAccessible(true);
targetField.set(target, sourceField.get(source));
} else {
if (targetFiledType.getTypeName().toUpperCase().equals(DataType.STRING) && sourceField.getGenericType().getTypeName().toUpperCase().equals(DataType.DATE)) {
Date value = (Date) sourceField.get(source);
String stringValue = DateUtil.format(value, "yyyy-MM-dd HH:mm:ss");
setValue(targetField, target, stringValue);
} else if (targetFiledType.getTypeName().toUpperCase().equals(DataType.LONG) && sourceField.getGenericType().getTypeName().toUpperCase().equals(DataType.DOUBLE)) {
Long value = ((Double) sourceField.get(source)).longValue();
setValue(targetField, target, value);
} else if (targetFiledType.getTypeName().toUpperCase().equals(DataType.DOUBLE) && sourceField.getGenericType().getTypeName().toUpperCase().equals(DataType.LONG)) {
Double value = ((Long) sourceField.get(source)).doubleValue();
setValue(targetField, target, value);
} else if (targetFiledType.getTypeName().toUpperCase().equals(DataType.DATE) && sourceField.getGenericType().getTypeName().toUpperCase().equals(DataType.STRING)) {
String value = String.valueOf(sourceField.get(source));
Date date = DateUtil.parse(value, "yyyy-MM-dd HH:mm:ss");
setValue(targetField, target, date);
}
}
}
private <T> void setValue(Field targetField, Target target, T value) throws IllegalAccessException {
targetField.setAccessible(true);
targetField.set(target, value);
}
}
}
2.注解类
/**
* @author wangfuxu
* 标记需要被copy的属性或类
* EXCLUDE:排除
* CONTAIN:包含
* 默认扫描包含注解的属性
*/
@Target(value = {ElementType.FIELD, ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
@Documented
public @interface CopyValue {
CopyValueType type() default CopyValueType.CONTAIN;
}
3.枚举类
/**
* @author wangfuxu
* 标记需要被copy的属性或类
* EXCLUDE:排除
* CONTAIN:包含
* 默认扫描包含注解的属性
*/
@Target(value = {ElementType.FIELD, ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
@Documented
public @interface CopyValue {
CopyValueType type() default CopyValueType.CONTAIN;
}
4.转换器属性类
/**
* @author wangfuxu
*/
public interface DataType {
String STRING = "JAVA.LANG.STRING";
String INTEGER = "JAVA.LANG.INTEGER";
String LONG = "JAVA.LANG.LONG";
String DOUBLE = "JAVA.LANG.DOUBLE";
String SHORT = "JAVA.LANG.SHORT";
String DATE = "JAVA.UTIL.DATE";
String CHAR = "JAVA.LANG.CHAR";
}
备注:此方法采用反射模式,对于JavaBean应该采用自省模式比较好,时间有限,仅做备注.后期有时间补充