I have a mysterious java.lang.NoSuchMethodError exception after upgrading form spring boot 2.1.4 to spring boot 2.3.0. From my java knowledge this error is even not allowed to occur.

2020-05-30 15:08:53.690  INFO 41096 --- [           main] ConditionEvaluationReportLoggingListener :

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-05-30 15:08:53.756 ERROR 41096 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   :

***************************
APPLICATION FAILED TO START
***************************

Description:

An attempt was made to call a method that does not exist. The attempt was made from the following location:

    de.mvbonline.commons.amqp.util.ListenerUtil.createListenerContainer(ListenerUtil.java:21)

The following method did not exist:

    org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.setMessageListener(Ljava/lang/Object;)V

The method's class, org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer, is available from the following locations:

    jar:file:/C:/projects/maven-repository/org/springframework/amqp/spring-rabbit/2.2.7.RELEASE/spring-rabbit-2.2.7.RELEASE.jar!/org/springframework/amqp/rabbit/listener/SimpleMessageListenerContainer.class

It was loaded from the following location:

    file:/C:/projects/maven-repository/org/springframework/amqp/spring-rabbit/2.2.7.RELEASE/spring-rabbit-2.2.7.RELEASE.jar


Action:

Correct the classpath of your application so that it contains a single, compatible version of org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer

The lines form above

2020-05-30 15:08:52.849  INFO 41096 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'taskExecutor'
2020-05-30 15:08:53.534  WARN 41096 --- [           main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataUpdateListenerContainer' defined in class path resource [de/mvbonline/pubx/restapi/config/RabbitDataUpdateConsumerConfiguration$DataUpdateRabbitConsumerConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.amqp.rabbit.listener.MessageListenerContainer]: Factory method 'dataUpdateListenerContainer' threw exception; nested exception is java.lang.NoSuchMethodError: org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.setMessageListener(Ljava/lang/Object;)V
2020-05-30 15:08:53.538  INFO 41096 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'taskExecutor'

The class ListenerUtil

package de.mvbonline.commons.amqp.util;

import org.springframework.amqp.core.MessageListener;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.MessageListenerContainer;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;

public class ListenerUtil {

    private ListenerUtil() {
        // No instanciation
    }

    public static MessageListenerContainer createListenerContainer(final ConnectionFactory connectionFactory, final MessageListener messageListener,
            final String queueName, final int queueConsumers, final int queuePrefetch, final boolean queueListenersEnabled) {
        if (!queueListenersEnabled || (queueConsumers <= 0)) {
            return null;
        }
        final SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        container.setMessageListener(messageListener);
        container.setQueueNames(queueName);
        container.setConcurrentConsumers(queueConsumers);
        container.setPrefetchCount(queuePrefetch);
        return container;
    }
}

I have recognized that it is searching for setMessageListener(java.lang.Object) while the method should be setMessageListener(org.springframework.amqp.core.MessageListener) but why is there something searched - we are not using any spring magic at this line of code.

Comment From: bmaehr

Sorry for bothering you. The Problem was a change of the method signature of setMessageListener between spring-rabbit 2.2.7 and spring-rabbit 1.4.0

Comment From: anandbikas

@bmaehr How did you solve it?

Comment From: bmaehr

@anandbikas You shouldnt have a problem if you support only one of the versions.

We have both - thats why I use this code:

        try {
            container.setMessageListener(messageListener);
        }
        catch (final NoSuchMethodError e) {
            // Compatibility with new spring-rabbit versions
            try {
                final Method m = AbstractMessageListenerContainer.class.getDeclaredMethod("setMessageListener", MessageListener.class);
                m.invoke(container, messageListener);
            }
            catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e2) {
                // Restore previous exception
                throw e;
            }
        }

Comment From: anandbikas

@bmaehr Earlier, I had got it working with xml based container configuration.

Recently I learned that one of the dependent jar was compiled with an older version of AMQP 1.7.11.RELEASE whereas the main application was using 2.3.5.

I compiled the dependent jar with upgraded AMQP and then it started working. This looks to me like some compile time binding.

Comment From: bmaehr

No, the signature has changed (the type of the parameter). Both signatures accept a parameter of the type MessageListener. but the old one did accept more. It was really tricky to find.