如何使用springframework BeanUtils copyProperties忽略空值?
Posted
技术标签:
【中文标题】如何使用springframework BeanUtils copyProperties忽略空值?【英文标题】:How to ignore null values using springframework BeanUtils copyProperties? 【发布时间】:2013-11-13 07:05:00 【问题描述】:我想知道如何使用 Spring Framework 将属性从 Object Source 复制到 Object Dest 并忽略空值。
我实际上是用 Apache beanutils 和这段代码
beanUtils.setExcludeNulls(true);
beanUtils.copyProperties(dest, source);
去做。但现在我需要使用 Spring。
有什么帮助吗?
非常感谢
【问题讨论】:
你不能把 BeanUtils 作为你的 Spring 项目类路径的一部分吗?我不认为 Spring 的 BeanUtils 以这种方式工作。 【参考方案1】:您可以创建自己的方法来复制属性,同时忽略空值。
public static String[] getNullPropertyNames (Object source)
final BeanWrapper src = new BeanWrapperImpl(source);
java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();
Set<String> emptyNames = new HashSet<String>();
for(java.beans.PropertyDescriptor pd : pds)
Object srcValue = src.getPropertyValue(pd.getName());
if (srcValue == null) emptyNames.add(pd.getName());
String[] result = new String[emptyNames.size()];
return emptyNames.toArray(result);
// then use Spring BeanUtils to copy and ignore null using our function
public static void myCopyProperties(Object src, Object target)
BeanUtils.copyProperties(src, target, getNullPropertyNames(src));
【讨论】:
这是一个非常好的解决方案。我希望框架已经安排了一种方法来解决这个问题,但这会完美地工作。谢谢 我也是这样做的。我将这些方法包含在一个带有其他一些自定义实现的新类中。我的新类扩展了 BeanUtils 类,以便我可以添加其他特性和功能。 myCopyProps 方法的 call sig 中有错字... Object 后面多了一个逗号【参考方案2】:来自 alfredx 的 post 的 Java 8 版本的 getNullPropertyNames 方法:
public static String[] getNullPropertyNames(Object source)
final BeanWrapper wrappedSource = new BeanWrapperImpl(source);
return Stream.of(wrappedSource.getPropertyDescriptors())
.map(FeatureDescriptor::getName)
.filter(propertyName -> wrappedSource.getPropertyValue(propertyName) == null)
.toArray(String[]::new);
【讨论】:
【参考方案3】:SpringBeans.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="source" class="com.core.HelloWorld">
<property name="name" value="Source" />
<property name="gender" value="Male" />
</bean>
<bean id="target" class="com.core.HelloWorld">
<property name="name" value="Target" />
</bean>
</beans>
创建一个java Bean,
public class HelloWorld
private String name;
private String gender;
public void printHello()
System.out.println("Spring 3 : Hello ! " + name + " -> gender -> " + gender);
//Getters and Setters
创建主类进行测试
public class App
public static void main(String[] args)
ApplicationContext context = new ClassPathXmlApplicationContext("SpringBeans.xml");
HelloWorld source = (HelloWorld) context.getBean("source");
HelloWorld target = (HelloWorld) context.getBean("target");
String[] nullPropertyNames = getNullPropertyNames(target);
BeanUtils.copyProperties(target,source,nullPropertyNames);
source.printHello();
public static String[] getNullPropertyNames(Object source)
final BeanWrapper wrappedSource = new BeanWrapperImpl(source);
return Stream.of(wrappedSource.getPropertyDescriptors())
.map(FeatureDescriptor::getName)
.filter(propertyName -> wrappedSource.getPropertyValue(propertyName) == null)
.toArray(String[]::new);
【讨论】:
【参考方案4】:我建议你使用 ModelMapper。
这是一个解决你疑惑的示例代码。
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration().setSkipNullEnabled(true).setMatchingStrategy(MatchingStrategies.STRICT);
Company a = new Company();
a.setId(123l);
Company b = new Company();
b.setId(456l);
b.setName("ABC");
modelMapper.map(a, b);
System.out.println("->" + b.getName());
它应该打印 B 值。但是如果你设置了“A”这个名字,结果就是一个“A”值的打印。
秘诀是将 SkipNullEnabled 的值更改为 true。
ModelMapper
ModelMapper MVN
【讨论】:
它不起作用,我试过了。如果发现它会替换值,否则它会创建新值。【参考方案5】:public static List<String> getNullProperties(Object source)
final BeanWrapper wrappedSource = new BeanWrapperImpl(source);
return Stream.of(wrappedSource.getPropertyDescriptors())
.map(FeatureDescriptor::getName)
.filter(propertyName -> Objects.isNull(wrappedSource.getPropertyValue(propertyName)))
.collect(Collectors.toList());
【讨论】:
最好在您的答案中添加某种形式的解释;这将提高其质量并使其更有可能获得支持:) ...特别是因为它与上面发布的答案(4 年前)有 99% 相似:***.com/a/32066155【参考方案6】:基于 Pawel Kaczorowski 的回答的更好解决方案:
public static String[] getNullPropertyNames(Object source)
final BeanWrapper wrappedSource = new BeanWrapperImpl(source);
return Stream.of(wrappedSource.getPropertyDescriptors())
.map(FeatureDescriptor::getName)
.filter(propertyName ->
try
return wrappedSource.getPropertyValue(propertyName) == null
catch (Exception e)
return false
)
.toArray(String[]::new);
例如,如果我们有一个 DTO:
class FooDTO
private String a;
public String getA() ... ;
public String getB();
其他答案将在这种特殊情况下引发异常。
【讨论】:
以上是关于如何使用springframework BeanUtils copyProperties忽略空值?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 org.springframework.jdbc.object 实现可重用的 ddl 语句?
如何解决 org.springframework.web.util.NestedServletException:请求处理失败;使用 SAML
如何在 org.springframework.jdbc.CannotGetJdbcConnectionException 上记录 JDBC 连接信息
干掉 BeanUtils!试试这款 Bean 自动映射工具,真心强大!
如何在 Grails 3 中捕获“org.springframework.web.multipart.MultipartException”