What does context annotation do in Spring? - spring

In Rest API design, I am wondering what the exact purpose of the context annotation is?
private HttpServletRequest request;
#Context
public void setRequest(final HttpServletRequest req) {
request = req;
}

The purpose is to indicate that the request property should be set from the context.
#Context is used to inject various HTTP-ish contextual data, from here:
In general #Context can be used to obtain contextual Java types related to the request or response.
API docs (Not horribly useful IMO. Or, perhaps more accurately, horribly-useful.)

This annotation is used to inject information into a class field, bean property or method parameter.
JAX-RS #Context to get the ServletContext, and WebApplicationContextUtils to get the Spring application context, with this Spring application context, you are able to access and get beans from Spring container

Related

How to make WebFilter work in a non-WebFlux/non-reactive Spring Boot application?

I'm trying to solve this: How to rewrite URLs with Spring (Boot) via REST Controllers?
by creating some kind of "filter" which would be applied to every incoming HTTP request.
The matter is covered by some answers like for this question: Spring Boot Adding Http Request Interceptors
but interface HandlerInterceptor deals with javax' HttpServletRequest and HttpServletResponse which are not as practical as the new class introduced by Spring i.e. the ServerWebExchange (see the use of setLocation() in the code below) which appears in an interface whose name sounds promising, org.springframework.web.server.WebFilter:
So I ended with something like:
#Component
public class LegacyRestRedirectWebFilter implements WebFilter {
#Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
URI origin = exchange.getRequest().getURI();
String path = origin.getPath();
if (path.startsWith("/api/")) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.MOVED_PERMANENTLY);
URI location = UriComponentsBuilder.fromUri(origin).replacePath(path.replaceFirst("/api/", "/rest/")).build().toUri();
response.getHeaders().setLocation(location);
}
return chain.filter(exchange);
}
}
...in the same way people are doing something similar like:
Spring WebFlux add WebFIlter to match specific paths
WebFilter in WebFlux application
Alas, my filter is never called!!!
The thing is: I am not in a "WebFlux" context (on the contrary to the questions above) because:
I don't need to, and
I tried and got the following problems:
Reactive Webfilter is not working when we have spring-boot-starter-web dependency in classpath (but no definitive answer); marked duplicate of:
Don't spring-boot-starter-web and spring-boot-starter-webflux work together?
Spring WebFlux with traditional Web Security (I have the "traditional" spring-boot-starter-security dependency in my pom.xml plus a #Configuration class extending WebSecurityConfigurerAdapter - but not willing to migrate it to... what by the way?)
Also I don't understand why would I need to be in a WebFlux context, because org.springframework.web.server.WebFilter neither deals with reactive nor Webflux, right? ..or does it? This is not very clear in the Javadoc.
In fact, I didn't find a way to make WebFilter work in a non-WebFlux context, but I could successfully implement such a filter, which both implements javax.servlet.Filter (non-reactive) AND org.springframework.web.server.WebFilter (reactive).
Here is my answer to the other related question: https://stackoverflow.com/a/63780659/666414

How to inject ResourceInfo in a ContainerRequestFilter in CXF

I am trying to build a token based authentication and authorization system using Apache CXF and Spring. I am completely following this fantastic post for doing this.
But I am stuck in a problem with my AuthorizationFilter at the very beginnig. I have seen many posts, apache JIRA, github comments about it, but could not yet found the workaround about this seemingly CXF issue.
#PreMatching
#Priority(Priorities.AUTHORIZATION)
public class AuthorizationFilter implements ContainerRequestFilter {
private ResourceInfo resourceInfo;
#Context
public void setResourceInfo(ResourceInfo resourceInfo) {
this.resourceInfo = resourceInfo;
}
#Override
public void filter(final ContainerRequestContext requestContext) throws IOException {
Method method = resourceInfo.getResourceMethod();
In the above code, the injected resourceInfo is a proxy object, and it has none of the associated properties present. So, anything from that resourceInfo object is returning null, more specifically resourceInfo.getResourceMethod() is null, leading to NPE.
This is the JIRA post pertaining to this very issue, saying that:
In some circumstances (like using #ApplicationScoped annotation for example) the CDI runtime will create a proxy class for a particular bean. As the result, the CXF side is going to bind the particular provider metadata to this proxy instance. It looks logical and unambiguous.
However, the interesting things are happening when CXF will try to inject contextual proxies (#Context annotations) into the provider instance. The injections are successful but the target object for them will be the proxy instance (not the real instance behind it). Consequently, at runtime, when the proxy delegates the call to a backing instance, all contextual proxies are null in there (simply put, not set).
Referring to the recent discussions with Sergey Beryozkin, the best solution would be to delegate the #Context annotation to CDI framework (as such, relieving the CXF from doing the injection work). This proposal may need a support from the JAX-RS specification side.
Simpler (interim?) possible solution would be to complement the CDI injection with #Context injection (delegating this work to the CXF as it works right now for non-proxy beans and non-CDI deployments). This could be done by observing ProcessInjectionTarget events and supplying our own InjectionTarget (have working PoC for this approach).
Regarding constructor injection, it seems like CXF does not support passing the arguments to provider constructor (in case of CDI, w/o #Context annotation) so I it would be another (separate) issue to look at.
Can someone help me point out what is this simpler approach is all about:
Simpler (interim?) possible solution would be to complement the CDI injection with #Context injection (delegating this work to the CXF as it works right now for non-proxy beans and non-CDI deployments). This could be done by observing ProcessInjectionTarget events and supplying our own InjectionTarget (have working PoC for this approach)
Or is there any other way, where Spring Framework can inject the ResourceInfo object in a correct way?
I have registered the filters like this in my applicationContext.xml :
<jaxrs:server id="endpoints">
<jaxrs:providers>
<ref bean="authenticationFilter" />
<ref bean="authorizationFilter" />
</jaxrs:providers>
</jaxrs:server>
The problem is the #PreMatching annotation.
Global binding annotation that can be applied to a container request filter to indicate that such filter should be applied globally on all resources in the application before the actual resource matching occurs.
The key is highlighted part "before the actual resource matching occurs". So even before the resource is matched to the request, the filter is called. And if there is no resource matched yet, then it is impossible to get any information from the ResourceInfo. If you just remove the #PreMatching annotation, then the filter will be called after a matching resource is found, and you will be able to access all the info from the ResourceInfo.

#Autowired HttpServletRequest inside integration tests

Finally I have managed to setup the context for some integration test and to test methods that expect #PathVariable or #ModelAttribute. Still, I cannot figure out how can I setup the HTTPServletRequest used inside the controller.
MyController {
#Autowired
private HttpServletRequest request;
}
The request never updates while I'm running the test.
I might misunderstand something (as far as I'm new to Spring).
How can I achieve this?
Thanks in advance for the answer!
Isn't the HttpServletRequest passed in to the controller via a method parameter?
Use #Autowired to connect an instance variable to a Spring context bean.
Maybe you can have a look at MockHttpServletRequest for testing Web controllers.
I didn't have time to fill in the answer: I am using MockHttpServletRequest and Spring 3.1.2.
I have managed to solve it not by using #Autowired, but by getting the request bean from the controler. Something like this:
mockRequest = (MockHttpServletRequest) applicationContext.getBean ("request");
Hope that this will help someone else ...

AbstractTransactionalJUnit4SpringContextTests http request

i try to write a test with
AbstractTransactionalJUnit4SpringContextTests
somewhere deep in my beans
FacesContext currentInstance = FacesContext.getCurrentInstance();
is called, but there is no request so it returns null.
Is there a way to fake a complete http request in my tests?
Of course there's a way, there is always a way. Spring provides a whole hierarchy of servlet mock objects in the spring-test artifact. You can use a MockHttpRequest. But how you can tie that to FacesContext.getCurrentInstance() is beyond my understanding of JSF. You'll probably need a Mock JSF implementation somewhere along the way.

#Context HttpServletRequest scope in Jersey

I'm building an API using Jersey on the Glassfish 3.1 server and need to get access to the HttpServletRequest object in order to get certain headers, caller's ip, etc. I could just inject it into every API method call but it seems more efficient to just do it globally. Is it safe to inject it at the class level like in the snippet below or will this cause some kind of concurrency issues with Glassfish?
#Path("/myapi")
#RequestScoped
public class MyApiResource {
#Context private UriInfo context;
#Context private HttpServletRequest request;
It is safe. Don't use the #RequestScoped annotation - JAX-RS resources are request scoped by default. That means a new instance gets created for each request hence no concurrency issues.

Resources