2

My Spring Web App returns java.lang.NullPointerException when I try to use a service which is Autowired inside a component.

I tried solutions here but it didn't work for me since I am already using @component.

Here is my full exception:

java.lang.NullPointerException
    at ir.yasharne.rpi.websocket.MyStompSessionHandler.handleFrame(MyStompSessionHandler.java:81)
    at org.springframework.messaging.simp.stomp.DefaultStompSession.invokeHandler(DefaultStompSession.java:448)
    at org.springframework.messaging.simp.stomp.DefaultStompSession.handleMessage(DefaultStompSession.java:399)
    at org.springframework.web.socket.messaging.WebSocketStompClient$WebSocketTcpConnectionHandlerAdapter.handleMessage(WebSocketStompClient.java:342)
    at org.springframework.web.socket.sockjs.client.AbstractClientSockJsSession.handleMessageFrame(AbstractClientSockJsSession.java:271)
    at org.springframework.web.socket.sockjs.client.AbstractClientSockJsSession.handleFrame(AbstractClientSockJsSession.java:213)
    at org.springframework.web.socket.sockjs.client.WebSocketTransport$ClientSockJsWebSocketHandler.handleTextMessage(WebSocketTransport.java:162)
    at org.springframework.web.socket.handler.AbstractWebSocketHandler.handleMessage(AbstractWebSocketHandler.java:43)
    at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter.handleTextMessage(StandardWebSocketHandlerAdapter.java:110)
    at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter.access$000(StandardWebSocketHandlerAdapter.java:42)
    at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter$3.onMessage(StandardWebSocketHandlerAdapter.java:81)
    at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter$3.onMessage(StandardWebSocketHandlerAdapter.java:78)
    at org.apache.tomcat.websocket.WsFrameBase.sendMessageText(WsFrameBase.java:395)
    at org.apache.tomcat.websocket.WsFrameBase.processDataText(WsFrameBase.java:495)
    at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:294)
    at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:133)
    at org.apache.tomcat.websocket.WsFrameClient.processSocketRead(WsFrameClient.java:95)
    at org.apache.tomcat.websocket.WsFrameClient.resumeProcessing(WsFrameClient.java:209)
    at org.apache.tomcat.websocket.WsFrameClient.access$300(WsFrameClient.java:31)
    at org.apache.tomcat.websocket.WsFrameClient$WsFrameClientCompletionHandler.doResumeProcessing(WsFrameClient.java:186)
    at org.apache.tomcat.websocket.WsFrameClient$WsFrameClientCompletionHandler.completed(WsFrameClient.java:163)
    at org.apache.tomcat.websocket.WsFrameClient$WsFrameClientCompletionHandler.completed(WsFrameClient.java:148)
    at sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:126)
    at sun.nio.ch.Invoker$2.run(Invoker.java:218)
    at sun.nio.ch.AsynchronousChannelGroupImpl$1.run(AsynchronousChannelGroupImpl.java:112)
    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)

line 81 is moduleService.saveModule(module); in MyStompSessionHandler.java:

@Component
public class MyStompSessionHandler extends StompSessionHandlerAdapter {

    @Autowired
    private ModuleService moduleService;

    @Override
    public void afterConnected(StompSession session, StompHeaders connectedHeaders) {
        session.subscribe("/topic/messages", this);
    }

    @Override
    public Type getPayloadType(StompHeaders headers) {
        return ServerMessage.class;
    }

    @Override
    public void handleFrame(StompHeaders headers, Object payload) {
        ServerMessage message = (ServerMessage) payload;
        if (message.getTopic().equals("newModule")){
            ObjectMapper mapper = new ObjectMapper();
            try {
                Map<String, Object> readValue = mapper.readValue(message.getMessage(), Map.class);
                int id = (int) readValue.get("id");
                boolean programmable = (boolean) readValue.get("programmable");
                float value = Float.parseFloat(readValue.get("value").toString());
                Module module = new Module();
                module.setId(id);
                module.setProgrammable(programmable);
                module.setValue(value);
                moduleService.saveModule(module);
            } catch (IOException e) {
                System.out.println("HandlerFrame: ");
                e.printStackTrace();
            }
        }
    }

    @Override
    public void handleException(StompSession session, StompCommand command, StompHeaders headers, byte[] payload, Throwable exception) {
        exception.printStackTrace();
    }
}

and my WebAppConfiguration.java:

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "ir.yasharne.rpi")
public class WebAppConfiguration extends WebMvcConfigurerAdapter {

    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registery){
        registery.addResourceHandler("/static/**").addResourceLocations("/static/");
    }
}

ModuleServiceImpl.java:

@Service("moduleService")
@Transactional
public class ModuleServiceImpl implements ModuleService {

    @Autowired
    private ModuleDao moduleDao;

    @Override
    public void saveModule(Module module) {
        moduleDao.saveModule(module);
    }
}

How can I fix it?

BTW, I can Autowire and use moduleService inside of controller and use it with no problem

Yashar
  • 2,455
  • 3
  • 25
  • 31
  • What is the package of `ModuleServiceImpl` ? – Arnaud Aug 30 '17 at 09:37
  • @Berger `package ir.yasharne.rpi.service.impl;` – Yashar Aug 30 '17 at 09:40
  • I had same problems. Solved them with passing parameters to constructor. – Serg Shapoval Aug 30 '17 at 09:43
  • @Abdelhak I update my question, I can use it inside of controller so I think Component scan is not the problem – Yashar Aug 30 '17 at 09:44
  • can you set up a minimalistic example on github and post that? There doesnt seem to be anything missing in your code. You also say that you dont get the NPE when you use the service in your controller, so I suspect there is something with the DI in `MyStompSessionHandler `... though not sure.. A github code I could work with ..this is not enough – codeCruncher Aug 30 '17 at 09:52
  • An `@Autowired` field cannot be `null` in a Spring Managed bean. It can only be `null` if it isn't managed by Spring. So you must be doing `new MyStompSessionHandler()` in your code. – M. Deinum Aug 30 '17 at 10:09
  • @M.Deinum actually I did `new MyStompSessionHandler()` on contextInitialization and works fine until I try to use `moduleService` – Yashar Aug 30 '17 at 10:16
  • 1
    Don't create a new instance unless it is in a `@Bean` method (which makes it a Spring Bean). – M. Deinum Aug 30 '17 at 10:17
  • @M.Deinum creating new instance inside of Bean annotated method solved the problem. – Yashar Aug 30 '17 at 15:27
  • You don't need a new instance with a `@Bean` method. It already is a `@Component` and will be detected. – M. Deinum Aug 31 '17 at 05:51

1 Answers1

0

What's the package for MyStompSessionHandler? I'm guessing it's not covered under ir.yasharne.rpi. Try moving it under that package (ir.yasharne.rpi), or update @ComponentScan(basePackages = "ir.yasharne.rpi") to @ComponentScan(basePackages = {"ir.yasharne.rpi", "package.of.MyStompSessionHandler"})

I'm guessing MyStompSessionHandler is not on the "component scan" path and that's why autowired dependencies within it are not picked.

The Student Soul
  • 2,272
  • 2
  • 14
  • 12