Modify HttpResponses in Java

Vijayakumar
6 min readJan 11, 2019
Basic flow of messages in a filter architecture

The reason for coming up with this article is , though there are quite a lot of articles on how to get the response in filter, there are only a few of them on how to write new content/modify existing the content and send it in the response. I’ve banged my head for a couple of days until I came up with the solution. I hope this article helps those are struggling to get the response modified

Table of Contents

Short Story: Need for Filter

Filters as the name suggests are used to get the silted set of objects from a HTTP Flow. As a general use case , a user may need to identify how many number of users have logged into his web application, or more precisely the users who are using his services. This will not come under the hood of business needs but as a software developer one is expected to have this use case solution embedded as a part of his development. These are more precisely like cross cutting concerns but that may need AOP framework.

Logging the requests that are coming in is another example of one such use case

Filters when used as a cross cutting mechanism provides one of the solutions but there is more to it when comes to Filters.

Short Story: Interceptors

The most commonly used Java web framework is SpringBoot. The scope of the article does not deal with setting up an app using SpringBoot.

Here are a few links to get started

Now in each of these APIs created, Springboot magically maps the incoming request and the request object/body is auto converted to the required type and the appropriate controller method is called. The same happens with the construction of responses

HandlerMapping

When the magic in unboxed, what we get behind the scenes is that, when a URL is triggered with the HTTP verb , be it GET/POST/PUT/HEAD/DELETE , the context of the application is determined from the URL

The DispatcherServlet , which is the frontController of any SpringBoot application, determines the call to the appropriate method bymeans of identifying the endpoint from the URL.

But how does the mapping take place. Enter HandlerMapping!!!

This predetermines what methods are mapped to URLs and thus enabling the DispatcherServlet to map it appropriately when a request is triggered. This takes care of the all the message converters (even the custom ones implemented) to be mapped to the controller methods and handles the serialization and the deserialization part

The filter constructs can be achieved to a certain extent using interceptions in Springboot. Interceptord cannot be used to achieve the entire flexibility of filters but nevertheless they are useful

The very basic of serialization and deserialization in spring boot is built on top of Interceptors.

HandlerInterceptor

Now to achieve the preprocessing and postprocessing of the HttpRequests and and partially responses, SpringBoot by default provides HandlerInterceptors

This interface contains three main methods:

  • prehandle() — called before the actual handler is executed, but the view is not generated yet
  • postHandle() — called after the handler is executed
  • afterCompletion() — called after the complete request has finished and view was generated

Interceptor vs Filter

One of the major issue with the Interceptors is that althoug being much similar to that of filters, it just allows preprocessing of responses but never modify the response itself. Now inorder to handler that, we have to enter the world of Filters

Filters in itself are more powerful than interceptors, allows easy custom wrapping of requests and responses along with the streams

Filters get executed in order they are placed. They are executed when requests are sent from clients and also when responses are sent back from the server and the order is maintained in each flow.

For example, consider the below diagram, where the client sends the request, and the order of execution of filters is Filter1 -> Filter2 -> Filter3 and finally the request reaches the Server. When the response is sent back, the order of execution is Filter3 -> Filter2 -> Filter1.

Order in Spring Apps can be applied using @Order annotation

Handling request and response in Filter

The doFilter() method is the crux in all Filters. This is where the processing of requests and responses take place.

The Filter example provided shows the how the response of Swagger-/v2/api-docs can be modified albeit in a very simple way. Note that this can be used to apply for complex scenarios as well

Note: Modifying requests is pretty straight forward and hence the example is not provided. Here is a sample link from SO

The example I provided had an issue with openAPI spec where /v2/api-doc generated a very weird content containing some XMLs in the JSON string. This is a configuration related issue where one has to drill down each and every controllers , models to resolve it. But in my case, the timeline was pretty short and I had numerous controllers for a given module. So I took the easier part of modifying the response using a filter.

Below are the steps I followed

  1. First we convert the Servlet requests and responses as HttpRequest and HttpResponse
  2. Next we have a custom implementation of Printwriter as ByteArrayPrintWriter for the responseStream to be overwritten

3. Now we wrap the HttpResponse with the custom implementation of the responseWrapper

4. Note that the responseWrapper now has the outputStream of the custom PrintWriter — ByteArrayPrintWriter which in turn has its own OutputStream implementation.

5. Next we chain the request and response (In this case the custom responseWrapper). Chaining merely passes on the requests and responses to the next layer of filter and if there is none to the default Dispatcher Servlet

6. We then modify the response outputStream , by first getting the byteArray from the custom printWriter (this takes care of the exactly once semantics of streams where once consumed the stream is no longer available), and then write to the actual HttpResponse OutputStream (since we consumed the cloned stream, we get the details required , we are then able to modify it and then write to the same outputStream).

BONUS: Removing XML elements in JSON

This is a sample implementation of removing an XML element from the JSON string. This is a JAVA 8 implementation which is going to be integrated with the Filter written above

BONUS: Writing response from File

This gives an example of how to send static content read from a file as a response

Note: The Filter Bean has to be described as a separated bean for the spring container and the dispatcher servlet to recognize. We could also register the URLs to which the filter has to be applied. Here is a sample. My implementation required that it has to be applied to swagger apis

@Bean
public FilterRegistrationBean<DumpFilter> dumpFilterRegistrationBean() {
DumpFilter filter = new DumpFilter();
FilterRegistrationBean<DumpFilter> bean = new FilterRegistrationBean<>();
bean.setFilter(filter);
List<String> match = new ArrayList<>();
match.add("/v2/api-docs");
match.add("/api-docs");
match.add("/api-docs?group=dataaccess-api");
bean.setUrlPatterns(match);
return bean;
}

Please shoot me up with any questions. Happy coding!!!

--

--