Using Spring #RestController to handle HTTP GET with ZonedDateTime parameters - java

I'm creating an endpoint that will receive dates to do some filtering in the server side. The code looks like this:
#RequestMapping(
value = "/test",
method = RequestMethod.GET,
produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE}
)
#ResponseStatus(HttpStatus.OK)
public TestSummaryModel getTestSummaryByDate(
#RequestParam ZonedDateTime start,
#RequestParam ZonedDateTime end) {
return testService.getTestBetween(start, end);
}
When I try to invoke my endpoint I get an HTTP 400 error "The request sent by the client was syntactically incorrect."
I have try different date formats but none of them worked. Am I missing something? I read about the #DateTimeFormat but even though I added it, was not working.
#RequestParam #DateTimeFormat(pattern = "dd-MM-yyyy") ZonedDateTime start
This is an example of the request I'm doing:
http://host/test-api/v1/test-summary/test?start=09-09-2015&end=09-09-2015
Thanks!

#DateTimeFormat is what you need. Spring MVC 4 has the appropriate converters for ZonedDateTime.
However, you need to provide an appropriate pattern and send an appropriate value.
The information provided in a date formatted as dd-MM-yyyy is not enough to produce a ZonedDateTime.
Try
#RequestParam("start") #DateTimeFormat(iso = ISO.DATE_TIME) ZonedDateTime start
and send
...?start=2014-04-23T04:30:45.123Z
Alternatively, use a date type that doesn't need zone or time information and provide an appropriate date format to #DateTimeFormat.

Related

How to get time zone from user request in Spring Weblux

In non-Reactive spring we can get Time zone from request in that way -
RequestContext.getTimeZone(request)
Is there any way to get time zone from ServerRequest, using Spring WebFlux ?
you can use ServerRequest.headers() which return a Headers object, from which you can call the first method passing the "Accept-Language" or "Timezone" header name, and get the timezone.
public Mono<String> getTimezone(ServerRequest request) {
return request.headers().header("Accept-Language").next().map(timezone -> timezone);
}

How to correctly pass a formatted datetime into a HTTP request?

I was tasked with writing a test for a REST service by calling its endpoint with an HTTP request. One part of the HTTP request should be a date (to filter only items modified after that date). The problem is, that I cannot seem to properly pass the date into the HTTP request.
This is how the endpoint is defined in the Rest Controller:
#GetMapping("/{resourceType}/{application}")
public Map<String, Map<String, Map<String, Map<String, String>>>> findByTypeAndApplication(#PathVariable("resourceType") ResourceType type,
#PathVariable("application") String application,
#RequestParam(name = "modifiedAfter", required = false) #DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date modifiedAfter)
It is the "modifiedAfter" parameter that is giving me trouble. Trying to pass a date formatted according to the "pattern" does not appear to work for me. After parsing into URL, the request would look like this:
http://.../LANGTEXT/INTEGRATION-EXCEL-TEST?modifiedAfter=2019-06-11%2021%3A28%3A44
I also tried restassured.given to build the requests. I tried to pass the parameter in the address itself, as a param(), as a queryParam(), and as a formParam(). I tried to pass it both as a formatted string (as per the pattern), and as a Date object. Nothing seems to work.
I cannot change the controller itself (including the date format), so I need to properly pass the date in the HTTP request.
I'd be grateful for any advice.
Thanks, Petr
On server side, spring does this automatically. You don't need specify date pattern.

How to use Gson instead of Jackson for MockMvc?

I have spent the past day trying to find a solution to this and could not find any online resource that solves this.
I am using Gson for Message conversion for my application, which works fine outside of unit testing. I even added a HttpMessageConverters bean to take precedence over Jackson instead of writing config values to application.yml. This only works when running the application.
Now my question is, how do I use the Gson serialization/deserialization for MockMvc? I have a class with the #SerializedName("field_one") annotation which the value differs from the actual name. The closest I got to finding an answer was the one below which didn't help:
https://stackoverflow.com/a/20510028/3948882
Any ideas how to replace the ObjectMapper or have MockMvc use Gson instead of Jackson?
Edit: To add a little more context:
When I try to send a Model which was converted to Json with Gson, it get's immediately refused (400) because I have #NotNull annotation for each field in the model. When it deserializes in the controller, it sets fields to null. The below example has #Valid, which makes sure the Model checks out.
#RequestMapping(value = "accept", method = RequestMethod.POST)
public Model resp(#Valid #RequestBody Model model){
return model;
}
On the flip side, when I go to hit an endpoint without #Valid, passing a json that pleases Jackson, and I get the a model back, I cannot check any of the fields:
mockMvc.perform(
post("/test/accept")
.contentType(MediaType.APPLICATION_JSON)
.content(json))
.andExpect(jsonPath("$.field_one", is("Hello world!")))
Exception:
java.lang.AssertionError: No value at JSON path "$.field_one", exception: No results for path: $['field_one']
You have to set-up the MockMvc correctly:
MockMvc mvc = MockMvcBuilders.standaloneSetup(new YourController())
.setControllerAdvice(new SomeExceptionHandler())
.setMessageConverters(new GsonHttpMessageConverter()) //<-- THIS
.build();

How to configure locale based date format support in spring

Does someone had this problem:
I need to configure spring to recognize locale based date and number format, i.e. the following user behavior should be valid:
User select language to EN, then the number format 1.23 should be valid, spring mvc will accept this format and no valid error triggered. User can also change the date with date format MM/dd/yyyy and no valid error raised, user can post this form.
User select language to DE, then the number format 1,23 should bevalid, spring mvc will accept this format and no valid error triggered. User can also change the date with date format dd.MM.yyyy and no valid error triggerd. User can post this form.
I'v tried to use #DateTimeFormat(pattern="#{messageSource['date_format']}"),(I have date_format defined in messages_(locale).properties) but seems spring doesn't support this yet, see JIRA ISSUE
Does someone has the similar problem and got a solution.
Does it help to write my own converter, and register it in org.springframework.format.support.FormattingConversionServiceFactoryBean? I need some kind of request based converter
Since nobody answers my question, I just post one of my solution to solve this problem, it could help others:
I had a request scoped bean, which resolves locale using: RequestContextUtils.getLocale(request); request can be autowired to the request scoped class(NOTICE, it works only with field injection, not with construction or setter). In this class I get locale based date/number format.
In my controller (we have actually a abstractController). I have code like this:
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Date.class, new LocalizedDateEditor(formatHelper));
}
formatHelper is the request scoped bean. LocalizedDateEditor looks like this:
public class LocalizedDateEditor extends CustomDateEditor {
public LocalizedDateEditor(FormatHelper formatHelper) {
super(new SimpleDateFormat(formatHelper.getDefaultDateFormat()), true);
}
}
It just tell spring to use my dateFormat.
That's all.

How to add a parameter at the end of a restFul service URL?

I am trying to add a parameter at the end of the restFul web service URL.
USING Spring3
#RequestMapping(value="/searchForXmlFormat/{lastName}*?format=xml"* ,headers="Accept=application/atom+xml",method=RequestMethod.GET)
I want to get something like this:
rest/name/abcd?format=xml
or
rest/name/abcd?format=json.
I have the codes to get the data in JSON /XML format. I need to figure out how to add the ?format=xml or ?format=json at the end.
Why doesn't the recipient of your request just check what data format you're accepting from your request headers?
Otherwise, I guess you could specify them as query parameters, but this is totally dependant on what language and frameworks you're using.
If you use JAX-RS, I think what you're looking for is the annotation QueryParam. Here's an example that may fit your case:
#GET
#Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON } )
public String doGet(#QueryParam("format") String fmt) {
//...
}
With the code above the fmt will contain the value of the parameter format in your URL rest/name/abcd?format=...

Categories