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 StringTrim开发者_如何学PythonmerEditor that can be registered as property editor to trim strings to null
.
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.
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
In web.xml use below code
<init-param>
<param-name>convertNull</param-name>
<param-value>true</param-value>
</init-param>
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.
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.
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]
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
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.
精彩评论