Use Jersey Filter in Spring Boot Jersey - spring-boot

I have a Jersey rest API which we are planning to migrate to Spring boot.
I have a filter that implements ContainerRequestFilter and had #Provider annotation in the filter. I registered the filter in ResourceConfig. But still i don't see the filter executing.
However I do get a warning message:-
A provider "My Filter class" registered in SERVER runtime does not implement any provider interfaces applicable in the SERVER runtime. Due to constraint configuration problems the provider "My Filter class" will be ignored.
I wanted to use jersey as servlet so changing the jersey to behave as filter is not working for my app.
Can someone help me on this?
Here is my code
Jersey filter
#Provider
public class CustomJerseyLoggingFilter implements ContainerRequestFilter, ContainerResponseFilter {
#Override
public ContainerRequest filter(ContainerRequest request) { }
#Override
public ContainerResponse filter(ContainerRequest request, ContainerResponse response) { }
}
#Component
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(CustomJerseyLoggingFilter.class);
}
}

You're implementing the wrong ContainerRequestFilter. The one you are using is from Jersey 1.x. I don't know why you even have Jersey 1.x jars in your project. The ContainerRequestFilter (for 2.x) that you should be implementing is
javax.ws.rs.container.ContainerRequestFilter
javax.ws.rs.container.ContainerResponseFilter

Related

Why Servlet Filter can be Spring Bean?

What i know about Filter and Interceptor is that Filters as J2EE Specifications are part of the webserver and not the Spring framework. So some older articles explain that it is impossible to register filters as Spring Bean while Interceptor is possible.
But the results I got when I tested today is that Filters can be Spring Bean and also inject Spring Bean on Filters are possible too like Interceptors.
(I tested on SpringBoot Framework)
#Component
public class CustomFilterTest implements Filter {
#Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws ServletException, IOException {
chain.doFilter(request, response);
}
#Override
public void init(final FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
#Override
public void destroy() {
Filter.super.destroy();
}
}
#RestController
#RequiredArgsConstructor
public class ProductController {
private final CustomFilterTest customFilterTest;
#GetMapping("/test")
public ResponseEntity<Void> temp() {
System.out.println(customFilterTest);
return ResponseEntity.noContent().build();
}
}
Can anyone please explain to me?
We have to make a distinction between a regular Spring application and a Spring Boot application here. As with both, you can register a servlet filter as a bean, but the mechanism is a bit different.
Spring Framework
In plain Spring use the DelegatingFilterProxy to achieve this. The task of the DelegatingFilterProxy is to look for a bean with the same name as the filter in the root application context (the ApplicationContext registered through the ContextLoaderListener). This bean has to be your managed servlet filter.
#Configuration
#EnableWebMvc
public class WebConfiguration {
#Bean
public void YourFilter myFilter() { ... }
}
Then for the web application you would register a DelegatingFilterProxy with the name myFilter to make this work.
public class MyWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
public void onStartup(ServletContext servletContext)
throws ServletException {
super.onStartup(servletContext);
servletContext.addFilter("myFilter", DelegatingFilterProxy.class);
}
Spring Boot
In Spring Boot it is a bit different as Spring Boot is also in control of your servlet container, like Tomcat. It basically means that Tomcat is also a managed bean in your ApplicationContext and Spring Boot can inject dependencies into it. So when Spring Boot detects a bean for the servlet filter it will automatically add it to the filter chain (without the need of a DelegatingFilterProxy).
Which means only an #Bean for your filter is needed.
#Configuration
public class WebConfiguration {
#Bean
public YourFilter myFilter() { ... }
}
Additionally you can configure things like URLs etc. by adding an additional FilterRegistrationBean for this filter.
Conclusion
For plain Spring the DelegatingFilterProxy has been around since Spring 1.2 which was released in 2005. This means if you are reading really, really, really old articles (before 2005) this was true, however with the addition of the DelegatingFilterProxy, this isn't anymore. With the release of Spring Boot, this became even a lesser issue, is it more or less is the only way to register a filter (as a managed bean).

Error on injecting service: UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl

I am trying to inject service in spring boot app. However I'm getting following error:
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=RecommendationService,parent=RecommendationResourceImpl,qualifiers={},position=-1,optional=false,self=false,unqualified=null,1163111460)
Here is the code:
package com.example.test.recommendations.resources;
#Provider
public class RecommendationResourceImpl implements RecommendationResource {
#Inject
private RecommendationService recommendationService;
#Override
public List<Recommendation> get(String currency,
String entity) {
return recommendationService.getRecommendations(currency, entity));
}
}
Service interface
package com.example.test.recommendations.resources;
// imports
public interface RecommendationService {
List<Recommendation> getRecommendations(String currency, String entity);
Recommendation get(UUID uuid);
}
Service implementation
package com.example.test.recommendations.resources;
//imports
#Component
public class RecommendationServiceImpl implements RecommendationService{
#Override
public List<Recommendation> getRecommendations(String currency, String entity) {
return Collections.emptyList();
}
#Override
public Recommendation get(UUID uuid) {
return null;
}
}
What is correct way to inject services in spring boot applications?
I am using spring boot version 1.3.8 and Jersey version 2.25.1
From your stacktrace it is evident that the server cannot find the dependency bean to be injected.So initially check that the desired bean for the class is getting created during applciation start up.Verify that the service class is in the classpath for component scan to take place, otherwise include the package for scanning.
You are using the #Inject annotation instead of the spring #Autowired annotation to inject the beans.It will work fine but the first and most important difference between #Autowired and #Inject annotation is that the #Inject annotation is only available from Spring 3.0 onwards, so if you want to use annotation-driven dependency injection in Spring 2.5 then you have to use the #Autowired annotation.
Secondly, use the annotation #Service for the service layer rather than using the #Component annotation.
Indicates that an annotated class is a "Service", originally defined
by Domain-Driven Design (Evans, 2003) as "an operation offered as an
interface that stands alone in the model, with no encapsulated state."
May also indicate that a class is a "Business Service Facade" (in the
Core J2EE patterns sense), or something similar. This annotation is a
general-purpose stereotype and individual teams may narrow their
semantics and use as appropriate.
This annotation serves as a specialization of #Component, allowing for
implementation classes to be autodetected through classpath scanning.
#Service
public class RecommendationServiceImpl implements RecommendationService{
#Override
public List<Recommendation> getRecommendations(String currency, String entity) {
return Collections.emptyList();
}
#Override
public Recommendation get(UUID uuid) {
return null;
}
}
I am not an expert on using jersey with springboot , so i do not know if any configurations are causing this issue.
Maybe this thread might be of help to you more:
Dependency injection with Jersey 2.0
You probably never registered your Service with the DI-container. You can do that in your ResourceConfig, which you probably have since you are using jersey:
public class MyApplication extends ResourceConfig {
public MyApplication() {
register(new org.glassfish.hk2.utilities.binding.AbstractBinder() {
#Override
protected void configure() {
bind(RecommendationServiceImpl.class).to(RecommendationService.class).in(Singleton.class);
}
});
packages("com.example.test.recommendations.resources");
}
}
I am using hk2 without spring, so I usually annotate my interfaces with org.jvnet.hk2.annotations.Contract and the implementations with org.jvnet.hk2.annotations.Service. (note: not the spring #Service annotation), so I recommend trying that as well.

Adding Jersey Configuration disables register view controller

i am using springboot 1.5.2 and i am using jersey and jsf
i have mapping for default view / as follows:
#Bean
public WebMvcConfigurerAdapter defaultView() {
return new WebMvcConfigurerAdapter() {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("forward:/faces/public/login.xhtml");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
super.addViewControllers(registry);
}
};
}
before i added jersey configuration, it was working fine, and after i added the following jersey configuration it stopped working:
#Configuration
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(MyService.class);
}
}
when i remove the JerSeyConfig class, the mapping works fine, but when i add it, the mapping stops working, please advise how to make them both working together fine.
Could you try:
Annotate JerseyConfig with #Component instead of #Configuration and make sure package is being scanned via #ComponentScan in main class.
Make sure Spring MVC dispatcher servlet is mapped to a path different than Jersey servlet's, for instance:
# Spring MVC dispatcher servlet path. Needs to be different than Jersey's to enable/disable Actuator endpoints access (/info, /health, ...)
server.servlet-path: /
# Jersey dispatcher servlet
spring.jersey.application-path: /api
More details could be found at my blog post: Microservices using Spring Boot, Jersey, Swagger and Docker

Add interceptor to spring boot mongodb rest example

I am trying to add an interceptor to a simple Spring-boot-mongodb-rest app, as can be seen here : http://spring.io/guides/gs/accessing-mongodb-data-rest/, in order to perform certain actions after the default rest handler is invoked. Here is my MongoRepository, whose CRUD operation is called upon a POST request to the server:
#RepositoryRestResource(collectionResourceRel = "reminder", path = "reminder")
public interface ReminderRepository extends MongoRepository<Reminder, String> {
List<Reminder> findBySendee(#Param("sendee") String sendee);
}
I am trying to register an interceptor for all HTTP requests by extending the WebMvcConfigurerAdapter class like this:
#Configuration
#ComponentScan
public class RemindxWebConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(new RemindxInterceptor());
}
}
As mentioned in the spring boot docs, I have not added the #EnableWebMvc annotation to this. While running the application, the addInterceptors function does get called and adds the interceptor. However, the given interceptor is not called after the POST handler is invoked. I am unable to figure out a way to have spring use this RemindxWebConfig for all MongoRepository http requests. Any inputs are appreciated.

Custom default headers for REST API only using Spring Data REST

I have a use case where my application hosts REST API and web application and we need to add custom header to REST APIs only. REST APIs are enabled through Spring Data REST. Typically we could use Servlet Filter to achieve this but we need code the logic of isolating requests to our REST API and add the custom headers. It would be nice if Spring Data REST API allows to add a default header to all the responses it generates. What are your thoughts? Don't say I am lazy :)
For folks looking for actual implementation details..
Interceptor
public class CustomInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
System.out.println("adding CORS headers.....");
response.addHeader("HEADER-NAME", "HEADER-VALUE");
return true;
}
}
Java Configuration
#Configuration
public class RepositoryConfig extends
RepositoryRestMvcConfiguration {
#Override
public RequestMappingHandlerMapping repositoryExporterHandlerMapping() {
RequestMappingHandlerMapping mapping = super
.repositoryExporterHandlerMapping();
mapping.setInterceptors(new Object[] { new CustomInterceptor() });
return mapping;
}
}
As Spring Data REST is built on top of Spring MVC, the easiest way is to configure a custom HandlerInterceptor as described in the reference documentation.
With Spring Data REST the easiest way is to extend RepositoryRestMvcConfiguration and override repositoryExporterHandlerMapping, call the parent method and then invoke ….setInterceptors(…) on it.
Finally I managed to make the setup of custom interceptor working also on spring-data-rest 2.4.1.RELEASE.
#Configuration
public class RestMvcConfig extends RepositoryRestMvcConfiguration {
#Autowired UserInterceptor userInterceptor;
#Autowired ApplicationContext applicationContext;
#Override
public DelegatingHandlerMapping restHandlerMapping() {
RepositoryRestHandlerMapping repositoryMapping = new RepositoryRestHandlerMapping(resourceMappings(), config());
repositoryMapping.setInterceptors(new Object[] { userInterceptor }); // FIXME: not nice way of defining interceptors
repositoryMapping.setJpaHelper(jpaHelper());
repositoryMapping.setApplicationContext(applicationContext);
repositoryMapping.afterPropertiesSet();
BasePathAwareHandlerMapping basePathMapping = new BasePathAwareHandlerMapping(config());
basePathMapping.setApplicationContext(applicationContext);
basePathMapping.afterPropertiesSet();
List<HandlerMapping> mappings = new ArrayList<HandlerMapping>();
mappings.add(basePathMapping);
mappings.add(repositoryMapping);
return new DelegatingHandlerMapping(mappings);
}
}
I had to override the restHandlerMapping method, copy-paste it's content and add a line repositoryMapping.setInterceptors for adding custom interceptor, in my case the UserInterceptor.
Is there any better way?

Resources