22

I want to connect to a Sonic Broker Topic and Listen for any incoming XML message. I did something like below;

Application.java

@SpringBootApplication
@ComponentScan({"com.mainpack", "com.msgpack.jms"})
@EnableJms
public class Application extends SpringBootServletInitializer {

@Autowired
private JmsTopicListener jmsTopicListener;

@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
    return application.sources(Application.class);
}

@Override
public void onStartup(final ServletContext servletContext) throws ServletException {
    try {
        LogService.info(Application.class.getName(), "Starting Service...");
        super.onStartup(servletContext);
        jmsTopicListener.listenMessage();
        LogService.info(Application.class.getName(), "Service Started");
    } catch (Exception ex) {
        LogService.error(this.getClass().getName(), ex);
    }
}

public static void main(String[] args) {
    ApplicationContext context = SpringApplication.run(Application.class, args);
    LogService.info(Application.class.getName(), "Service Started...");
 }
}

JmsTopicListener.java

@Component
public class JmsTopicListener {

@Autowired
private ApplicationProperties properties;

@Autowired
private MsgListener msgListener;

public void listenMessage() {
    TopicConnectionFactory factory;
    TopicConnection connection = null;
    LogService.info(this.getClass().getName(), "Registering Broker Connection");
    try {
        factory = new progress.message.jclient.TopicConnectionFactory(properties.getBrokerURL());
        connection = factory.createTopicConnection(properties.getUserName(), properties.getPass());

        javax.jms.TopicSession subSession = (TopicSession) connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);

        javax.jms.Topic topic = subSession.createTopic(properties.getTopicName());
        MessageConsumer subscriber = subSession.createSubscriber(topic);
        subscriber.setMessageListener(msgListener);
        connection.start();
        LogService.info(this.getClass().getName(), "Broker connected");
    } catch (Exception ex) {
        LogService.error(this.getClass().getName(), ex);
    }
 }
}

MsgListener.java

@Component
public class MsgListener implements MessageListener {

@Override
public void onMessage(Message msg) {
    if (msg instanceof XMLMessage) {
        try {
            XMLMessage m = (XMLMessage) msg;
            if (m.getText().contains("Applications")) {
                LogService.info(this.getClass().getName(), "Recieved A Applications Message");
            } else {
                LogService.info(this.getClass().getName(), "Recieved Message Does not contain Applications Tag");
            }
        } catch (Exception ex) {
            LogService.info(this.getClass().getName(), "Exception: " + ex.getMessage());
        }
    }
 }
}

When, i run this code i get nullPointer at line jmsTopicListener.listenMessage() in Application.java.

What mistake i have made here? Is there a way i can improve this (I mean get the work done in less code maybe)?.

NOTE: com.mainpack have classes Application.java and ApplicationProp.java com.msgpack.jms have JmsTopicListener.java and MsgListner.java

Error From Logger:

ERROR [2015-07-14 14:34:52] [com.mainpack.Application] [localhost-startStop-1] - [Exception: ]java.lang.NullPointerException
    at com.mainpack.Application.onStartup(Application.java:33)
    at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:175)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5156)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:725)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:701)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:717)
    at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:945)
    at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1768)
    at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
5
  • can you print the full stack trace here
    – kuhajeyan
    Commented Jul 14, 2015 at 8:23
  • 1
    @kbird : Added the stack trace. Please see updated post. I get this in logger when i start the service in tomcat. Then nothing happens. Service doesn't run further. Commented Jul 14, 2015 at 9:08
  • As @SpringBootApplication is just a shortcut for @Configuration, @EnableAutoConfiguration and @ComponentScan this might already be your issue. You are trying to access an @Autowired resource in your Application class which is neither @Component, @Service, ... that would qualify for management by Spring and inject dependencies, afair. You should double check by running in --debug mode. Commented Jul 14, 2015 at 10:54
  • @hrrgttnchml : I have checked removing @SpringBootApplication, and adding @Configuration, @EnableAutoConfiguration. Same Exception. I dont understand why spring cannot Autowire that bean, cause JmsTopicListener is annotated with @Component already. Commented Jul 14, 2015 at 10:58
  • @Rajkishan: Yes, it is nice that you do have JmsTopicListener annotated with @Component but you also need to make the Application.class be aware that dependencies should be injected. @Configuration is as far as I remember not sufficient. You should also annotate it with @Component. But be aware of side effects. Commented Jul 14, 2015 at 11:01

2 Answers 2

40

onStartup is called by the servlet container very early in your application's lifecycle and is called on an instance of the class that was created by the servlet container, not Spring Boot. This is why jmsTopicListener is null.

Rather than overriding onStartup you could use a method annotated with @PostConstruct. It will be called by Spring once it's created an instance of Application and injected any dependencies:

@SpringBootApplication
@ComponentScan({"com.mainpack", "com.msgpack.jms"})
@EnableJms
public class Application extends SpringBootServletInitializer {

    @Autowired
    private JmsTopicListener jmsTopicListener;

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

    @PostConstruct
    public void listen() { 
        jmsTopicListener.listenMessage();
    }

    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(Application.class, args);
        LogService.info(Application.class.getName(), "Service Started...");
    }
}
4
  • When i deploy the application on tomcat, it doesnot use the main(). So i used the onStartUp() to give the "Application Service Started Message" on tomcat. If i dont use onStartUp(), is there a way i can give the message like "My Service Name" starting/started (successfully) or something similar? Commented Jul 14, 2015 at 12:13
  • 2
    Thank You. It works fine after i added the @PostConstruct. Commented Jul 14, 2015 at 12:59
  • Various events are published when the application starts. See the javadoc for some more details. You could listen for one (or more) of those. Doing so would work for either way of starting your application. Commented Jul 14, 2015 at 15:07
  • I added @PostConstruct it prints my value to console but when I open up local host I receive a null value?
    – JayC
    Commented Dec 7, 2016 at 16:20
3

Just add

@PostConstruct

method, and run the code from this method, it will work.

1
  • This worked for me. Commented Sep 22, 2023 at 16:56

Not the answer you're looking for? Browse other questions tagged or ask your own question.