No,Hibernate(或JPA)不会直接提供该功能,但使用JavaBeans机制(或许多提供对其进行抽象的库之一)很容易实现。
使用普通JavaBean内省
这是一种方法,如果beanB
中的属性为null,则使用标准的JavaBeans Introspector
机制从beanA
复制所有属性到beanB
:
public static void copyBeanProperties(
final Object beanA, final Object beanB){
if(beanA.getClass() != beanB.getClass()){
throw new IllegalArgumentException();
}
try{
for( final PropertyDescriptor pd :
Introspector
.getBeanInfo(beanB.getClass(), Object.class)
.getPropertyDescriptors()){
if(pd.getReadMethod().invoke(beanB)==null){
pd.getWriteMethod().invoke(beanB,
pd.getReadMethod().invoke(beanA)
);
}
}
} catch(IntrospectionException e){
throw new IllegalStateException(e);
} catch(IllegalAccessException e){
throw new IllegalStateException(e);
} catch(InvocationTargetException e){
throw new IllegalStateException(e);
}
}
当然,这只是一个快速而简单的实现,但它应该能让你开始了解。
使用Apache Commons / BeanUtils
下面是使用
Commons / BeanUtils稍微更加优雅的版本。它会隐藏反射并提供基于映射的属性访问:
public static void copyBeanProperties(final Object beanA, final Object beanB){
try{
@SuppressWarnings("unchecked")
final Map<String, Object> beanAProps = PropertyUtils.describe(beanA);
@SuppressWarnings("unchecked")
final Map<String, Object> beanBProps = PropertyUtils.describe(beanB);
if(!beanAProps.keySet().containsAll(beanBProps.keySet())){
throw new IllegalArgumentException("Incompatible types: "
+ beanA + ", " + beanB);
}
for(final Entry<String, Object> entryA : beanAProps.entrySet()){
if(beanBProps.get(entryA.getKey()) == null){
PropertyUtils.setMappedProperty(beanB, entryA.getKey(),
entryA.getValue());
}
}
} catch(final IllegalAccessException e){
throw new IllegalStateException(e);
} catch(final InvocationTargetException e){
throw new IllegalStateException(e);
} catch(final NoSuchMethodException e){
throw new IllegalStateException(e);
}
}
使用Spring的BeanWrapper
这里还有另一种使用Spring的BeanWrapper
接口的版本(它是最简洁的,因为Spring提供了一个在反射之上的抽象,并且进行自己的异常处理),但不幸的是BeanWrapper
技术仅与Spring IOC容器一起提供(当然,如果您不使用容器,这只是不幸):
public static void copyBeanProperties(final Object beanA, final Object beanB){
final BeanWrapper wrapperA = new BeanWrapperImpl(beanA);
final BeanWrapper wrapperB = new BeanWrapperImpl(beanB);
try{
for(final PropertyDescriptor descriptor : wrapperB
.getPropertyDescriptors()){
final String propertyName = descriptor.getName();
if(wrapperB.getPropertyValue(propertyName) == null){
wrapperB.setPropertyValue(propertyName,
wrapperA.getPropertyValue(propertyName));
}
}
} catch(final InvalidPropertyException e){
throw new IllegalArgumentException("Incompatible types: " + beanA
+ ", " + beanB, e);
}
}