不同风格的实体类的转化
场景分析
有时候我们写外包的时候会遇到这么个情况,原系统已经有一套实体类了,但是因为某些原因又生成了一套实体类。那么我们应该怎么实现转化呢?很多聪明的小伙伴肯定一下就想到了BeanUtils.copyProperties(source, target),但是呢,这个方法只能实现属性名相同的转化,如果属性名不同,就会出现null的情况(比如原实体类是下划线风格,新实体类是驼峰风格)。这种情况如果我们想要和BeanUtils.copyProperties()方法一样,那么我们就需要自定义转化方法,再封装为一个工具类。
解决方法
public class BeanCopyUtils {
/**
* 驼峰命名转下划线命名并复制属性
* 例如:basicdataUserId -> basicdata_user_id
*
* @param source 源对象
* @param target 目标对象
*/
public static void copyPropertiesCamelToUnderscore(Object source, Object target) {
if (source == null || target == null) {
return;
}
BeanWrapper sourceBeanWrapper = new BeanWrapperImpl(source);
BeanWrapper targetBeanWrapper = new BeanWrapperImpl(target);
PropertyDescriptor[] sourceProperties = sourceBeanWrapper.getPropertyDescriptors();
for (PropertyDescriptor sourcePd : sourceProperties) {
String sourcePropertyName = sourcePd.getName();
if ("class".equals(sourcePropertyName)) {
continue;
}
// 将驼峰命名转为下划线命名
String targetPropertyName = camelToUnderscore(sourcePropertyName);
try {
// 检查目标对象是否有对应的属性
PropertyDescriptor targetPd = targetBeanWrapper.getPropertyDescriptor(targetPropertyName);
if (targetPd != null && targetPd.getWriteMethod() != null) {
Object value = sourceBeanWrapper.getPropertyValue(sourcePropertyName);
// 处理类型转换,例如 Double 到 Float
if (value != null &&
value instanceof Double &&
targetPd.getPropertyType().equals(Float.class)) {
value = ((Double) value).floatValue();
}
targetBeanWrapper.setPropertyValue(targetPropertyName, value);
}
} catch (Exception e) {
// 属性不存在或无法设置,忽略
}
}
}
/**
* 驼峰命名转下划线命名
* 例如:basicdataUserId -> basicdata_user_id
*/
private static String camelToUnderscore(String camel) {
if (camel == null || camel.isEmpty()) {
return "";
}
StringBuilder sb = new StringBuilder();
boolean prevUpperCase = false;
for (int i = 0; i < camel.length(); i++) {
char c = camel.charAt(i);
// 如果是大写字母
if (Character.isUpperCase(c)) {
// 如果前一个字符不是大写,添加下划线
if (!prevUpperCase && i > 0) {
sb.append('_');
}
// 将大写字母转为小写
sb.append(Character.toLowerCase(c));
prevUpperCase = true;
} else {
sb.append(c);
prevUpperCase = false;
}
}
return sb.toString();
}
/**
* 下划线命名转驼峰命名并复制属性
* 例如:basicdata_quilt_id -> basicdataQuiltId
*
* @param source 源对象
* @param target 目标对象
*/
public static void copyPropertiesUnderscoreToCamel(Object source, Object target) {
if (source == null || target == null) {
return;
}
BeanWrapper sourceBeanWrapper = new BeanWrapperImpl(source);
BeanWrapper targetBeanWrapper = new BeanWrapperImpl(target);
PropertyDescriptor[] sourceProperties = sourceBeanWrapper.getPropertyDescriptors();
for (PropertyDescriptor sourcePd : sourceProperties) {
String sourcePropertyName = sourcePd.getName();
if ("class".equals(sourcePropertyName)) {
continue;
}
// 将下划线命名转为驼峰命名
String targetPropertyName = underscoreToCamel(sourcePropertyName);
try {
// 检查目标对象是否有对应的属性
PropertyDescriptor targetPd = targetBeanWrapper.getPropertyDescriptor(targetPropertyName);
if (targetPd != null && targetPd.getWriteMethod() != null) {
Object value = sourceBeanWrapper.getPropertyValue(sourcePropertyName);
// 处理类型转换,例如 Double 到 Float
if (value != null &&
value instanceof Double &&
targetPd.getPropertyType().equals(Float.class)) {
value = ((Double) value).floatValue();
}
targetBeanWrapper.setPropertyValue(targetPropertyName, value);
}
} catch (Exception e) {
// 属性不存在或无法设置,忽略
}
}
}
/**
* 下划线命名转驼峰命名
* 例如:basicdata_quilt_id -> basicdataQuiltId
*/
private static String underscoreToCamel(String underscore) {
if (underscore == null || underscore.isEmpty()) {
return "";
}
StringBuilder sb = new StringBuilder();
boolean nextUpperCase = false;
for (int i = 0; i < underscore.length(); i++) {
char c = underscore.charAt(i);
if (c == '_') {
nextUpperCase = true;
} else {
if (nextUpperCase) {
sb.append(Character.toUpperCase(c));
nextUpperCase = false;
} else {
sb.append(c);
}
}
}
return sb.toString();
}
/**
* 获取对象中所有为null的属性名
*/
public static String[] getNullPropertyNames(Object source) {
final BeanWrapper src = new BeanWrapperImpl(source);
PropertyDescriptor[] pds = src.getPropertyDescriptors();
Set<String> emptyNames = new HashSet<>();
for (PropertyDescriptor pd : pds) {
Object srcValue = src.getPropertyValue(pd.getName());
if (srcValue == null) {
emptyNames.add(pd.getName());
}
}
return emptyNames.toArray(new String[0]);
}
/**
* 复制属性,忽略null值
*/
public static void copyPropertiesIgnoreNull(Object source, Object target) {
BeanUtils.copyProperties(source, target, getNullPropertyNames(source));
}
}
