18
18
19
19
import java .lang .annotation .Annotation ;
20
20
import java .lang .reflect .Method ;
21
+ import java .util .Arrays ;
21
22
import java .util .HashMap ;
22
23
import java .util .LinkedList ;
23
24
import java .util .List ;
84
85
*/
85
86
class GatewayMethodInboundMessageMapper implements InboundMessageMapper <Object []>, BeanFactoryAware {
86
87
87
- private static final Log logger = LogFactory .getLog (GatewayMethodInboundMessageMapper .class );
88
+ private static final Log LOGGER = LogFactory .getLog (GatewayMethodInboundMessageMapper .class );
88
89
89
90
private static final SpelExpressionParser PARSER = new SpelExpressionParser ();
90
91
@@ -145,18 +146,18 @@ class GatewayMethodInboundMessageMapper implements InboundMessageMapper<Object[]
145
146
this .globalHeaderExpressions = globalHeaderExpressions ;
146
147
this .parameterList = getMethodParameterList (method );
147
148
this .payloadExpression = parsePayloadExpression (method );
148
- if (mapper == null ) {
149
- this .argsMapper = new DefaultMethodArgsMessageMapper ();
150
- }
151
- else {
152
- this .argsMapper = mapper ;
153
- }
154
149
if (messageBuilderFactory == null ) {
155
150
this .messageBuilderFactory = new DefaultMessageBuilderFactory ();
156
151
}
157
152
else {
158
153
this .messageBuilderFactory = messageBuilderFactory ;
159
154
}
155
+ if (mapper == null ) {
156
+ this .argsMapper = new DefaultMethodArgsMessageMapper ();
157
+ }
158
+ else {
159
+ this .argsMapper = mapper ;
160
+ }
160
161
}
161
162
162
163
@@ -194,13 +195,11 @@ private Message<?> mapArgumentsToMessage(Object[] arguments, @Nullable Map<Strin
194
195
try {
195
196
return this .argsMapper .toMessage (new MethodArgsHolder (this .method , arguments ), headers );
196
197
}
198
+ catch (MessagingException e ) { // NOSONAR fto avoid if..else
199
+ throw e ;
200
+ }
197
201
catch (Exception e ) {
198
- if (e instanceof MessagingException ) {
199
- throw (MessagingException ) e ;
200
- }
201
- else {
202
- throw new MessageMappingException ("Failed to map arguments" , e );
203
- }
202
+ throw new MessageMappingException ("Failed to map arguments: " + Arrays .toString (arguments ), e );
204
203
}
205
204
}
206
205
@@ -235,8 +234,8 @@ private void copyHeaders(Map<?, ?> argumentValue, Map<String, Object> headers) {
235
234
for (Entry <?, ?> entry : argumentValue .entrySet ()) {
236
235
Object key = entry .getKey ();
237
236
if (!(key instanceof String )) {
238
- if (logger .isWarnEnabled ()) {
239
- logger .warn ("Invalid header name [" + key +
237
+ if (LOGGER .isWarnEnabled ()) {
238
+ LOGGER .warn ("Invalid header name [" + key +
240
239
"], name type must be String. Skipping mapping of this header to MessageHeaders." );
241
240
}
242
241
}
@@ -286,13 +285,16 @@ private static Expression parsePayloadExpression(Method method) {
286
285
287
286
public class DefaultMethodArgsMessageMapper implements MethodArgsMessageMapper {
288
287
288
+ private final MessageBuilderFactory messageBuilderFactory =
289
+ GatewayMethodInboundMessageMapper .this .messageBuilderFactory ;
290
+
289
291
@ Override
290
292
public Message <?> toMessage (MethodArgsHolder holder , @ Nullable Map <String , Object > headers ) {
291
293
Object messageOrPayload = null ;
292
294
boolean foundPayloadAnnotation = false ;
293
295
Object [] arguments = holder .getArgs ();
294
296
EvaluationContext methodInvocationEvaluationContext = createMethodInvocationEvaluationContext (arguments );
295
- headers =
297
+ Map < String , Object > headersToPopulate =
296
298
headers != null
297
299
? new HashMap <>(headers )
298
300
: new HashMap <>();
@@ -309,76 +311,114 @@ public Message<?> toMessage(MethodArgsHolder holder, @Nullable Map<String, Objec
309
311
false );
310
312
if (annotation != null ) {
311
313
if (annotation .annotationType ().equals (Payload .class )) {
312
- if (messageOrPayload != null ) {
313
- throwExceptionForMultipleMessageOrPayloadParameters (methodParameter );
314
- }
315
- String expression = (String ) AnnotationUtils .getValue (annotation );
316
- if (!StringUtils .hasText (expression )) {
317
- messageOrPayload = argumentValue ;
318
- }
319
- else {
320
- messageOrPayload = evaluatePayloadExpression (expression , argumentValue );
321
- }
314
+ messageOrPayload =
315
+ processPayloadAnnotation (messageOrPayload , argumentValue , methodParameter , annotation );
322
316
foundPayloadAnnotation = true ;
323
317
}
324
318
else if (annotation .annotationType ().equals (Header .class )) {
325
- String headerName = determineHeaderName (annotation , methodParameter );
326
- if ((Boolean ) AnnotationUtils .getValue (annotation , "required" ) // NOSONAR never null
327
- && argumentValue == null ) {
328
- throw new IllegalArgumentException ("Received null argument value for required header: '"
329
- + headerName + "'" );
330
- }
331
- headers .put (headerName , argumentValue );
319
+ processHeaderAnnotation (headersToPopulate , argumentValue , methodParameter , annotation );
332
320
}
333
321
else if (annotation .annotationType ().equals (Headers .class )) {
334
- if (argumentValue != null ) {
335
- if (!(argumentValue instanceof Map )) {
336
- throw new IllegalArgumentException (
337
- "@Headers annotation is only valid for Map-typed parameters" );
338
- }
339
- for (Object key : ((Map <?, ?>) argumentValue ).keySet ()) {
340
- Assert .isInstanceOf (String .class , key , "Invalid header name [" + key +
341
- "], name type must be String." );
342
- Object value = ((Map <?, ?>) argumentValue ).get (key );
343
- headers .put ((String ) key , value );
344
- }
345
- }
322
+ processHeadersAnnotation (headersToPopulate , argumentValue );
346
323
}
347
324
}
348
325
else if (messageOrPayload == null ) {
349
326
messageOrPayload = argumentValue ;
350
327
}
351
328
else if (Map .class .isAssignableFrom (methodParameter .getParameterType ())) {
352
- if (messageOrPayload instanceof Map && !foundPayloadAnnotation ) {
353
- if (GatewayMethodInboundMessageMapper .this .payloadExpression == null ) {
354
- throw new MessagingException ("Ambiguous method parameters; found more than one " +
355
- "Map-typed parameter and neither one contains a @Payload annotation" );
356
- }
357
- }
358
- GatewayMethodInboundMessageMapper .this .copyHeaders ((Map <?, ?>) argumentValue , headers );
329
+ processMapArgument (messageOrPayload , foundPayloadAnnotation , headersToPopulate ,
330
+ (Map <?, ?>) argumentValue );
359
331
}
360
332
else if (GatewayMethodInboundMessageMapper .this .payloadExpression == null ) {
361
- GatewayMethodInboundMessageMapper .this
362
- .throwExceptionForMultipleMessageOrPayloadParameters (methodParameter );
333
+ throwExceptionForMultipleMessageOrPayloadParameters (methodParameter );
363
334
}
364
335
}
365
- Assert .isTrue (messageOrPayload != null , "unable to determine a Message or payload parameter on method ["
366
- + GatewayMethodInboundMessageMapper .this .method + "]" );
336
+
337
+ Assert .isTrue (messageOrPayload != null ,
338
+ () -> "unable to determine a Message or payload parameter on method ["
339
+ + GatewayMethodInboundMessageMapper .this .method + "]" );
340
+ populateSendAndReplyTimeoutHeaders (methodInvocationEvaluationContext , headersToPopulate );
341
+
342
+ return buildMessage (headersToPopulate , messageOrPayload , methodInvocationEvaluationContext );
343
+ }
344
+
345
+ @ Nullable
346
+ private Object processPayloadAnnotation (@ Nullable Object messageOrPayload ,
347
+ Object argumentValue , MethodParameter methodParameter , Annotation annotation ) {
348
+
349
+ if (messageOrPayload != null ) {
350
+ throwExceptionForMultipleMessageOrPayloadParameters (methodParameter );
351
+ }
352
+ String expression = (String ) AnnotationUtils .getValue (annotation );
353
+ if (!StringUtils .hasText (expression )) {
354
+ return argumentValue ;
355
+ }
356
+ else {
357
+ return evaluatePayloadExpression (expression , argumentValue );
358
+ }
359
+ }
360
+
361
+ private void processHeaderAnnotation (Map <String , Object > headersToPopulate , @ Nullable Object argumentValue ,
362
+ MethodParameter methodParameter , Annotation annotation ) {
363
+
364
+ String headerName = determineHeaderName (annotation , methodParameter );
365
+ if ((Boolean ) AnnotationUtils .getValue (annotation , "required" ) // NOSONAR never null
366
+ && argumentValue == null ) {
367
+ throw new IllegalArgumentException ("Received null argument value for required header: '"
368
+ + headerName + "'" );
369
+ }
370
+ headersToPopulate .put (headerName , argumentValue );
371
+ }
372
+
373
+ private void processHeadersAnnotation (Map <String , Object > headersToPopulate , @ Nullable Object argumentValue ) {
374
+ if (argumentValue != null ) {
375
+ if (!(argumentValue instanceof Map )) {
376
+ throw new IllegalArgumentException (
377
+ "@Headers annotation is only valid for Map-typed parameters" );
378
+ }
379
+ for (Object key : ((Map <?, ?>) argumentValue ).keySet ()) {
380
+ Assert .isInstanceOf (String .class , key , "Invalid header name [" + key +
381
+ "], name type must be String." );
382
+ Object value = ((Map <?, ?>) argumentValue ).get (key );
383
+ headersToPopulate .put ((String ) key , value );
384
+ }
385
+ }
386
+ }
387
+
388
+ private void processMapArgument (Object messageOrPayload , boolean foundPayloadAnnotation ,
389
+ Map <String , Object > headersToPopulate , Map <?, ?> argumentValue ) {
390
+
391
+ if (messageOrPayload instanceof Map && !foundPayloadAnnotation ) {
392
+ if (GatewayMethodInboundMessageMapper .this .payloadExpression == null ) {
393
+ throw new MessagingException ("Ambiguous method parameters; found more than one " +
394
+ "Map-typed parameter and neither one contains a @Payload annotation" );
395
+ }
396
+ }
397
+ copyHeaders (argumentValue , headersToPopulate );
398
+ }
399
+
400
+ private void populateSendAndReplyTimeoutHeaders (EvaluationContext methodInvocationEvaluationContext ,
401
+ Map <String , Object > headersToPopulate ) {
402
+
367
403
if (GatewayMethodInboundMessageMapper .this .sendTimeoutExpression != null ) {
368
- headers .computeIfAbsent (GenericMessagingTemplate .DEFAULT_SEND_TIMEOUT_HEADER ,
404
+ headersToPopulate .computeIfAbsent (GenericMessagingTemplate .DEFAULT_SEND_TIMEOUT_HEADER ,
369
405
v -> GatewayMethodInboundMessageMapper .this .sendTimeoutExpression
370
406
.getValue (methodInvocationEvaluationContext , Long .class ));
371
407
}
372
408
if (GatewayMethodInboundMessageMapper .this .replyTimeoutExpression != null ) {
373
- headers .computeIfAbsent (GenericMessagingTemplate .DEFAULT_RECEIVE_TIMEOUT_HEADER ,
409
+ headersToPopulate .computeIfAbsent (GenericMessagingTemplate .DEFAULT_RECEIVE_TIMEOUT_HEADER ,
374
410
v -> GatewayMethodInboundMessageMapper .this .replyTimeoutExpression
375
411
.getValue (methodInvocationEvaluationContext , Long .class ));
376
412
}
377
- MessageBuilderFactory messageBuilderFactory = GatewayMethodInboundMessageMapper .this .messageBuilderFactory ;
413
+ }
414
+
415
+ private Message <?> buildMessage (Map <String , Object > headers , Object messageOrPayload ,
416
+ EvaluationContext methodInvocationEvaluationContext ) {
417
+
378
418
AbstractIntegrationMessageBuilder <?> builder =
379
419
(messageOrPayload instanceof Message )
380
- ? messageBuilderFactory .fromMessage ((Message <?>) messageOrPayload )
381
- : messageBuilderFactory .withPayload (messageOrPayload );
420
+ ? this . messageBuilderFactory .fromMessage ((Message <?>) messageOrPayload )
421
+ : this . messageBuilderFactory .withPayload (messageOrPayload );
382
422
builder .copyHeadersIfAbsent (headers );
383
423
// Explicit headers in XML override any @Header annotations...
384
424
if (!CollectionUtils .isEmpty (GatewayMethodInboundMessageMapper .this .headerExpressions )) {
0 commit comments