How to prevent parameter binding from interpreting commas in Spring 3.0.5?
I've tested your code: it's unbelievable, but I can't reproduce your issue. I've downloaded the latest version of spring (3.0.5), this is my controller:
package test;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping("/test/**")
public class MyController {
private static final Logger logger = Logger.getLogger(MyController.class);
@RequestMapping(value = "/test/params", method = RequestMethod.GET)
public void test(SearchRequestParams requestParams, BindingResult result) {
logger.debug("fq = " + StringUtils.join(requestParams.getFq(), "|"));
}
}
this is my SearchRequestParams class:
package test;
public class SearchRequestParams {
private String[] fq;
public String[] getFq() {
return fq;
}
public void setFq(String[] fq) {
this.fq = fq;
}
}
and this is my simple spring configuration:
<bean id="urlMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean class="test.MyController" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/jsp/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
I've tested my code within tomcat 7.0.8; when I type http://localhost:8080/testweb/test/params.htm?fq=foo,bar
I'm able to read in my log file this line: DEBUG fq = foo,bar
.
What are the the differences from my code to yours? Am I doing something wrong?
I'd like to help you, so if you have any doubts or if I can do some other tests for you, it will be a pleasure.
UPDATE / SOLUTION
With your code I've reproduced the issue; you have the tag <mvc:annotation-driven />
in your dispatcher servlet configuration, so you silently use a default conversion service, instance of FormattingConversionService
, which contains a default converter from String
to String[]
that uses comma as separator.
You have to use a different conversion service bean containing your own converter from String
to String[]
. You should use a different separator, I've choosed to use ";" because it's the separator commonly used into query string ("?first=1;second=2;third=3"):
import org.springframework.core.convert.converter.Converter;
import org.springframework.util.StringUtils;
public class CustomStringToArrayConverter implements Converter<String, String[]>{
@Override
public String[] convert(String source) {
return StringUtils.delimitedListToStringArray(source, ";");
}
}
Then you have to specify this conversion service bean in your configuration:
<mvc:annotation-driven conversion-service="conversionService" />
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="au.org.ala.testspringbinding.CustomStringToArrayConverter" />
</list>
</property>
</bean>
The issue has fixed, now you should check for any side effects. I hope you don't need in your application the original conversion from String
to String[]
(with comma as separator). ;-)
How to prevent Spring MVC from interpreting commas when converting to a Collection in Spring Boot?
You can remove the StringToCollectionConverter and replace it with your own in WebMvcConfigurerAdapter.addFormatters(FormatterRegistry registry) method:
Something like this:
@Configuration
public class MyWebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.removeConvertible(String.class,Collection.class);
registry.addConverter(String.class,Collection.class,myConverter);
}
}
Modify Spring MVC Request to List Parameter Binding to Not Separate on Commas
The conversion seems to happen in:
org.springframework.core.convert.support.StringToCollectionConverter
which must be a defult converter registered by the framework.
You can use an @InitBinder
method in a controller or a Controller Advice to register converters however I am not sure how you override or disable this default converter.
The simplest thing to do then is just to fall back to accessing the param directly from the HttpServletRequest:
@Controller
public class TestController {
@RequestMapping("/test")
public String test(@RequestParam("names") List<String> names, HttpServletRequest request) {
//1
System.out.println(request.getParameterValues("names").length);
System.out.println(Arrays.toString(request.getParameterValues("names")));
//2
System.out.println(names.size());
System.out.println(names);
return null;
}
}
After additional experimentation, you can disable the invocation of the framework's StringToCollectionConverter
in Spring Boot by explicitly removing the conversion from String.class
to Collection.class
from the GenericConversionService
:
@Autowired
void conversionService(GenericConversionService genericConversionService) {
List<String> names = genericConversionService.convert("Ed, Al", List.class);
System.out.println(names.size()); // 2
genericConversionService.removeConvertible(String.class, Collection.class);
names = genericConversionService.convert("Ed, Al", List.class);
System.out.println(names.size()); // 1
}
How to disable spring boot parameter split
I find the solution.
To override a default conversion we must add a new one. If we remove the old one only it doesn't work.
The correct (example) code should be:
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.removeConvertible(String.class, String[].class);
registry.addConverter(String.class, String[].class, noCommaSplitStringToArrayConverter());
}
@Bean
public Converter<String, String[]> noCommaSplitStringToArrayConverter() {
return new Converter<String, String[]>() {
@Override
public String[] convert(String source) {
String[] arrayWithOneElement = {source};
return arrayWithOneElement;
}
};
}
}
This way any controller like the one in the main question will not split parameters values:
- [...]/countphrases?phrase=a,b will return 1 (and fq=["a,b"])
- [...]/countphrases?phrase=a,b&phrase=c,d will return 2 (and fq=["a,b", "c,d"])
Binding multiple select where option values may contain commas in Spring 3
I believe this thread is related to your issue: How to prevent parameter binding from interpreting commas in Spring 3.0.5?. This Spring issue may also be helpful: https://jira.springsource.org/browse/SPR-7963
The solution provided at https://stackoverflow.com/a/5239841/1259928, which details how to create a new conversion service which uses a different string separator and wiring it into Spring config should do the trick.
Encoded Comma in URL is read as List in Spring
You can set your Delimiter
. The comma is just the default one used in org.springframework.boot.convert.DelimitedStringToCollectionConverter
when it isn't set. If you wish, you can disable the Delimiter
completely. For your code, it would look like this:
import org.springframework.boot.convert.Delimiter;
@RequestMapping(value = "/route", method = RequestMethod.GET)
public Object thisIsTheMethod(@Delimiter(Delimiter.None) @RequestParam(value = "value", required = false) List<String> values) {
return OtherClass.doTheThing(values);
}
Spring ModelAttribute correct parsing
I did some investigation and figured out that for first request value=John%2CBill%2CAlex
Spring using org.springframework.format.supportDefaultFormattingConversionService
class which under the hood has org.springframework.core.convert.support.StringToArrayConverter
whose convert()
method split your string by to array using comma as a separator.
You have 2 ways to resolve this issue:
- Use ; instead of , as separator for you value (
value=John;Bill;Alex
) - Use different conversion service bean containing your own converter from String to String[]. For more details look at this answer
How to escape commas in environment-variables mapped to lists in Spring configuration classes
You cannot escape comma for list in spring boot , I'm afraid you will have to think of alternative way to load those environment variables
Related Topics
Scheduledexecutorservice Exception Handling
How to Pass an Integer Class Correctly by Reference
Soap Request to Webservice with Java
Permutation Algorithm Without Recursion? Java
What Does an Integer That Has Zero in Front of It Mean and How to Print It
Preparedstatement Syntax Error
How to View Bytecode of Class File
Check If a Value Exists in Arraylist
Can an Interface Extend Multiple Interfaces in Java
Why Integer.Max_Value + 1 == Integer.Min_Value
How Does the JPA @Sequencegenerator Annotation Work
Xml Element with Attribute and Content Using Jaxb
No Tests Found with Test Runner 'Junit 4'
Java 9, Compatability Issue with Classloader.Getsystemclassloader