spring-integrationspring-integration-dslspring-integration-amqp

SimpleMessageListenerContainer - ClassNotFoundException warning on AMQP receive message


I have just updated my application to version spring-integration-amqp-5.2.4.RELEASE and when I receive message from queue everything works fine, but I noticed warning java.lang.ClassNotFoundException in DefaultAmqpHeaderMapper class. I use custom DefaultJackson2JavaTypeMapper with IdClassMapping. How can I avoid tracking the warning?

@Bean
public Jackson2JavaTypeMapper defaultJackson2JavaTypeMapper() {
    DefaultJackson2JavaTypeMapper defaultJackson2JavaTypeMapper = new DefaultJackson2JavaTypeMapper();
    Map<String, Class<?>> classMapping = new HashMap<>();
    classMapping.put("event.request", RequestDTO.class);
    defaultJackson2JavaTypeMapper.setIdClassMapping(classMapping);
    return defaultJackson2JavaTypeMapper;
}

@Bean
public MessageConverter messageConverterJson(ObjectMapper objectMapper) {
    Jackson2JsonMessageConverter messageConverter = new Jackson2JsonMessageConverter(objectMapper);
    messageConverter.setJavaTypeMapper(defaultJackson2JavaTypeMapper());
    return messageConverter;
}

LOG warning

o.s.i.a.support.DefaultAmqpHeaderMapper  : error occurred while mapping from AMQP properties to MessageHeaders

java.lang.IllegalStateException: java.lang.ClassNotFoundException: event.request
    at org.springframework.integration.mapping.support.JsonHeaders.getClassForValue(JsonHeaders.java:89)
    at org.springframework.integration.mapping.support.JsonHeaders.buildResolvableType(JsonHeaders.java:72)
    at org.springframework.integration.amqp.support.DefaultAmqpHeaderMapper.createJsonResolvableTypHeaderInAny(DefaultAmqpHeaderMapper.java:169)
    at org.springframework.integration.amqp.support.DefaultAmqpHeaderMapper.extractStandardHeaders(DefaultAmqpHeaderMapper.java:155)
    at org.springframework.integration.amqp.support.DefaultAmqpHeaderMapper.extractStandardHeaders(DefaultAmqpHeaderMapper.java:61)
    at org.springframework.integration.mapping.AbstractHeaderMapper.toHeaders(AbstractHeaderMapper.java:266)
    at org.springframework.integration.mapping.AbstractHeaderMapper.toHeadersFromRequest(AbstractHeaderMapper.java:203)
    at org.springframework.integration.amqp.support.DefaultAmqpHeaderMapper.toHeadersFromRequest(DefaultAmqpHeaderMapper.java:337)
    at org.springframework.integration.amqp.support.DefaultAmqpHeaderMapper.toHeadersFromRequest(DefaultAmqpHeaderMapper.java:61)
    at org.springframework.integration.amqp.inbound.AmqpInboundGateway$Listener.convert(AmqpInboundGateway.java:351)
    at org.springframework.integration.amqp.inbound.AmqpInboundGateway$Listener.onMessage(AmqpInboundGateway.java:314)
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1579)
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.actualInvokeListener(AbstractMessageListenerContainer.java:1498)
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:1486)
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:1477)
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:1421)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:963)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:913)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1600(SimpleMessageListenerContainer.java:81)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.mainLoop(SimpleMessageListenerContainer.java:1284)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1190)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.ClassNotFoundException: event.request
    at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:92)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)
    at org.springframework.util.ClassUtils.forName(ClassUtils.java:282)
    at org.springframework.integration.mapping.support.JsonHeaders.getClassForValue(JsonHeaders.java:86)
    ... 21 common frames omitted

Solution

  • Since you have already mapped an AMQP message into the target payload via Jackson2JsonMessageConverter, it looks like you don't need any incoming headers at all.

    To avoid that warning and extra mapping job, I suggest you to inject a custom AmqpHeaderMapper. Probably just an extension to the DefaultAmqpHeaderMapper, when you return an empty headers for mapping from request:

    amqpInboundGateway.setHeaderMapper(new DefaultAmqpHeaderMapper(null, null) {
    
            @Override
            public Map<String, Object> toHeadersFromRequest(MessageProperties source) {
                return new HashMap<>();
            }
    
        });
    

    On the other hand it is just a WARN: you can simply decrease logging level to ERROR for that org.springframework.integration.amqp.inbound category.

    The point is that we can't just ignore such an error if we can't find a class for the __Type__ header. The framework can't make an assumption what you expect.

    Another possible way to fix is to remove those JSON header from the MessageProperties.getHeaders() in the Jackson2JsonMessageConverter extension when you override fromMessage().