Skip to content

Commit 078cfb3

Browse files
committed
Add @ReplyTo/@ReplyToUser, remove deps on spring-web
1 parent 55dae74 commit 078cfb3

30 files changed

+1385
-307
lines changed

build.gradle

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,6 @@ project("spring-messaging") {
320320
compile(project(":spring-beans"))
321321
compile(project(":spring-core"))
322322
compile(project(":spring-context"))
323-
optional(project(":spring-web")) // TODO: MediaType/HandlerMethod/EHMR
324323
optional(project(":spring-websocket"))
325324
optional("com.fasterxml.jackson.core:jackson-databind:2.2.0")
326325
optional("org.projectreactor:reactor-core:1.0.0.BUILD-SNAPSHOT")

spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/ReplyTo.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,9 @@
3232
@Documented
3333
public @interface ReplyTo {
3434

35-
3635
/**
37-
* The destination value for the reply.
36+
* The destination for a message created from the return value of a method.
3837
*/
39-
String value();
38+
String[] value() default {};
4039

4140
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/*
2+
* Copyright 2002-2013 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.messaging.handler.annotation.support;
18+
19+
import java.lang.reflect.Method;
20+
import java.util.ArrayList;
21+
import java.util.Arrays;
22+
import java.util.Collections;
23+
import java.util.List;
24+
import java.util.Map;
25+
import java.util.concurrent.ConcurrentHashMap;
26+
27+
import org.springframework.core.ExceptionDepthComparator;
28+
import org.springframework.core.annotation.AnnotationUtils;
29+
import org.springframework.messaging.handler.annotation.MessageExceptionHandler;
30+
import org.springframework.messaging.handler.method.HandlerMethodSelector;
31+
import org.springframework.util.Assert;
32+
import org.springframework.util.ClassUtils;
33+
import org.springframework.util.ReflectionUtils.MethodFilter;
34+
35+
36+
/**
37+
* Discovers annotated exception handling methods in a given class type, including all
38+
* super types, and helps to resolve an Exception to a method that can handle it. The
39+
* exception types supported by a given method can also be discovered from the method
40+
* signature.
41+
*
42+
* @author Rossen Stoyanchev
43+
* @since 4.0
44+
*/
45+
public class ExceptionHandlerMethodResolver {
46+
47+
private static final Method NO_METHOD_FOUND = ClassUtils.getMethodIfAvailable(System.class, "currentTimeMillis");
48+
49+
private final Map<Class<? extends Throwable>, Method> mappedMethods =
50+
new ConcurrentHashMap<Class<? extends Throwable>, Method>(16);
51+
52+
private final Map<Class<? extends Throwable>, Method> exceptionLookupCache =
53+
new ConcurrentHashMap<Class<? extends Throwable>, Method>(16);
54+
55+
56+
/**
57+
* A constructor that finds {@link MessageExceptionHandler} methods in the given type.
58+
* @param handlerType the type to introspect
59+
*/
60+
public ExceptionHandlerMethodResolver(Class<?> handlerType) {
61+
for (Method method : HandlerMethodSelector.selectMethods(handlerType, EXCEPTION_HANDLER_METHOD_FILTER)) {
62+
for (Class<? extends Throwable> exceptionType : detectExceptionMappings(method)) {
63+
addExceptionMapping(exceptionType, method);
64+
}
65+
}
66+
}
67+
68+
/**
69+
* Extract exception mappings from the {@code @ExceptionHandler} annotation
70+
* first and as a fall-back from the method signature.
71+
*/
72+
@SuppressWarnings("unchecked")
73+
private List<Class<? extends Throwable>> detectExceptionMappings(Method method) {
74+
List<Class<? extends Throwable>> result = new ArrayList<Class<? extends Throwable>>();
75+
76+
detectAnnotationExceptionMappings(method, result);
77+
78+
if (result.isEmpty()) {
79+
for (Class<?> paramType : method.getParameterTypes()) {
80+
if (Throwable.class.isAssignableFrom(paramType)) {
81+
result.add((Class<? extends Throwable>) paramType);
82+
}
83+
}
84+
}
85+
86+
Assert.notEmpty(result, "No exception types mapped to {" + method + "}");
87+
88+
return result;
89+
}
90+
91+
protected void detectAnnotationExceptionMappings(Method method, List<Class<? extends Throwable>> result) {
92+
MessageExceptionHandler annot = AnnotationUtils.findAnnotation(method, MessageExceptionHandler.class);
93+
result.addAll(Arrays.asList(annot.value()));
94+
}
95+
96+
private void addExceptionMapping(Class<? extends Throwable> exceptionType, Method method) {
97+
Method oldMethod = this.mappedMethods.put(exceptionType, method);
98+
if (oldMethod != null && !oldMethod.equals(method)) {
99+
throw new IllegalStateException(
100+
"Ambiguous @ExceptionHandler method mapped for [" + exceptionType + "]: {" +
101+
oldMethod + ", " + method + "}.");
102+
}
103+
}
104+
105+
/**
106+
* Whether the contained type has any exception mappings.
107+
*/
108+
public boolean hasExceptionMappings() {
109+
return (this.mappedMethods.size() > 0);
110+
}
111+
112+
/**
113+
* Find a method to handle the given exception.
114+
* Use {@link ExceptionDepthComparator} if more than one match is found.
115+
* @param exception the exception
116+
* @return a method to handle the exception or {@code null}
117+
*/
118+
public Method resolveMethod(Exception exception) {
119+
Class<? extends Exception> exceptionType = exception.getClass();
120+
Method method = this.exceptionLookupCache.get(exceptionType);
121+
if (method == null) {
122+
method = getMappedMethod(exceptionType);
123+
this.exceptionLookupCache.put(exceptionType, method != null ? method : NO_METHOD_FOUND);
124+
}
125+
return method != NO_METHOD_FOUND ? method : null;
126+
}
127+
128+
/**
129+
* Return the method mapped to the given exception type or {@code null}.
130+
*/
131+
private Method getMappedMethod(Class<? extends Exception> exceptionType) {
132+
List<Class<? extends Throwable>> matches = new ArrayList<Class<? extends Throwable>>();
133+
for(Class<? extends Throwable> mappedException : this.mappedMethods.keySet()) {
134+
if (mappedException.isAssignableFrom(exceptionType)) {
135+
matches.add(mappedException);
136+
}
137+
}
138+
if (!matches.isEmpty()) {
139+
Collections.sort(matches, new ExceptionDepthComparator(exceptionType));
140+
return mappedMethods.get(matches.get(0));
141+
}
142+
else {
143+
return null;
144+
}
145+
}
146+
147+
148+
/** A filter for selecting annotated exception handling methods. */
149+
public final static MethodFilter EXCEPTION_HANDLER_METHOD_FILTER = new MethodFilter() {
150+
151+
@Override
152+
public boolean matches(Method method) {
153+
return AnnotationUtils.findAnnotation(method, MessageExceptionHandler.class) != null;
154+
}
155+
};
156+
157+
}
Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,26 @@
1919
import org.springframework.core.MethodParameter;
2020
import org.springframework.messaging.Message;
2121
import org.springframework.messaging.handler.annotation.MessageBody;
22-
import org.springframework.messaging.handler.method.MessageArgumentResolver;
22+
import org.springframework.messaging.handler.method.HandlerMethodArgumentResolver;
2323
import org.springframework.messaging.support.converter.MessageConverter;
2424
import org.springframework.util.Assert;
2525

2626

2727
/**
28+
* TODO
29+
*
30+
* <p>This {@link HandlerMethodArgumentResolver} should be ordered last as it supports all
31+
* types and does not require the {@link MessageBody} annotation.
32+
*
2833
* @author Rossen Stoyanchev
2934
* @since 4.0
3035
*/
31-
public class MessageBodyArgumentResolver implements MessageArgumentResolver {
36+
public class MessageBodyMethodArgumentResolver implements HandlerMethodArgumentResolver {
3237

3338
private final MessageConverter<?> converter;
3439

3540

36-
public MessageBodyArgumentResolver(MessageConverter<?> converter) {
41+
public MessageBodyMethodArgumentResolver(MessageConverter<?> converter) {
3742
Assert.notNull(converter, "converter is required");
3843
this.converter = converter;
3944
}

spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/MessageExceptionHandlerMethodResolver.java

Lines changed: 0 additions & 63 deletions
This file was deleted.

0 commit comments

Comments
 (0)