I have a REST endpoint in my Spring application that looks like this
@RequestMapping(value="/customer/device/startDate/{startDate}/endDate/{endDate}", method=RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE)
public Page<DeviceInfo> getDeviceListForCustomerBetweenDates(@PathVariable ZonedDateTime startDate, @PathVariable ZonedDateTime endDate, Pageable pageable) {
... code here ...
}
I have tried passing in the path variables as both milliseconds and seconds. However, I get the following exception both ways:
"Failed to convert value of type 'java.lang.String' to required type 'java.time.ZonedDateTime'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type java.lang.String to type @org.springframework.web.bind.annotation.PathVariable java.time.ZonedDateTime for value '1446361200'; nested exception is java.time.format.DateTimeParseException: Text '1446361200' could not be parsed at index 10"
Can someone please explain how I can pass in (either as seconds or milliseconds) a String such as 1446361200 and get it to convert to ZonedDateTime?
Or is the only way to pass as String and then do the conversion myself? If so is there a generic way to get this handled for multiple methods with similar design?
From Spring 4.3. 3 version, @PathVariable annotation has required attribute, to specify it is mandatorily required in URI. The default value for this attribute is true if we make this attribute value to false, then Spring MVC will not throw an exception.
The @PathVariable annotation is used for data passed in the URI (e.g. RESTful web services) while @RequestParam is used to extract the data found in query parameters. These annotations can be mixed together inside the same controller. @PathParam is a JAX-RS annotation that is equivalent to @PathVariable in Spring.
One of the ways to handle this problem is to annotate the parameters with the @DateTimeFormat annotation, and provide a formatting pattern parameter: @RestController public class DateTimeController { @PostMapping("/date") public void date(@RequestParam("date") @DateTimeFormat(iso = DateTimeFormat.
The @PathVariable annotation is used to extract the value from the URI. It is most suitable for the RESTful web service where the URL contains some value. Spring MVC allows us to use multiple @PathVariable annotations in the same method. A path variable is a critical part of creating rest resources.
There's a default converter for ZonedDateTime
parameters. It uses Java 8's DateTimeFormatter
created like
DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
This could've been any FormatStyle
or really any DateTimeFormatter
as far as you're concerned, your example wouldn't have worked. DateTimeFormatter
parses and formats to date strings, not timestamps, which is what you've provided.
You could have provided an appropriate custom @org.springframework.format.annotation.DateTimeFormat
to your parameter such as
public Page<DeviceInfo> getDeviceListForCustomerBetweenDates(
@PathVariable @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) ZonedDateTime startDate,
@PathVariable @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) ZonedDateTime endDate,
Pageable pageable) { ...
or with an appropriate pattern
and a corresponding date string like
2000-10-31T01:30:00.000-05:00
You won't be able to do any of the above with a unix timestamp. The canonical way to do timestamp to ZonedDateTime
conversion is through Instant#ofEpochSecond(long)
, given an appropriate ZoneId
.
long startTime = 1446361200L;
ZonedDateTime start = Instant.ofEpochSecond(startTime).atZone(ZoneId.systemDefault());
System.out.println(start);
To make this work with @PathVariable
, register a custom Converter
. Something like
class ZonedDateTimeConverter implements Converter<String, ZonedDateTime> {
private final ZoneId zoneId;
public ZonedDateTimeConverter(ZoneId zoneId) {
this.zoneId = zoneId;
}
@Override
public ZonedDateTime convert(String source) {
long startTime = Long.parseLong(source);
return Instant.ofEpochSecond(startTime).atZone(zoneId);
}
}
And register it in a WebMvcConfigurationSupport
@Configuration
annotated class, overriding addFormatters
@Override
protected void addFormatters(FormatterRegistry registry) {
registry.addConverter(new ZonedDateTimeConverter(ZoneId.systemDefault()));
}
Now, Spring MVC will use this converter to deserialize the String
path segment into a ZonedDateTime
object.
In Spring Boot, I think you can just declare a @Bean
for the corresponding Converter
and it will register it automatically, but don't take my word for it.
You gonna need to accept what you passed to @PathVariable
as a String
data type, then do the conversion yourself, your error logs pretty clearly tells you that.
Spring library cannot conver String values"1446361200" to ZonedDateTime
type through @PathVariable
binding unfortunately.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With