PagedRequestHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver { @Override public Object resolveArgument(final MethodParameter param, final ModelAndViewContainer mavContainer, final NativeWebRequest webRequest, final WebDataBinderFactory binderFactory) throws Exception { LOG.debug("Debugging PagedRequest Parsing:"); HttpServletRequest httpRequest = (HttpServletRequest) webRequest.getNativeRequest(); Map<String, Object> parameters = parametersRetriever.getParameters(webRequest); Object resource = resourceParameterResolver.getResource(param, parameters); Integer limit = limitParameterResolver.getLimit(param.getParameterAnnotation(Limit.class), param.getParameterType().getDeclaredField("limit"), httpRequest); Integer offset = offsetParameterResolver.getOffset(param.getParameterAnnotation(Offset.class), param.getParameterType().getDeclaredField("offset"), httpRequest); List<OrderBy> orders = orderByFieldResolver.getOrdersBy(httpRequest.getParameter(Constants.ORDER_BY), resource); PagedRequest<Object> pagedRequest = new PagedRequest<Object>(resource, offset, limit, orders); return pagedRequest; }  @Override boolean supportsParameter(final MethodParameter parameter); @Override Object resolveArgument(final MethodParameter param,
			final ModelAndViewContainer mavContainer, final NativeWebRequest webRequest,
			final WebDataBinderFactory binderFactory); void setResourceParameterResolver(final ResourceParameterResolver resourceParameterResolver); void setParametersRetriever(final ParametersRetriever parametersRetriever); void setOrderByFieldResolver(final OrderByFieldResolver orderByFieldResolver); void setOffsetParameterResolver(final OffsetParameterResolver offsetParameterResolver); void setLimitParameterResolver(final LimitParameterResolver limitParameterResolver); void setResourceParamterResolver(final ResourceParameterResolver resourceParamterResolver);  }
@Test public void testResolveArgument() throws Exception { final Integer limitValue = 20; final Integer offsetValue = 0; String orderByParameterValue = "name-asc, description-desc"; String id = "1"; String name = "Ivan"; Map<String, String> pathVariables = new HashMap<>(); pathVariables.put("id", id); Map<String, String[]> parameterMap = new HashMap<>(); parameterMap.put("name", new String[] { name }); Map<String, String> requestParameters = new HashMap<>(); requestParameters.put("id", id); requestParameters.put("name", name); Map<String, Object> parameters = new HashMap(); parameters.put("id", id); parameters.put("name", Arrays.asList(name)); PersonResource resource = new PersonResource(); resource.setName(name); resource.setId(Long.valueOf(id)); OrderBy order1 = new OrderBy("name", OrderByType.ASC); OrderBy order2 = new OrderBy("description", OrderByType.DESC); List<OrderBy> orders = Arrays.asList(order1, order2); PagedRequest<PersonResource> expected = new PagedRequest<PersonResource>(resource, offsetValue, limitValue, orders); when(webRequest.getNativeRequest()).thenReturn(httpRequest); when(webRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST)) .thenReturn(pathVariables); when(webRequest.getParameterMap()).thenReturn(parameterMap); when(parametersRetriever.getParameters(any(NativeWebRequest.class))).thenReturn(parameters); when(resourceParamterResolver.getResource(any(MethodParameter.class), anyMapOf(String.class, Object.class))).thenReturn(resource); Limit limit = (Limit) Proxy.newProxyInstance(Limit.class.getClassLoader(), new Class[] { Limit.class }, new InvocationHandler() { @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { return String.valueOf(limitValue); } }); when(param.getParameterAnnotation(Limit.class)).thenReturn(limit); doReturn(paramType).when(param).getParameterType(); when(httpRequest.getParameter("limit")).thenReturn(String.valueOf(limitValue)); when(limitParameterResolver.getLimit(any(Limit.class), any(Field.class), any(HttpServletRequest.class))).thenReturn(limitValue); Offset offset = (Offset) Proxy.newProxyInstance(Offset.class.getClassLoader(), new Class[] { Offset.class }, new InvocationHandler() { @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { return String.valueOf(offsetValue); } }); when(param.getParameterAnnotation(Offset.class)).thenReturn(offset); doReturn(paramType).when(param).getParameterType(); when(httpRequest.getParameter("offset")).thenReturn(String.valueOf(limitValue)); when(offsetParameteResolver.getOffset(any(Offset.class), any(Field.class), any(HttpServletRequest.class))).thenReturn(offsetValue); when(httpRequest.getParameter("orderBy")).thenReturn(orderByParameterValue); when(orderByFieldResolver.getOrdersBy(anyString(), any())).thenReturn(orders); Object actual = unit.resolveArgument(param, mavContainer, webRequest, binderFactory); assertEquals(expected, actual); }
@Test public void testResolveArgumentWithCapitalLetter() throws Exception { final Integer limitValue = 20; final Integer offsetValue = 0; String orderByParameterValue = "name-ASC, description-desc"; String id = "1"; String name = "Ivan"; Map<String, String> pathVariables = new HashMap<>(); pathVariables.put("id", id); Map<String, String[]> parameterMap = new HashMap<>(); parameterMap.put("name", new String[] { name }); Map<String, String> requestParameters = new HashMap<>(); requestParameters.put("id", id); requestParameters.put("name", name); Map<String, Object> parameters = new HashMap(); parameters.put("id", id); parameters.put("name", Arrays.asList(name)); PersonResource resource = new PersonResource(); resource.setName(name); resource.setId(Long.valueOf(id)); OrderBy order1 = new OrderBy("name", OrderByType.ASC); OrderBy order2 = new OrderBy("description", OrderByType.DESC); List<OrderBy> orders = Arrays.asList(order1, order2); PagedRequest<PersonResource> expected = new PagedRequest<PersonResource>(resource, offsetValue, limitValue, orders); when(webRequest.getNativeRequest()).thenReturn(httpRequest); when(webRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST)) .thenReturn(pathVariables); when(webRequest.getParameterMap()).thenReturn(parameterMap); when(parametersRetriever.getParameters(any(NativeWebRequest.class))).thenReturn(parameters); when(resourceParamterResolver.getResource(any(MethodParameter.class), anyMapOf(String.class, Object.class))).thenReturn(resource); Limit limit = (Limit) Proxy.newProxyInstance(Limit.class.getClassLoader(), new Class[] { Limit.class }, new InvocationHandler() { @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { return String.valueOf(limitValue); } }); when(param.getParameterAnnotation(Limit.class)).thenReturn(limit); doReturn(paramType).when(param).getParameterType(); when(httpRequest.getParameter("limit")).thenReturn(String.valueOf(limitValue)); when(limitParameterResolver.getLimit(any(Limit.class), any(Field.class), any(HttpServletRequest.class))).thenReturn(limitValue); Offset offset = (Offset) Proxy.newProxyInstance(Offset.class.getClassLoader(), new Class[] { Offset.class }, new InvocationHandler() { @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { return String.valueOf(offsetValue); } }); when(param.getParameterAnnotation(Offset.class)).thenReturn(offset); doReturn(paramType).when(param).getParameterType(); when(httpRequest.getParameter("offset")).thenReturn(String.valueOf(limitValue)); when(offsetParameteResolver.getOffset(any(Offset.class), any(Field.class), any(HttpServletRequest.class))).thenReturn(offsetValue); when(httpRequest.getParameter("orderBy")).thenReturn(orderByParameterValue); when(orderByFieldResolver.getOrdersBy(anyString(), any())).thenReturn(orders); Object actual = unit.resolveArgument(param, mavContainer, webRequest, binderFactory); assertEquals(expected, actual); }
@Test public void testResolveArgumentWithSingleOrder() throws Exception { final Integer limitValue = 20; final Integer offsetValue = 0; String orderByParameterValue = "name-asc"; String id = "1"; String name = "Ivan"; Map<String, String> pathVariables = new HashMap<>(); pathVariables.put("id", id); Map<String, String[]> parameterMap = new HashMap<>(); parameterMap.put("name", new String[] { name }); Map<String, String> requestParameters = new HashMap<>(); requestParameters.put("id", id); requestParameters.put("name", name); Map<String, Object> parameters = new HashMap(); parameters.put("id", id); parameters.put("name", Arrays.asList(name)); PersonResource resource = new PersonResource(); resource.setName(name); resource.setId(Long.valueOf(id)); OrderBy order1 = new OrderBy("name", OrderByType.ASC); List<OrderBy> orders = Arrays.asList(order1); PagedRequest<PersonResource> expected = new PagedRequest<PersonResource>(resource, offsetValue, limitValue, orders); when(webRequest.getNativeRequest()).thenReturn(httpRequest); when(webRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST)) .thenReturn(pathVariables); when(webRequest.getParameterMap()).thenReturn(parameterMap); when(parametersRetriever.getParameters(any(NativeWebRequest.class))).thenReturn(parameters); when(resourceParamterResolver.getResource(any(MethodParameter.class), anyMapOf(String.class, Object.class))).thenReturn(resource); Limit limit = (Limit) Proxy.newProxyInstance(Limit.class.getClassLoader(), new Class[] { Limit.class }, new InvocationHandler() { @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { return String.valueOf(limitValue); } }); when(param.getParameterAnnotation(Limit.class)).thenReturn(limit); doReturn(paramType).when(param).getParameterType(); when(httpRequest.getParameter("limit")).thenReturn(String.valueOf(limitValue)); when(limitParameterResolver.getLimit(any(Limit.class), any(Field.class), any(HttpServletRequest.class))).thenReturn(limitValue); Offset offset = (Offset) Proxy.newProxyInstance(Offset.class.getClassLoader(), new Class[] { Offset.class }, new InvocationHandler() { @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { return String.valueOf(offsetValue); } }); when(param.getParameterAnnotation(Offset.class)).thenReturn(offset); doReturn(paramType).when(param).getParameterType(); when(httpRequest.getParameter("offset")).thenReturn(String.valueOf(limitValue)); when(offsetParameteResolver.getOffset(any(Offset.class), any(Field.class), any(HttpServletRequest.class))).thenReturn(offsetValue); when(httpRequest.getParameter("orderBy")).thenReturn(orderByParameterValue); when(orderByFieldResolver.getOrdersBy(anyString(), any())).thenReturn(orders); Object actual = unit.resolveArgument(param, mavContainer, webRequest, binderFactory); assertEquals(expected, actual); }
@Test public void testResolveArgumentWithEmptyOrders() throws Exception { final Integer limitValue = 20; final Integer offsetValue = 0; String orderByParameterValue = ""; String id = "1"; String name = "Ivan"; Map<String, String> pathVariables = new HashMap<>(); pathVariables.put("id", id); Map<String, String[]> parameterMap = new HashMap<>(); parameterMap.put("name", new String[] { name }); Map<String, String> requestParameters = new HashMap<>(); requestParameters.put("id", id); requestParameters.put("name", name); Map<String, Object> parameters = new HashMap(); parameters.put("id", id); parameters.put("name", Arrays.asList(name)); PersonResource resource = new PersonResource(); resource.setName(name); resource.setId(Long.valueOf(id)); List<OrderBy> orders = Collections.emptyList(); PagedRequest<PersonResource> expected = new PagedRequest<PersonResource>(resource, offsetValue, limitValue, orders); when(webRequest.getNativeRequest()).thenReturn(httpRequest); when(webRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST)) .thenReturn(pathVariables); when(webRequest.getParameterMap()).thenReturn(parameterMap); when(parametersRetriever.getParameters(any(NativeWebRequest.class))).thenReturn(parameters); when(resourceParamterResolver.getResource(any(MethodParameter.class), anyMapOf(String.class, Object.class))).thenReturn(resource); Limit limit = (Limit) Proxy.newProxyInstance(Limit.class.getClassLoader(), new Class[] { Limit.class }, new InvocationHandler() { @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { return String.valueOf(limitValue); } }); when(param.getParameterAnnotation(Limit.class)).thenReturn(limit); doReturn(paramType).when(param).getParameterType(); when(httpRequest.getParameter("limit")).thenReturn(String.valueOf(limitValue)); when(limitParameterResolver.getLimit(any(Limit.class), any(Field.class), any(HttpServletRequest.class))).thenReturn(limitValue); Offset offset = (Offset) Proxy.newProxyInstance(Offset.class.getClassLoader(), new Class[] { Offset.class }, new InvocationHandler() { @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { return String.valueOf(offsetValue); } }); when(param.getParameterAnnotation(Offset.class)).thenReturn(offset); doReturn(paramType).when(param).getParameterType(); when(httpRequest.getParameter("offset")).thenReturn(String.valueOf(limitValue)); when(offsetParameteResolver.getOffset(any(Offset.class), any(Field.class), any(HttpServletRequest.class))).thenReturn(offsetValue); when(httpRequest.getParameter("orderBy")).thenReturn(orderByParameterValue); Object actual = unit.resolveArgument(param, mavContainer, webRequest, binderFactory); assertEquals(expected, actual); }
@Test public void testResolveArgumentWithNullOrders() throws Exception { final Integer limitValue = 20; final Integer offsetValue = 0; String orderByParameterValue = null; String id = "1"; String name = "Ivan"; Map<String, String> pathVariables = new HashMap<>(); pathVariables.put("id", id); Map<String, String[]> parameterMap = new HashMap<>(); parameterMap.put("name", new String[] { name }); Map<String, String> requestParameters = new HashMap<>(); requestParameters.put("id", id); requestParameters.put("name", name); Map<String, Object> parameters = new HashMap(); parameters.put("id", id); parameters.put("name", Arrays.asList(name)); PersonResource resource = new PersonResource(); resource.setName(name); resource.setId(Long.valueOf(id)); List<OrderBy> orders = Collections.emptyList(); PagedRequest<PersonResource> expected = new PagedRequest<PersonResource>(resource, offsetValue, limitValue, orders); when(webRequest.getNativeRequest()).thenReturn(httpRequest); when(webRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST)) .thenReturn(pathVariables); when(webRequest.getParameterMap()).thenReturn(parameterMap); when(parametersRetriever.getParameters(any(NativeWebRequest.class))).thenReturn(parameters); when(resourceParamterResolver.getResource(any(MethodParameter.class), anyMapOf(String.class, Object.class))).thenReturn(resource); Limit limit = (Limit) Proxy.newProxyInstance(Limit.class.getClassLoader(), new Class[] { Limit.class }, new InvocationHandler() { @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { return String.valueOf(limitValue); } }); when(param.getParameterAnnotation(Limit.class)).thenReturn(limit); doReturn(paramType).when(param).getParameterType(); when(httpRequest.getParameter("limit")).thenReturn(String.valueOf(limitValue)); when(limitParameterResolver.getLimit(any(Limit.class), any(Field.class), any(HttpServletRequest.class))).thenReturn(limitValue); Offset offset = (Offset) Proxy.newProxyInstance(Offset.class.getClassLoader(), new Class[] { Offset.class }, new InvocationHandler() { @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { return String.valueOf(offsetValue); } }); when(param.getParameterAnnotation(Offset.class)).thenReturn(offset); doReturn(paramType).when(param).getParameterType(); when(httpRequest.getParameter("offset")).thenReturn(String.valueOf(limitValue)); when(offsetParameteResolver.getOffset(any(Offset.class), any(Field.class), any(HttpServletRequest.class))).thenReturn(offsetValue); when(httpRequest.getParameter("orderBy")).thenReturn(orderByParameterValue); Object actual = unit.resolveArgument(param, mavContainer, webRequest, binderFactory); assertEquals(expected, actual); }
@Test public void testResolveArgumentWithInvalidOrderFormat() throws Exception { final Integer limitValue = 20; final Integer offsetValue = 0; String orderByParameterValue = "name*asc, description\\-desc"; String id = "1"; String name = "Ivan"; Map<String, String> pathVariables = new HashMap<>(); pathVariables.put("id", id); Map<String, String[]> parameterMap = new HashMap<>(); parameterMap.put("name", new String[] { name }); Map<String, String> requestParameters = new HashMap<>(); requestParameters.put("id", id); requestParameters.put("name", name); Map<String, Object> parameters = new HashMap(); parameters.put("id", id); parameters.put("name", Arrays.asList(name)); PersonResource resource = new PersonResource(); resource.setName(name); resource.setId(Long.valueOf(id)); List<OrderBy> orders = Collections.emptyList(); PagedRequest<PersonResource> expected = new PagedRequest<PersonResource>(resource, offsetValue, limitValue, orders); when(webRequest.getNativeRequest()).thenReturn(httpRequest); when(webRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST)) .thenReturn(pathVariables); when(webRequest.getParameterMap()).thenReturn(parameterMap); when(parametersRetriever.getParameters(any(NativeWebRequest.class))).thenReturn(parameters); when(resourceParamterResolver.getResource(any(MethodParameter.class), anyMapOf(String.class, Object.class))).thenReturn(resource); Limit limit = (Limit) Proxy.newProxyInstance(Limit.class.getClassLoader(), new Class[] { Limit.class }, new InvocationHandler() { @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { return String.valueOf(limitValue); } }); when(param.getParameterAnnotation(Limit.class)).thenReturn(limit); doReturn(paramType).when(param).getParameterType(); when(httpRequest.getParameter("limit")).thenReturn(String.valueOf(limitValue)); Offset offset = (Offset) Proxy.newProxyInstance(Offset.class.getClassLoader(), new Class[] { Offset.class }, new InvocationHandler() { @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { return String.valueOf(offsetValue); } }); when(param.getParameterAnnotation(Offset.class)).thenReturn(offset); doReturn(paramType).when(param).getParameterType(); when(httpRequest.getParameter("offset")).thenReturn(String.valueOf(limitValue)); when(offsetParameteResolver.getOffset(any(Offset.class), any(Field.class), any(HttpServletRequest.class))).thenReturn(offsetValue); when(httpRequest.getParameter("orderBy")).thenReturn(orderByParameterValue); when(orderByFieldResolver.getOrdersBy(anyString(), any())).thenThrow(new InvalidOrderByException("Invalid string for order by field")); exception.expect(InvalidOrderByException.class); exception.expectMessage("Invalid string for order by field"); Object actual = unit.resolveArgument(param, mavContainer, webRequest, binderFactory); assertEquals(expected.toString(), actual.toString()); }
@Test public void testResolveArgumentWithInvalidOrderField() throws Exception { final Integer limitValue = 20; final Integer offsetValue = 0; String orderByParameterValue = "name-asc, personId-desc"; String id = "1"; String name = "Ivan"; Map<String, String> pathVariables = new HashMap<>(); pathVariables.put("id", id); Map<String, String[]> parameterMap = new HashMap<>(); parameterMap.put("name", new String[] { name }); Map<String, String> requestParameters = new HashMap<>(); requestParameters.put("id", id); requestParameters.put("name", name); Map<String, Object> parameters = new HashMap(); parameters.put("id", id); parameters.put("name", Arrays.asList(name)); PersonResource resource = new PersonResource(); resource.setName(name); resource.setId(Long.valueOf(id)); List<OrderBy> orders = Collections.emptyList(); PagedRequest<PersonResource> expected = new PagedRequest<PersonResource>(resource, offsetValue, limitValue, orders); when(webRequest.getNativeRequest()).thenReturn(httpRequest); when(webRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST)) .thenReturn(pathVariables); when(webRequest.getParameterMap()).thenReturn(parameterMap); when(parametersRetriever.getParameters(any(NativeWebRequest.class))).thenReturn(parameters); when(resourceParamterResolver.getResource(any(MethodParameter.class), anyMapOf(String.class, Object.class))).thenReturn(resource); Limit limit = (Limit) Proxy.newProxyInstance(Limit.class.getClassLoader(), new Class[] { Limit.class }, new InvocationHandler() { @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { return String.valueOf(limitValue); } }); when(param.getParameterAnnotation(Limit.class)).thenReturn(limit); doReturn(paramType).when(param).getParameterType(); when(httpRequest.getParameter("limit")).thenReturn(String.valueOf(limitValue)); Offset offset = (Offset) Proxy.newProxyInstance(Offset.class.getClassLoader(), new Class[] { Offset.class }, new InvocationHandler() { @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { return String.valueOf(offsetValue); } }); when(param.getParameterAnnotation(Offset.class)).thenReturn(offset); doReturn(paramType).when(param).getParameterType(); when(httpRequest.getParameter("offset")).thenReturn(String.valueOf(offsetValue)); when(offsetParameteResolver.getOffset(any(Offset.class), any(Field.class), any(HttpServletRequest.class))).thenReturn(offsetValue); when(httpRequest.getParameter("orderBy")).thenReturn(orderByParameterValue); when(orderByFieldResolver.getOrdersBy(anyString(), any())).thenThrow(new IllegalArgumentException("Fields that contains 'Id' are not supported for ordering")); exception.expect(IllegalArgumentException.class); exception.expectMessage("Fields that contains 'Id' are not supported for ordering"); Object actual = unit.resolveArgument(param, mavContainer, webRequest, binderFactory); assertEquals(expected.toString(), actual.toString()); }