I try to make a RestController use my custom formatter for a java.time.Duration, but I am not successful not knowing why. I have a simple Order entity, a OrderController and a DurationFormatter that should be applied for the conversion of the Duration typed fields of the Order from and to Strings. The Formatter is registered with a FormattingConversionServiceFactoryBean in the Configuration class. This is the code:
public class Order {
@Getter
@Setter
private String id;
@Getter
@Setter
@NotNull
private String customerId;
@Getter
@Setter
private ZonedDateTime validFrom;
@Getter
@Setter
private ZonedDateTime validTo;
@Getter
@Setter
private Duration maxDuration;
@Getter
@Setter
private Duration actDuration;
}
@RestController
@RequestMapping("order")
public class OrderController {
@RequestMapping(method = RequestMethod.POST)
public ResponseEntity<?> createOrder(@RequestBody @Valid Order order) {
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ServletUriComponentsBuilder.fromCurrentRequest().path("/" + order.getId()).build().toUri());
return new ResponseEntity<>(null, headers, HttpStatus.CREATED);
}
@RequestMapping(method = RequestMethod.GET)
public Order getExample() {
Order order = new Order();
order.setMaxDuration(Duration.ofHours(10));
return order;
}
}
public class DurationFormatter implements Formatter<Duration>{
@Override
public String print(Duration duration, Locale locale) {
return new Long(duration.toHours()).toString();
}
@Override
public Duration parse(String text, Locale locale) throws ParseException {
return Duration.ofHours(Long.parseLong(text));
}
}
@Configuration
public class AppConfig {
@Bean
public FormattingConversionServiceFactoryBean getFormattingConversionServiceFactory() {
FormattingConversionServiceFactoryBean factory = new FormattingConversionServiceFactoryBean();
Set<Formatter<?>> formatters = new HashSet<>();
formatters.add(new DurationFormatter());
factory.setFormatters(formatters);
return factory;
}
}
When I try to post an Order this is the error I get:
at [Source: java.io.PushbackInputStream@595e3818; line: 4, column: 30] (through reference chain: com.sap.sptutorial.rest.Order["maxDuration"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not instantiate value of type [simple type, class java.time.Duration] from String value ('67'); no single-String constructor/factory method
Can anybody suggest me the right way to apply formatters?
Formatters have nothing to do with JSON deserialization. That's the task of Jackson
in your case. It should be enough to add the following dependency to your pom.xml
to get support for the new Java 8 types.
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.6.1</version>
</dependency>