diff --git a/spring-messaging/src/test/java/org/springframework/messaging/handler/invocation/AbstractMethodMessageHandlerTests.java b/spring-messaging/src/test/java/org/springframework/messaging/handler/invocation/AbstractMethodMessageHandlerTests.java new file mode 100644 index 0000000000..09dd89ad95 --- /dev/null +++ b/spring-messaging/src/test/java/org/springframework/messaging/handler/invocation/AbstractMethodMessageHandlerTests.java @@ -0,0 +1,291 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.messaging.handler.invocation; + +import org.hamcrest.Matchers; +import org.junit.Before; +import org.junit.Test; + +import org.springframework.beans.DirectFieldAccessor; +import org.springframework.context.support.StaticApplicationContext; +import org.springframework.messaging.Message; +import org.springframework.messaging.handler.DestinationPatternsMessageCondition; +import org.springframework.messaging.handler.HandlerMethod; +import org.springframework.messaging.handler.HandlerMethodSelector; +import org.springframework.messaging.handler.annotation.support.MessageMethodArgumentResolver; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.messaging.support.MessageHeaderAccessor; +import org.springframework.util.AntPathMatcher; +import org.springframework.util.PathMatcher; +import org.springframework.util.ReflectionUtils.MethodFilter; + +import java.lang.reflect.Method; +import java.util.*; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; + +/** + * Test fixture for {@link org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler}. + * @author Brian Clozel + */ +public class AbstractMethodMessageHandlerTests { + + private static final String DESTINATION_HEADER = "testDestination"; + + private MyMethodMessageHandler messageHandler; + + private TestController testController; + + @Before + public void setup() { + List destinationPrefixes = new ArrayList(); + destinationPrefixes.add("/test/"); + + this.messageHandler = new MyMethodMessageHandler(); + this.messageHandler.setApplicationContext(new StaticApplicationContext()); + this.messageHandler.setDestinationPrefixes(destinationPrefixes); + this.messageHandler.afterPropertiesSet(); + this.testController = new TestController(); + this.messageHandler.registerHandler(this.testController); + } + + @Test(expected=IllegalStateException.class) + public void duplicateMapping() { + this.messageHandler.registerHandler(new DuplicateMappingsController()); + } + + @Test + public void registeredMappings() { + + DirectFieldAccessor fieldAccessor = new DirectFieldAccessor(this.messageHandler); + Map handlerMethods = (Map) + fieldAccessor.getPropertyValue("handlerMethods"); + + assertNotNull(handlerMethods); + assertThat(handlerMethods.keySet(), Matchers.hasSize(3)); + } + + @Test + public void antPatchMatchWildcard() throws Exception { + + Method method = this.testController.getClass().getMethod("handlerPathMatchWildcard"); + this.messageHandler.registerHandlerMethod(this.testController, method, "/handlerPathMatch**"); + + MessageHeaderAccessor headers = new MessageHeaderAccessor(); + headers.setHeader(DESTINATION_HEADER, "/test/handlerPathMatchFoo"); + Message message = MessageBuilder.withPayload(new byte[0]).setHeaders(headers).build(); + this.messageHandler.handleMessage(message); + + assertEquals("pathMatchWildcard", this.testController.method); + } + + @Test + public void bestMatchWildcard() throws Exception { + + Method method = this.testController.getClass().getMethod("bestMatch"); + this.messageHandler.registerHandlerMethod(this.testController, method, "/bestmatch/{foo}/path"); + + method = this.testController.getClass().getMethod("secondBestMatch"); + this.messageHandler.registerHandlerMethod(this.testController, method, "/bestmatch/*/*"); + + MessageHeaderAccessor headers = new MessageHeaderAccessor(); + headers.setHeader(DESTINATION_HEADER, "/test/bestmatch/bar/path"); + Message message = MessageBuilder.withPayload(new byte[0]).setHeaders(headers).build(); + this.messageHandler.handleMessage(message); + + assertEquals("bestMatch", this.testController.method); + } + + @Test + public void argumentResolver() { + + MessageHeaderAccessor headers = new MessageHeaderAccessor(); + headers.setHeader(DESTINATION_HEADER, "/test/handlerArgumentResolver"); + Message message = MessageBuilder.withPayload(new byte[0]).setHeaders(headers).build(); + this.messageHandler.handleMessage(message); + + assertEquals("handlerArgumentResolver", this.testController.method); + assertNotNull(this.testController.arguments.get("message")); + } + + @Test + public void exceptionResolver() { + + MessageHeaderAccessor headers = new MessageHeaderAccessor(); + headers.setHeader(DESTINATION_HEADER, "/test/handlerThrowsExc"); + Message message = MessageBuilder.withPayload(new byte[0]).setHeaders(headers).build(); + this.messageHandler.handleMessage(message); + + assertEquals("illegalStateException", this.testController.method); + assertNotNull(this.testController.arguments.get("exception")); + + } + + private static class TestController { + + public String method; + + private Map arguments = new LinkedHashMap(); + + public void handlerPathMatchWildcard() { + this.method = "pathMatchWildcard"; + } + + public void handlerArgumentResolver(Message message) { + this.method = "handlerArgumentResolver"; + this.arguments.put("message", message); + } + + public void handlerThrowsExc() { + throw new IllegalStateException(); + } + + public void bestMatch() { + this.method = "bestMatch"; + } + + public void secondBestMatch() { + this.method = "secondBestMatch"; + } + + public void illegalStateException(IllegalStateException exception) { + this.method = "illegalStateException"; + this.arguments.put("exception", exception); + } + + } + + private static class DuplicateMappingsController { + + public void handlerFoo() { } + + public void handlerFoo(String arg) { } + } + + + private static class MyMethodMessageHandler extends AbstractMethodMessageHandler { + + private PathMatcher pathMatcher = new AntPathMatcher(); + + public void registerHandler(Object handler) { + super.detectHandlerMethods(handler); + } + + public void registerHandlerMethod(Object handler, Method method, String mapping) { + super.registerHandlerMethod(handler, method, mapping); + } + + @Override + protected List initArgumentResolvers() { + List resolvers = new ArrayList(); + resolvers.add(new MessageMethodArgumentResolver()); + resolvers.addAll(getCustomArgumentResolvers()); + return resolvers; + } + + @Override + protected List initReturnValueHandlers() { + List handlers = new ArrayList(); + handlers.addAll(getCustomReturnValueHandlers()); + return handlers; + } + + @Override + protected boolean isHandler(Class beanType) { + return beanType.getName().contains("Controller"); + } + + @Override + protected String getMappingForMethod(Method method, Class handlerType) { + String methodName = method.getName(); + if(methodName.startsWith("handler")) { + return "/" + methodName; + } + return null; + } + + @Override + protected Set getDirectLookupDestinations(String mapping) { + Set result = new LinkedHashSet(); + if (!this.pathMatcher.isPattern(mapping)) { + result.add(mapping); + } + return result; + } + + @Override + protected String getDestination(Message message) { + return (String) message.getHeaders().get(DESTINATION_HEADER); + } + + @Override + protected String getMatchingMapping(String mapping, Message message) { + + String destination = getLookupDestination(getDestination(message)); + if(mapping.equals(destination) || this.pathMatcher.match(mapping, destination)) { + return mapping; + } + return null; + } + + @Override + protected Comparator getMappingComparator(Message message) { + return new Comparator() { + @Override + public int compare(String info1, String info2) { + DestinationPatternsMessageCondition cond1 = new DestinationPatternsMessageCondition(info1); + DestinationPatternsMessageCondition cond2 = new DestinationPatternsMessageCondition(info2); + return cond1.compareTo(cond2, message); + } + }; + } + + @Override + protected AbstractExceptionHandlerMethodResolver createExceptionHandlerMethodResolverFor(Class beanType) { + return new MyExceptionHandlerMethodResolver(beanType); + } + } + + private static class MyExceptionHandlerMethodResolver extends AbstractExceptionHandlerMethodResolver { + + public MyExceptionHandlerMethodResolver(Class handlerType) { + super(initExceptionMappings(handlerType)); + } + + private static Map, Method> initExceptionMappings(Class handlerType) { + Map, Method> result = new HashMap, Method>(); + for (Method method : HandlerMethodSelector.selectMethods(handlerType, EXCEPTION_HANDLER_METHOD_FILTER)) { + for(Class exception : getExceptionsFromMethodSignature(method)) { + result.put(exception, method); + } + } + return result; + } + + public final static MethodFilter EXCEPTION_HANDLER_METHOD_FILTER = new MethodFilter() { + + @Override + public boolean matches(Method method) { + return method.getName().contains("Exception"); + } + }; + + } + +} 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 4fe4d88428..4b751179e0 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 @@ -82,11 +82,6 @@ public class SimpAnnotationMethodMessageHandlerTests { assertEquals("bar", ((Map) this.testController.arguments.get("headers")).get("foo")); } - @Test(expected=IllegalStateException.class) - public void duplicateMappings() { - this.messageHandler.registerHandler(new DuplicateMappingController()); - } - @Test public void messageMappingDestinationVariableResolution() { SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(); @@ -112,27 +107,6 @@ public class SimpAnnotationMethodMessageHandlerTests { assertEquals("value", this.testController.arguments.get("name")); } - @Test - public void antPatchMatchWildcard() { - SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(); - headers.setDestination("/pre/pathmatch/wildcard/test"); - Message message = MessageBuilder.withPayload(new byte[0]).setHeaders(headers).build(); - this.messageHandler.handleMessage(message); - - assertEquals("pathMatchWildcard", this.testController.method); - } - - @Test - public void bestMatchWildcard() { - SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE); - headers.setDestination("/pre/bestmatch/bar/path"); - Message message = MessageBuilder.withPayload(new byte[0]).setHeaders(headers).build(); - this.messageHandler.handleMessage(message); - - assertEquals("bestMatch", this.testController.method); - assertEquals("bar", this.testController.arguments.get("foo")); - } - @Test public void simpleBinding() { SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(); @@ -201,22 +175,6 @@ public class SimpAnnotationMethodMessageHandlerTests { this.arguments.put("name", param2); } - @MessageMapping("/pathmatch/wildcard/**") - public void pathMatchWildcard() { - this.method = "pathMatchWildcard"; - } - - @MessageMapping("/bestmatch/{foo}/path") - public void bestMatch(@DestinationVariable("foo") String param1) { - this.method = "bestMatch"; - this.arguments.put("foo", param1); - } - - @MessageMapping("/bestmatch/*/*") - public void secondBestMatch() { - this.method = "secondBestMatch"; - } - @MessageMapping("/binding/id/{id}") public void simpleBinding(@DestinationVariable("id") Long id) { this.method = "simpleBinding"; @@ -235,16 +193,6 @@ public class SimpAnnotationMethodMessageHandlerTests { } } - @Controller - private static class DuplicateMappingController { - - @MessageMapping(value="/duplicate") - public void handle1() { } - - @MessageMapping(value="/duplicate") - public void handle2() { } - } - private static class StringNotEmptyValidator implements Validator { @Override public boolean supports(Class clazz) {