Closed mdhtr closed 4 years ago
This issue consists of two parts, the first part is to validate the input and throw an exception with validation results, the second is to catch that exception, and return it in a good format.
For the first part, there is several ways to do validation, I will elaborate in separate comments below.
For the second part, the Problem Details spec can come in handy: https://tools.ietf.org/html/rfc7807
Some references:
Tl;dr:
Pros:
Cons:
How-to:
Tl;dr:
Pros:
Cons:
@JsonDeserialize(using = TestValidationDtoDeserializer.class)
public class TestValidationDto {
...
implement the deserializer
public class TestValidationDtoDeserializer extends JsonDeserializer {
@Override
public TestValidationDto deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser);
... // throw custom exception on validation error
return new TestValidationDto( ... );
}
Tl;dr:
Pros:
Cons:
@JsonCreator
public TestValidationDto(
@JsonProperty(value = "number", required = true) Integer number,
@JsonProperty(value = "text", required = true) String text) {
this.number = number;
this.text = text;
}
Tl;dr:
Pros:
Cons:
jakarta.validation:jakarta.validation-api
that maven marked as undeclared.
<!-- VALIDATION -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.2.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator-annotation-processor</artifactId>
<version>6.0.2.Final</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.6</version>
</dependency>
public abstract class DataValidator<T> extends StdConverter<T, T> {
@Override
public T convert(T t) {
ValidatorFactory validatorFactory = Validation.byDefaultProvider()
.configure()
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
Set<ConstraintViolation<T>> violations = validator.validate(t);
if (!violations.isEmpty()) {
throw new ConstraintViolationException(violations);
}
return t;
}
}
@JsonDeserialize(converter = TestValidationDto.Validator.class)
public class TestValidationDto {
...
static class Validator extends DataValidator<TestValidationDto> {}
}
I chose option D: custom converter + javax.validation. The javax validation annotations make specifying validations easy, and the custom converter is highly reusable and easy to use.
A possible future improvement could be to return the validation errors is a machine parsable format, in an additional field.
Required field validation + list all missing fields is response