Search code examples
spring-mvcspring-mvc-test

Spring 4.3.6 Can't inject bean into controller


I'm unable to put data in model because Spring doesn't wire bean to controller, reference is null. Bean interface and implementation in same package as controller. I tried to list available beans through implementing ApplicationContextAware in controller(also tried in test with output to console in method setApplicationContext, but method doesn't invoked, there was no output) but it's also null. I use automatic configuration, implementation of interface which used as a bean annotated with @Component, @ComponentScan enabled in servlet config class. This is controller:

package webapp.mvc;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;



@Controller
public class HomeController implements ApplicationContextAware {

    public QuoteResource quoteResource;


    public ApplicationContext context;

    public HomeController() {
    }

    @Autowired
    public HomeController(QuoteResource resource) {
        this.quoteResource = resource;
        System.out.println("Constructor with resource triggered");
    }

    @RequestMapping(value="/", method=RequestMethod.GET)
    public String home(){
        System.out.println("Controller triggered");
        return "home";
    }

    @RequestMapping(value="/random", method=RequestMethod.GET)
    public String randomQuotes(Model model){
        model.addAttribute("randomQuote", quoteResource.getQuote());
        return "random";
    }

    @Autowired
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;      
    }

}

When I launch test is prints "Resource is null: true Start test Constructor with resource triggered" and fails with nullPointerException in line model.addAttribute("randomQuote", quoteResource.getQuote()); This is test:

package spr1;

import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.servlet.view.InternalResourceView;

import webapp.mvc.HomeController;
import webapp.mvc.QuoteResource;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*;


public class RandomQuoteTest {

    @Autowired
    public QuoteResource resource;

    @Before
    public void initObjects() {
        System.out.println("Resource is null:");
        System.out.println(resource == null);
    }

    @Test
    public void test() throws Exception {
        System.out.println("Start test");
        HomeController controller = new HomeController(resource);
        MockMvc mvc = standaloneSetup(controller)
                .setSingleView(new InternalResourceView("src/main/webapp/views/random.jsp"))
                .build();
        mvc.perform(get("/random"))
        .andExpect(view().name("random"));
    }

}

QuoteResource is interface with one implementation which annotated with @Component, but it's constructor doesn't invoked(I write to console in constructor)


Solution

  • It seems like @Autowired doesn't work in mvc tests. It works if controller created manually HomeController controller = new HomeController(new XmlQuoteResource()); without autowiring QuoteResource. Found solution in spring-mvc-showcase in redirect example.