如何从Hibernate实体类深拷贝内部对象到DTO?
解决BeanUtils.copyProperties()无法复制嵌套对象的问题
你遇到的这个情况太常见了!默认的BeanUtils.copyProperties()(不管是Spring还是Apache Commons的版本)只会自动复制属性类型完全一致的字段,像address和profile这种嵌套对象,因为AddressEntity和AddressDTO、ProfileEntity和ProfileDTO是不同的类,所以默认不会帮你转换复制。
下面给你两种可行的解决办法:
方法一:手动处理嵌套属性
最简单的方式就是先复制基础属性,再单独对嵌套对象进行转换复制,代码示例如下:
// 先复制基础属性 BeanUtils.copyProperties(studentEntity, studentDTO); // 手动处理address的转换复制 AddressDTO addressDTO = new AddressDTO(); BeanUtils.copyProperties(studentEntity.getAddress(), addressDTO); studentDTO.setAddress(addressDTO); // 手动处理profile的转换复制 ProfileDTO profileDTO = new ProfileDTO(); BeanUtils.copyProperties(studentEntity.getProfile(), profileDTO); studentDTO.setProfile(profileDTO);
这种方式适合嵌套层级少、字段不多的场景,缺点是如果嵌套对象多了,代码会显得很繁琐。
方法二:编写自定义递归复制工具类
如果你的项目里有很多这种嵌套对象转换的需求,最好写一个通用的工具类,递归处理所有嵌套属性的转换。下面是一个简单的实现示例:
import org.springframework.beans.BeanUtils; import java.lang.reflect.Field; import java.util.Objects; public class CustomBeanCopier { public static <T> T copyProperties(Object source, Class<T> targetClass) throws IllegalAccessException, InstantiationException { if (source == null) { return null; } // 创建目标对象实例 T target = targetClass.newInstance(); // 复制基础属性 BeanUtils.copyProperties(source, target); // 获取源对象的所有字段 Field[] sourceFields = source.getClass().getDeclaredFields(); for (Field sourceField : sourceFields) { sourceField.setAccessible(true); Object sourceValue = sourceField.get(source); if (sourceValue == null) { continue; } // 获取目标对象对应的字段 try { Field targetField = targetClass.getDeclaredField(sourceField.getName()); targetField.setAccessible(true); Class<?> targetFieldType = targetField.getType(); // 判断源字段类型和目标字段类型是否为不同的实体/DTO类型(这里简单判断是否是自定义类,你可以根据实际情况调整) if (!sourceField.getType().equals(targetFieldType) && !isBasicType(sourceField.getType())) { // 递归复制嵌套对象 Object nestedTarget = copyProperties(sourceValue, targetFieldType); targetField.set(target, nestedTarget); } } catch (NoSuchFieldException e) { // 如果目标类没有对应的字段,跳过 continue; } } return target; } // 判断是否是基本类型或包装类、String等常用基础类型 private static boolean isBasicType(Class<?> clazz) { return clazz.isPrimitive() || clazz.equals(String.class) || clazz.equals(Integer.class) || clazz.equals(Long.class) || clazz.equals(Double.class) || clazz.equals(Float.class) || clazz.equals(Boolean.class) || clazz.equals(Byte.class) || clazz.equals(Short.class); } }
使用这个工具类的方式也很简单:
StudentDTO studentDTO = CustomBeanCopier.copyProperties(studentEntity, StudentDTO.class);
这个工具类会自动递归处理所有嵌套的自定义对象,帮你完成Entity到DTO的转换。
另外,如果你不想自己写工具类,也可以考虑用一些成熟的对象映射框架,比如MapStruct,它可以通过注解自动生成转换代码,性能比BeanUtils更好,不过需要额外引入依赖和配置。
内容的提问来源于stack exchange,提问作者Shakthi
相关产品推荐
相关产品推荐

