28

When using Spring, is it possible to set a property only if the value passed is not null?

Example:

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

The behavior I'm looking for is:

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

The reason I need this is since abc has a default value which I don't want to override with a null. And the Bean I am creating is not under my source control - so I cannot change its behavior. (Also, abc for this purpose might be a primitive, so I can't set it with a null anyway.

EDIT:
According to the answers I think my question requires clarification.

I have bean I need to instantiate and pass to 3rd party I use. This bean has many properties (12 currently) of various types (int, boolean, String, etc.)
Each property has a default value - I don't know what it is and would prefer not needing to know unless it becomes an issue. What I'm looking for is a generic solution that comes from Spring's abilities - currently the only solution I have is a reflection based.

Configuration

<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>

Code

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))
        {
          ...
        }
        ...
    }
}

The real "difficulty" is in implementing convertToValue for all possible value types. I have done this more than once in my life - so it is not a major issue to implement it for all possible types that I need (mostly primitives and a few enums) - but I hoped a more intelligent solution existed.

RonK
  • 9,472
  • 8
  • 51
  • 87

6 Answers6

41

You can use SpEL and placeholder and default value for placeholder mechanisms together as following:

<bean name="myBean" class="some.Type">
    <property name="abc" value="${some.param:#{null}}"/>
</bean>
ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
Sam
  • 6,770
  • 7
  • 50
  • 91
5

For solve your problem, you have to use SEL(Spring Expression Language). By this feature (added in SPring 3.0) you can such as other dynamic language writing your condition. For your context, answer is:

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

for more information see(this tutorial says what use SEL in context file): http://static.springsource.org/spring/docs/3.0.5.RELEASE/reference/expressions.html

Sam
  • 6,770
  • 7
  • 50
  • 91
  • 6
    Wouldn't it still pass an empty string if the param is null? The OP doesn't want to pass anything: he wants to avoid calling the setter. – JB Nizet Feb 19 '12 at 10:34
  • `#{ ${some.param} != #null ? ${some.param} : #null }` seems to be more correct – Vadzim Nov 22 '13 at 13:23
3

You can use default value concept in property configurer in Spring framework as following:

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

you can set default value by this approach. By this context config if some.param key exist so its value set in abc property and if don't exist your-default-value set in abc property.

Note: Another benefit of this approah is:"In POJO programming model better approzh is member of class don't have any default value,and default value injected from out of class."

Sam
  • 6,770
  • 7
  • 50
  • 91
  • Thanks for the tip - this can be helpful in the future, but in my case I can't use it - as I said, this bean is not in my source control - so I don't know what its default is (and don't want to know). I was hoping for something the lines of: `` – RonK Feb 19 '12 at 09:37
1

You can create a Utility class that will act as a Factory class for some.Type, and wrap the logic there

For Example :

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

and on XML configure the bean creation using this Factory method

<bean id="myBean" class="some.Type"
      factory-method="craeteType">
    <constructor-arg ref="param"/>  
</bean>
ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
jmj
  • 237,923
  • 42
  • 401
  • 438
0

I've got it working with following snippet:

<bean name="myBean" class="some.Type">
    <property name="abc" value="#{'${some.param}'=='' ? null : '${some.param}'}" />
</bean>
volkovs
  • 1,153
  • 2
  • 11
  • 24
  • @Ronk - did you find a solutions to do this? I need to do exactly this and I cant find a solution. – dharag Nov 21 '13 at 16:01
  • @dharag - I eventually implemented a reflection based solution of my own using a FactoryBean to create the objects I wanted. I found no built in solution. – RonK Nov 21 '13 at 16:19
0

This looks like a job for Java-based container configuration. You'll be able to do what you do in your XML config, but with all the power of Java.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255