恕我直言,最好的解决方案是摆脱 commons-beanutils 并使用 Spring Framework org.springframework.beans.PropertyAccessorFactory
BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(targetObject);
wrapper.setAutoGrowNestedPaths(true);
我不会深入研究它的工作原理,但如果你想查看它,请查看上面的链接,这个 API 非常直观,但你需要在你的classpath,所以我不建议你仅仅为了这个特性而添加 spring。
然而,
如果您只有commons-beanutils作为您的盟友,那么以下代码片段可能会帮助您在设置值时增加嵌套路径,因此,您无需关注路径属性中的空对象。
在此示例中,我使用 JPA Tuple Query 构造了一个自定义对象,该对象具有一些特定的属性路径以及要设置的相应值。
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Tuple;
import javax.persistence.TupleElement;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.beanutils.expression.DefaultResolver;
public class TupleToObject<T> {
public List<T> transformResult(List<Tuple> result, Class<T> targetClass) {
try {
List<T> objects = new ArrayList<>();
for (Tuple tuple : result) {
T target = targetClass.newInstance();
List<TupleElement<?>> elements = tuple.getElements();
for (TupleElement<?> tupleElement : elements) {
String alias = tupleElement.getAlias();
Object value = tuple.get(alias);
if (value != null) {
instantiateObject(target, alias);
PropertyUtils.setNestedProperty(target, alias, value);
}
}
objects.add(target);
}
return objects;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void instantiateObject(T target, String propertyPath) throws Exception {
DefaultResolver resolver = new DefaultResolver();
Object currentTarget = target;
while (resolver.hasNested(propertyPath)) {
final String property = resolver.next(propertyPath);
Object value = PropertyUtils.getSimpleProperty(currentTarget, property);
if (value == null) {
Class<?> propertyType = PropertyUtils.getPropertyType(currentTarget, property);
value = propertyType.newInstance();
PropertyUtils.setSimpleProperty(currentTarget, property, value);
}
currentTarget = value;
propertyPath = resolver.remove(propertyPath);
}
}
}
此代码使用 commons-beanutils-1.9.3.jar