diff --git a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/AbstractNamedValueMethodArgumentResolver.java b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/AbstractNamedValueMethodArgumentResolver.java index 882ad75be0..f9b9444df6 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/AbstractNamedValueMethodArgumentResolver.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/AbstractNamedValueMethodArgumentResolver.java @@ -30,7 +30,6 @@ import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.messaging.Message; import org.springframework.messaging.handler.annotation.ValueConstants; import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver; -import org.springframework.util.Assert; import org.springframework.util.ClassUtils; /** @@ -88,28 +87,28 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle Class paramType = parameter.getParameterType(); NamedValueInfo namedValueInfo = getNamedValueInfo(parameter); - Object value = resolveArgumentInternal(parameter, message, namedValueInfo.name); - if (value == null) { + Object arg = resolveArgumentInternal(parameter, message, namedValueInfo.name); + if (arg == null) { if (namedValueInfo.defaultValue != null) { - value = resolveDefaultValue(namedValueInfo.defaultValue); + arg = resolveDefaultValue(namedValueInfo.defaultValue); } - else if (namedValueInfo.required) { + else if (namedValueInfo.required && !parameter.getParameterType().getName().equals("java.util.Optional")) { handleMissingValue(namedValueInfo.name, parameter, message); } - value = handleNullValue(namedValueInfo.name, value, paramType); + arg = handleNullValue(namedValueInfo.name, arg, paramType); } - else if ("".equals(value) && namedValueInfo.defaultValue != null) { - value = resolveDefaultValue(namedValueInfo.defaultValue); + else if ("".equals(arg) && namedValueInfo.defaultValue != null) { + arg = resolveDefaultValue(namedValueInfo.defaultValue); } - if (!ClassUtils.isAssignableValue(paramType, value)) { - value = this.conversionService.convert(value, - TypeDescriptor.valueOf(value.getClass()), new TypeDescriptor(parameter)); + if (!ClassUtils.isAssignableValue(paramType, arg)) { + arg = this.conversionService.convert( + arg, TypeDescriptor.valueOf(arg.getClass()), new TypeDescriptor(parameter)); } - handleResolvedValue(value, namedValueInfo.name, parameter, message); + handleResolvedValue(arg, namedValueInfo.name, parameter, message); - return value; + return arg; } /** @@ -140,10 +139,12 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle String name = info.name; if (info.name.length() == 0) { name = parameter.getParameterName(); - Assert.notNull(name, "Name for argument type [" + parameter.getParameterType().getName() - + "] not available, and parameter name information not found in class file either."); + if (name == null) { + throw new IllegalArgumentException("Name for argument type [" + parameter.getParameterType().getName() + + "] not available, and parameter name information not found in class file either."); + } } - String defaultValue = ValueConstants.DEFAULT_NONE.equals(info.defaultValue) ? null : info.defaultValue; + String defaultValue = (ValueConstants.DEFAULT_NONE.equals(info.defaultValue) ? null : info.defaultValue); return new NamedValueInfo(name, info.required, defaultValue); } diff --git a/spring-messaging/src/test/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandlerTests.java b/spring-messaging/src/test/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandlerTests.java index 8f27ab32cb..5c1366bdd0 100644 --- a/spring-messaging/src/test/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandlerTests.java +++ b/spring-messaging/src/test/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandlerTests.java @@ -20,16 +20,23 @@ import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; + import org.springframework.context.support.StaticApplicationContext; import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.SubscribableChannel; -import org.springframework.messaging.handler.annotation.*; +import org.springframework.messaging.handler.annotation.DestinationVariable; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.messaging.handler.annotation.Headers; +import org.springframework.messaging.handler.annotation.MessageExceptionHandler; +import org.springframework.messaging.handler.annotation.MessageMapping; +import org.springframework.messaging.handler.annotation.Payload; import org.springframework.messaging.handler.annotation.support.MethodArgumentNotValidException; import org.springframework.messaging.simp.SimpAttributes; import org.springframework.messaging.simp.SimpAttributesContextHolder; @@ -45,7 +52,7 @@ import org.springframework.validation.Errors; import org.springframework.validation.Validator; import org.springframework.validation.annotation.Validated; -import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; /** @@ -66,7 +73,6 @@ public class SimpAnnotationMethodMessageHandlerTests { @Before public void setup() { - SubscribableChannel channel = Mockito.mock(SubscribableChannel.class); SimpMessageSendingOperations brokerTemplate = new SimpMessagingTemplate(channel); @@ -80,7 +86,6 @@ public class SimpAnnotationMethodMessageHandlerTests { } - @SuppressWarnings("unchecked") @Test public void headerArgumentResolution() { SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(); @@ -96,6 +101,35 @@ public class SimpAnnotationMethodMessageHandlerTests { assertEquals("bar", ((Map) this.testController.arguments.get("headers")).get("foo")); } + @Test + public void optionalHeaderArgumentResolutionWhenPresent() { + SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(); + headers.setSessionId("session1"); + headers.setSessionAttributes(new ConcurrentHashMap<>()); + headers.setDestination("/pre/optionalHeaders"); + headers.setHeader("foo", "bar"); + Message message = MessageBuilder.withPayload(new byte[0]).setHeaders(headers).build(); + this.messageHandler.handleMessage(message); + + assertEquals("optionalHeaders", this.testController.method); + assertEquals("bar", this.testController.arguments.get("foo1")); + assertEquals("bar", this.testController.arguments.get("foo2")); + } + + @Test + public void optionalHeaderArgumentResolutionWhenNotPresent() { + SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(); + headers.setSessionId("session1"); + headers.setSessionAttributes(new ConcurrentHashMap<>()); + headers.setDestination("/pre/optionalHeaders"); + Message message = MessageBuilder.withPayload(new byte[0]).setHeaders(headers).build(); + this.messageHandler.handleMessage(message); + + assertEquals("optionalHeaders", this.testController.method); + assertNull(this.testController.arguments.get("foo1")); + assertNull(this.testController.arguments.get("foo2")); + } + @Test public void messageMappingDestinationVariableResolution() { SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(); @@ -213,7 +247,6 @@ public class SimpAnnotationMethodMessageHandlerTests { private Map arguments = new LinkedHashMap(); - @MessageMapping("/headers") public void headers(@Header String foo, @Headers Map headers) { this.method = "headers"; @@ -221,6 +254,13 @@ public class SimpAnnotationMethodMessageHandlerTests { this.arguments.put("headers", headers); } + @MessageMapping("/optionalHeaders") + public void optionalHeaders(@Header(value="foo", required=false) String foo1, @Header(value="foo") Optional foo2) { + this.method = "optionalHeaders"; + this.arguments.put("foo1", foo1); + this.arguments.put("foo2", (foo2.isPresent() ? foo2.get() : null)); + } + @MessageMapping("/message/{foo}/{name}") public void messageMappingDestinationVariable(@DestinationVariable("foo") String param1, @DestinationVariable("name") String param2) { diff --git a/spring-web/src/main/java/org/springframework/web/method/annotation/AbstractCookieValueMethodArgumentResolver.java b/spring-web/src/main/java/org/springframework/web/method/annotation/AbstractCookieValueMethodArgumentResolver.java index f49909345a..a5d1b222bc 100644 --- a/spring-web/src/main/java/org/springframework/web/method/annotation/AbstractCookieValueMethodArgumentResolver.java +++ b/spring-web/src/main/java/org/springframework/web/method/annotation/AbstractCookieValueMethodArgumentResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -60,10 +60,9 @@ public abstract class AbstractCookieValueMethodArgumentResolver extends Abstract } @Override - protected void handleMissingValue(String cookieName, MethodParameter param) throws ServletRequestBindingException { - String paramType = param.getParameterType().getName(); + protected void handleMissingValue(String cookieName, MethodParameter parameter) throws ServletRequestBindingException { throw new ServletRequestBindingException( - "Missing cookie named '" + cookieName + "' for method parameter type [" + paramType + "]"); + "Missing cookie named '" + cookieName + "' for method parameter type " + parameter.getParameterType().getSimpleName()); } private static class CookieValueNamedValueInfo extends NamedValueInfo { diff --git a/spring-web/src/main/java/org/springframework/web/method/annotation/AbstractNamedValueMethodArgumentResolver.java b/spring-web/src/main/java/org/springframework/web/method/annotation/AbstractNamedValueMethodArgumentResolver.java index 2e6d0d28d4..6cadcec0f5 100644 --- a/spring-web/src/main/java/org/springframework/web/method/annotation/AbstractNamedValueMethodArgumentResolver.java +++ b/spring-web/src/main/java/org/springframework/web/method/annotation/AbstractNamedValueMethodArgumentResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -91,7 +91,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle if (namedValueInfo.defaultValue != null) { arg = resolveDefaultValue(namedValueInfo.defaultValue); } - else if (namedValueInfo.required) { + else if (namedValueInfo.required && !parameter.getParameterType().getName().equals("java.util.Optional")) { handleMissingValue(namedValueInfo.name, parameter); } arg = handleNullValue(namedValueInfo.name, arg, paramType); @@ -138,8 +138,10 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle String name = info.name; if (info.name.length() == 0) { name = parameter.getParameterName(); - Assert.notNull(name, "Name for argument type [" + parameter.getParameterType().getName() - + "] not available, and parameter name information not found in class file either."); + if (name == null) { + throw new IllegalArgumentException("Name for argument type [" + parameter.getParameterType().getName() + + "] not available, and parameter name information not found in class file either."); + } } String defaultValue = (ValueConstants.DEFAULT_NONE.equals(info.defaultValue) ? null : info.defaultValue); return new NamedValueInfo(name, info.required, defaultValue); diff --git a/spring-web/src/main/java/org/springframework/web/method/annotation/RequestHeaderMethodArgumentResolver.java b/spring-web/src/main/java/org/springframework/web/method/annotation/RequestHeaderMethodArgumentResolver.java index 5668b3541c..48c6c2c80b 100644 --- a/spring-web/src/main/java/org/springframework/web/method/annotation/RequestHeaderMethodArgumentResolver.java +++ b/spring-web/src/main/java/org/springframework/web/method/annotation/RequestHeaderMethodArgumentResolver.java @@ -76,13 +76,9 @@ public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMetho } @Override - protected void handleMissingValue(String headerName, MethodParameter param) throws ServletRequestBindingException { - Class paramType = param.getParameterType(); - if (!paramType.getName().equals("java.util.Optional")) { - throw new ServletRequestBindingException( - "Missing header '" + headerName + "' for method parameter type [" + paramType.getName() + "]"); - - } + protected void handleMissingValue(String name, MethodParameter parameter) throws ServletRequestBindingException { + throw new ServletRequestBindingException("Missing header '" + name + + "' for method parameter type " + parameter.getParameterType().getSimpleName()); } private static class RequestHeaderNamedValueInfo extends NamedValueInfo { diff --git a/spring-web/src/main/java/org/springframework/web/method/annotation/RequestParamMethodArgumentResolver.java b/spring-web/src/main/java/org/springframework/web/method/annotation/RequestParamMethodArgumentResolver.java index 9ec42eb1c7..bb923c21e4 100644 --- a/spring-web/src/main/java/org/springframework/web/method/annotation/RequestParamMethodArgumentResolver.java +++ b/spring-web/src/main/java/org/springframework/web/method/annotation/RequestParamMethodArgumentResolver.java @@ -250,10 +250,8 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod } @Override - protected void handleMissingValue(String paramName, MethodParameter parameter) throws ServletException { - if (!parameter.getParameterType().getName().equals("java.util.Optional")) { - throw new MissingServletRequestParameterException(paramName, parameter.getParameterType().getSimpleName()); - } + protected void handleMissingValue(String name, MethodParameter parameter) throws ServletException { + throw new MissingServletRequestParameterException(name, parameter.getParameterType().getSimpleName()); } @Override diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MatrixVariableMethodArgumentResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MatrixVariableMethodArgumentResolver.java index 6fd415e689..c5842b6917 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MatrixVariableMethodArgumentResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MatrixVariableMethodArgumentResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -114,12 +114,9 @@ public class MatrixVariableMethodArgumentResolver extends AbstractNamedValueMeth } @Override - protected void handleMissingValue(String name, MethodParameter param) throws ServletRequestBindingException { - Class paramType = param.getParameterType(); - if (!paramType.getName().equals("java.util.Optional")) { - throw new ServletRequestBindingException( - "Missing matrix variable '" + name + "' for method parameter type [" + paramType.getName() + "]"); - } + protected void handleMissingValue(String name, MethodParameter parameter) throws ServletRequestBindingException { + throw new ServletRequestBindingException("Missing matrix variable '" + name + + "' for method parameter type " + parameter.getParameterType().getSimpleName()); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/PathVariableMethodArgumentResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/PathVariableMethodArgumentResolver.java index 0a47c4b83c..8d5da19d8c 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/PathVariableMethodArgumentResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/PathVariableMethodArgumentResolver.java @@ -101,10 +101,9 @@ public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethod } @Override - protected void handleMissingValue(String name, MethodParameter param) throws ServletRequestBindingException { - String paramType = param.getParameterType().getName(); - throw new ServletRequestBindingException( - "Missing URI template variable '" + name + "' for method parameter type [" + paramType + "]"); + protected void handleMissingValue(String name, MethodParameter parameter) throws ServletRequestBindingException { + throw new ServletRequestBindingException("Missing URI template variable '" + name + + "' for method parameter type " + parameter.getParameterType().getSimpleName()); } @Override