Spring mappingjackson2messageconverter give null pointer exception
Asked Answered
R

4

6

I'm trying to convert a java object to json format using mappingjackson2messageconvertor but looks like it is not converting to json object instead throwing nullpoint exception error. Wondering what i'm doing wrong.

I have checked one of the example here . But i'm not using rabbitmq instead of i'm using activemq.

source

@SpringBootApplication
@EnableJms
public class Application {
    @Bean
    JmsListenerContainerFactory<?> myJmsContainerFactory(ConnectionFactory connectionFactory) {
        SimpleJmsListenerContainerFactory factory = new SimpleJmsListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setMessageConverter(new MappingJackson2MessageConverter());
        return factory;
    }


    public static void main(String[] args) {
        // Clean out any ActiveMQ data from a previous run
        FileSystemUtils.deleteRecursively(new File("activemq-data"));

        // Launch the application
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
        AssetApi asset = new AssetApi();
        asset.setBroadcasterId("test");
        asset.setNotes("test");

        // Send a message
        MessageCreator messageCreator = new MessageCreator() {
            @Override
            public Message createMessage(Session session) throws JMSException {
                MessageConverter message = new MappingJackson2MessageConverter();
                return message.toMessage(asset, session);
            }
        };
        JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
        System.out.println("Sending a new message.");
        jmsTemplate.send("mailbox-destination", messageCreator);
    }
}

Error

java.lang.NullPointerException: null
    at org.apache.activemq.command.ActiveMQMessage.getStringProperty(ActiveMQMessage.java:676)
    at org.springframework.jms.support.converter.MappingJackson2MessageConverter.getJavaTypeForMessage(MappingJackson2MessageConverter.java:377)
    at org.springframework.jms.support.converter.MappingJackson2MessageConverter.fromMessage(MappingJackson2MessageConverter.java:195)
    at org.springframework.jms.listener.adapter.AbstractAdaptableMessageListener.extractMessage(AbstractAdaptableMessageListener.java:215)
    at org.springframework.jms.listener.adapter.AbstractAdaptableMessageListener$MessagingMessageConverterAdapter.extractPayload(AbstractAdaptableMessageListener.java:397)
    at org.springframework.jms.support.converter.MessagingMessageConverter.fromMessage(MessagingMessageConverter.java:108)
    at org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter.toMessagingMessage(MessagingMessageListenerAdapter.java:77)
    at org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.java:62)
    at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:678)
    at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:638)
    at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:608)
    at org.springframework.jms.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:579)
    at org.springframework.jms.listener.SimpleMessageListenerContainer.processMessage(SimpleMessageListenerContainer.java:329)
    at org.springframework.jms.listener.SimpleMessageListenerContainer$2.onMessage(SimpleMessageListenerContainer.java:305)
    at org.apache.activemq.ActiveMQMessageConsumer.dispatch(ActiveMQMessageConsumer.java:1390)
    at org.apache.activemq.ActiveMQSessionExecutor.dispatch(ActiveMQSessionExecutor.java:131)
    at org.apache.activemq.ActiveMQSessionExecutor.iterate(ActiveMQSessionExecutor.java:202)
    at org.apache.activemq.thread.PooledTaskRunner.runTask(PooledTaskRunner.java:133)
    at org.apache.activemq.thread.PooledTaskRunner$1.run(PooledTaskRunner.java:48)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Reprobative answered 3/9, 2015 at 20:42 Comment(0)
H
3

With the JMS converter, you need to tell the converter what type (id) you want to create from the JSON.

You do that by telling it which JMS property (header) contains the type id).

There is then a Map from type ids to class names.

Or you can subclass and override getJavaTypeForMessage().

See the javadoc for method getJavaTypeForMessage() on the converter.

Heaves answered 3/9, 2015 at 21:30 Comment(3)
converter.setTypeIdPropertyName(AssetApi.class.getName()); Will this work?Reprobative
No; it needs the name of a header in the message with a type id, that maps to a class. Or, you need to subclass the converter and provide your own implementation.Heaves
This is only half a solution, because getJavaTypeForMesssage() returns an abstract class.Caelum
L
1

I did as Gary Russell pointed out, from my calling class

Map<String, Class<?>> typeIdMappings = new HashMap<String, Class<?>>();
typeIdMappings.put("JMSType",Audit.class);
mappingJackson2MessageConverter.setTypeIdMappings(typeIdMappings);
mappingJackson2MessageConverter.setTypeIdPropertyName("JMSType"); 
Audit audit = (Audit) mappingJackson2MessageConverter.fromMessage(message);

Then I overrode the MappingJackson2MessageConverter's methods:

@Component
public class MecMappingJackson2MessageConverter extends MappingJackson2MessageConverter {

    private Map<String, Class<?>> idClassMappings = new HashMap<String, Class<?>>();

    private Map<Class<?>, String> classIdMappings = new HashMap<Class<?>, String>();

    private ObjectMapper objectMapper = new ObjectMapper();

    private ClassLoader beanClassLoader;

    @Override
    public JavaType getJavaTypeForMessage(Message message){

        Class<?> mappedClass = this.idClassMappings.get("JMSType");
    if (mappedClass != null) {
        return this.objectMapper.getTypeFactory().constructType(mappedClass);
    }
    try {
        Class<?> typeClass = ClassUtils.forName("JMSType", this.beanClassLoader);
            return this.objectMapper.getTypeFactory().constructType(typeClass);
        }
        catch (Throwable ex) {
            throw new MessageConversionException("Failed to resolve type id [" + "JMSType" + "]", ex);
        }

    }

    @Override
    public void setTypeIdMappings(Map<String, Class<?>> typeIdMappings) {
        this.idClassMappings = new HashMap<String, Class<?>>();
        for (Map.Entry<String, Class<?>> entry : typeIdMappings.entrySet()) {
            String id = entry.getKey();
            Class<?> clazz = entry.getValue();
        this.idClassMappings.put(id, clazz);
        this.classIdMappings.put(clazz, id);
    }
}

}

Louanneloucks answered 11/9, 2015 at 21:9 Comment(2)
What is your beanClassLoader?Esque
The beanClassLoader is JMSType. I updated the code in my response.Louanneloucks
U
0

I had created my own de-serialzer and set the same in my MappingJackson2MessageConverter object like below

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(WebResponse.class,new WebResponseDeserializer());
mapper.registerModule(module);
new MappingJackson2MessageConverter().setObjectMapper(mapper);

Where WebResponseDeserializer extends com.fasterxml.jackson.databind.JsonDeserializer to provide custom way of unmarshalling of my json object

Unstrung answered 14/3, 2016 at 5:45 Comment(0)
V
0

You just need to call setTypeIdPropertyName on your message converter and pass the desired name for message header where message converter will hold the class name of your pojo.

Vivien answered 25/8, 2016 at 10:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.