【问题标题】:Spring - set a property only if the value is not nullSpring - 仅当值不为空时才设置属性
【发布时间】:2012-03-10 00:20:46
【问题描述】:

在使用Spring时,是否可以只在传递的值不为null的情况下设置属性?

例子:

<bean name="myBean" class="some.Type">
   <property name="abc" value="${some.param}"/>
</bean>

我正在寻找的行为是:

some.Type myBean = new some.Type();
if (${some.param} != null) myBean.setAbc(${some.param});

我需要这个的原因是因为abc 有一个我不想用null 覆盖的默认值。 而且我正在创建的 Bean 不在我的源代码控制之下——所以我无法改变它的行为。 (另外,为此目的,abc 可能是一个原语,所以无论如何我都不能将它设置为 null。

编辑:
根据答案,我认为我的问题需要澄清。

我有 bean 我需要实例化并传递给我使用的第 3 方。这个 bean 有许多不同类型的属性(目前有 12 个)(intbooleanString 等)
每个属性都有一个默认值——我不知道它是什么,除非它成为一个问题,否则我宁愿不需要知道。 我正在寻找的是来自 Spring 能力的通用解决方案 - 目前我唯一的解决方案是基于反射的。

配置

<bean id="myBean" class="some.TypeWrapper">
   <property name="properties">
     <map>
         <entry key="abc" value="${some.value}"/>
         <entry key="xyz" value="${some.other.value}"/>
         ...
      </map>
   </property>
</bean>

代码

public class TypeWrapper
{
    private Type innerBean;

    public TypeWrapper()
    {
        this.innerBean = new Type();
    }

    public void setProperties(Map<String,String> properties)
    {
        if (properties != null)
        {
            for (Entry<String, Object> entry : properties.entrySet())
            {
                String propertyName = entry.getKey();
                Object propertyValue = entry.getValue();

                setValue(propertyName, propertyValue);
            }
        }
    }

    private void setValue(String propertyName, Object propertyValue)
    {
        if (propertyValue != null)
        {
           Method method = getSetter(propertyName);
           Object value = convertToValue(propertyValue, method.getParameterTypes()[0]);
           method.invoke(innerBean, value);
        }
    }

    private Method getSetter(String propertyName)
    {
      // Assume a valid bean, add a "set" at the beginning and toUpper the 1st character.
      // Scan the list of methods for a method with the same name, assume it is a "valid setter" (i.e. single argument)
      ... 
    }

    private Object convertToValue(String valueAsString, Class type)
    {
        // Check the type for all supported types and convert accordingly
        if (type.equals(Integer.TYPE))
        {
          ...
        }
        else if (type.equals(Integer.TYPE))
        {
          ...
        }
        ...
    }
}

真正的“困难”在于为所有可能的值类型实现convertToValue。 我一生中已经不止一次这样做了——所以为我需要的所有可能的类型(主要是原语和一些枚举)实现它并不是一个主要问题——但我希望存在一个更智能的解决方案。

【问题讨论】:

    标签: java spring javabeans


    【解决方案1】:

    您可以将SpEL 与占位符和默认值一起用于占位符机制,如下所示:

    <bean name="myBean" class="some.Type">
        <property name="abc" value="${some.param:#{null}}"/>
    </bean>
    

    【讨论】:

    • 你已经回答过一次这个问题了 :) (也有点不同)
    • 哦,是的,但更新的答案更简单:)
    • 这是迄今为止所有答案中最好的解决方案,谢谢1
    • 我在尝试这个时遇到错误 -- After parsing a valid expression, there is still more data in the expression: 'colon(:)'
    • 出于某种原因,我总是得到null 值,而不管这些值是否存在于属性文件中。
    【解决方案2】:

    为了解决您的问题,您必须使用 SEL(Spring 表达式语言)。 通过此功能(在 SPring 3.0 中添加)您可以使用其他动态语言编写您的条件。对于您的上下文,答案是:

    <bean name="myBean" class="some.Type">
       <property name="abc" value="#(if(${some.param} != null) ${some.param})"/>
    </bean>
    

    有关更多信息,请参阅(本教程说明在上下文文件中使用 SEL 的内容): http://static.springsource.org/spring/docs/3.0.5.RELEASE/reference/expressions.html

    【讨论】:

    • 如果参数为空,它不会仍然传递一个空字符串吗? OP 不想传递任何东西:他想避免调用 setter。
    • #{ ${some.param} != #null ? ${some.param} : #null } 似乎更正确
    【解决方案3】:

    您可以在 Spring 框架的属性配置器中使用默认值概念,如下所示:

    <bean name="myBean" class="some.Type">
       <property name="abc" value="${some.param : your-default-value}"/>
    </bean>
    

    您可以通过这种方法设置默认值。通过此上下文配置,如果some.param 键存在,则其值设置在abc 属性中,如果不存在your-default-value,则设置在abc 属性中。

    注意:这种方法的另一个好处是:“在 POJO 编程模型中更好的方法是类的成员没有任何默认值,并且默认值是从类外注入的。”

    【讨论】:

    • 感谢您的提示-这在将来可能会有所帮助,但就我而言,我无法使用它-正如我所说,此 bean 不在我的源代码控制中-所以我没有知道它的默认值是什么(并且不想知道)。我希望得到以下内容:&lt;property name="abc" cond="${some.param}!=null" value="${some.param}"&gt;
    【解决方案4】:

    您可以创建一个实用程序类,它将充当some.Type 的工厂类,并在其中包装逻辑

    例如:

    public class TypeFactory {
        public static Type craeteType(SomeType param){
            Type t = new Type();
            if(param!=null)
                t.setParam(param);
        }
    }
    

    并在 XML 上使用此工厂方法配置 bean 创建

    <bean id="myBean" class="some.Type"
          factory-method="craeteType">
        <constructor-arg ref="param"/>  
    </bean>
    

    【讨论】:

      【解决方案5】:

      这看起来像是Java-based container configuration 的工作。您将能够执行您在 XML 配置中执行的操作,但使用 Java 的所有功能。

      【讨论】:

        【解决方案6】:

        我已经让它与以下 sn-p 一起工作:

        <bean name="myBean" class="some.Type">
            <property name="abc" value="#{'${some.param}'=='' ? null : '${some.param}'}" />
        </bean>
        

        【讨论】:

        • @Ronk - 你找到解决方案了吗?我需要这样做,但我找不到解决方案。
        • @dharag - 我最终实现了我自己的基于反射的解决方案,使用 FactoryBean 创建我想要的对象。我发现没有内置解决方案。
        猜你喜欢
        • 2016-02-29
        • 2016-08-29
        • 1970-01-01
        • 2018-01-15
        • 2021-02-25
        • 1970-01-01
        • 2013-12-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多