4949import org .springframework .kafka .listener .ListenerExecutionFailedException ;
5050import org .springframework .kafka .support .Acknowledgment ;
5151import org .springframework .kafka .support .KafkaHeaders ;
52+ import org .springframework .kafka .support .KafkaNull ;
5253import org .springframework .kafka .support .KafkaUtils ;
5354import org .springframework .kafka .support .converter .MessagingMessageConverter ;
5455import org .springframework .kafka .support .converter .RecordMessageConverter ;
5960import org .springframework .messaging .converter .MessageConversionException ;
6061import org .springframework .messaging .handler .annotation .Header ;
6162import org .springframework .messaging .handler .annotation .Payload ;
63+ import org .springframework .messaging .support .GenericMessage ;
6264import org .springframework .messaging .support .MessageBuilder ;
6365import org .springframework .util .Assert ;
6466import org .springframework .util .ObjectUtils ;
@@ -83,6 +85,11 @@ public abstract class MessagingMessageListenerAdapter<K, V> implements ConsumerS
8385
8486 private static final ParserContext PARSER_CONTEXT = new TemplateParserContext ("!{" , "}" );
8587
88+ /**
89+ * Message used when no conversion is needed.
90+ */
91+ protected static final Message <KafkaNull > NULL_MESSAGE = new GenericMessage <>(KafkaNull .INSTANCE ); // NOSONAR
92+
8693 private final Object bean ;
8794
8895 protected final LogAccessor logger = new LogAccessor (LogFactory .getLog (getClass ())); //NOSONAR
@@ -99,6 +106,8 @@ public abstract class MessagingMessageListenerAdapter<K, V> implements ConsumerS
99106
100107 private boolean isMessageList ;
101108
109+ private boolean conversionNeeded = true ;
110+
102111 private RecordMessageConverter messageConverter = new MessagingMessageConverter ();
103112
104113 private Type fallbackType = Object .class ;
@@ -174,6 +183,10 @@ public boolean isConsumerRecords() {
174183 return this .isConsumerRecords ;
175184 }
176185
186+ public boolean isConversionNeeded () {
187+ return this .conversionNeeded ;
188+ }
189+
177190 /**
178191 * Set the topic to which to send any result from the method invocation.
179192 * May be a SpEL expression {@code !{...}} evaluated at runtime.
@@ -481,14 +494,26 @@ protected Type determineInferredType(Method method) { // NOSONAR complexity
481494
482495 Type genericParameterType = null ;
483496 int allowedBatchParameters = 1 ;
497+ int notConvertibleParameters = 0 ;
484498
485499 for (int i = 0 ; i < method .getParameterCount (); i ++) {
486500 MethodParameter methodParameter = new MethodParameter (method , i );
487501 /*
488502 * We're looking for a single non-annotated parameter, or one annotated with @Payload.
489- * We ignore parameters with type Message because they are not involved with conversion.
503+ * We ignore parameters with type Message, Consumer, Ack, ConsumerRecord because they
504+ * are not involved with conversion.
490505 */
491- if (eligibleParameter (methodParameter )
506+ Type parameterType = methodParameter .getGenericParameterType ();
507+ boolean isNotConvertible = parameterIsType (parameterType , ConsumerRecord .class );
508+ boolean isAck = parameterIsType (parameterType , Acknowledgment .class );
509+ this .hasAckParameter |= isAck ;
510+ isNotConvertible |= isAck ;
511+ boolean isConsumer = parameterIsType (parameterType , Consumer .class );
512+ isNotConvertible |= isConsumer ;
513+ if (isNotConvertible ) {
514+ notConvertibleParameters ++;
515+ }
516+ if (!isNotConvertible && !isMessageWithNoTypeInfo (parameterType )
492517 && (methodParameter .getParameterAnnotations ().length == 0
493518 || methodParameter .hasParameterAnnotation (Payload .class ))) {
494519 if (genericParameterType == null ) {
@@ -500,8 +525,7 @@ protected Type determineInferredType(Method method) { // NOSONAR complexity
500525 break ;
501526 }
502527 }
503- else if (methodParameter .getGenericParameterType ().equals (Acknowledgment .class )) {
504- this .hasAckParameter = true ;
528+ else if (isAck ) {
505529 allowedBatchParameters ++;
506530 }
507531 else if (methodParameter .hasParameterAnnotation (Header .class )) {
@@ -511,11 +535,10 @@ else if (methodParameter.hasParameterAnnotation(Header.class)) {
511535 }
512536 }
513537 else {
514- if (methodParameter . getGenericParameterType (). equals ( Consumer . class ) ) {
538+ if (isConsumer ) {
515539 allowedBatchParameters ++;
516540 }
517541 else {
518- Type parameterType = methodParameter .getGenericParameterType ();
519542 if (parameterType instanceof ParameterizedType
520543 && ((ParameterizedType ) parameterType ).getRawType ().equals (Consumer .class )) {
521544 allowedBatchParameters ++;
@@ -524,6 +547,9 @@ else if (methodParameter.hasParameterAnnotation(Header.class)) {
524547 }
525548 }
526549
550+ if (notConvertibleParameters == method .getParameterCount ()) {
551+ this .conversionNeeded = false ;
552+ }
527553 boolean validParametersForBatch = method .getGenericParameterTypes ().length <= allowedBatchParameters ;
528554
529555 if (!validParametersForBatch ) {
@@ -587,27 +613,26 @@ private boolean isWildCardWithUpperBound(Type paramType) {
587613 && ((WildcardType ) paramType ).getUpperBounds ().length > 0 ;
588614 }
589615
590- /*
591- * Don't consider parameter types that are available after conversion.
592- * Acknowledgment, ConsumerRecord, Consumer, ConsumerRecord<...>, Consumer<...>, and Message<?>.
593- */
594- private boolean eligibleParameter (MethodParameter methodParameter ) {
595- Type parameterType = methodParameter .getGenericParameterType ();
596- if (parameterType .equals (Acknowledgment .class ) || parameterType .equals (ConsumerRecord .class )
597- || parameterType .equals (Consumer .class )) {
598- return false ;
599- }
616+ private boolean isMessageWithNoTypeInfo (Type parameterType ) {
600617 if (parameterType instanceof ParameterizedType ) {
601618 ParameterizedType parameterizedType = (ParameterizedType ) parameterType ;
602619 Type rawType = parameterizedType .getRawType ();
603- if (rawType .equals (ConsumerRecord . class ) || rawType . equals ( Consumer .class )) {
604- return false ;
620+ if (rawType .equals (Message .class )) {
621+ return parameterizedType . getActualTypeArguments ()[ 0 ] instanceof WildcardType ;
605622 }
606- else if (rawType .equals (Message .class )) {
607- return !(parameterizedType .getActualTypeArguments ()[0 ] instanceof WildcardType );
623+ }
624+ return parameterType .equals (Message .class ); // could be Message without a generic type
625+ }
626+
627+ private boolean parameterIsType (Type parameterType , Type type ) {
628+ if (parameterType instanceof ParameterizedType ) {
629+ ParameterizedType parameterizedType = (ParameterizedType ) parameterType ;
630+ Type rawType = parameterizedType .getRawType ();
631+ if (rawType .equals (type )) {
632+ return true ;
608633 }
609634 }
610- return ! parameterType .equals (Message . class ); // could be Message without a generic type
635+ return parameterType .equals (type );
611636 }
612637
613638 /**
0 commit comments