基于注解-实现不同对象间,不同属性名之间的属性值复制

不同对象间,不同属性名之间的属性值复制

场景:
注意: 不涉及任何业务逻辑
在系统间接口调用,存在各种对象的转换, 这里指的是将 A 类中的 a 的值,赋值给 B 类中的 b . 然后自己系统的数据库存的是 B。
最恐怖的是, 如果进行数据下载的时候, 我们还要把 B 原封不动转换成 A .供其他系统调用.
如下图:
一个完整的 Student 类 ,由3个不同的类的字段值拼凑得到。
然后进行数据下载的时候, 还是把 Student中某些指定的属性,转换成映射的对象.
在这里插入图片描述

字段少的话可能是这样

这里只是模拟一下


        SubjectInfo subjectInfo = new SubjectInfo("语文","80.36");
        UserInfo userInfo = new UserInfo("英旭","30","2020-07-08 12:25:12",subjectInfo);
        EmailInfo email =new EmailInfo("inxu","@163.com",20);

        Student student = new Student();
        student.setName(userInfo.getUname());
        student.setSubName(userInfo.getSubjectInfo().getName());
        student.setEmail(email.getAddr());

问题: 如果字段多了呢??

眼要写瞎了. 我太难了 o(╥﹏╥)o

基于注解实现

自定义注解

/**
 * @program: springBootStudy
 * @Date: 2020/7/10 20:54
 * @Author: Inxu
 * @Description:
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface AimField {
    /*目标对象的属性名*/
    String value();
    /*目标对象的属性类型 基本类型 */
    Class type();

} 
/**
 * @program: springBootStudy
 * @Date: 2020/7/10 20:49
 * @Author: Inxu
 * @Description:
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.FIELD})
public @interface AimObject {
    Class value() ;
}

/**
 * @program: springBootStudy
 * @Date: 2020/7/11 13:36
 * @Author: Inxu
 * @Description:
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface AimOther {
    /*目标对象的属性名*/
    String value();
    /*目标对象的属性类型 基本类型 */
    Class type();
    /*映射的指定类*/
    Class clazz();
}
通过反射 获取注解信息 ,然后给映射的对象赋值

完整代码如下:

/**
 * @program: springBootStudy
 * @Date: 2020/7/10 20:59
 * @Author: Inxu
 * @Description: 对象属性复制类
 */
public class BeanCopyUtil {
    private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final String DATE="Date";
    private static final String LOCAL_DATE_TIME="LocalDateTime";

    /**
     * 对象属性赋值方法
     * 将 S 中的属性值,按照属性名的对应关系, 复制到 T 中
     * @param s  源对象数据
     * @param t  目标对象 类的实例
     * @param <S> 泛型
     * @param <T> 泛型
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws ParseException
     * @throws NoSuchObjectException
     */
    public static <S,T> T copy(S s,T t) throws IllegalAccessException,
            InstantiationException, ParseException,
            NoSuchObjectException, NoSuchMethodException,
            NoSuchFieldException, InvocationTargetException {

        Class<?> clazz = s.getClass();
        AimObject type_AimObject = clazz.getAnnotation(AimObject.class);
        Class type_Class = type_AimObject.value();
        if( !type_Class.isAssignableFrom(t.getClass())){
            throw  new NoSuchObjectException("注解的映射类与目标类不匹配.");
        }
        // 获取要映射的类的实例
        Object newInstance =null;
        if(null ==t){
            newInstance = type_Class.newInstance();
        }else {
            newInstance=t;
        }
        // 1 : 反射得到 源对象的属性列表
        Field[] s_Fields = clazz.getDeclaredFields();
        for (Field sField : s_Fields) {
            sField.setAccessible(true);
            // 2: 获取源对象中, 属性上需要映射的类
            AimObject field_AimObject = sField.getAnnotation(AimObject.class);
            if(null != field_AimObject){
                // 如果源对象中的 对象属性 的映射类 和源对象映射的类一致, 继续延用当前的 对象(newInstance)
                if(field_AimObject.value().isAssignableFrom(type_Class)){
                    copy(sField.get(s),newInstance);
                }else {
                    continue;
                }
               field_AimObject=null;
            }
            // 3: 获取源对象中属性的映射
            AimField aimField = sField.getAnnotation(AimField.class);
            if(null == aimField && null == field_AimObject){
                continue;
            }
            // Class field_orm_other_obj = aimField.clazz();
            // 获取目标类的属性名
            String target_Field = aimField.value();
            // 获取目标类的 属性类型
            Class target_Field_Type = aimField.type();
            // 获取源对象 的 属性值 , 最终把它赋值给目标类的属性 target_Field
            Object o = sField.get(s);
            if(null == o) {
                continue;
            }
            /*获取源对象属性的类型*/
            Class<?> s_field_Type = sField.getType();
            // 赋值
            setTargetFieldValueByNameAndValue(newInstance,target_Field,target_Field_Type,o,s_field_Type);
        }
        return t;
    }

    /**
     *  对象属性赋值方法
     *  将 S 属性中的 @AimOther注解 ,根据属性名和指定的类, 复制到 T
     * @param s  源对象
     * @param t  目标对象
     * @param <S> 泛型
     * @param <T> 泛型
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws NoSuchObjectException
     * @throws NoSuchMethodException
     * @throws NoSuchFieldException
     * @throws ParseException
     * @throws InvocationTargetException
     */
    public static <S,T> T copyPartByAimOther(S s ,T t) throws IllegalAccessException,
            InstantiationException, NoSuchObjectException,
            NoSuchMethodException, NoSuchFieldException, ParseException,
            InvocationTargetException {
        if(null == s || null == t){
            throw  new NullPointerException("源对象 或者 目标对象 不能为空.");
        }
        Field[] fields = s.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            AimOther type_Aim_other = field.getAnnotation(AimOther.class);
            if(null == type_Aim_other){
                continue;
            }
            Class type_Class = type_Aim_other.clazz();
            if(!type_Class.isAssignableFrom(t.getClass())){
                continue;
            }
            String target_Field = type_Aim_other.value();
            Class target_Field_Type = type_Aim_other.type();
            Class<?> s_field_Type = field.getType();
            Object o = field.get(s);
            if(null == o) {
                continue;
            }
            setTargetFieldValueByNameAndValue(t,target_Field,target_Field_Type,o,s_field_Type);
        }
        return  t;
    }

    /**
     *
     * @param s
     * @param t
     * @param <S>
     * @param <T>
     * @return
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws ParseException
     * @throws InstantiationException
     * @throws NoSuchObjectException
     * @throws NoSuchFieldException
     */
    public  static <S,T> T copyPartByAimObjectOnField(S s ,T t) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, ParseException, InstantiationException, NoSuchObjectException, NoSuchFieldException {
        if(null == s || null == t){
            throw  new NullPointerException("源对象 或者 目标对象 不能为空.");
        }
        Field[] fields = s.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            // 获取源对象中, 属性上需要映射的类
            AimObject field_AimObject = field.getAnnotation(AimObject.class);
            if(null == field_AimObject){
                continue;
            }
            t=copy(field.get(s),t);
        }

        return t;
    }

    /**
     *  为目标类的属性 通过属性名赋值
     * @param t  目标类
     * @param fieldName  目标类的变量名
     * @param target_Field_Type   变量类型
     * @param value    源数据
     * @param s_field_Type  源数据 类型
     * @param <T>  泛型
     * @return
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     * @throws NoSuchFieldException
     */
    public  static <T> void setTargetFieldValueByNameAndValue(T t ,
                                                              String fieldName,
                                                              Class target_Field_Type,
                                                              Object value,
                                                              Class<?> s_field_Type) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException, ParseException {

        Field field = t.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        // 如果与映射属性的类型不一致, 转换成目标属性的类型
        if(!target_Field_Type.isAssignableFrom(s_field_Type)  ){
                // 时间转 String
                if((DATE).equals (s_field_Type.getSimpleName())|| s_field_Type.getSimpleName().equals(LOCAL_DATE_TIME)){
                    value=covertDate2String(s_field_Type.getSimpleName(),value);
                }else {
                    value= convertValueByType(target_Field_Type,value.toString());
                }
            }
        field.set(t,value);
}

    /**
     * 将 值 进行类型转换
     * @param target_Field_Type  目标类变量的类型
     * @param val  值
     * @return
     * @throws ParseException
     */
    public static  Object convertValueByType(Class target_Field_Type ,String val) throws ParseException {
        String typeName = target_Field_Type.getSimpleName();
        Object o =null;
        switch (typeName){
            case "Integer":
                o=Integer.parseInt(val);break;
            case "Long":
                o=Long.parseLong(val);break;
            case "Double":
                o=Double.parseDouble(val);break;
            case "Short":
                o= Short.parseShort(val); break;
            case "Byte":
                o= Byte.parseByte(val);break;
            case "Date":
                o=SIMPLE_DATE_FORMAT.parse(val);
            case "LocalDateTime":
               o= LocalDateTime.parse(val,DATE_TIME_FORMATTER);break;
            default:
                o=val;break;
        }

        return  o;
    }

    public static  Object covertDate2String(String typeName,Object value){
        Object o =null;
        switch (typeName){
            case "Date":
                Date date =(Date)value;
                o=SIMPLE_DATE_FORMAT.format(date);
                break;
            case "LocalDateTime":
                LocalDateTime parse=(LocalDateTime)value;
                o= parse.format(DATE_TIME_FORMATTER);
                break;
            default:
                o=value;break;
        }

        return  o;
    }
}

测试

UserInfo 类
/**
 * @program: springBootStudy
 * @Date: 2020/7/10 21:30
 * @Author: Inxu
 * @Description:
 */
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
@AimObject(Student.class)
public class UserInfo {
    @AimField(value = "name",type = String.class)
    private String uname;

    @AimField(value = "age",type = Integer.class)
    private String uage;

    @AimField(value = "dateTime",type = LocalDateTime.class)
    private String udate;

    @AimObject(Student.class)
    private SubjectInfo subjectInfo;
}
SubjectInfo 类

/**
 * @program: springBootStudy
 * @Date: 2020/7/10 23:46
 * @Author: Inxu
 * @Description:
 */
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
@AimObject(Student.class)
public class SubjectInfo {
    @AimField(value = "subName",type = String.class)
    private String name;
    @AimField(value = "score",type = Double.class)
    private String score;
}
EmailInfo 类

/**
 * @program: springBootStudy
 * @Date: 2020/7/11 13:17
 * @Author: Inxu
 * @Description:
 */
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
@AimObject(Student.class)
public class EmailInfo {
    @AimField(value = "email",type = String.class)
    private String addr;
    @AimField(value = "emailIP",type = String.class)
    private String ip;
    private Integer times;
}
Student 类

/**
 * @program: springBootStudy
 * @Date: 2020/7/10 21:28
 * @Author: Inxu
 * @Description:
 */
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
@AimObject(UserInfo.class)
public class Student {
    @AimField(value = "uname",type = String.class)
    private String name;
    @AimField(value = "uage",type = String.class)
    private Integer age;
    @AimField(value = "udate",type = String.class)
    private LocalDateTime dateTime;

    @AimOther(value = "name",type = String.class,clazz = SubjectInfo.class)
    private String subName;
    @AimOther(value = "score",type = String.class,clazz = SubjectInfo.class)
    private Double score;

    @AimOther(value = "addr",type = String.class,clazz = EmailInfo.class)
    private String email;
    @AimOther(value = "ip",type = String.class,clazz = EmailInfo.class)
    private String emailIP;

}

效果如下: 基本实现,把终端提交的原数据转换成自身数据库需要的数据格式,然后如果需要的话,在转换成终端需要的数据格式。
在这里插入图片描述

待完善

不支持 集合 ,仅支持对象间基本类型的转换。
可能有BUG。还请谅解, 修改后,望告知 inxu0317@163.com. 谢谢!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值