I want to call a common service for all the controllers to get a commmon ModelAndView object with some common objects inside it.
So I created a superclass for all the controllers- BaseController, and I am initiating the common model object inside the constructor of BaseController by calling the a method, initCommonData which uses a @Autowired bean CommonDataService, which is not present at the construction time of object and returns null, so what I should do to get @autowired dependency inside constructor.
FYI - I am using this common servie and common data to get some commod data which will be used on each jsp in header and footer of the site. So if there is some another way of doing this without calling the common service in each controller method, in each controller please suggest. Here is my code - BaseController
@Controller
public class BaseController {
@Autowired
private CommonDataService commonDataService;
protected ModelAndView model;
public BaseController() {
this.initCommonData();
}
public void initCommonData(){
this.model = new ModelAndView();
this.model.addObject("headerData",commonDataService.getHeaderData());
this.model.addObject("footerData",commonDataService.getFooterData());
}
subclass controller -
@Controller
public class HomeController extends BaseController {
@Autowired
CategoryService categoryService;
@Autowired
CompanyService companyService;
@RequestMapping(value = { "", "/", "home" })
public ModelAndView homePage() {
model.setViewName("home");
.
.
.
model.addObject("name", value);
model.addObject("name2", value2);
return model;
}
CommonServiceClass -
@Service
public class CommonDataService {
@Autowired
CompanyService companyService;
@Autowired
CategoryService categoryService;
@Cacheable
public List<Category> getHeaderData(){
return categoryService.getTopCategoryList();
}
@Cacheable
public List<Company> getFooterData(){
return companyService.getTopCompanyList();
}
Please suggest if there is any other good way of doing this, getting common data from server to jsp.
Whatever @Andreas has suggested is the best solution i.e., mark your BaseController as abstract and use @Postconstruct. This makes perfect scense because BaseController itself does not own any url mappings in your case, so do not mark it as @Controller
Because of any reason, if you are looking for other options, you can consider marking your BaseController as @Component and use @Postconstruct for initCommonData so that this method will be called automatically once the BaseController bean has been loaded by the spring container:
@Component
public class BaseController {
@Autowired
private CommonDataService commonDataService;
protected ModelAndView model;
@Postconstruct
public void initCommonData(){
this.model = new ModelAndView();
this.model.addObject("headerData",commonDataService.getHeaderData());
this.model.addObject("footerData",commonDataService.getFooterData());
}
}
First, remove @Controller from your base class. You might even make the class abstract to help indicate/document that it must be subclassed.
Next, don't call initCommonData() from the constructor. Spring cannot inject field values until after the object is created, so there is no way for Spring to wire in commonDataService before constructor completes.
Instead, annotate initCommonData() with @PostConstruct:
public class BaseController {
@Autowired
private CommonDataService commonDataService;
protected ModelAndView model;
@PostConstruct
public void initCommonData(){
this.model = new ModelAndView();
this.model.addObject("headerData",commonDataService.getHeaderData());
this.model.addObject("footerData",commonDataService.getFooterData());
}