I am having trouble seeing how i can read form the stream when its being read up in the chain somewhere.
here is my function
#POST
#Consumes(["application/json"])
public Response addGift(#Context HttpServletRequest request,#QueryParam("from") int from,
#ApiParam(value = "Indiviual Gift object to be inserted", required = true) posiba.api.v1.IndividualGift gift) {
return Response.ok().entity("{\"Submit\": \"Success\"}").build();
}
I have a json data POST (payload , body) and a queryparam(for testing)
the request variable can access the params but when i try and read from the stream
stream.available() returns 0 and if i try and get anything out of the stream it closes it.
is there a way to inline override the input stream reader so whatever is up the chain does not read from it and i can use it locally.
solved it myself -- a bit of a hack way tho ----
the goal was to use swagger UI in my grails app so i have one method( as seen above) to tell swagger about the parameters and required etc...and then i made a separate function that accepts the request and does my custom handling of it
#POST
#Consumes(["application/json"])
public Response addGiftt(#Context HttpServletRequest request, InputStream requestBody){
//stuff...
}
Related
In spring I have a controller with an endpoint like so:
#RequestMapping(method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
#ResponseBody
public OutputStuff createStuff(#RequestBody Stuff stuff) {
//my logic here
}
This way if doing a POST on this endpoint, the JSON in request body will be automatically deserialized to my model (Stuff). The problem is, I just got a requirement to log the raw JSON as it is coming in! I tried different approaches.
Inject HttpServletRequest into createStuff, read the body there and log:
Code:
#RequestMapping(method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
#ResponseBody
public OutputStuff createStuff(#RequestBody Stuff stuff, HttpServletRequest req) {
StringBuilder sb = new StringBuilder();
req.getReader().getLines().forEach(line -> {
sb.append(line);
});
//log sb.toString();
//my logic here
}
The problem with this is that by the time I execute this, the reader's InputStream would have already been executed to deserialize JSON into Stuff. So I will get an error because I can't read the same input stream twice.
Use custom HandlerInterceptorAdapter that would log raw JSON before the actual handler is called.
Code (part of it):
public class RawRequestLoggerInterceptor extends HandlerInterceptorAdapter {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
StringBuilder sb = new StringBuilder();
req.getReader().getLines().forEach(line -> {
sb.append(line);
});
//log sb.toString();
return true;
}
}
The problem with this tho is, that by the time the deserialization to stuff happens, the InputStream from the request would have been read already! So I would get an exception again.
Another option I considered, but not implemented yet, would be somehow forcing Spring to use my custom implementation of HttpServletRequest that would cache the input stream and allow multiple read of it. I have no idea if this is doable tho and I can't find any documentation or examples of that!
Yet another option would be not to read Stuff on my endpoint, but rather read the request body as String, log it and then deserialize it to Stuff using ObjectMapper or something like that. I do not like this idea either tho.
Are there better solutions, that I did not mention and/or am not aware of? I would appreciate help. I am using the latest release of SpringBoot.
To read the request body multiple times, we must cache the initial payload. Because once the original InputStream is consumed we can't read it again.
Firstly, Spring MVC provides the ContentCachingRequestWrapper class which stores the original content. So we can retrieve the body multiple times calling the getContentAsByteArray() method.
So in your case, you can make use of this class in a Filter:
#Component
public class CachingRequestBodyFilter extends GenericFilterBean {
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest currentRequest = (HttpServletRequest) servletRequest;
ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(currentRequest);
// Other details
chain.doFilter(wrappedRequest, servletResponse);
}
}
Alternatively, you can register CommonsRequestLoggingFilter in your application. This filter uses ContentCachingRequestWrapper behind the scenes and is designed for logging the requests.
As referenced in this post: How to Log HttpRequest and HttpResponse in a file?, spring provides the AbstractRequestLoggingFilter you can use to log the request.
AbstractRequestLoggingFilter API Docs, found here
I also tried to do that in Spring but i could not find way to pass my custom http request to chain so what did was,i have written traditional j2ee filter in that i have passed my custom http request to chain that is it then onward i can read http request more than once
Check this example http://www.myjavarecipes.com/how-to-read-post-request-data-twice-in-spring/
I am practicing developing a jenkins plugin. And I want to send an ajax request with some cookies in front end for back end processing and then receive some json response to continue processing my front end logic. Is it possible for me to bind a url to a back end java method with parameters like StaplerRequest and StaplerResponse and simply get the returned json from the method as my response?
After searching around, I found a site introducing how Jenkins stapler works. Particularly, the action method might be helpful for me
According the document I found:
Action Method
If url is of the form "/fooBar/...." and node has a public "action" method named doFooBar(...), then this method is invoked.
to retrieve a json response,
In front end,
$.ajax({
url: "./someUrl/",
}).done(doSomethingOnData(data));
In back end, define a corresponding action method:
public void doSomeUrl(StaplerRequest request, StaplerResponse response) {
Cookie[] myCookies = request.getCookie();
doSometingBasedOnCookies(myCookies);
response.setStatus(200);
response.setContentType("application/json;charset=UTF-8");
String myJson = getJson();
response.getWriter().print(myJson);
}
Yes, you can create simple Rest Method which consume nothing but response back in JSON, something like this
#POST
#Path("/somemethod")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public CommonResponseBean somemethod() {
return response(); // return CommonResponseBean, this will automatically converted into json using jackson
}
I am working on a Jersey service client for one of my services and am having trouble determining the best way to pass a null entity through the client's put. On the service side of things this is my endpoint:
#PUT
#Path("/rule/disable/key/{key}")
#Produces(MediaType.APPLICATION_JSON)
public Response disableRuleByKey(#PathParam("key") String key)
throws Exception {
try {
DAL.getWriter().disableRuleByKey(key);
return Response.ok().build();
} catch (BlahException bla) {
throw de;
}
Basically all the method does in the backend is flip a toggle for other parts of the application to use. I'm not sure if put is the correct call to use here (but this was written by a teammate). I know it doesn't even have a JSON payload.
Anyways, on the client side I have this generic putItem() code for all of my clients to use via extends:
public static <T> boolean putItem(Client client, String uri, T item)
throws InterruptedException,
ExecutionException {
Invocation putConfig = client.target(uri).request()
.buildPut(Entity.entity(item, MediaType.APPLICATION_JSON));
Future<Response> asyncResponse = putConfig.submit();
Response response = asyncResponse.get();
return response.getStatus() == Status.OK.getStatusCode();
}
This PUTs into the database fine with a JSON payload, but since the method above doesn't specifically have a payload I was wondering what the best course of action would be. Would modifying the Invocation's .buildPut() to have null in it be okay since I am not passing in a payload.
I am open to modifying the endpoint too but this is what I currently have and can't figure out the best way to send this value to the backend. Should I just modify the endpoint to consume a JSON object rather than passing the key as a #PathParam?
When replacing the state of a resource with a PUT request, you should send the new representation in the request payload.
Have a look the the RFC 7231, the current reference for semantics and content in HTTP/1.1:
4.3.4. PUT
The PUT method requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message payload. [...]
I have a Spring REST application that accepts JSON messages, written like
#RequestMapping(value = "/myhook", method = RequestMethod.POST,
produces = JSON, consumes = JSON)
public #ResponseBody MyResponse doIt
(#Valid #RequestBody(required = true) MyContractRequest request) {
MyResponse response;
...
return response;
}
This works really well with almost no code to support, but now I have a requirement to sign both response and request.
I started from simply computing the shared signature of all message fields at Java level and assigning it to the dedicated signature field. However this requires to have and maintain code for computing the signatures:
public void update(java.security.Signature sign) throws Exception {
sign.update(name);
sign.update(value);
sign.update(etc);
}
Some people around me expressed opinion that the need to write and maintain this signing code may not be the best design, and it may be better to sign the whole message as a single JSON string. I could fetch the request as a string manually, and then process JSON manually, but I really would like to preserve the Spring controller concepts.
Also, I cannot longer have the signature field in the message itself because the value of this field obviously also changes the signature of the JSON string.
Is there any way to compute the signature of the whole JSON message body on the message departure and arrival, and where to place the signature so it could be passed together with the message? One of the idea is to use the custom HTTP header for the signature. Anyway, how to compute it first?
You can use a servlet filter with Spring MVC and modified your content whatever you want in request and response as well
Example :
http://www.mkyong.com/spring-mvc/how-to-register-a-servlet-filter-in-spring-mvc/
or you can use Spring 3 MVC Interceptor
http://viralpatel.net/blogs/spring-mvc-interceptor-example/
I'm using Spring MVC, and I'm trying to experiment with the Facebook API, just for fun.
The problem I'm having currently, is that Facebook's GRAPH Api returns other status codes than 200 when it encounters an OAuthException. However, the body of the response is still a valid json object, and I would like to parse it into my object.
This way, my restTemplate will invoke the errorhandler, when the status code is anything else than HTTP.2xx, and not parse the response to my object.
Is there any way of configuring the RestTemplate so that it should parse the response body regardless of http status?
Thanks!
you could set a customer ResponseErrorHandler
restTemplate.setErrorHandler(customerErrorHandler)
you'll just need to implement the following two methods
boolean hasError(ClientHttpResponse response) throws IOException;
void handleError(ClientHttpResponse response) throws IOException;
in your case hasErrorcould always return false