Spring boot JMS parsing json object handling method

Viewed 711

I have Spring Boot app that handles incoming ArtemisMQ

    @JmsListener(destination = "work-started")
    public fun workStarted(work: Work) {
        handleNewWork(work)
    }

I created MappingJackson2MessageConverter with default setup

    @Bean
    fun jacksonJmsMessageConverter(): MessageConverter? {
        val converter = MappingJackson2MessageConverter()
        converter.setTargetType(MessageType.OBJECT)
        // I don't receive class type
        converter.setTypeIdPropertyName("_type")
        return converter
    }

And application.properties

spring.artemis.mode=native
spring.artemis.host=localhost
spring.artemis.port=61616
spring.artemis.user=root
spring.artemis.password=root

I want Spring to parse message by the input object, in my case I have Work as an argument, which I expect to be parsed from json.

When I run it, I'm getting this error:

Caused by: org.springframework.jms.support.converter.MessageConversionException: Could not find type id property [_type] on message [null] from destination [ActiveMQQueue[work-started]]
    at org.springframework.jms.support.converter.MappingJackson2MessageConverter.getJavaTypeForMessage(MappingJackson2MessageConverter.java:456) ~[spring-jms-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.jms.support.converter.MappingJackson2MessageConverter.fromMessage(MappingJackson2MessageConverter.java:232) ~[spring-jms-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.jms.listener.adapter.AbstractAdaptableMessageListener.extractMessage(AbstractAdaptableMessageListener.java:251) ~[spring-jms-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.jms.listener.adapter.AbstractAdaptableMessageListener$MessagingMessageConverterAdapter.extractPayload(AbstractAdaptableMessageListener.java:476) ~[spring-jms-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.jms.listener.adapter.AbstractAdaptableMessageListener$MessagingMessageConverterAdapter$LazyResolutionMessage.unwrapPayload(AbstractAdaptableMessageListener.java:543) ~[spring-jms-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.jms.listener.adapter.AbstractAdaptableMessageListener$MessagingMessageConverterAdapter$LazyResolutionMessage.getPayload(AbstractAdaptableMessageListener.java:525) ~[spring-jms-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.messaging.handler.annotation.support.PayloadMethodArgumentResolver.resolveArgument(PayloadMethodArgumentResolver.java:116) ~[spring-messaging-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:117) ~[spring-messaging-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:148) ~[spring-messaging-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:116) ~[spring-messaging-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:114) ~[spring-jms-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    ... 10 common frames omitted

It's looking for _type property which is missing.

I did a small hack to check if my idea is correct. Here I map name of destination to Class, so that it later parses. But it feels like super wrong way of doing it.

val converter = object : MappingJackson2MessageConverter() {
            override fun getJavaTypeForMessage(message: Message): JavaType {
                var clazz :Class<*>? = null
                val jmsDestination = message.jmsDestination as ActiveMQQueue
                when(jmsDestination.address) {
                    "work-started" -> {
                        clazz = Work::class.java
                    }
                }
                if(clazz == null) {
                    return super.getJavaTypeForMessage(message)
                }
                return jacksonObjectMapper().typeFactory.constructType(clazz)
            }
        }

How can I resolve this by method argument or some annotation?

0 Answers
Related