Add interceptor to spring boot mongodb rest example - spring

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.

Related

How to get Application properties configuration into Annotation as parameter

I want to use #CrossOrigin annotation on my RestController in my Spring Boot application and set origins parameter with the values from application.properties file.
#CrossOrigin(origins = {"${app.cors.origins}"})
public class SomeController(){
//
//
}
I set the property in my application.properties file like
app.cors.origins =http://www.google.com,http://localhost:8001
However that doesn't work as a cross origin request from http://localhost:8001 to my app fails with CORS error on the browser.
Am I missing something on setting the property?
Update : Problem is to set origins as a string array from the value of application property entry. When I hardcode the urls in origin, it works.
Thanks
If you want to use application.properties to set origins of CORS then this is the solution.
#Configuration
public class WebMvcConfig implements WebMvcConfigurer {
#Value("${app.cors.origins}")
private String corsAllowedOrigins;
#Value("${app.cors.methods}")
private String corsAllowedMethods;
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins(corsAllowedOrigins)
.allowedMethods(corsAllowedMethods);
}
application.properties
app.cors.origins=http://www.google.com,http://localhost:8001
app.cors.methods=GET,OPTIONS
I'm also working on this issue, I found another post mentioned about controller level parameter annotation for Cors. I haven't try it yet. share it with you:
Create your custom annotation and annotate the API with that.
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD})
#CrossOrigin
public #interface CrossOriginsList {
public String[] crossOrigins() default {
"http://domain1.com", "http://domain1.com"
"http://domain1.com", "http://domain1.com"
// Pass as many as you want
};
}
And now Annotate your API with this custom Annotation
#CrossOriginsList
public String methodName() throws Exception
{
//Business Logic
}

Configure path prefixes for different WebAPIs in one Spring Boot App

I have a Spring Boot App with several WebAPIs. How can I configure the path prefix of each WebAPI differently via application properties?
For example I have a UserRestController and a StarShipRestController. Both are part of different WebAPIs, but served by the same Spring Boot App. The RestControllers should only feature the last part of the URL to the resource. The path prefix should not be part of the RestController:
#RestController
#RequestMapping("users")
class UserRestController {
// methods...
}
and
#RestController
#RequestMapping("starships")
class StarShipRestController {
// methods...
}
The concrete path prefixes are in application.properties:
api.user.pathPrefix=/api/v1
api.starship.pathPrefix=/universe
The question is how to apply the path prefixes to the RestControllers?
If there was only one WebAPI in the Spring Boot App, I could use a WebMvcConfigurer. But that doesn't work because I have several WebAPIs.
#Configuration
public class WebMvcConfig implements WebMvcConfigurer {
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.addPathPrefix("api", HandlerTypePredicate.forAnnotation(RestController.class));
}
}
You can only have one context-path for a single Spring-Boot application (which can be configured using server.servlet.context-path). This means what you are asking is not possible.
The only way to achieve it is by changing the #RequestMapping annotations in your Controllers to include the full path that you want.
#RestController
#RequestMapping("/api/v1/users")
class UserRestController {
// methods...
}
#RestController
#RequestMapping("/universe/starships")
class StarShipRestController {
// methods...
}
To my knowledge, there is no other way.
Considering your request, I ask myself if you shouldn't have two different Spring-Boot applications instead of just one.

Use Jersey Filter in Spring Boot Jersey

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

How to designate public endpoints using custom annotation in spring rest controllers?

We are using OAuth2 for securing our REST endpoints. Nearly all of our endpoints require authentication. We have couple of public endpoints. We configure spring security using #EnableWebSecurity. All the public endpoints are explicitly listed in the configuration (see "publicpath_x" in the example below). Instead of explicitly adding each new public enpodint in the configuration, it would be much easier to have a custom annotation, e.g. #PublicAccess which will designate each public endpoint. Is it possible to configure that endpoints annotated with this annotation will be considered as public, i.e. no authentication will be required? We don't want to designate public endpoints in path (e.g. all public endpoints path will start/end with "/public").
Security configuration:
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//...
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatchers("publicpath1", "publicpath2").permitAll() //...
}
}
Example public REST controller with custom annotation:
#RestController
public class PublicController1 {
#PublicAccess //our custom annotation
#RequestMapping(value = "publicpath1", method = RequestMethod.GET)
public void publicEndpoint1() {
//...
}
}
I was trying the following classes with no success.
javax.servlet.Filter
org.springframework.web.servlet.handler.HandlerInterceptorAdapter
You can use the #PreAuthorize Annotations as method security
Detail see here

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