Programmatically invoking a Jersey ResourceMethod - jersey

I have a need to intercept Jersey resource calls and run code before/after each ResourceMethod call. I have a ModelProcessor and am able to intercept the calls:
for(Resource resource: resourceModel.getResources()) {
for (ResourceMethod resourceMethod : resource.getResourceMethods()) {
Resource.Builder resourceBuilder = Resource.builder(...);
resourceBuilder
.addMethod(resourceMethod)
.handledBy(new Inflector<ContainerRequestContext, Response>() {
#Override
public Response apply(ContainerRequestContext containerRequestContext) {
...
}
});
}
}
However, I can't figure out how to call the original ResourceMethod here.

You might consider using Jersey Filters or Interceptors.
From the documentation:
https://eclipse-ee4j.github.io/jersey.github.io/documentation/latest/filters-and-interceptors.html#d0e9368
Filters and interceptors can be used on both sides, on the client and
the server side. Filters can modify inbound and outbound requests and
responses including modification of headers, entity and other
request/response parameters. Interceptors are used primarily for
modification of entity input and output streams. You can use
interceptors for example to zip and unzip output and input entity
streams.
Interceptors share a common API for the server and the client side.
Whereas filters are primarily intended to manipulate request and
response parameters like HTTP headers, URIs and/or HTTP methods,
interceptors are intended to manipulate entities, via manipulating
entity input/output streams. If you for example need to encode entity
body of a client request then you could implement an interceptor to do
the work for you.
So I think you want to use Interceptor because they will wrap the resource call and you will have access in the same method both before the resource call and after the resource call.
You might also go with Filters, but you will have to break your code to RequestFilter and ResponseFilter.

Related

Ways to handle exceptions like WebClientRequestException due to service unavailability for all calls from a WebClient instance than individually

As the title suggests, I'm using Spring WebClient to invoke an external api and process the response. I have added a ExchangeFilterFunction to handle the response based on the status code returned from the server as something like below.
ExchangeFilterFunction responseProcessor() {
return ExchangeFilterFunction.ofResponseProcessor(response -> {
if (response.statusCode().isError()) {
return Mono.error(new RuntimeException("WebClient Error"));
}
return Mono.just(response);
});
}
Now, this works fine with services that return a response for the request when it is up. But when the service is down, the request fails with WebClientRequestException which is fine but the error thrown is not handled by the responseProcessor and gets propagated.
I'm aware that the error can be handled on the WebClient call using any of the onErrorXXX methods. But if we use that WebClient instance to make many calls across different parts of the code, the handling looks inefficient. So, I'd like to know whether there's a way to handle this error for all calls done by that webclient instance instead of handling it in all of individual invocations. Something like what the responseProcessor does for all responses.
when you use .exchangeToMono() or .exchangeToFlux() methods it will give you back a mono or flux .
there is an interesting method on mono or flux which is transform() .
transform take a function an add it to your flux or mono chain.
you can define a chain as a function anywhere and use this chain many time in different chains.
so define your exception handling chain ( by using onError() method ) as a function and after you get your response by exchangeToMono() or exchangeToFlux() , use .transform method and pass your exception handling chain to it.
any way , there is another way too .
you can create a method which is your proxy to call any external resource , which use webClient in itself.
then you can apply AOP pattern to it and handle exception in this way.

How to set interceptors based on the rpc methods

I have a requirement where i don't want to execute interceptors for all the rpc methods, How i can set the interceptors conditionally?
looking for something similarly.
https://chenyitian.gitbooks.io/gin-tutorials/content/tdd/21.html
execute interceptors for few routes
The interceptors all have access to the RPC method string (in the format of /package.service/method).
https://github.com/grpc/grpc-go/blob/master/interceptor.go#L43
You can check the method string before executing the interceptor body.

Spring WebFlux WebClient builder set request body

How do we set the request body in case of WebClient.Builder? Here is my code -
WebClient.Builder webClientBuilder = WebClient.builder().baseUrl(clientMetadataServiceUri).defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).filters(exchangeFilterFunctions -> {
exchangeFilterFunctions.add(logRequest());
exchangeFilterFunctions.add(logResponse());
});
webClientBuilder.clientConnector(getHttpConnector()).build().get().exchange().doOnSuccess(clientResponse -> {...})
Where and how should I add the request body here?
I believe it cannot be done.
Generally, WebClient(or RestTemplate) is like a template which you use to call other Rest Service. You define this template once with all the customizations needed like interceptors,messageConverters, errorHandlers etc which you need to communicate with this particular Service.
Now coming to individual calls to the service, each call to the service may vary. For example you might be calling different methods like Get, Post.. etc. You might call different endpoints. You might call with/without body. Since you always use the same client(WebClient/RestTemplate) to communicate with that service, you cannot create a WebClient instance with body or method or url(you can only set baseUrl) which are specific to individual call.
This is similar to RestTemplateBuilder. You cannot find any method to set either endpoint or method or body.
You might create a separate instance of webclient for each call. But that is not how it is generally used or advisable(Generally you define a bean of type WebClient and Autowire it). Hence it is not available.
The issue is with get() like many other frameworks Spring WebFlux also doesn't support the request body for the get calls. In the case of post, it goes like this -
WebClient.Builder webClientBuilder = WebClient.builder().baseUrl(clientMetadataServiceUri).defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).filters(exchangeFilterFunctions -> {
exchangeFilterFunctions.add(logRequest());
exchangeFilterFunctions.add(logResponse());
});
webClientBuilder.clientConnector(getHttpConnector()).build().post().body(...).exchange().doOnSuccess(clientResponse -> {...})

Good idea using ControllerAdvice to perform REST authentication of a request?

In my current Spring Boot application i seem to hit a wall when trying to implement a REST request filter. My goal with the request filter was to read the header and body part and validate the incoming data and check if it meets the HMAC construction we are using.
So the request filter seemed not to work an alternative solutions is to use #ControllerAdvice.
Then the request validation can be implemented very easy. But i am not sure if it normally seen as an incorrect usage of the #ControllerAdvice annotation.
#ControllerAdvice
public class GenericWebControllerAdvice {
#ModelAttribute
public void authenticationFilter(#RequestHeader(value = "Authorization") String authHeader, #RequestBody String payload) {
// process authentication based on header info and body content
// calculate the hash and check if meets the security settings
// if the hash fails throw an exception that returns a http status code
}
}
Any comments on the solution or alternatives that are better?
No you should do the validation in the controller (ie method with #RequestMapping).
Spring supports JSR 303/349 bean validation. Thus if your request body is a POJO and you have the correct annotation Spring will automatically do the validation for you. There is a tutorial of that here:
http://www.leveluplunch.com/java/tutorials/017-validate-spring-rest-webservice-request/
As for request parameter validation (ie not bean validation) I have had to make my own transfer objects and exception handling. How you do global exception handling is covered in the Spring Reference guide but generally you extend and/or register a org.springframework.web.servlet.handler.SimpleMappingExceptionResolver. Ironically #ControllerAdvice can be used for exception handling but I find it better to extend and register an Exception Resolver. More info can be found here:
https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-exceptionhandlers
Edit based on OP comments and edits:
If your doing authentication or some other request based validation/authorization its probably best to use an Interceptor. Reference doc. #ControllerAdvice will probably not work as the request handling is too far a long. That is you want something before databinding happens.

How to pass customized request to controller in spring mvc?

Generally, when user's form is submitted, request is passed to spring controller.
and Controllers are shaped like this
TestController(HttpServletRequest request, HttpServletResponse response)
I want to pass "MyHttpSevletRequest, MyHttpServletResponse" not "HttpSevletRequest, HttpServletResponse".
Is it possible?
I want to know is it possible, and how? in technique.
Don't say that "No need to to that, alternative way is here"
Any answer will be appreiciated. Thank you.
I dont know how to do it directly but I know a workaround to get what you intend to do done.
You can use spring aop methodbeforeadvice and afterreturningadvice to get hold of the request and response objects before and after they enter/leave the action method. Basically kind of a request response interceptor you would be doing. In that you can write a transformer method that would take the standard request and response object as input and output you with your custom request and response object(your custom class should implement the HttpServletRequest interface) and then override the request and reponse objects with your custom objects.

Resources