JsonSerializer and JsonDeserializer using HTTP Headers - jersey

I have a requirement in which the REST consumer will be sending in the date data in the client or consumer's locale. The HTTP header will be configured to send the client locale information.
The REST server implementation needs to process the Http header and convert the date from the client locale to the UTC format and store the date into the database.
Similarly when returning back the response when there is a date field the reverse operation is expected. This will ensure the consumer sees the same date which was input by the client.
I want to know how I can access the HTTPRequest object OR pass custom parameters to the my implementated JSONSerializer and JSONDeserializer.

I think you can use the ThreadLocal variable to save the information of ServletRequest and then use it anywhere. For example:
In your filter to get the information you need in request
public class YourFilter implements Filter {
private static final ThreadLocal<String> _date = new ThreadLocal<>();
public static ThreadLocal<String> getDate() {
return _date;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//....
//other code
//get the date from request
Date date = request.xxxxxx();
//set the date to the local thread variable
_date.set(date);
}
}
Use the ThreadLocal variable in your JSONSerializer
#Override
public void serialize(String resourceIdMsg,
JsonGenerator jsonGenerator,
SerializerProvider serializerProvider)
throws IOException {
String date = YourFilter.getDate().get();
}

Related

How to get data from a void returning get request in spring?

A micro-service is providing an api(get request) to download a file which is having a return type as void. It is populating HttpServletResponse but not returning it. How can I get the data from such api?
#GetMapping(value="/download/{id}")
public void download(#PathVariable(value = "id") String id, HttpServletResponse response) {
FileDTO file = downloadFile(id, response);
response.setContentType("text/html");
....
....
}
How can we get the html/text data from the above sample snippet? (Assume all required parameters are set.)

How to pass/inject a session-specific info to the below level?

I have a rest controller and I want to give means to access to a "Session" bean that I create by extracting the infos from the http header.
For this reason I created an HttpInterceptor that pre-handles the request by extracting the headers:
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String remoteUser = request.getHeader("x-remote-user");
log.info("Helo {}", remoteUser);
MySession session = new MySession();
session.setUser(remoteUser);
//what now?
return true;
}
But, how can I do something like this:
public MyController {
public ResponseEntitity<String> action(Request a){
MySession user = getUserSession(); //here I should be able to retrieve the session for that specific user
}
}

How to reject the request and send custom message if extra params present in Spring boot REST Api

#PostMapping()
public ResponseEntity<ApiResponse> createContact(
#RequestBody ContactRequest contactRequest) throws IOException {
}
How to reject the API request, if extra params present in the request, by default spring boot ignoring extra parameters.
I believe you can add an HttpServletRequest as a parameter to the controller method (createContact in this case). Then you'll get access to all the parameters that come with the requests (query params, headers, etc.):
#PostMapping
public ResponseEntity<ApiResponse> createContact(HttpServletRequest request,
#RequestBody ContactRequest contactRequest) throws IOException {
boolean isValid = ...// validate for extra parameters
if(!isValid) {
// "reject the request" as you call it...
}
}
First add an additional parameter to the method. This gives you access to information about the request. If Spring sees this parameter then it provides it.
#PostMapping()
public ResponseEntity<ApiResponse> createContact(
#RequestBody ContactRequest contactRequest,
WebRequest webRequest) throws IOException {
if (reportUnknownParameters(webRequest) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}
I do something like this to get the bad request into the log.
private boolean reportUnknownParameters(WebRequest webRequest) {
LongAdder unknownCount = new LongAdder();
webRequest.getParameterMap().keySet().stream()
.filter(key -> !knownParameters.contains(key))
.forEach(key -> {
unknownCount.increment();
log.trace("unknown request parameter \"{}\"=\"{}\"", key, webRequest.getParameter(key));});
return unknownCount.longValue() > 0;
}
add #RequestParam annotation in your methods parameter list and add it as a map, then you can access for it's key list and check if it contains anything else other than your required params.
public ResponseEntity<ApiResponse> createContact(#RequestParam Map<String,String> requestParams, #RequestBody ContactRequest contactRequest) throws IOException {
//Check for requestParams maps keyList and then pass accordingly.
}

Copy RequestParams to RequestHeaders before handling in RestController

To replace a legacy system and not breaking the interface, I'm looking for a way to implement the following scenario:
If a REST client hasn't set a specific HTTP header (applicationId) but sends it as a query-paramter (aka RequestParameter), this value should be taken as a method parameter in a Spring Boot RestController.
The current method looks like this:
#RequestMapping(value = "/something", method = RequestMethod.GET)
public void doSomething(#RequestHeader("applicationId") String applicationId) { }
I think there could be two possible ways:
Annotate the method somehow to map a query-parameter OR a header to a method parameter
Write an Interceptor which reads all query-parameters of a request and set non-existing headers with their values. This way, the method wouldn't have to be touched at all.
In both ways I'm not sure how to implement them (don't know if 1. is even possible). I tried with an own HandlerInterceptor which reads query-params in preHandle (successfully) but isn't able to set headers in the request before it is forwarded to the RestController.
Write a Filter that wraps the incoming request using a HttpServletRequestWrapper. This wrapper should override the getHeader method.
public ParameterToHeaderWrappingRequestFilter extends OncePerRequestFilter {
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
filterChain.doFilter(new ParameterToHeaderWrappingRequest(request), response, filterChain);
}
}
Register this filter as a #Bean in your Spring Boot application and it will be applied automatically.
public class ParameterToHeaderWrappingRequest extends HttpServletRequestWrapper {
public String getHeader(String name) {
String header = super.getHeader(name);
if (header == null) {
header = getParameter(name);
}
return header;
}
}
Something like that should do the trick. Depending on your needs you might want/need to override some additional header based methods and you probably want to limit the number of headers to override with parameters.
The rest of your code can now be written as is.

Alter request header before controller method using #RequestHeader is called

I have a few controllers that use the #RequestHeader annotation to get the logged in user. I cannot seem to find the correct way to alter the header before the method is called.
I already tried to wrap the request and using an interceptor (in the prehandle method, if I'm not mistaken) and pass along the request,but it seems like the headers are not being queried. An exception is thrown by the servlet dispatcher that the username is missing in the header.
Therefore I'm wondering whether someone knows how and when spring handles this annotation, so I can write the proper interceptor.
Don't have the code at hand, but if needed, I will post fragments later on. But the question is simple: how to inject a param into the request header when #RequestHeader is used on a controller method?
Kind regards,
Tom
First edit:
#Sotirios
I tried using the Filter, which works. But this is less convenient for me than the handlerinterceptor. Since I only need the filter for debugging. So again the better question: why isn't this not working with an interceptor?
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
final HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletRequestWrapper wrapper = new HttpServletRequestWrapper(httpRequest) {
#Override
public Enumeration getHeaders(String name) {
Enumeration headers = super.getHeaders(name);
if( isUseFilter() && Constants.REMOTE_USER.equalsIgnoreCase(name) ){
String user = super.getHeader(name);
headers = enumeration(asList(isEmpty(user)? getDebuggingUserId() :user));
}
return headers;
}
};
chain.doFilter(wrapper, response);
}

Resources