添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement . We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

3.0.6

Describe the bug

I am not sure if it is a bug but I can not explain the thrown exception Caused by: org.springframework.amqp.AmqpException: Ambiguous methods for payload type for the given situation.

On integration test with test containers and spying a class with Mockito annotated with @RabbitListener and its methods annotated with @RabbitHandler leads to AmqpException.

Obviously, the original @RabbitHanlder method is loaded and the mocked one at the same time.
MessagingMessageListenerAdapter::invokeHandlerAndProcessResult at line 140 (this.handlerAdapter.delegatingHanlder)

    if (this.messagingMessageConverter.method == null && amqpMessage != null) {
      amqpMessage.getMessageProperties().setTargetMethod(this.handlerAdapter.getMethodFor(message.getPayload()));

It there anything I can do to avoid this situation?

To Reproduce

You need to start the tests which are located in the linked project.

Expected behavior

I would not expect the error since the methods are not loaded twice.

Sample

Starting the DifferentTypesDistributorListenerIntegrationTest or ManyCustomersWorkersSpyListenerIntegrationTest from the project led to the exception https://github.com/kstojanovski-novatec/spring-amqp-testing-issue.

Obviously, the original @RabbitHanlder method is loaded and the mocked one at the same time.

Might indeed be a case.
Not sure how to fix such a situation since you are indeed expecting only those stubs to be available for your testing.

Well, let's see if @RabbitListenerTest can help you somehow: https://docs.spring.io/spring-amqp/reference/html/#test-harness.

Your project is too complex to give an immediate advice...

Hello Artem, thanks for the fast answer.

I saw the linked documentation and have also downloaded the four files from the GitHub repo:

  • org.springframework.amqp.rabbit.test.examples.ExampleRabbitListenerCaptureTest
  • org.springframework.amqp.rabbit.test.examples.ExampleRabbitListenerSpyAndCaptureTest
  • org.springframework.amqp.rabbit.test.examples.ExampleRabbitListenerSpyTest
  • org.springframework.amqp.rabbit.test.examples.TestRabbitTemplateTests
  • Only TestRabbitTemplateTests works well, but this kind of test I already have. I am interested in the other test where RabbitListenerTestHarness is used.
    Unfortunately the private RabbitListenerTestHarness harness; is marked red with the message "Could not auto-wire. No beans of 'RabbitListenerTestHarness' type found." for the other three classes as well.

    Then I downloaded the whole project Spring AMQP(spring-amqp-dist) and there the reference is also marked with the same message. I have tried to debug the tests and only TestRabbitTemplateTests could be debugged. The other tests are skipped. Should that be that way?

    The harness as red is just a flaw of an IDE.
    That bean is provided by the framework and IDE does not have an ability to scan classpath for manually registered beans like it happens with this one via RabbitListenerTestBootstrap.

    Those tests does not pass for your because you don't have a RabbitMQ broker on the default host/port.
    See that @RabbitAvailable what all those tests are marked with.
    In other words: the listener tests with mocks and spies still require a real RabbitMQ to interact with.

    However you probably can combine both TestRabbitTemplate and RabbitListenerTestHarness.

    spring-amqp/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/annotation/EnableRabbitIntegrationTests.java Lines 1979 to 1982 ee681bd

    As stated, all methods are doubled up; in this case I get

    java.lang.IllegalStateException: Failed to load ApplicationContext for [MergedContextConfiguration@41bb1f09 testClass = org.springframework.amqp.rabbit.annotation.EnableRabbitIntegrationTests, locations = [], classes = [org.springframework.amqp.rabbit.annotation.EnableRabbitIntegrationTests.EnableRabbitConfig], contextInitializerClasses = [], activeProfiles = [], propertySourceLocations = [], propertySourceProperties = ["spring.application.name=testConnectionName"], contextCustomizers = [], contextLoader = org.springframework.test.context.support.DelegatingSmartContextLoader, parent = null]
    Caused by: java.lang.IllegalStateException: Only one @RabbitHandler can be marked 'isDefault', found: public java.lang.String org.springframework.amqp.rabbit.annotation.EnableRabbitIntegrationTests$MultiListenerBean$MockitoMock$GPAkOvLI.defaultHandler(java.lang.Object) and public java.lang.String org.springframework.amqp.rabbit.annotation.EnableRabbitIntegrationTests$MultiListenerBean.defaultHandler(java.lang.Object)
    	at org.springframework.util.Assert.state(Assert.java:97)
    	at org.springframework.amqp.rabbit.annotation.RabbitListenerAnnotationBeanPostProcessor.processMultiMethodListeners(RabbitListenerAnnotationBeanPostProcessor.java:368)
    	at org.springframework.amqp.rabbit.annotation.RabbitListenerAnnotationBeanPostProcessor.postProcessAfterInitialization(RabbitListenerAnnotationBeanPostProcessor.java:320)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:434)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1773)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:598)
    	... 85 more
    

    Looks like we need to add code to the BPP to ignore methods from classes containing @MockitoMock...

    Spy method:

    public java.lang.String org.springframework.amqp.rabbit.annotation.EnableRabbitIntegrationTests$MultiListenerBean$MockitoMock$m0IRDAeN.defaultHandler(java.lang.Object)

    Real method:

    public java.lang.String org.springframework.amqp.rabbit.annotation.EnableRabbitIntegrationTests$MultiListenerBean.defaultHandler(java.lang.Object)

    Probably, yes; need to figure out what works (might need to filter out the non-mock methods) - but I am currently seeing another strange side-effect of making the bean a spy - when the queue name is anonymous, I am getting 2 containers/anonymous queues. If I name the queue, I only get one container. Very strange.

    Resolves spring-projects#2456
    When spying a `@RabbitListener` bean, duplicate methods are resolved as well
    as duplicate class level `@RabbitListener` annotations.
    **cherry-pick to 2.4.x** (will require instanceof polishing for Java 8)
    Resolves #2456
    When spying a `@RabbitListener` bean, duplicate methods are resolved as well
    as duplicate class level `@RabbitListener` annotations.
    **cherry-pick to 2.4.x** (will require instanceof polishing for Java 8)
    Resolves #2456
    When spying a `@RabbitListener` bean, duplicate methods are resolved as well
    as duplicate class level `@RabbitListener` annotations.
    **cherry-pick to 2.4.x** (will require instanceof polishing for Java 8)

    Thanks for the work, Gary and Artem.

    I wrote I found that issue in version 3.0.6, but it was the version of the pring-boot-starter-parent project. The version of the spring-amqp-dist project used there is 3.0.4, and of course, its modules, but the change is committed in the 3.0.5-SNAPSHOT.

    When will the modification be part of the spring-boot-starter-amqp?

    June 19, with Boot to follow a couple of days later.

    https://github.com/spring-projects/spring-amqp/milestones

    https://calendar.spring.io/

    The framework is intended for use with Spring Framework 5.3.
    However, this change was the only thing preventing it being used
    with 5.2.
    The framework is intended for use with Spring Framework 5.3.
    However, this change was the only thing preventing it being used
    with 5.2.