Change the body of a request - java

I have a Java Servlet, which is handling a REST request. However, this is breaking when it receives invalid data. This is POSTed in XML format, and to attempt to resolve this I have added a filter into the filter chain. The filter is being called, and I can access the data in the body of the request, accessing the XML.
I can validate this and manipulate it to ensure that the data is correct, but I cannot work out how to reset it back into the request object.
How can you set the body of an HttpServletRequest object?

You can wrap Your HttpServletRequest object with a new class lets name it: NewHttpServletRequest. The actual rewriting should be done in the appropriate overriden methods e.g getParameter(String)
package com.example;
import javax.servlet.http.HttpServletRequestWrapper;
public class MyHttpServletRequest extends HttpServletRequestWrapper {
public MyHttpServletRequest(HttpServletRequest request) {
super(request);
}
public String getParameter(String name) {
String str = super.getParameter(name);
// DO THE REWRITING
return str;
}
}

Take look at HttpServletRequestWrapper
You can wrap original request with a new object by using public HttpServletRequestWrapper(HttpServletRequest request) constructor, you won't have to do a lot work yourself.

Related

NPE while using Custom Logging in Jetty 10/11

I am implementing Custom logging in Jetty11 and getting the null pointer exception for the below code while fetching anything from the request object.
I know the reason but do not the solution to it. The reason is: calling the request object methods before setting it.
I know, there should be another way to do it.
My use case is to set the int and string attributes to the logger. In this example, I am calling request.getMethod() but I also have to call other methods as well
import org.eclipse.jetty.server.CustomRequestLog;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
public class JettyCustomLogger extends CustomRequestLog
{
private static Request request;
#Override
public void log(Request request, Response response)
{
this.request = request;
super.log(request, response);
}
public JettyCustomLogger(Writer writer, String logStr)
{
super(writer, setCustomAttributesToLog(logStr));
}
private static String setCustomAttributesToLog(String logStr)
{
String method = request.getMethod();
StringBuilder logBuffer = new StringBuilder(logStr);
logBuffer.append(method);
logBuffer.append("Ashish");
logBuffer.append(" ");
logBuffer.append("Goyanka");
logBuffer.append(" ");
logBuffer.append("absgdh");
logBuffer.append(" ");
return logBuffer.toString();
}
}
Note: this code works fine if I don't call request object methods.
Update: the reason to create setCustomAttributesToLog() is that I need to fetch the string parameters from other methods on runtime but here, I have given hardcoded string for code readability
The log(request, response) method is called for every request response pair, this method is expected to produce some formatted log string and then give it to the RequestLogWriter. You should not be using setCustomAttributesToLog() in the constructor as there is no request yet, and you should not be storing the request as a static field. All your logic to convert produce the log string based on the request must be done in the log() method.
For your current implementation, there should be no reason you cannot use the standard CustomRequestLog. If you read the javadoc on this class there is the concept of the format string. The format string is generic and takes % codes to be replaced with information from an actual request/response.
To get what you're trying to achieve here you could do something like
CustomRequestLog requestLog = new CustomRequestLog(writer, "%m Ashnish Goyanka absgdh ")
Then for each request the %m will be replaced with the request method, then this string will be given to the writer.
If you do not wish to use the format string functionality of CustomRequestLog I would suggest you implement the RequestLog interface directly instead of extending CustomRequestLog.

Spring MVC Get POST body before controllers

I need to read POST requests body without consuming it.
I've tried it in a several ways in my custom HandlerInterceptor and nothing works. All I've tried to do to wrap and cache request bodies, at a some point, didn't work, probably even because I cannot control what Spring does.
So I thinked another thing: at some point Spring will try to map request body to an object and pass it to the right Controller. I can intercept this action and get that object before the Controller is called?
Once the request body is read from the request before reaching controller you can not use anywhere. So what you can do is to read the body from HttpServletRequest in the Filter implementation and set it in ThreadLocal variable. Then you can read from that ThreadLocal. Below is the sample code.
Inside Filter implementation class
try {
YourModel yourModel = // Read the request body
RequestContextHolder.setContext(yourModel);
}finally {
RequestContextHolder.clearContext();
}
and at any point of time in the current request you can do like below.
RequestContextHolder.getContext();
Here is the RequestContextHolder class
public class RequestContextHolder {
private static final ThreadLocal<YourModel> THREAD_LOCAL = new ThreadLocal<>();
public static void setContext(YourModel yourModel) {
THREAD_LOCAL.set(yourModel);
}
public static YourModel getContext() {
return THREAD_LOCAL.get();
}
public static void clearContext() {
THREAD_LOCAL.remove();
}
}
I've found a solution: using a CommonsRequestLoggingFilter Spring can log even the payload of the requests. The only bother I'm finding is that I can read the payload only in afterRequest method because in the beforeRequest is absent.
More info on CommonsRequestLoggingFilter here.

Modifying object for each web service call

In our web application we have a lot of REST services. Suddenly it found out that we need to modify one object inside of each request before we go on.
So let's say we have n different controllers with REST services. In each controller, before we call the service from next layer, we need to modify an object inside the request.
The question is how to achieve this without providing hundreds of changes inside the controllers... Is there any simple way to do this?
UPDATE:
#RestController
public class OrderController {
#Autowired
private OrderService orderService;
#RequestMapping(path = "/order", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public OrderResponse getOrderData(#RequestHeader HttpHeaders httpHeaders,
#RequestBody OrderDataRequest orderDataRequest) {
// Use here interceptor to modify the object Details
// (inside OrderDataRequest) before below call:
OrderResponse resp = orderService.getOrderData(orderDataRequest);
return resp;
}
#RequestMapping(path = "/cancel/{orderId}", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public boolean cancelOrder(#RequestHeader HttpHeaders httpHeaders,
#RequestBody Details details, #PathVariable Integer orderId) {
// Use here interceptor to modify object Details before below call:
return orderService.cancelOrder(details, orderId);
}
}
In each controller I need to modift the object Details, which as you can see could be inside another object like in the first example or exist alone like in the second option.
You can use Spring AOP to achieve this. Another option using traditional Filters.
You should consider writing an interceptor, that would allow you to do what you want .
You could also use AOP to do this.. though, I think it's quite over-complicated, especially when such a solution already exists through interceptors!
EDIT :
A few other links :
EDIT 2 :
Follow the "before advice" from mykong.com example, then go that way to edit your specific object according to its class (for exemple) :
package com.your.company;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class HijackBeforeMethod implements MethodBeforeAdvice
{
#Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
for(Object arg : args) {
if(com.your.company.OrderDataRequest.class.isAssignableFrom(arg.getClass())) {
// update you object here
}
}
}
}
- Get response body
- Json To Java

Custom HttpMessageConverter in Spring MVC

When implementing RESTful API I wrap all my data in an object so it looks like this.
{error: null, code: 200, data: {...actual data...}}
This results in repetitive code I use everywhere to wrap data:
#Transactional
#RequestMapping(value = "/", method = RequestMethod.GET)
public #ResponseBody Result<List<BookShortDTO>> books() {
List<Book> books = booksDao.readBooks();
return Result.ok(books); // this gets repeated everywhere
}
So the question is how do I modify this (maybe with use of custom HttpMessageConverter maybe some other ways?) to just return booksDao.readBooks() and to get it wrapped automatically.
Like #Ralph suggested you can use a HandlerMethodReturnValueHandler to wrap your handlers return value.
The easiest way to achieve this is by extending RequestResponseBodyMethodProcessor and alter it's behavior a bit. Best is to create a custom annotation to mark your handler methods with. This will make sure your HandlerMethodReturnValueHandler will be called instead of others included by RequestMappingHandlerAdapter by default.
#Target({ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
public #interface ResultResponseBody {}
Here is a simple implementation of the custom HandlerMethodReturnValueHandler named ResultResponseHandlerMethodProcessor which will support values returned from methods annotated with ResultResponseBody. It's pretty simple. Just override the supportsReturnType() and handleReturnValue() methods to suit your needs (wrap the return value into a Result type).
public class ResultResponseHandlerMethodProcessor extends RequestResponseBodyMethodProcessor {
public ResultResponseHandlerMethodProcessor(final List<HttpMessageConverter<?>> messageConverters) {
super(messageConverters);
}
public ResultResponseHandlerMethodProcessor(final List<HttpMessageConverter<?>> messageConverters, final ContentNegotiationManager contentNegotiationManager) {
super(messageConverters, contentNegotiationManager);
}
#Override
public boolean supportsReturnType(final MethodParameter returnType) {
return returnType.getMethodAnnotation(ResultResponseBody.class) != null;
}
#Override
public void handleReturnValue(final Object returnValue, final MethodParameter returnType, final ModelAndViewContainer mavContainer, final NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException {
super.handleReturnValue(Result.ok(returnValue), returnType, mavContainer, webRequest);
}
}
The only thing left is to add this class to the list of custom HandlerMethodReturnValueHandlers and provide it with a MappingJackson2HttpMessageConverter instance.
#EnableWebMvc
#Configuration
public class ApplicationConfiguration extends WebMvcConfigurerAdapter
#Override
public void addReturnValueHandlers(final List<HandlerMethodReturnValueHandler> returnValueHandlers) {
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
messageConverters.add(new MappingJackson2HttpMessageConverter());
returnValueHandlers.add(new ResultResponseHandlerMethodProcessor(messageConverters));
}
}
I think, rather than changing the message converters (which would work), I would use an AOP approach - around advice on all the relevant controller methods would be quite easy to set up. It would also give you a nicer programming model, and finer grained control of which methods are intercepted.
You could use a HandlerMethodReturnValueHandler to replace the result.
The key point is: to replace the return value before delegating the (modified) retunr value to the serialisation.
See this blog: http://martypitt.wordpress.com/2012/11/05/custom-json-views-with-spring-mvc-and-jackson/ for an example how to archive a similar (not the same) goal. It also describe one way to register the HandlerMethodReturnValueHandler (for an other see Bart´s answer)
I'd like to try and convince you that what you are doing is right and does not require any changes.
As you've posted in the comments to your question, you have a number of different Result methods which set the error message, the code, and the data. Something like
Result.ok(data)
Result.forbidden()
Result.badRequest("<Something> caused a syntax error.")
Result.notModified("The entity was not modified.")
I'm assuming these methods are meant to map to the various HTTP status codes, but with custom error messages.
Your #Controller handler methods are meant to handle a request and prepare a response. That's what your method is currently doing and it is very explicit about what it does. The logic about what the Result should be belongs to the handler method, not a HandlerMethodReturnValueHandler, like others are proposing.
I would even suggest using ResponseEntity instead of #ResponseBody. You can return a ResponseEntity and set the HTTP response headers and status code explicitly. You would also set the response body.
Something like
return new ResponseEntity<>(Result.ok(books));
In this case, the default status code is 200.
But if you wanted to use
return Result.forbidden();
you would use
return new ResponseEntity<>(Result.forbidden(), HttpStatus.FORBIDDEN);
Spring will use the same HttpMessageConverter to convert your Result into JSON, but here you will have more control over the HTTP response.
I think it is necessary to
replace the default RequestResponseBodyMethodProcessor with you owner
processor
, otherwise the default RequestResponseBodyMethodProcessor will take control of handling return value.

How to set the values to one setter method using Reflection without knowing class?

I am new to java reflection.I will directly come to the question.
This is my class
public class RequestClass{
#XmlElement(name="Request")
private Request mRequest;
public Request getRequest() {
return mRequest;
}
public void setRequest(Request request) {
this.mRequest= request;
}
this my another class in this I am passing RequestClass object here
//The supplied requestObject is of type RequestClass
Object initialize(Object requestObject) {
//requestObject
}
In this code I want to manipulate, dynamically, the request property of the RequestClass. I don't know how to proceed further, so if anyone could provide some guidance, I would appreciate it. Thanks.
try this requestObject.getClass().getMethod(method_name).invoke(requestObject);
also, there is an overload of getMethod & invoke, through which you can pass parameter to that method (like in setters)

Categories

Resources