Hibernate Validator and Jackson: using @JsonProperty as a ConstraintViolation PropertyPath?

Say I have a simple POJO, such as below, annotated by the comments of Jackson 2.1 and Hibernate Validator 4.3.1:

final public class Person { @JsonProperty("nm") @NotNull final public String name; public Person(String name) { this.name = name; } } 

And I am sending JSON as such to the web service:

 {"name": null} 

Hibernation, when it reports ConstraintViolation, uses the class member identifier "name" instead of the JsonProperty annotation value. Does anyone know if Hibernate Validator can be forced to look at class annotation and use this value?

+4
source share
2 answers

No, It is Immpossible. Hibernate Validator 5 (Bean Validation 1.1) has the concept of ParameterNameProvider , which returns the names that are reported in case of method parameter parameter restrictions, but nothing is comparable for property restrictions.

+3
source

Unfortunately, there is no easy way to do this. But here are some ideas that might help you:

Violations with tolerance restrictions

From a ConstraintViolationException you can get a set of ConstraintViolation that exposes the context of a constraint violation:

From the properties path, you can get the node sheet:

 Path propertyPath = constraintViolation.getPropertyPath(); Optional<Path.Node> leafNodeOptional = StreamSupport.stream(propertyPath.spliterator(), false).reduce((a, b) -> b); 

Then check if the node type is PROPERTY and get its name:

 String nodeName = null; if (leafNodeOptional.isPresent()) { Path.Node leafNode = leafNodeOptional.get(); if (ElementKind.PROPERTY == leafNode.getKind()) { nodeName = leafNode.getName(); } } 

Introspection of a class using Jackson

To get the available JSON properties from the bean class, you can view it with Jackson (see this and answer for more information):

 Class<?> beanClass = constraintViolation.getLeafBean().getClass(); JavaType javaType = mapper.getTypeFactory().constructType(beanClass); BeanDescription introspection = mapper.getSerializationConfig().introspect(javaType); List<BeanPropertyDefinition> properties = introspection.findProperties(); 

Then filter the properties by comparing the name of the leaf node with the name Field of BeanPropertyDefinition :

 Optional<String> jsonProperty = properties.stream() .filter(property -> nodeName.equals(property.getField().getName())) .map(BeanPropertyDefinition::getName) .findFirst(); 

Using JAX-RS?

Using JAX-RS (if you use it), you can define an ExceptionMapper to handle ConstraintViolationException s:

 @Provider public class ConstraintViolationExceptionMapper implements ExceptionMapper<ConstraintViolationException> { @Override public Response toResponse(ConstraintViolationException exception) { ... } } 

To use ObjectMapper in ExceptionMapper , you can provide a ContextResolver<T> for it:

 @Provider public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> { private final ObjectMapper mapper; public ObjectMapperContextResolver() { mapper = createObjectMapper(); } @Override public ObjectMapper getContext(Class<?> type) { return mapper; } private ObjectMapper createObjectMapper() { ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationFeature.INDENT_OUTPUT, true); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); return mapper; } } 

Add the Providers interface to ExceptionMapper :

 @Context private Providers providers; 

Find the ContextResolver<T> , and then get the ObjectMapper instance:

 ContextResolver<ObjectMapper> resolver = providers.getContextResolver(ObjectMapper.class, MediaType.WILDCARD_TYPE); ObjectMapper mapper = resolver.getContext(ObjectMapper.class); 

If you are interested in getting @XxxParam names, refer to this.

+2
source

Source: https://habr.com/ru/post/1502872/


All Articles