【问题标题】:How to ignore null values using springframework BeanUtils copyProperties?如何使用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 以这种方式工作。

标签: java spring copy notnull


【解决方案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>
    
    1. 创建一个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
      }
      
    2. 创建主类进行测试

      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% 相似:stackoverflow.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();
      }
      

      其他答案将在这种特殊情况下引发异常。

      【讨论】:

        猜你喜欢
        • 2013-06-29
        • 2011-02-05
        • 2013-10-19
        • 1970-01-01
        • 2020-06-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-03-27
        相关资源
        最近更新 更多