I am trying to use Json-B with Spring Boot version: 2.3.1
Json-b
<dependency>
<groupId>javax.json.bind</groupId>
<artifactId>javax.json.bind-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.eclipse</groupId>
<artifactId>yasson</artifactId>
<version>1.0.5</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1.4</version>
</dependency>
The Rest Controller:
@RestController
public class MyController {
@PostMapping("/api/test")
public ResponseEntity init(@Valid @RequestBody MyRequest request) {
return ResponseEntity.ok("ok");
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public Map<String, String> handleValidationExceptions(
MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String errorMessage = error.getDefaultMessage();
final Object rejectedValue = ((FieldError) error).getRejectedValue();
errors.put("Rejected Value: ", rejectedValue.toString());
errors.put(fieldName, errorMessage);
});
return errors;
}
}
The request:
public class MyRequest {
@DurationMin(minutes = 1")
@DurationMax(minutes = 10)
@JsonbTypeAdapter(DurationAdapter.class)
private Duration expiredTime;
....getter setter...
}
The Json-B Adapter:
public class DurationAdapter implements JsonbAdapter<Duration, JsonValue> {
@Override
public JsonValue adaptToJson(Duration duration) throws Exception {
final JsonNumber value = Json.createValue(duration.toMillis());
return value;
}
@Override
public Duration adaptFromJson(JsonValue jsonValue) throws Exception {
final long timeInMillis = ((JsonNumber) jsonValue).longValue();
return Duration.ofMillis(timeInMillis);
}
}
I also tried this adapter as well:
public class DurationAdapter implements JsonbAdapter<Duration, Long> {
@Override
public Long adaptToJson(Duration obj) throws Exception {
return obj.toMillis();
}
@Override
public Duration adaptFromJson(Long obj) throws Exception {
return Duration.ofMillis(obj);
}
}
I used Postman to send a post request with content like this:
{
"expiredTime": 6000
}
I put break points in my adapter but the app never ran through the break points. I put a break points at the rejected value in the exception handler in the rest controller, and I saw that the duration was always in "seconds", not milliseconds. If the request has "expiredTime":6000, then the Java object will have expriredTime field with value Duration=6000 seconds (use debugger to see the value) and an exception will be thrown (that's why I can use the debugger at the exception handler).
How can I make Spring boot use my Json-B Adapter? Thank you!
Updated: I also have specified this in application.properties:
spring.http.converters.preferred-json-mapper=jsonb
Your code works, I prepared another example to show here. I excluded jackson like below just to make sure it is not used.
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
and used println to show in the log. and looks like this
as far as I understand spring.http.converters.preferred-json-mapper
is not very effective. As long as it finds any mapper in class path spring uses that. And in https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html there is no http.converter