Edit I added more detail to help others and left the original question for history
Background I have prototyped a REST call that returns JSON in a Spring Controller that works with my client software. The client software has a specific way it queries for data. That query is not compatible with the my Spring code, so I had a few lines that did the conversion. I refactored the conversion code into its own object. Instead of creating each time in my REST methods that require it, I would like to have it pre-populated before it gets to my method.
Question In a Spring Controller can I have Spring pre-populate an object from the values in the URL and the header, similar to how Spring populates and object from a form?
Current code
@RequestMapping(value="", headers = "Accept=application/json", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<String> searchUserProjects(
@RequestParam(required = false) String projectName,
@RequestParam(required = false) String sortBy,
@RequestHeader(value = "Range") String range) {
Original Question I know in Spring you can take the properties of a form and map them to an object. In addition, I know you can map a field to property converter object, I cannot remember the exact name, but I have done it. My question, is it possible to have Spring populate an object from values in the URL and the header and then pass that into the method instead of declaring them at the method signature of the controller?
Edit:
The registration method in the applicationContext.xml
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="app.util.dojo.DojoQueryProcessorHandlerMethodArgumentResolver"/>
</mvc:argument-resolvers>
</mvc:annotation-driven>
And the handler method with parameter
public ResponseEntity<String> searchUserProjects(@RequestParam(required = false) String projectName, @ProcessDojoQuery DojoRestQueryProcessor dojoQueryResults) {
DojoRestQueryProcessor.java
package app.util.dojo;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
public class DojoRestQueryProcessor {
protected String[] rangeArray;
protected String range;
protected String sortBy;
protected int startIndex;
protected int endIndex;
public DojoRestQueryProcessor() {
}
public DojoRestQueryProcessor(String range, String sortBy) {
if (range== null && sortBy == null)
return;
if (range.length() <= 3 || !range.contains("-"))
throw new DojoRestQueryProcessorException("Range value does not meet spec. " + range);
this.rangeArray = range.substring(6).split("-");
this.range = range;
this.sortBy = sortBy;
}
public PageRequest createPageRequest() {
startIndex = Integer.parseInt(rangeArray[0]);
endIndex = Integer.parseInt(rangeArray[1]);
if (startIndex >= endIndex)
throw new IllegalArgumentException("The starting index for a range needs to be less than the end index.");
Sort.Order[] sortOrders = null;
if (sortBy != null && sortBy.length() > 2)
sortOrders = convertDojoSortValuesToSpringSorts(sortBy.split(","));
int pageSize = endIndex-startIndex+1;
int pageNum = ((endIndex+1)/pageSize)-1;
PageRequest pageRequest = null;
if (sortOrders != null)
pageRequest = new PageRequest(pageNum, pageSize, new Sort(sortOrders));
else
pageRequest = new PageRequest(pageNum, pageSize);
return pageRequest;
}
public static Sort.Order[] convertDojoSortValuesToSpringSorts(String[] sortStrings) {
if (sortStrings == null)
return null;
Sort.Order[] sortOrders = new Sort.Order[sortStrings.length];
for (int i = 0; i < sortStrings.length; i++) {
String sortString = sortStrings[i];
if (sortString.startsWith("-")) {
sortOrders[i] = new Sort.Order(Direction.DESC, sortString.substring(1));
} else {
sortOrders[i] = new Sort.Order(Direction.ASC, sortString.substring(1));
}
}
return sortOrders;
}
public int getStartIndex() {
return startIndex;
}
public int getEndIndex() {
return endIndex;
}
public String getRange() {
return range;
}
public String getSortBy() {
return sortBy;
}
}
My Method Handler:
package app.util.dojo;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.HandlerMapping;
public class DojoQueryProcessorHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(ProcessDojoQuery.class) && parameter.getParameterType().equals(DojoRestQueryProcessor.class) ;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
throws Exception {
String rangeField = parameter.getParameterAnnotation(ProcessDojoQuery.class).rangeField();
String sortByField = parameter.getParameterAnnotation(ProcessDojoQuery.class).sortByField();
String range = getRangeValue(rangeField, webRequest);
String sortBy = getSortByValue(sortByField, webRequest);
return new DojoRestQueryProcessor(range, sortBy);
}
private String getSortByValue(String rangeField, NativeWebRequest webRequest) {
Map<String, String> pathVariables = getPathVariables(webRequest);
return pathVariables.get(rangeField);
}
private Map<String, String> getPathVariables(NativeWebRequest webRequest) {
HttpServletRequest httpServletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
return (Map<String, String>) httpServletRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
}
private String getHeaderValue(String headerName, NativeWebRequest webRequest) {
HttpServletRequest httpServletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
return httpServletRequest.getHeader(headerName);
}
private String getRangeValue(String rangeField, NativeWebRequest webRequest) {
return getHeaderValue(rangeField, webRequest);
}
}