I have written a interceptor to make some changes before service call in my spring boot rest service.
Added picture to show my code how I written preHandle method.
In the picture, I want to bring the "orginationTaskServerMockEnabled = true" value which is in
handler -> bean-> mHandler -> dashboardConfig-> originationTaskServerMockEnabled
I tried by it doesnt, is it possible to bring the values from HanlderMethod. If so please help me.
It is not possible to access the handler arguments in the interceptor's preHandle. It is called before the actual invocation of the handler method. The resolution of actual argument types is done during its invocation, so during the execution of preHandle, the argument's value are not resolved yet (but are described by Object handler argument). Only HttpServletRequest and HttpServletResponse are known during the execution so, if the data is attached to the request, you can grab it from there.
Alternatively, you can use an aspect and wrap it around your controller method. From there, you can grab the method arguments then perform your preprocessing.
#Around("execution (* com.pck.controllers.*.*(..)) && #annotation(org.springframework.web.bind.annotation.RequestMapping)")
public Object beforeHandler(ProceedingJoinPoint p){
Object args[] = joinpoint.getArgs();
return joinpoint.proceed();
}
Related
The HandlerInterceptor interface has a parameter Object handler, which means implementing code has to do type checking on the handler object in order to use it, and cast it as appropriate.
Code snippets I've found seem to assume the handler is always a HandlerMethod object and return true if this isn't the case, but I want to understand why this seems to be a common implementation to make a robust implementation.
A standard way of implementing this interface seems to be:
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if (handler instanceof HandlerMethod) {
// ...
return x; // whether or not to proceed with execution
}
return true; // fallback value in case handler wasn't a HandlerMethod
}
}
The Spring javadoc seems to ignore the fact that the interface has an Object type in it, it's very unhelpful for my understanding of this interface.
Some questions that might aid my understanding of how this interface is supposed to be implemented:
Why is true a sensible default if we get a handler that's not the object we expect it to be?
Which types can an HandlerInterceptor take for its handler parameter?
Under what circumstances could handler be a different type, if any?
Why is it an Object, not a HandlerMethod, parameter?
Basically the handler argument can be any type for which a HandlerAdapter exists. Most commonly used will be the RequestMappingHandlerAdapter utilizing a HandlerMethod.
But it could be a regular class, a servlet, or even a function (when using the functional approach). Spring Web Services also has an implementation as well as Spring Integration.
Spring itself will support the following out-of-the-box
HandlerMethod
HandlerFunction
Controller
Servlet
HttpRequestHandler
WsdlDefinition (Spring Web Services)
XsdDefinition (Spring Web Services)
So no it isn't always a HandlerMethod but it will be for most users.
Here's what javadoc of HandlerInterceptor#preHandle() says:
Interception point before the execution of a handler. Called after HandlerMapping determined an appropriate handler object, but before HandlerAdapter invokes the handler.
DispatcherServlet processes a handler in an execution chain, consisting of any number of interceptors, with the handler itself at the end. With this method, each interceptor can decide to abort the execution chain, typically sending an HTTP error or writing a custom response.
This means interceptors are not supposed to touch the handler at all so they don't need to know anything about it. Their only job is to decide whether to pass the request further or not.
BTW, none of the standard HandlerInterceptor#preHandle() implementations in org.springframework.web.servlet.* try to analyze the true handler parameter type and do any logic based on it.
Why is it an Object, not a HandlerMethod, parameter?
From the org.springframework.web.servlet.HandlerMapping#getHandler() javadoc:
Return a handler and any interceptors for this request. The choice may be made on request URL, session state, or any factor the implementing class chooses.
The returned HandlerExecutionChain contains a handler Object, rather than even a tag interface, so that handlers are not constrained in any way. For example, a HandlerAdapter could be written to allow another framework's handler objects to be used.
I am building a service with RestAPI's. I want to put a custom annotation as mentioned below.
#CustomAnnnotation
public APIResponse apiMethod(APIRequest request) {
}
Functionality of this custom annotation :
Whenever there is a request to this apiMethod, before the execution of this method , i want to call an API in different server with some of the request parameters from this function. Example mentioned below. Basically for every method invocation i want to call a different server.
Instead of doing this
public APIResponse apiMethod(APIRequest request) {
newServiceClient.newAPI(request.getName())
}
I want to do this functionality by using a custom annotation. I know that i can use interceptors to intercept this request and call the API. Is there any other way ?
Edit :
To summarise this question. There is a method(This might not be API start point. It can also be a normal method in your application) in my java code. Whenever i annotate this method, for every invocation of this method in application, i want do some functionality. I want to have this in annotation because i am thinking of providing a library for this annotation so that any function can be annotated
Say I have a Dropwizard/Jersey resource defined like so:
// Pseudo-code
#Path("/fizz")
#Produces(MediaType.APPLICATION_JSON)
class FizzResource {
FizzDao fizzDao
#GET
List<Fizz> getFizzesByType(#PathParam("type") String type) {
// Do some stuff up here
return fizzDao.getFizzesByType(type)
}
#POST
Widget determineWidgetByFoobaz(#PathParam("foobaz") String foobaz) {
// Do some stuff
List<Fizz> fizzes = getFizzesByType(foobaz.type)
Widget w = new Widget(fizzes, true, blah)
// Do some more stuff
return w
}
}
What happens when I call one endpoint (getFizzesByType) from inside another endpoint (determineWidgetByFoobaz)?
Does the framework know to just make a Java method call? Or is an actual network call (to localhost/loopback/etc.) made? If a network call is made, does the framework provide any way to configure it so that just a local Java method invocation is called instead?
If you access the endpoint as a method (i.e. this.getFizzesByType(type)) then it will be called like any other Java method. If you access it via a URI (e.g. ClientBuilder.newClient().target("http://localhost/fizz/" + type).request().get()) then it will be accessed as a network resource.
The getFizzesByType call inside determineWidgetByFoobaz is just another local method call. There's nothing special in those methods, and you can also call them safely in, let's say, a unit test.
What Jersey does on it's bootstrapping process is to scan for classes annotated with #Path and then bind each method annotated with an HTTP method to it's endpoint (if any). That way, when someone fires a GET to /fizz, in a nutshell Jersey gets a FizzResource instance, call it's getFizzesByType method, serializes the returned object to JSON, creates the appropriate HTTP response and sends it back to the client.
I am writing a Servlet that retrieves request parameters but needs to use them in the init method. Since the init method would be called before the doGet method and since the init method does not have a HttpServletRequest object as an argument, I don't know how to get the request parameters.
public class OpenIdServlet extends HttpServlet
{
...
...
private OpenIdManager manager;
#Override
public void init() throws ServletException
{
super.init();
manager = new OpenIdManager();
manager.setRealm("http://localhost:8080/OpenIDSample");
manager.setReturnTo("http://localhost:8080/OpenIDSample/openid"); //I need to append the value of a request parameter here...
}
...
...
}
So the question is: is there any way I can get HttpServletRequest parameters in the init() method of a servlet? If no what other better approach can one use to solve this problem? Thanks.
The init is called once on startup. So you have to live with a partial returnTo, and on request handling (doGet/doPost) complete it with the request parameters.
In fact the manager seems to be request dependent and hence should be created in the request - never as field. As there might be several requests. Maybe persisting as session attribute.
Your question doesn't make sense. There is no request when the init() method is called. It is called during container initialisation.
Do you mean initial parameter? They are available via the ServletContext provided as an argument to init().
I'm playing with spring interceptors in last few days and want to catch and handle specific requests through interceptor. What I want to do is to intercept each request before it is processed by specific controller, check whether request contains specific parameters or not. If yes, do some stuff and than sign that stuff to controller which maps that request.
At the end I managed to do that, but when I execute multiple requests at once, with different param values, only param value from last request is assigned to each of controller handler, even every controller should have params which are contained within the request.
Example (executed at the same time):
http://domain.com/controller/method?param=xfg
http://domain.com/controller/method?param=mtc
http://domain.com/controller/method?param=abc
in responses from each request, I get abc! (sometimes I get xfg and abc, or mtc and abc, but never all three of them). When I execute these requests with timeout where every request have time to complete before next one is called, it is working fine.
Does anyone know how to handle this?
Thanks
UPDATED:
public class OLMyInterceptor extends HandlerInterceptorAdapter {
static Logger LOG = Logger.getLogger(OLAuthentificationInterceptor.class);
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Map<String, Object> activeParamsMap = request.getParameterMap();
for(Entry<String, Object> param : activeParamsMap.entrySet()) {
if(param.getKey().startsWith("aP_")) {
activeParams.put(param.getKey().substring(3), param.getValue());
}
}
((MainController) handler).setParams(activeParams);
return true;
}
}
There you have code sample. Every controller of mine extends MainController, that's why I cast handler to MainController, which have setParams method. Every other controller use params in different way.
You must invoke a controller handler method with params, not setter which changes controller state.
The controller must be stateless or thread-safe. When you change state you do not have a guarantee when the setter applies changes - before handlers invoked in another thread, or after. Or another thread invokes setter with other params and previous thread invokes handler method for new params.