|
17 | 17 | package org.springframework.integration.aop;
|
18 | 18 |
|
19 | 19 | import java.lang.annotation.Annotation;
|
| 20 | +import java.lang.reflect.AnnotatedElement; |
20 | 21 | import java.lang.reflect.Method;
|
21 | 22 | import java.util.Collections;
|
22 | 23 | import java.util.HashMap;
|
23 | 24 | import java.util.Map;
|
24 | 25 | import java.util.Set;
|
25 | 26 | import java.util.concurrent.ConcurrentHashMap;
|
26 |
| -import java.util.stream.Collectors; |
27 | 27 |
|
28 | 28 | import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
29 | 29 | import org.springframework.core.ParameterNameDiscoverer;
|
30 |
| -import org.springframework.core.annotation.AnnotatedElementUtils; |
31 |
| -import org.springframework.core.annotation.AnnotationUtils; |
| 30 | +import org.springframework.core.annotation.MergedAnnotation; |
| 31 | +import org.springframework.core.annotation.MergedAnnotations; |
32 | 32 | import org.springframework.expression.Expression;
|
33 | 33 | import org.springframework.integration.annotation.Publisher;
|
| 34 | +import org.springframework.lang.Nullable; |
34 | 35 | import org.springframework.messaging.handler.annotation.Header;
|
35 | 36 | import org.springframework.messaging.handler.annotation.Payload;
|
36 | 37 | import org.springframework.util.Assert;
|
@@ -80,143 +81,105 @@ public void setChannelAttributeName(String channelAttributeName) {
|
80 | 81 |
|
81 | 82 | @Override
|
82 | 83 | public String getChannelName(Method method) {
|
83 |
| - return this.channels.computeIfAbsent(method, method1 -> { |
84 |
| - String channelName = getAnnotationValue(method, this.channelAttributeName, String.class); |
85 |
| - if (channelName == null) { |
86 |
| - channelName = getAnnotationValue(method.getDeclaringClass(), this.channelAttributeName, String.class); |
87 |
| - } |
88 |
| - return StringUtils.hasText(channelName) ? channelName : null; |
89 |
| - }); |
90 |
| - |
| 84 | + return this.channels.computeIfAbsent(method, |
| 85 | + method1 -> { |
| 86 | + String channelName = getAnnotationValue(method, this.channelAttributeName); |
| 87 | + if (channelName == null) { |
| 88 | + channelName = getAnnotationValue(method.getDeclaringClass(), this.channelAttributeName); |
| 89 | + } |
| 90 | + return StringUtils.hasText(channelName) ? channelName : null; |
| 91 | + }); |
91 | 92 | }
|
92 | 93 |
|
93 | 94 | @Override
|
94 | 95 | public Expression getExpressionForPayload(Method method) {
|
95 |
| - return this.payloadExpressions.computeIfAbsent(method, method1 -> { |
96 |
| - Expression payloadExpression = null; |
97 |
| - Annotation methodPayloadAnnotation = AnnotationUtils.findAnnotation(method, Payload.class); |
98 |
| - |
99 |
| - if (methodPayloadAnnotation != null) { |
100 |
| - String payloadExpressionString = getAnnotationValue(methodPayloadAnnotation, null, String.class); |
101 |
| - if (!StringUtils.hasText(payloadExpressionString)) { |
102 |
| - payloadExpression = RETURN_VALUE_EXPRESSION; |
103 |
| - } |
104 |
| - else { |
105 |
| - payloadExpression = EXPRESSION_PARSER.parseExpression(payloadExpressionString); |
106 |
| - } |
107 |
| - } |
| 96 | + return this.payloadExpressions.computeIfAbsent(method, |
| 97 | + method1 -> { |
| 98 | + Expression payloadExpression = null; |
| 99 | + MergedAnnotation<Payload> payloadMergedAnnotation = |
| 100 | + MergedAnnotations.from(method, MergedAnnotations.SearchStrategy.EXHAUSTIVE) |
| 101 | + .get(Payload.class); |
| 102 | + if (payloadMergedAnnotation.isPresent()) { |
| 103 | + String payloadExpressionString = payloadMergedAnnotation.getString("expression"); |
| 104 | + if (!StringUtils.hasText(payloadExpressionString)) { |
| 105 | + payloadExpression = RETURN_VALUE_EXPRESSION; |
| 106 | + } |
| 107 | + else { |
| 108 | + payloadExpression = EXPRESSION_PARSER.parseExpression(payloadExpressionString); |
| 109 | + } |
| 110 | + } |
108 | 111 |
|
109 |
| - Annotation[][] annotationArray = method.getParameterAnnotations(); |
110 |
| - for (int i = 0; i < annotationArray.length; i++) { |
111 |
| - Annotation[] parameterAnnotations = annotationArray[i]; |
112 |
| - for (Annotation currentAnnotation : parameterAnnotations) { |
113 |
| - if (Payload.class.equals(currentAnnotation.annotationType())) { |
114 |
| - Assert.state(payloadExpression == null, |
115 |
| - "@Payload can be used at most once on a @Publisher method, " + |
116 |
| - "either at method-level or on a single parameter"); |
| 112 | + Annotation[][] annotationArray = method.getParameterAnnotations(); |
| 113 | + for (int i = 0; i < annotationArray.length; i++) { |
| 114 | + Annotation[] parameterAnnotations = annotationArray[i]; |
| 115 | + payloadMergedAnnotation = MergedAnnotations.from(parameterAnnotations).get(Payload.class); |
| 116 | + if (payloadMergedAnnotation.isPresent()) { |
| 117 | + Assert.state(payloadExpression == null, |
| 118 | + "@Payload can be used at most once on a @Publisher method, " + |
| 119 | + "either at method-level or on a single parameter"); |
117 | 120 |
|
118 |
| - Assert.state("".equals(AnnotationUtils.getValue(AnnotationUtils.synthesizeAnnotation(currentAnnotation, null))), |
119 |
| - "@Payload on a parameter for a @Publisher method may not contain an expression"); |
| 121 | + Assert.state("".equals(payloadMergedAnnotation.getString("expression")), |
| 122 | + "@Payload on a parameter for a @Publisher method may not contain an 'expression'"); |
120 | 123 |
|
121 |
| - payloadExpression = |
122 |
| - EXPRESSION_PARSER.parseExpression("#" + ARGUMENT_MAP_VARIABLE_NAME + "[" + i + "]"); |
| 124 | + payloadExpression = |
| 125 | + EXPRESSION_PARSER.parseExpression("#" + ARGUMENT_MAP_VARIABLE_NAME + "[" + i + "]"); |
| 126 | + } |
123 | 127 | }
|
124 |
| - } |
125 |
| - } |
126 |
| - if (payloadExpression == null || |
127 |
| - RETURN_VALUE_EXPRESSION.getExpressionString().equals(payloadExpression.getExpressionString())) { |
128 |
| - Assert.isTrue(!void.class.equals(method.getReturnType()), |
129 |
| - "When defining @Publisher on a void-returning method, an explicit payload " + |
130 |
| - "expression that does not rely upon a #return value is required."); |
131 |
| - } |
132 |
| - return payloadExpression; |
133 |
| - }); |
134 |
| - } |
135 |
| - |
136 |
| - @Override |
137 |
| - @Deprecated |
138 |
| - public String getPayloadExpression(Method method) { |
139 |
| - return getExpressionForPayload(method) |
140 |
| - .getExpressionString(); |
| 128 | + if (payloadExpression == null || |
| 129 | + RETURN_VALUE_EXPRESSION.getExpressionString() |
| 130 | + .equals(payloadExpression.getExpressionString())) { |
| 131 | + Assert.isTrue(!void.class.equals(method.getReturnType()), |
| 132 | + "When defining @Publisher on a void-returning method, an explicit payload " + |
| 133 | + "expression that does not rely upon a #return value is required."); |
| 134 | + } |
| 135 | + return payloadExpression; |
| 136 | + }); |
141 | 137 | }
|
142 | 138 |
|
143 | 139 | @Override
|
144 | 140 | public Map<String, Expression> getExpressionsForHeaders(Method method) {
|
145 |
| - return this.headersExpressions.computeIfAbsent(method, method1 -> { |
146 |
| - Map<String, Expression> headerExpressions = new HashMap<>(); |
147 |
| - String[] parameterNames = this.parameterNameDiscoverer.getParameterNames(method); |
148 |
| - Annotation[][] annotationArray = method.getParameterAnnotations(); |
149 |
| - for (int i = 0; i < annotationArray.length; i++) { |
150 |
| - Annotation[] parameterAnnotations = annotationArray[i]; |
151 |
| - for (Annotation currentAnnotation : parameterAnnotations) { |
152 |
| - if (Header.class.equals(currentAnnotation.annotationType())) { |
153 |
| - String name = getAnnotationValue(currentAnnotation, null, String.class); |
154 |
| - if (!StringUtils.hasText(name)) { |
155 |
| - name = parameterNames[i]; |
| 141 | + return this.headersExpressions.computeIfAbsent(method, |
| 142 | + method1 -> { |
| 143 | + Map<String, Expression> headerExpressions = new HashMap<>(); |
| 144 | + String[] parameterNames = this.parameterNameDiscoverer.getParameterNames(method); |
| 145 | + Annotation[][] annotationArray = method.getParameterAnnotations(); |
| 146 | + for (int i = 0; i < annotationArray.length; i++) { |
| 147 | + Annotation[] parameterAnnotations = annotationArray[i]; |
| 148 | + MergedAnnotation<Header> headerMergedAnnotation = |
| 149 | + MergedAnnotations.from(parameterAnnotations).get(Header.class); |
| 150 | + if (headerMergedAnnotation.isPresent()) { |
| 151 | + String name = |
| 152 | + headerMergedAnnotation |
| 153 | + .getString("name"); |
| 154 | + if (!StringUtils.hasText(name)) { |
| 155 | + if (parameterNames != null) { |
| 156 | + name = parameterNames[i]; |
| 157 | + } |
| 158 | + else { |
| 159 | + name = method.getName() + ".arg#" + i; |
| 160 | + } |
| 161 | + } |
| 162 | + headerExpressions.put(name, |
| 163 | + EXPRESSION_PARSER.parseExpression('#' + ARGUMENT_MAP_VARIABLE_NAME + '[' + i + ']')); |
156 | 164 | }
|
157 |
| - headerExpressions.put(name, |
158 |
| - EXPRESSION_PARSER.parseExpression("#" + ARGUMENT_MAP_VARIABLE_NAME + "[" + i + "]")); |
159 | 165 | }
|
160 |
| - } |
161 |
| - } |
162 |
| - return headerExpressions; |
163 |
| - }); |
| 166 | + return headerExpressions; |
| 167 | + }); |
164 | 168 | }
|
165 | 169 |
|
166 |
| - @Override |
167 |
| - @Deprecated |
168 |
| - public Map<String, String> getHeaderExpressions(Method method) { |
169 |
| - return getExpressionsForHeaders(method) |
170 |
| - .entrySet() |
171 |
| - .stream() |
172 |
| - .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getExpressionString())); |
173 |
| - } |
174 |
| - |
175 |
| - private <T> T getAnnotationValue(Method method, String attributeName, Class<T> expectedType) { |
176 |
| - T value = null; |
| 170 | + @Nullable |
| 171 | + private String getAnnotationValue(AnnotatedElement element, String attributeName) { |
| 172 | + MergedAnnotations mergedAnnotations = |
| 173 | + MergedAnnotations.from(element, MergedAnnotations.SearchStrategy.EXHAUSTIVE); |
| 174 | + String value = null; |
177 | 175 | for (Class<? extends Annotation> annotationType : this.annotationTypes) {
|
178 |
| - Annotation annotation = AnnotatedElementUtils.findMergedAnnotation(method, annotationType); |
179 |
| - if (annotation != null) { |
| 176 | + MergedAnnotation<? extends Annotation> mergedAnnotation = mergedAnnotations.get(annotationType); |
| 177 | + if (mergedAnnotation.isPresent()) { |
180 | 178 | if (value != null) {
|
181 | 179 | throw new IllegalStateException(
|
182 |
| - "method [" + method + "] contains more than one publisher annotation"); |
| 180 | + "The [" + element + "] contains more than one publisher annotation"); |
183 | 181 | }
|
184 |
| - value = getAnnotationValue(annotation, attributeName, expectedType); |
185 |
| - } |
186 |
| - } |
187 |
| - return value; |
188 |
| - } |
189 |
| - |
190 |
| - private <T> T getAnnotationValue(Class<?> clazz, String attributeName, Class<T> expectedType) { |
191 |
| - T value = null; |
192 |
| - for (Class<? extends Annotation> annotationType : this.annotationTypes) { |
193 |
| - Annotation annotation = AnnotatedElementUtils.findMergedAnnotation(clazz, annotationType); |
194 |
| - if (annotation != null) { |
195 |
| - if (value != null) { |
196 |
| - throw new IllegalStateException( |
197 |
| - "class [" + clazz + "] contains more than one publisher annotation"); |
198 |
| - } |
199 |
| - value = getAnnotationValue(annotation, attributeName, expectedType); |
200 |
| - } |
201 |
| - } |
202 |
| - return value; |
203 |
| - } |
204 |
| - |
205 |
| - @SuppressWarnings("unchecked") |
206 |
| - private <T> T getAnnotationValue(Annotation annotation, String attributeName, Class<T> expectedType) { |
207 |
| - T value = null; |
208 |
| - Object valueAsObject = (attributeName == null) ? |
209 |
| - AnnotationUtils.getValue(AnnotationUtils.synthesizeAnnotation(annotation, null)) : |
210 |
| - AnnotationUtils.getValue(annotation, attributeName); |
211 |
| - |
212 |
| - if (valueAsObject != null) { |
213 |
| - if (expectedType.isAssignableFrom(valueAsObject.getClass())) { |
214 |
| - value = (T) valueAsObject; |
215 |
| - } |
216 |
| - else { |
217 |
| - throw new IllegalArgumentException("expected type [" + expectedType.getName() + |
218 |
| - "] for attribute '" + attributeName + "' on publisher annotation [" + |
219 |
| - annotation.annotationType() + "], but actual type was [" + valueAsObject.getClass() + "]"); |
| 182 | + value = mergedAnnotation.getString(attributeName); |
220 | 183 | }
|
221 | 184 | }
|
222 | 185 | return value;
|
|
0 commit comments