[에러 해결] RabbitMQ com.fasterxml.jackson.databind.exc.MismatchedInputException

이재훈·2023년 6월 1일
0

삽질모음집

목록 보기
2/8

해당 에러는 다양한 경우에 발생하는 에러입니다.
일단 에러로그 투척

Caused by: org.springframework.amqp.support.converter.MessageConversionException: Failed to convert Message content
	at org.springframework.amqp.support.converter.AbstractJackson2MessageConverter.doFromMessage(AbstractJackson2MessageConverter.java:350) ~[spring-amqp-2.4.5.jar:2.4.5]
	at org.springframework.amqp.support.converter.AbstractJackson2MessageConverter.fromMessage(AbstractJackson2MessageConverter.java:309) ~[spring-amqp-2.4.5.jar:2.4.5]
	at org.springframework.amqp.support.converter.AbstractJackson2MessageConverter.fromMessage(AbstractJackson2MessageConverter.java:292) ~[spring-amqp-2.4.5.jar:2.4.5]
	at org.springframework.amqp.rabbit.listener.adapter.AbstractAdaptableMessageListener.extractMessage(AbstractAdaptableMessageListener.java:342) ~[spring-rabbit-2.4.5.jar:2.4.5]
	at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter$MessagingMessageConverterAdapter.extractPayload(MessagingMessageListenerAdapter.java:366) ~[spring-rabbit-2.4.5.jar:2.4.5]
	at org.springframework.amqp.support.converter.MessagingMessageConverter.fromMessage(MessagingMessageConverter.java:132) ~[spring-amqp-2.4.5.jar:2.4.5]
	at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.toMessagingMessage(MessagingMessageListenerAdapter.java:243) ~[spring-rabbit-2.4.5.jar:2.4.5]
	at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.java:146) ~[spring-rabbit-2.4.5.jar:2.4.5]
	... 11 common frames omitted
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `java.lang.String` from Object value (token `JsonToken.START_OBJECT`)

그리고 그 해당 에러가 발생하는 코드입니다.

@RabbitListener(queues = "#{@syncQueue}")
public String received(String message) throws JsonProcessingException {

	// ... 내용 생략
}

제가 커스텀한 큐로 메세지가 받는데 String 으로 conversion이 실패하여 에러가 발생하였습니다. Dto 객체로 값을 받으면 conversion이 실패하지 않습니다. 이유는 무엇일까요?

@RabbitListener 로 데이터를 받을 때 자동으로 메시지 컨버터가 작동하기 때문입니다.

해결 방법

RabbitListenerContainerFactory에 MessageConverter를 null로 지정해주면 메시지 컨버터가 작동하고 string 값으로 받을 수 있습니다.

MyQueueConfig.java

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@RequiredArgsConstructor
@Slf4j
public class SyncQueueConfig {

    @Value("${rabbitmq.host}")
    private String host;

    @Value("${rabbitmq.port}")
    private int port;

    @Value("${rabbitmq.username}")
    private String userName;

    @Value("${rabbitmq.password}")
    private String password;

    private final Jackson2JsonMessageConverter messageConverter;
    private final String exchangeName = "exchange.command.sync";
    private final String routingKey = "myroutingKey";
    private final String queueName = "queue.sync";

    @Bean
    public TopicExchange topicExchange() {
        return new TopicExchange(exchangeName);
    }

    @Bean
    public Queue syncQueue() {
        return new Queue(queueName, true, false, false);
    }

    @Bean
    public Binding syncBinding(Queue queue, TopicExchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(routingKey);
    }

    @Bean
    public ConnectionFactory connectionFactory() {
        var connectionFactory = new CachingConnectionFactory(host, port);
        connectionFactory.setUsername(userName);
        connectionFactory.setPassword(password);
        return connectionFactory;
    }

    @Bean
    public RabbitTemplate rabbitTemplate() {
        var rabbitTemplate = new RabbitTemplate(connectionFactory());
        rabbitTemplate.setMessageConverter(messageConverter);
        return rabbitTemplate;
    }

    @Bean
    public RabbitListenerContainerFactory<?> rabbitListenerContainerFactory() {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory());
        factory.setMessageConverter(null);
        return factory;
    }

}

마지막 bean 설정을 추가해주면 됩니다.

profile
부족함을 인정하고 노력하자

0개의 댓글