Is there any way to configure Struts to bind null instead of empty String?
Asked Answered
E

8

5

When user decides to leave the field in the form empty the Apache Struts binds empty String as value for properties in the ActionForm. Is there any way to modify the behavior globally and opt for null instead of empty String?

I know that Spring MVC does exactly the same, but there is also StringTrimmerEditor that can be registered as property editor to trim strings to null.

Emigration answered 1/6, 2011 at 11:31 Comment(5)
By definition (html form submit), unless the attribute of the form isn't submitted, an empty string is sent. If the attribute doesn't exist in as a request parameter, a null is populated. I don't think that's what you want to know, but it's a 5 cent info. :)Briticism
This is fair comment. And I reckon this make sense. But can I configure Struts to trim/strip the empty fields to null?Emigration
I don't think such configuration exists.Briticism
:| That's not great news I'm afraid. Is there any way to actually customize binding behavior in Struts?Emigration
See JAB's answer for Struts 1. Or upgrade to Struts 2 and use a Parameter Interceptor.Flatiron
B
4

A possible solution - one that will allow a single conversion entry point for all your String fields - would be to register a custom convertor, but not with Struts but with BeanUtils.

For mapping request parameters to form properties, Struts makes use of the populate method of its RequestUtils class. This class in turn uses a BeanUtils implementation do do its work.

A simplistic flow would be something of the likes of Struts' RequestUtils > BeanUtils > BeanUtilsBean > ConvertUtils > ConvertUtilsBean > Converter.

The interesting thing is that there is also a StringConverter which converts from String to... aaaaaa... String!

The ConvertUtils class has a register method which you can use to register convertors, overwriting the existing ones. This means you could write yourself the custom String convertor which returns null for empty strings and then you could wait for your Struts application to load completely so that you have no surprises (i.e. make sure your converter is the last registered for type String).

After the application loads, you step in and overwrite the default String convertor with your own implementation. For example, you could do that using a ServletContextListener and call the ConvertUtils.register(...) in the contextInitialized method.

You then configure the listener in web.xml and you should be good to go.

Bemoan answered 1/6, 2011 at 20:39 Comment(3)
I like that one, looks like the type of the solution I've been looking for. I don't mind implementing one, two or three classes as long as the solution works for all the form beans. I'll give it a try and let you know here.Emigration
@Tomasz Blachowicz: I added some details to my answer on how you might register your converter. See if it helps!Bemoan
This is nice but might affect many other things...a Struts parameter interceptor is safer.Flatiron
M
1

I think you might as well use your own implementation of the BeanUtils, overriding the class org.apache.commons.beanutils.converters.AbstractConverter and org.apache.commons.beanutils.converters.StringConverter

Magna answered 16/12, 2011 at 19:40 Comment(0)
R
1

In web.xml use below code

<init-param>
      <param-name>convertNull</param-name>
      <param-value>true</param-value>
</init-param>
Raynell answered 28/12, 2012 at 5:26 Comment(0)
P
0

Declare String value by default in ActionForm as NULL .
Eg: private String str = null;

EDIT : solution for this is . I think for that attribute you have setter and getter methods, in getter method check if the value is empty, then you explisitly set for null value.

Perth answered 1/6, 2011 at 11:39 Comment(2)
Not really a solution. What I have in my form is private String str; which is the same as private String str = null;. Struts assigns the "" to str if the field str is left empty in form.Emigration
It is one of the solutions I can also think of. The real issue is that I have lots of forms in quite large application and what's even worst some of the forms use other external POJO beans (Hibernate/JPA) that I can't image I had to modify by hand.Emigration
B
0

See Apache's StringUtils.stripToNull() method.

As for a configuration, Struts has not given us that functionality (I don't recall). I would have suggested overriding reset() method from the ActionForm but that is called before the controller repopulates the form bean.

Briticism answered 1/6, 2011 at 11:41 Comment(1)
I know this one already. But my questions is about global setting I could use intead of writing trimming code for each String property of the action forms.Emigration
L
0

Cf http://struts.apache.org/development/1.x/userGuide/configuration.html for convertNull ;-)

convertNull - Force simulation of the version 1.0 behavior when populating forms. If set to "true", the numeric Java wrapper class types (like java.lang.Integer ) will default to null (rather than 0). (Since version 1.1) [false]

Lodge answered 12/3, 2013 at 14:53 Comment(0)
J
0

It's a little old question, but I resolved this issue by implementing another solution (I think in an easier way).

I implement a TypeConverter to convert empty string to null. Two files is necessary :

The converter.

public class StringEmptyToNullConverter implements TypeConverter {

    private static final Logger log = LoggerFactory.getLogger(StringEmptyToNullConverter.class);

    @Override
    public Object convertValue(Map arg0, Object arg1, Member member, String arg3, Object obj, Class arg5) {
        String[] value = (String[]) obj;
        if (value == null || value[0] == null || value[0].isEmpty()) {
            logDebug("is null or empty: return null");
            return null;
        }
        logDebug("not null and not empty: return '{}'", value[0]);
        return value[0];
    }

    private void logDebug(String msg, Object... obj) {
        if (log.isDebugEnabled()) {
            log.debug(msg, obj);
        }
    }
}

And the register, named xwork-conversion.properties. You have to put this file in your java path.

# syntax: <type> = <converterClassName>
java.lang.String = StringEmptyToNullConverter

see the struts converter documentation

Jug answered 20/11, 2013 at 15:59 Comment(1)
Question is about S1.Barbour
F
0

Struts 2 offers a good mechanism for this with interceptors, which I think is much safer and easier than mucking around with BeanUtils. Here is the code I used, based on Cimballi's Blog but edited to compile in Java 7 (the original was from 2009):

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;

public class RemoveEmptyParametersInterceptor implements Interceptor {

public RemoveEmptyParametersInterceptor() {
    super();
}

/**
 * @see com.opensymphony.xwork2.interceptor.Interceptor#destroy()
 */
public void destroy() {
    // Nothing to do.
}

/**
 * @see com.opensymphony.xwork2.interceptor.Interceptor#init()
 */
public void init() {
    // Nothing to do.
}


public String intercept(final ActionInvocation invocation) throws Exception   {
   final String result;

    final ActionContext actionContext = invocation.getInvocationContext();
    final Map<String, Object> parameters = actionContext.getParameters();

    if (parameters == null) {
        // Nothing to do.
    } else {
        final Collection<String> parametersToRemove = new ArrayList<String>();

        for (final Map.Entry entry : parameters.entrySet()) {
            final Object object = entry.getValue();
            if (object instanceof String) {
                final String value = (String) object;

                if (StringUtils.isEmpty(value)) {
                    parametersToRemove.add((String) entry.getKey());
                }
            } else if (object instanceof String[]) {
                final String[] values = (String[]) object;

                final Object[] objects =
                    ArrayUtils.removeElement(values, "");

                if (objects.length == 0) {
                    parametersToRemove.add((String) entry.getKey());
                }
            } else {
                throw new IllegalArgumentException();
            }
        }

        for (final String parameterToRemove : parametersToRemove) {
            parameters.remove(parameterToRemove);
        }
    }

    result = invocation.invoke();

    return result;
  }
}

And here is how I use it in my struts.xml file:

<package name="webdefault" namespace="/" extends="struts-default">
      <interceptors>
        <interceptor name="removeEmptyParameters" class="com.sentrylink.web.struts.RemoveEmptyParametersInterceptor"/>
        <interceptor-stack name="webStack">
            <interceptor-ref name="removeEmptyParameters"/>
            <interceptor-ref name="defaultStack"/>
        </interceptor-stack>
      </interceptors>

     <default-interceptor-ref name="webStack"/>
     ...
</package>

It was pointed out to me that ActionForm in the original question is a Struts 1 convention (the question has since been correctly tagged) but since Google still brings one here with a Struts 2 query I hope this answer will be useful to someone else.

Flatiron answered 1/5, 2015 at 20:16 Comment(4)
Question is about S1.Barbour
The person who asked the question did not specify that. And this question is the first Google result for this question re Struts 2.Flatiron
ActionForm is from S1.Barbour
Well in that case there is a simple answer, given by JAB that no one has upvoted. But Struts 2 has been out since 2007...Flatiron

© 2022 - 2024 — McMap. All rights reserved.