Search code examples
springspring-mvcwebsocketspring-websocketspring-messaging

Spring MVC can't access @Autowired fields from @MessageMapping annotated methods


I've been setting up my Spring 4 MVC application to work with STOMP over WebSocket and so far i've succeeded, my servlet can handle and dispatch STOMP messages without problems.

However, i've encountered an annoying problem when handling these messages from @MessageMapping annotated methods inside my controllers: I can't access any of the @Autowired controller's fields from inside these methods (they all are null pointers), but i can access these fields on the same controller from @RequestMapping annotated methods without any problem.

My Dispatcher Servlet Config:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:oxm="http://www.springframework.org/schema/oxm"
    xmlns:security="http://www.springframework.org/schema/security"
    xmlns:websocket="http://www.springframework.org/schema/websocket"
    xsi:schemaLocation="http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-4.0.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket-4.0.xsd">


    <mvc:annotation-driven/>
    <mvc:resources location="assets" mapping="/assets/**"/>
    <mvc:resources location="assets/img/favicon.ico" mapping="/favicon.ico" />

    <context:component-scan base-package="com.company.web.controller"/>

    <security:global-method-security pre-post-annotations="enabled" />

    <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        <property name="order" value="1" />
        <property name="contentNegotiationManager">
            <bean class="org.springframework.web.accept.ContentNegotiationManager">
                <constructor-arg>
                    <bean class="org.springframework.web.accept.PathExtensionContentNegotiationStrategy">
                        <constructor-arg>
                            <map>
                                <entry key="json" value="application/json" />
                                <entry key="xml" value="application/xml" />
                            </map>
                        </constructor-arg>
                    </bean>
                </constructor-arg>
            </bean>
        </property>

    </bean>

    <mvc:interceptors>
        <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" p:paramName="language"/>
        <bean class="com.hxplus.web.interceptor.aCustomAwesomeInterceptor"/>
    </mvc:interceptors>

    <bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver" p:defaultLocale="es"/>

    <bean id="messageSource" 
    class="org.springframework.context.support.ResourceBundleMessageSource" 
    p:basename="messages"></bean>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" 
     p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" p:order="2"/>

     <bean class="org.springframework.web.servlet.view.BeanNameViewResolver" p:order="0"/>

     <bean id="multipartResolver"
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

         <!-- setting maximum upload size -->
        <property name="maxUploadSize" value="${upload.limit}" />

    </bean>

    <context:property-placeholder location="classpath*:upload_config.properties"/>

    <websocket:message-broker application-destination-prefix="/app">
        <websocket:stomp-endpoint path="/hello/{recipient}">
            <websocket:sockjs/>
        </websocket:stomp-endpoint>
        <websocket:simple-broker prefix="/topic" />
    </websocket:message-broker>

</beans>

My Controller:

@Controller
public class TheController {
    private static final Logger _logger = LoggerFactory.getLogger(TheController.class);

    @Autowired private TheService theService;
    @Autowired private SimpMessagingTemplate simpMessagingTemplate;

    @PreAuthorize("hasRole('GOD')")
    @RequestMapping(value = "/something/{id}", method = RequestMethod.GET)
    public String show(Model model, @PathVariable("id") Long id) {
        //HERE I CAN ACCESS BOTH "theService" AND
        //"simpMessagingTemplate" WITHOUT PROBLEMS
    }

    @MessageMapping("/hello/{recipient}")
    private VOID testing(StompEvent event, @DestinationVariable String recipient){
        //HERE BOTH "theService" AND "simpMessagingTemplate" ARE NULL
    }
}

Solution

  • I found my error and it had nothing to do with Spring Messaging or configuration, it was a pretty dumb error actually so i apologize:

    My @MessageMapping annotated method was private and it should have been public.