A good idea is to create a filter that converts Snake case values to Camel case (or any other format).
This filter will be run for every request, and will handle the parameters accordingly and pass the request to the controller with the request values already formatted.
Talk is easy! Show the code!
AppConfig.java
import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.OncePerRequestFilter;
import com.google.common.base.CaseFormat;
@Configuration
public class AppConfig {
@Bean
public Filter snakeConverter() {
return new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
final Map<String, String[]> formattedParams = new ConcurrentHashMap<>();
for (String param : request.getParameterMap().keySet()) {
String formattedParam = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, param);
formattedParams.put(formattedParam, request.getParameterValues(param));
}
filterChain.doFilter(new HttpServletRequestWrapper(request) {
@Override
public String getParameter(String name) {
return formattedParams.containsKey(name) ? formattedParams.get(name)[0] : null;
}
@Override
public Enumeration<String> getParameterNames() {
return Collections.enumeration(formattedParams.keySet());
}
@Override
public String[] getParameterValues(String name) {
return formattedParams.get(name);
}
@Override
public Map<String, String[]> getParameterMap() {
return formattedParams;
}
}, response);
}
};
}
}
Now we come to the explanation about the code above:
The setting in the snakeConverter
will make the magic happen:
The method doFilterInternal
is always executed before request to be passed to the controller, this way we are taking all the parameters passed, including a new one Map
with the values formatted in case, and forwarding forward through the filterChain.doFilter
, that will actually forward the request to the controller.
The HttpServletRequestWrapper
envelopes the request and answer, and returns the values we defined in our new parameter map.
Follow the documentation from Onceperrequestfilter
I’m using the Guava to convert from Snake case to Camel case, if using Maven just include this dependency in your pom.xml
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>27.1-jre</version>
</dependency>
The code is completely based on the filter created by azhawkes
Using Restlet to test on a simple controller:
To the URL: http://localhost:8080/snakecase? foo_bar=123
I noticed that this question was open on Stackoverflow, I took advantage and answered her too :)