自实现JavaBean 属性复制,对象转为Map等功能
1. 对象转为Map
@see toMap方法
2. 对象之间属性复制
@see transfer方法
3. 代码实现
依赖
bean
的setter
和getter
方法,将bean对象转为BeanInfo
对象,通过反射获取getter和setter方法对属性赋值
/**
* 无参构造器之间的类型转换
* 属性之间浅copy
* <p>
* Created by wangzhixiang on 2020/6/16.
*/
@UtilityClass
public class BeanUtil {
// 将before转为after,支持自定义setter操作
public static <Before, After> After transfer(Before before, Class<After> afterClass, Processor<Before, After> processor) {
try {
After after = transfer(before, afterClass);
processor.accept(before, after);
return after;
} catch (Exception e) {
throw new Error(e);
}
}
// 根据bean的getter方法将bean转为map
public static Map<String, Object> toMap(Object bean) {
if (bean == null) return null;
try {
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass(), Object.class);
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
Map<String, Object> map = new HashMap<>();
for (PropertyDescriptor descriptor : propertyDescriptors) {
Object propertyValue = descriptor.getReadMethod().invoke(bean);
map.put(descriptor.getName(), propertyValue);
}
return map;
} catch (Exception e) {
throw new Error(e);
}
}
// 将Before中的字段复制到after中,注:需要setter和getter方法
public static <Before, After> void copyProperty(Before before, After after) throws IntrospectionException {
PropertyDescriptor[] beforePropertyDescriptors = getPropertyDescriptor(before);
PropertyDescriptor[] afterPropertyDescriptors = getPropertyDescriptor(after);
try {
for (PropertyDescriptor descriptor : afterPropertyDescriptors) {
for (PropertyDescriptor beforePropertyDescriptor : beforePropertyDescriptors) {
Object value = beforePropertyDescriptor.getReadMethod().invoke(before);
descriptor.getWriteMethod().invoke(after, value);
}
}
} catch (Exception e) {
throw new Error(e);
}
}
public static <Before, After> After transfer(Before before, Class<After> afterClass) {
try {
After after = afterClass.getDeclaredConstructor().newInstance();
PropertyDescriptor[] beforePropertyDescriptors = getPropertyDescriptor(before);
PropertyDescriptor[] afterPropertyDescriptors = getPropertyDescriptor(after);
for (PropertyDescriptor descriptor : afterPropertyDescriptors) {
for (PropertyDescriptor beforePropertyDescriptor : beforePropertyDescriptors) {
if (beforePropertyDescriptor.getName().equals(descriptor.getName())) {
Object value = beforePropertyDescriptor.getReadMethod().invoke(before);
descriptor.getWriteMethod().invoke(after, value);
break;
}
}
}
return after;
} catch (Exception e) {
throw new Error(e);
}
}
private static PropertyDescriptor[] getPropertyDescriptor(Object bean) {
try {
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass(), Object.class);
return beanInfo.getPropertyDescriptors();
} catch (Exception e) {
throw new Error(e);
}
}
// 支持自定义修改字段
public interface Processor<Before, After> extends BiConsumer<Before, After> {
}
}
4. 测试
/**
* Created by wangzhixiang on 2020/6/15.
*/
class BeanUtilTest extends BaseTest {
def "test_transfer"() {
when:
def after = BeanUtil.transfer(before, afterClass)
def expectedAfterMap = BeanUtil.toMap(expectedAfter)
then:
BeanUtil.toMap(after).forEach(new BiConsumer<String, Object>() {
@Override
void accept(String k, Object v) {
if (expectedAfterMap.containsKey(k)) {
if (k == "metaClass") {
return
}
assert v == expectedAfterMap.get(k)
}
}
})
where:
before | afterClass || expectedAfter
new Before(id: 1, age: 20, name: "test", score: 99.0) | After.class || new After(id: 1, age: 20, name: "test", score: 99.0)
new Before(id: 1, age: 20, score: 99.0) | After.class || new After(id: 1, age: 20, score: 99.0)
}
@Data
static class Before {
long id
int age
String name
double score
}
@Data
static class After {
long id
int age
String name
double score
}
}