实现从一个类中的实体对象获取所有属性值注入到另一个不同类的实体对象的对应属性中

背景:

由于dao层的可视化对象(bean)跟service层以及controller层的bean对象是分开的,也就是同一业务流水线中,在controller层是跟界面或者接口的交互bean,而到了操作数据库层则用的匹配数据库表的实体bean。该俩个bean之间类名可能相同,属性也可能完全一致,就是包路径不一样,为了确保这个过程能够正常对接上,就需要有一个转换的工作名,而这个工作就交给了service层去处理,假若一个bean对象的属性数量相对少的时候,我们可以采取笨方法,挨个getset赋值转换,但假若一个bean对象的属性数量相对庞大,且该项目里存在大量该情况的bean的时候,就需要换个思路,能不能实现自动转换的工具类,因此才有了该工具并并记录于此,希望能够给相同处境的朋友提供上帮助

import org.springframework.util.StringUtils;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;
import com.test.User;
import com.test.UserB;

public class ConvertUtil {

    /**
     * 对象转换,前提是俩个对象的属性字段要相同
     *
     * @param tClass 目标class
     * @param object 需要被转换的对象
     * @param <T>    T
     * @return 目标对象
     */
    public static <T> T convertObj(Class<T> tClass, Object object) throws IllegalAccessException, InstantiationException {
        Class<?> aClass = object.getClass();
        Field[] objDeclaredFields = aClass.getDeclaredFields();
        AccessibleObject.setAccessible(objDeclaredFields, true);
        T tObj = tClass.newInstance();
        Arrays.stream(objDeclaredFields).forEach(field -> {
            try {
                String name = field.getName();
                if (name.equals("serialVersionUID")) {
                    // 现在大部分bean都包含序列号,忽略该值
                    return;
                }
                // 该属性对应的值
                Object value = field.get(object);
                if (Objects.isNull(value) || StringUtils.isEmpty(value.toString().trim()) || isBaseDefaultValue(value)) {
                    // 无值或空字符串或是基础类型的默认值(如:int型默认值为0,double默认值为0.0,以此类推)
                    return;
                }
                // 属性名改成大驼峰
                name = name.substring(0, 1).toUpperCase() + name.substring(1);
                Method declaredMethod = tClass.getDeclaredMethod("set" + name, new Class[]{value.getClass()});
                declaredMethod.invoke(tObj, value);
            } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
                e.printStackTrace();
            }
        });
        return tObj;
    }

    /**
     * 判断是否为基本类型的默认值
     *
     * @param object
     * @return
     */
    public static boolean isBaseDefaultValue(Object object) {
        Class className = object.getClass();
        if (className.equals(java.lang.Integer.class)) {
            return (int) object == 0;
        } else if (className.equals(java.lang.Byte.class)) {
            return (byte) object == 0;
        } else if (className.equals(java.lang.Long.class)) {
            return (long) object == 0L;
        } else if (className.equals(java.lang.Double.class)) {
            return (double) object == 0.0d;
        } else if (className.equals(java.lang.Float.class)) {
            return (float) object == 0.0f;
        } else if (className.equals(java.lang.Character.class)) {
            return (char) object == '\u0000';
        } else if (className.equals(java.lang.Short.class)) {
            return (short) object == 0;
        } else if (className.equals(java.lang.Boolean.class)) {
            return (boolean) object == false;
        }
        return false;
    }

    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        User user = new User();
        user.setId("123456");
        user.setName("name");
        UserB userB = convertObj(UserB.class, user);
        // user的num属性这里没有赋值,但是因为其实基础类型自带默认值, 因此要忽略掉
        // UserB(name=name, id=123456, num=null)
        System.out.println(userB);
    }
}

实体类A 和B (类中的属性名必须保持一致,声明类型如果是基础数据类型,另一个实体类该属性可以是对应的包装类)

import lombok.AccessLevel;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
// 该注解是lombok插件,自动生成getset方法,可以忽略
@Data
public class User implements Serializable {
    @Getter(AccessLevel.NONE)
    @Setter(AccessLevel.NONE)
    private static final long serialVersionUID = 3843044389018289214L;

    String name;

    // int默认值0
    int num;

    String id;

}

类名可以不相同,看个人习惯,个人觉得类名区分开还是比较好的,避免后续开发引包引错

import lombok.AccessLevel;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
// 该注解是lombok插件,自动生成getset方法,可以忽略
@Data
public class UserB implements Serializable {
    @Getter(AccessLevel.NONE)
    @Setter(AccessLevel.NONE)
    private static final long serialVersionUID = 3843044389018289214L;

    String name;

    // int默认值0
    int num;

    String id;

}

工具类中核心思路是采用反射的getFileds去搜索字段是否有有赋值,之后采用getMethod去获取getset方法,最后利用set方法执行invoke 往实例中注入值,大体处理思路是这样,有兴趣的可以查阅相应反射资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值