jackson - bean - javax.validation example
Hibernate Validator y Jackson: ¿Cómo usar el valor @JsonProperty como ConstraintViolation PropertyPath? (2)
Desafortunadamente no hay una manera fácil de hacerlo. Pero aquí hay algunas ideas que pueden ayudarte:
Revisar violaciones de restricciones
Desde ConstraintViolationException
, puede obtener un conjunto de ConstraintViolation
, que expone el contexto de violación de restricciones:
-
ConstraintViolation#getLeafBean()
: si se trata de una restricción de bean, este método devuelve la instancia de bean a la que se aplica la restricción. -
ConstraintViolation#getPropertyPath()
: Devuelve la ruta a la propiedad no válida.
Desde la ruta de la propiedad, puede obtener el nodo hoja:
Path propertyPath = constraintViolation.getPropertyPath();
Optional<Path.Node> leafNodeOptional =
StreamSupport.stream(propertyPath.spliterator(), false).reduce((a, b) -> b);
Luego verifique si el tipo del nodo es PROPERTY
y obtenga su nombre:
String nodeName = null;
if (leafNodeOptional.isPresent()) {
Path.Node leafNode = leafNodeOptional.get();
if (ElementKind.PROPERTY == leafNode.getKind()) {
nodeName = leafNode.getName();
}
}
Introspección de una clase con Jackson
Para obtener las propiedades JSON disponibles de la clase de hoja de frijol, puede introspectarlo con Jackson (consulte esta respuesta y esta respuesta para obtener más detalles):
Class<?> beanClass = constraintViolation.getLeafBean().getClass();
JavaType javaType = mapper.getTypeFactory().constructType(beanClass);
BeanDescription introspection = mapper.getSerializationConfig().introspect(javaType);
List<BeanPropertyDefinition> properties = introspection.findProperties();
A continuación, filtre las propiedades comparando el nombre del nodo hoja con el nombre del Field
desde BeanPropertyDefinition
:
Optional<String> jsonProperty = properties.stream()
.filter(property -> nodeName.equals(property.getField().getName()))
.map(BeanPropertyDefinition::getName)
.findFirst();
¿Usando JAX-RS?
Con JAX-RS (si lo está usando), puede definir un ExceptionMapper
para manejar los ConstraintViolationException
:
@Provider
public class ConstraintViolationExceptionMapper
implements ExceptionMapper<ConstraintViolationException> {
@Override
public Response toResponse(ConstraintViolationException exception) {
...
}
}
Para usar ObjectMapper
en su ExceptionMapper
, puede proporcionarle un ContextResolver<T>
:
@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;
}
}
Inyecte la interfaz de Providers
en su ExceptionMapper
:
@Context
private Providers providers;
ContextResolver<T>
su ContextResolver<T>
y luego obtenga la instancia de ObjectMapper
:
ContextResolver<ObjectMapper> resolver =
providers.getContextResolver(ObjectMapper.class, MediaType.WILDCARD_TYPE);
ObjectMapper mapper = resolver.getContext(ObjectMapper.class);
Si está interesado en obtener nombres de @XxxParam
, consulte esta respuesta .
Digamos que tengo un POJO simple como el que se indica a continuación con anotaciones de Jackson 2.1 e Hibernate Validator 4.3.1:
final public class Person {
@JsonProperty("nm")
@NotNull
final public String name;
public Person(String name) {
this.name = name;
}
}
Y envío JSON como tal a un servicio web:
{"name": null}
Hibernate cuando informa que ConstraintViolation usa el identificador de miembro de la clase "nombre" en lugar del valor de la anotación JsonProperty. ¿Alguien sabe si es posible hacer que el Validador de Hibernate observe la anotación de la clase y usar ese valor en su lugar?
No, eso no es posible. Hibernate Validator 5 (Bean Validation 1.1) tiene la noción de ParameterNameProvider
s que devuelve los nombres a los que se informa en caso de que se violen las restricciones de los parámetros del método, pero no hay nada comparable para las limitaciones de la propiedad.