We are using Spring MCV and i am trying to use spring auto wiring to decouple my code. however, autowiring is not happening at all. Can you please suggest any issue in following code/ dispatcher
dispatcher-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd"
xmlns:context="http://www.springframework.org/schema/context">
<context:component-scan base-package="com.eos.accounts" />
</beans>
User.java
package com.eos.accounts.data;
#Service
public class User {
.......
#Autowired
public UserMilesHelper userMilesHelper ;
.....
public static setUserPoints(User user){
user.setPoints(user.userMilesHelper.getUserPoints(user.getUserId()));
}
IUserMilesHelper.java
package com.eos.accounts.data;
public interface IUserMilesHelper {
public int getUserPoints(int userId);
}
UserMilesHelper.java
package com.eos.accounts.data;
import org.springframework.stereotype.Component;
//I have used #Repository or Qualifier etc, no avail
#Component
public class UserMilesHelper implements IUserMilesHelper {
#Override
public int getUserPoints(int userId) {
return 10;
}
}
Web.xml
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>throwExceptionIfNoHandlerFound</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>50</load-on-startup>
</servlet>
your User.java class have to be annotated with #Component too or any of its children for ex.
#Controller
#Service
#RestController
Spring initiliaze component in his context by scanning packages and looking for class annoted with stereotypes (#Controller, #Service, #Repository....) or by explicit instantiation with manually adding a bean. If you use a the new it won't call Spring initilization mecanism and won't inject the dependancy.
I suppose your User class is not a singleton class so you should add #Scope("prototype") and use applicationContext.getBean(User.class) to instantiate with dependancy.
But to be honest i would instead refactor the code to avoid public members and static method to set variable and have class like that:
#Service
public class UserService{
private IUserMilesHelper userHelper;
#Autowired
public UserService(IUserMilesHelper userHelper){
this.userHelper = userHelper:
}
public setUserPoints(User user){
user.setPoints(userHelper.getUserPoints(user.getUserId()));
}
}
By default, the name of the dispatcher servlet is xxx-servlet.xml where xxx is the servlet name. Which means that the spring is looking for dispatcher-servlet.xml, which is not the name of your XML config.
Thus the context itself is not loaded for you. Change it and test.
Apart from that, make sure that you follow best practises. Autowire on interfaces rather than on concrete class. Quick link for you - Spring: Why do we autowire the interface and not the implemented class?
pleae change <context:component-scan base-package="com.eos.accounts" /> to
<context:component-scan base-package="com.eos.accounts.*" />
give it a try and let me know the result.
hope it helps.
Related
In a simple spring application you register your bean in the spring IoC container by using #Component annotation and then to retrieve the bean you first read the spring configuration file and then retrieve the bean from container using:
ClassPathXMLApplicationContext context = new ClassPathXMLApplicationContext("spring config file")
Coach theCoach=context.getBean("beanId","classname")
Now, you can call the methods on theCoach.
How are we retrieving the bean from the container as we are not using
context.getBean();
Is the DispatcherServlet handling this?
After editing-
/*********************Spring Application*******************************/
applicationContext.xml
<beans _______>
<context:component-scan base-package="packageName"/>
</beans>
Coach.java
public interface Coach{
public String getDailyWorkOut();
}
TennisCoach.java
#Component
public class TennisCoach implements Coach{
public String getDailyWorkOut(){
return "practise back hand volley";
}
ApplicationDemo.java
public class ApplicationDemo{
public static void main(String[] args){
ClassPathXMLApplicationContext context = new ClassPathXMLApplicationContext("applicationContext.xml");
Coach theCoach=context.getBean("tennisCoach",Coach.class)
theCoach.getDailyWorkOut();
}
}
/*********************Spring Application*******************************/
Now for Spring MVC-
/*****************Spring-MVC Application**************************/
web.xml
<web-app>
<servlet>
<servlet-name>HelloWeb</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>contextConfigurationLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>HelloWeb</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
applicationContext.xml
<beans _______>
<context:component-scan base-package="packageName"/>
</beans>
Coach.java
public interface Coach{
public String getDailyWorkOut();
}
TennisCoach.java
#Component
public class TennisCoach implements Coach{
#RequestMapping("/")
public String getDailyWorkOut(){
return "practise back hand volley";
}
/*********************Spring-MVC Application*********************/
What I want to know is -
That in above given spring application I am retrieving bean from the container using context.getBean(), how is the Coach bean being retrieved in Spring-MVC application?
Yes, you can just create field with annotation #Autowired and spring inject it for you. Make sure your class where you are going to use this bean is also spring bean.
In you example you are retrieving bean via bean lookup from ApplicationContext.
Coach theCoach=context.getBean("tennisCoach",Coach.class)
In this case you know exact class name you need(such you are an author of your bean), and you simply get it from the context.
For DispatcherServlet it is not so easy, because it knows nothing about beans you've added to the context.
The only option it has is a full scanning of all defined in the context beans and detecting anything it can recognise (Controller, RestController, RequestMapping). Example of such detector is AbstractDetectingUrlHandlerMapping with it's implementations. SpringMvc has various implementations of such detectors, you can implement your own if you need.
Say I have a RestController:
#RestController
#RequestMapping("path")
public class MyRestController {
#GetMapping("path")
public void myMethod(final MyObject object) throws Exception {
...
}
}
By default Spring uses getters and setters to set fields values for the object variable.
How can I specify to use direct field access?
I've tried with a custom Configuration class, but it doesn't work.
#Configuration
public class CustomWebMvcConfigurationSupport extends WebMvcConfigurationSupport {
#Override
protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
final ConfigurableWebBindingInitializer initializer = super.getConfigurableWebBindingInitializer();
initializer.setDirectFieldAccess(true);
return initializer;
}
}
When working on projects you don't know very well keep an eye on every XML file. When working with a mixture of XML and Java configurations something may not work as expected (especially if you haven't read the Spring documentation carefully).
Basically if you've defined an XML configuration like:
<?xml version="1.0" encoding="UTF-8"?>
<beans ... [skipped]>
<description>Spring XML configuration</description>
<mvc:annotation-driven />
<context:component-scan base-package="com.my.package" />
</beans>
And you try customizing the web configuration extending WebMvcConfigurationSupport:
#Configuration
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
#Override
protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
final ConfigurableWebBindingInitializer initializer = super.getConfigurableWebBindingInitializer();
initializer.setDirectFieldAccess(true);
return initializer;
}
}
You're basically dealing with two different instances, one created by Spring using the XML description, and one created by WebMvcConfiguration.
I solved using only the Java configuration.
So, by coding your web.xml file this way, you can delete entirely the XML configuration. You can see I specified I want an Annotation configuration for the contextClass parameter, and my configuration class for the contextConfigLocation parameter
<servlet>
<servlet-name>SpringDispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.my.package.WebMvcConfiguration</param-value>
</init-param>
</servlet>
Remember to add the #ComponentScan annotation to the Java class:
#ComponentScan("com.my.package")
I could use some help testing the authentication (using spring authentication) of my spring REST endpoints.
I have defined some endpoints requiring authentication using the following annotation #PreAuthorize("isAuthenticated()").
This seems to be working, because when I start a webserver and go to the URL I'm asked to authenticate, after which I get the proper results.
I run into trouble with my tests.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = TestContext.class)
#WebAppConfiguration
public class ControllerTest {
#Autowired
private WebApplicationContext context;
private MockMvc mvc;
#Before
public void setup() {
mvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
#Test
public void testGetMethod() throws Exception {
mvc
.perform(get("/a-valid-url")
.accept(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isUnauthorized());
}
}
The TestContext class contains some autowired classes in the controller which are mocked, like this:
#Configuration
public class TestContext {
#Bean
public ClassToMock autowiredClass() {
return Mockito.mock(ClassToMock.class);
}
}
When run like this I get the following error:
java.lang.IllegalStateException: springSecurityFilterChain cannot be null. Ensure a Bean with the name springSecurityFilterChain implementing Filter is present or inject the Filter to be used.
The only solution I have found thus far to get everything running is by adding a springSecurityFilterChain bean in the TestContext class, like this:
#Bean
public Filter springSecurityFilterChain() {
return Mockito.mock(Filter.class);
}
However then I always get a Status = 200, even when I use an URL that is not defined in the controller.
If anyone could point me in the right direction it would be much appreciated!
Edit: Some of the configuration of the project.
web.xml
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
The project has another project as a dependency which contains the TokenContext and AuthenticationStatelessContext configuration XML files.
TokenContext.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd" >
<context:component-scan base-package="com.example.auth.service" resource-pattern="TokenServiceImpl.class"/>
<context:component-scan base-package="com.example.auth.service" resource-pattern="ActorRolServiceImpl.class"/>
</beans>
The AuthenticationStatelessContext.xml defines the following spring beans: DefaultMethodSecurityExpressionHandler, PreAuthenticatedAuthenticationProvider and UserDetailsByNameServiceWrapper.
Update:
Created a class named TestContext2:
#Configuration
#ImportResource({
"classpath:**/AuthenticationStatelessContext.xml",
"classpath:**/TokenContext.xml"})
public class TestContext2 {
}
And added that class to the test
#ContextConfiguration(classes = {TestContext.class, TestContext2.class})
This because spring doesn't allow loading of classes and xml files at the same time in the #ContextConfiguration annotation.
When I try to run the test I still get the following error:
java.lang.IllegalStateException: springSecurityFilterChain cannot be null.
PS: The used springframework version is 4.1.3 and the spring-security version is 4.0.4.
It is wrong to mock the Filter interface to inject a springSecurityFilterChain bean.
What you want is to inject a filter chain with atleast one authentication filter, e.g. UsernamePasswordAuthenticationFilter
CasAuthenticationFilter
BasicAuthenticationFilter.
Read this spring security filter chain guide to understand which filters to inject for your purpose.
Right now mockito is setting a filter on the springSecurityFilterChain that allows all urls and does not provide the intended filtering behaviour.
The fix could be as easy as including a referrence to the correct app context along with TestContext on the Test class, depends on how you have defined the context for the rest of the application. I suspect a filter chain bean may be available for auto wiring as well.
Update:
Tell spring to load the TokenContext and AuthenticationStatelessContext here:
#ContextConfiguration(classes = TestContext.class)
Remove any code to define security filter chain bean in TestContext
Is it possible to use #Value inside a class that extends another class?
Below are the relevant code snippets. In the Lo_Controller class it works perfectly, but in the Lo_DisplayHandler always returns null. The only reason I can think of is because it depends on another class, which is not annotated with #Component. If that is the cause, what is the recommended option to read a value from properties file similar to #Value?
Just to test it out, I changed from #Component to #Controller in Lo_DisplayHandler to see, if they are somehow related to each other, however it returns null as well.
This works:
package com.ma.common.controller;
imports ...
#Controller
#RequestMapping("/log")
public class Lo_Controller {
#Value("${log.display.lastpage}")
private String lastPageUrl;
...
This always returns null:
package com.ma.log.handler;
imports ...
#Component
public class Lo_DisplayHandler extends Lo_Handler {
public Lo_DisplayHandler() {
super();
}
#Value("${log.display.lastpage}")
private String lastPageUrl;
...
mvc-dispatcher-servlet.xml
<context:component-scan base-package="com.ma.common.controller, com.ma.log.handler" />
<context:property-placeholder location="classpath:restServices.properties"/>
<mvc:annotation-driven />
<mvc:resources mapping="/**" location="/" />
#Component
public class Lo_DisplayHandler extends Lo_Handler {
#Value("${log.display.lastpage}")
private String lastPageUrl;
public void anyOtherMethod(){
String _a = lastPageUrl; //FAIL - always null
}
#PostConstruct
public void initIt() throws Exception {
String _a = lastPageUrl; //OK - when the application is deployed and started for the first time
}
#PreDestroy
public void cleanUp() throws Exception {
String _a = lastPageUrl; //OK - when the application is stopped
}
web.xml
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Three possible problems here:
First, I disencourage to extends classes as Spring works better autowiring dependencies. But it should work
Second, you have to focus on the lifecycle of a bean. The property will be set after the instanciation. #PostConstruct to validate the content.
Third, The visibility in hierarchical context of the property holder is not straight forward. So if you define #value in the root applicationContext, it will not set by your dispatcherServlet context. To test it, please inject the dependency of the bean defined at root level, you will see that your #Value will be take in account.
The lastPageUrl property will be accessible from a bean within the same context (by push creation or pull creation).
In case of push creation, if another bean autowire the Lo_DisplayHandler bean and call your method anyOtherMethod(), it will get the value.
#Component
public class ScannableIntoYourContext{
#Autowired
private Lo_DisplayHandler myHandler;
}
Other way is to pull the bean from ObjectFactory.
#Autowired
private ObjectFactory<Lo_DisplayHandler> bean;
Lo_DisplayHandler instanceFromContext = bean.getObject();
I have created a new Spring MVC 3 project using NetBean. But there is no option of adding a new controller in the IDE.
Well adding a Controller is as simple as adding a class annotated with
#Controller
And specifying the package to be scanned from applicationContext.xml which in turn is specified in the web.xml. Something like this:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/appServlet/applicationContext.xml
</param-value>
</context-param>
in web.xml
Then in /WEB-INF/spring/appServlet/applicationContext.xml :
<context:component-scan base-package="your.package" />
Of course you need the actual schema in your applicationContext.xml
xmlns:context="http://www.springframework.org/schema/context"
And under schema location:
http://www.springframework.org/schema/context/spring-context-3.0.xsd
And then a class :
package your.package
.....
#Controller
MyController{
.....
If you are using an annotation driven implementation of Spring you don't need to do anything special. Create a standard Java class inside the package that Spring is configured to scan. Then annotate the class with #Controller then create your method(s) and mappings using #RequestMapping.
In its simplest form a controller would be something like:
#Controller
public class MyClass {
#RequestMapping("/myUrlMapping.do")
public ModelAndView myMethod() {
return new ModelAndView("myView");
}
}
This assumes you already have Spring configured correctly.