How to inject a Spring Data JPA Repository into a Servlet Filter? - spring

I'm using the Tuckey UrlRewriteFilter. I want to use a rewrite rule from a database, so using the <class-rule class="com.example.Foo" /> configuration, which lets you get rules at runtime. I created a class extending RewriteRule:
public class Foo extends RewriteRule {
#Autowired
private MyRepository myRepository;
public boolean init(ServletContext servletContext) {
return true;
}
#Override
public RewriteMatch matches(HttpServletRequest request, HttpServletResponse response) {
//myRepository is null
return super.matches(request, response);
}
#Override
public void destroy() {
}
}
I'd like to use a Spring Data JPA Repository inside this Foo class, but it looks the repository is null.
How can I inject it correctly?

Declare your filter in web.xml as usual, except that you will need to provide org.springframework.web.filter.DelegatingFilterProxy as the filter class name instead of your actual class name.
<filter>
<filter-name>urlRewriteFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>urlRewriteFilter</filter-name>
<url-pattern>/</url-pattern>
</filter-mapping>
Finally, in your ROOT application context, declare a bean pointing to your filter class and with the same name as the filter name provided in web.xml in the application context file loaded from web.xml:
<bean id="urlRewriteFilter" class="org.tuckey.web.filters.urlrewrite.UrlRewriteFilter"/>
Since your filter instance is now managed by Spring, you can inject any Spring managed bean into it.

Related

propleme with the injection of dependence of spring

For the project that we create during my formation we use spring to make dependency injection.
we have a servlet-context.xml file with the following configuration:
<context:component-scan base-package="fr.autoquiz3000" />
I created several controllers and I have no problem injecting the dao for example:
package fr.autoquiz3000;
#Controller
#RequestMapping("/public")
public class PublicController {
#Autowired
private UserDao uDao;
#GetMapping("/connection")
public ModelAndView getConnection() {
return new ModelAndView("public/viewConnexion");
}
but I try to create a filter with a dao like this:
package fr.autoquiz3000;
#Component
public class CountQuizStudent implements Filter {
#Autowired
private QuizToDoDao qtdDao;
and I have this error:
qtdDao= null
java.lang.NullPointerException
at fr.autoquiz3000.CountQuizStudent.doFilter(CountQuizStudent.java:41)
Someone could explain to me what I'm doing wrong!
thank you!
For filters override init method and set Spring beans there:
#Override
public void init(FilterConfig filterConfig) throws ServletException {
WebApplicationContext springContext =
WebApplicationContextUtils.getWebApplicationContext(filterConfig.getServletContext());
userDao = springContext.getBean(UserDao.class);
}
or use DelegatingFilterProxy:
<filter>
<filter-name>yourFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>yourFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
#Component("yourFilter")
public class YourFilter implements Filter {
// auto wiring available as it's just Spring Bean
}

Spring Data Rest: ResourceProcessor configuration is not working properly

I have a strange behaviour with a Spring Data Rest implementation (version 2.5.2.RELEASE).
I'm trying to register a #Bean of ResourceProcessor<Resource<Entity>>, but there is something strange.
I'm trying with two kinds of solutions:
1) Declaring the #Bean in a class:
#Bean
public ResourceProcessor<Resource<Author>> authorProcessor() {
return new ResourceProcessor<Resource<Author>>() {
#Override
public Resource<Author> process(Resource<Author> resource) {
System.out.println("method process of bean ResourceProcessor of class RepositoryBaseConfiguration");
return resource;
}
};
}
2) Implementing the interface ResourceProcessor:
#Component
public class AuthorResourceProcessor implements ResourceProcessor<Resource<Author>> {
#Override
public Resource<Author> process(Resource<Author> resource) {
System.out.println("method process of class AuthorResourceProcessor");
return resource;
}
}
The processors are completely ignored: the message is never printed.
I noticed that the class org.springframework.data.rest.webmvc.ResourceProcessorInvoker has a constructor:
public ResourceProcessorInvoker(Collection<ResourceProcessor<?>> processors) {
//...
}
This constructor is invoked 2 times at the start of the application instead of only one time (as I will expect), and I don't understand why.
The first time, the "processors" variable is solved with the two beans (as expected) and with the bean org.springframework.data.rest.webmvc.ProfileResourceProcessor.
But the second time, the "processors" variable is solved with only the bean org.springframework.data.rest.webmvc.ProfileResourceProcessor.
The second configuration #Override the first one.
Any idea?
The problem depends on the configurations loaded at the startup of the application.
I had this configuration on the web.xml:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/spring-web-config.xml</param-value>
</context-param>
<servlet>
<servlet-name>rest</servlet-name>
<servlet-class>org.springframework.data.rest.webmvc.RepositoryRestDispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
So, the ContextLoaderListener loaded the correct configuration in the first time; the "load-on-startup" property of the servlet "RepositoryRestDispatcherServlet" launch a second context configuration load.
I also had a custom class that extended org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration, but this custom class was ignored by the moment that the constructor of RepositoryRestDispatcherServlet load the default RepositoryRestMvcConfiguration, causing the lost of the configurations.
To solve that issue I have created a custom RepositoryRestDispatcherServlet in this way:
public class AppRepositoryRestDispatcherServlet extends DispatcherServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
public AppRepositoryRestDispatcherServlet() {
configure();
}
public AppRepositoryRestDispatcherServlet(WebApplicationContext webApplicationContext) {
super(webApplicationContext);
configure();
}
private void configure() {
setContextClass(AnnotationConfigWebApplicationContext.class);
setContextConfigLocation(RepositoryBaseConfiguration.class.getName());
}
}
The class is the same as RepositoryRestDispatcherServlet, with the only difference that in the setContextConfigLocation is passed the custom class that extends RepositoryRestMvcConfiguration (RepositoryBaseConfiguration in this example).
Obviously I had to update the web.xml as follows:
<servlet>
<servlet-name>rest</servlet-name>
<servlet-class>my.package.AppRepositoryRestDispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
In this way, the configuration is correctly loaded and mantained.

Dispatcher Servlet in Spring Boot

In my Spring Boot application with packaging type as war, i am configuring Spring MVC. As i understand we dont have to configure Dispatcher Servlet Manually. However, i old style of web.xml i used to configure Dispatcher Servlet and then i used to pass contextClass and contextConfigLocation as follows
<servlet>
<description>
</description>
<display-name>DispatcherServlet</display-name>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<description>contextClass</description>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<init-param>
<description>contextConfigLocation</description>
<param-name>contextConfigLocation</param-name>
<param-value>com.xxx.yyy.jdorderspringmvcweb.config.SpringMvcConfig</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
I belive this was to indicate that SpringMvcConfig (my custom class with spring mvc configuration) is the configuration class for Spring MVC..
However, In spring boot if Dispatcher Servlet is configured Automatically, how can i pass my custom class to dispatcher Servlet ?
In my Spring Boot application, my SpringMvcConfig class extends from WebMvcConfigurerAdapter and is annotated with #Configuration class
Help Needed...
Right in the configuration class which is annotated by #Configuration you could define your dispatcherServlet and pass init-parameter to it.
#Bean
public ServletRegistrationBean dispatcherServletRegistration() {
ServletRegistrationBean registrationBean = new ServletRegistrationBean(dispatcherServlet());
registrationBean.addInitParameter("contextClass","org.springframework.web.context.support.AnnotationConfigWebApplicationContext");
registrationBean.addInitParameter("contextConfigLocation","com.xxx.yyy.jdorderspringmvcweb.config.SpringMvcConfig");
return registrationBean;
}
Another way would be to create a paramter map and then set parameter for registration bean. This stream shows how to do it.
I think you have to create a config class as follow:
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class MySpringMvcDispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
// TODO Auto-generated method stub
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { DemoAppConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}

Spring Security with Java EE Restful Service

I have created a Java EE 6 restfull service and tried to integrate that with Spring Security. But, all the time I get different weird exceptions. Which doesn't make any sense or may be make sense but at least not for me.
Direction structure of my application is something like this:
com.security
UserDetailsSecurityConfig.java
com.service
ApplicationConfig.java
UserFacadeREST.java
com.config
AppConfig.java
My entities are auto generated so no error seems to be there. But, yes the three files seems fishy to me as UserFacadeREST is working fine when I don't integrate my application with Spring Security.
com.UserDetailsSecurityConfig.java
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
public class UserDetailsSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService( userDetailsService() );
}
#Override
protected void configure( HttpSecurity http ) throws Exception {
http
.httpBasic().and()
.sessionManagement().sessionCreationPolicy( SessionCreationPolicy.STATELESS ).and()
.authorizeRequests().antMatchers("/**").hasRole( "USER" );
}
#Bean
public UserDetailsService userDetailsService() {
return new UserDetailsService() {
#Override
public UserDetails loadUserByUsername( final String username )
throws UsernameNotFoundException {
if( username.equals( "admin" ) ) {
return new User( username, "password", true, true, true, true,
Arrays.asList(
new SimpleGrantedAuthority("ROLE_USER" ),
new SimpleGrantedAuthority( "ROLE_ADMIN" )
)
);
} else if ( username.equals( "user" ) ) {
return new User( username, "password", true, true, true, true,
Arrays.asList(
new SimpleGrantedAuthority( "ROLE_USER" )
)
);
}
return null;
}
};
}
}
com.service.ApplicationConfig.java
#javax.ws.rs.ApplicationPath("webresources")
public class ApplicationConfig extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new java.util.HashSet<>();
addRestResourceClasses(resources);
return resources;
}
/**
* Do not modify addRestResourceClasses() method.
* It is automatically populated with
* all resources defined in the project.
* If required, comment out calling this method in getClasses().
*/
private void addRestResourceClasses(Set<Class<?>> resources) {
resources.add(com.service.UserFacadeREST.class);
}
}
com.service.UserFacadeREST.java
#Stateless
#Path("user")
public class UserFacadeREST extends AbstractFacade<UpUser> {
#PersistenceContext(unitName = "PU")
private EntityManager em;
public UserFacadeREST() {
super(User.class);
}
#POST
#Override
#Consumes({"application/xml", "application/json"})
public void create(User entity) {
super.create(entity);
}
#GET
#Path("count")
#Produces("text/plain")
public String countREST() {
return String.valueOf(super.count());
}
}
com.config.AppConfig.java
#Configuration
#Import( UserDetailsSecurityConfig.class )
public class AppConfig {
#Bean
public ApplicationConfig applicationConfig() {
return new ApplicationConfig();
}
#Bean
public UserFacadeREST userRestService() {
return new UserFacadeREST();
}
}
In whole code I have made few changes for hit and trial. And currently, I am getting an exception.
java.lang.IllegalStateException: No WebApplicationContext found: no
ContextLoaderListener registered?
Before that I was getting another exception which was
WebSecurityConfigurers must be unique. Order of 100 was already used
I am not getting what I am doing wrong in integrating Spring Security with Java EE 6. I am new to Spring so may be I am doing a blunder which seems obvious to me.
My web.xml file is:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="rest-sec" version="3.0">
<display-name>rest</display-name>
<!-- Spring security -->
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
<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>
<filter>
<filter-name>etagFilter</filter-name>
<filter-class>org.springframework.web.filter.ShallowEtagHeaderFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>etagFilter</filter-name>
<url-pattern>/api/*</url-pattern>
</filter-mapping>
<!-- rest -->
<servlet>
<servlet-name>rest</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<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.labs.entities</param-value> <!-- won't find anything -->
</init-param>
<init-param>
<param-name>dispatchOptionsRequest</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>rest</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
<!-- Disables servlet container welcome file handling. Needed for compatibility
with Servlet 3.0 and Tomcat 7.0 -->
<welcome-file-list>
<welcome-file />
</welcome-file-list>
</web-app>
java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?
You need to tell the filter where to look for your context (it's default is to look in a place that is not used by the servlet you created). In your filter add an init param:
<init-param>
<param-name>contextAttribute</param-name>
<param-value>org.springframework.web.servlet.FrameworkServlet.CONTEXT.spring</param-value>
</init-param>
WebSecurityConfigurers must be unique. Order of 100 was already used
Do you have 2 beans of type WebSecurityConfigurerAdapter? Or is your UserDetailsSecurityConfig being loaded twice?

Adding a Filter and Init Params Progmatically

I need to copy the contents of a web.xml to the WebAppInitializer.class (Java Configuration Class). I have copied the YahooFilter Class from web.xml (see code) but I am not sure how to add the init-params pragmatically.
I have pasted the web.xml and snippet of the Java Configuration class below. Can somebody take a look and provide some feedback?
<web-app>
<display-name>sample</display-Aname>
<filter>
<filter-name>YOSFilter</filter-name>
<filter-class>com.yahoo.yos.YahooFilter</filter-class>
<!--
optional param -
underlying oauth client class
possible values:
net.oauth.client.URLConnectionClient (default)
net.oauth.client.httpclient3.HttpClient3
net.oauth.client.httpclient4.HttpClient4
-->
<init-param>
<param-name>oauthConnectionClass</param-name>
<param-value>net.oauth.client.httpclient4.HttpClient4</param-value>
</init-param>
<!--
optional param -
redirect end-user if an access token is not found, set to false if you
are only making two-legged oauth calls e.g. oauth calls without an
access token to retrieve public information
defauts to true
-->
<init-param>
<param-name>redirect</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<!--
The URL where the filter is mapped to will redirect the user to Yahoo for
authorization if an OAuth authorization token has not been obtained for the
user. Should correspond to your callback url
-->
<filter-mapping>
<filter-name>YOSFilter</filter-name>
<url-pattern>/login.jsp</url-pattern>
</filter-mapping>
</web-app>
Java Config Class
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
...
#Override
protected void registerDispatcherServlet(ServletContext servletContext) {
super.registerDispatcherServlet(servletContext);
servletContext.addListener(new HttpSessionEventPublisher());
// servletContext.addListener(new RequestContextListener());
}
#Override
protected Filter[] getServletFilters() {
DelegatingFilterProxy delegatingFilterProxy = new DelegatingFilterProxy();
delegatingFilterProxy.setTargetBeanName("springSecurityFilterChain");
// FilterConfig filterConfig = delegatingFilterProxy.getFilterConfig();
YahooFilter yosFilter = new YahooFilter();
return new Filter[] {delegatingFilterProxy,yosFilter};
}
}
Try overriding onStartup() method and programatically register your filter with ServletContext like this:
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
FilterRegistration yahooFilter = servletContext.addFilter("yahooFilter", new YahooFilter());
yahooFilter.setInitParameter("oauthConnectionClass", "net.oauth.client.httpclient4.HttpClient4");
yahooFilter.setInitParameter("redirect", "true");
}

Resources