不幸的是,没有简单的方法可以做到这一点。但这里有一些可以帮助你的见解:
解析约束违规
从 中ConstraintViolationException
,您可以获得一组ConstraintViolation
,它公开了约束违规上下文:
从属性路径中,您可以获取叶节点:
Path propertyPath = constraintViolation.getPropertyPath();
Optional<Path.Node> leafNodeOptional =
StreamSupport.stream(propertyPath.spliterator(), false).reduce((a, b) -> b);
然后检查节点的类型是否为PROPERTY
并获取其名称:
String nodeName = null;
if (leafNodeOptional.isPresent()) {
Path.Node leafNode = leafNodeOptional.get();
if (ElementKind.PROPERTY == leafNode.getKind()) {
nodeName = leafNode.getName();
}
}
与杰克逊一起自省一堂课
要从叶 bean 类中获取可用的 JSON 属性,您可以使用 Jackson 对其进行自省(有关详细信息,请参阅此答案和此答案):
Class<?> beanClass = constraintViolation.getLeafBean().getClass();
JavaType javaType = mapper.getTypeFactory().constructType(beanClass);
BeanDescription introspection = mapper.getSerializationConfig().introspect(javaType);
List<BeanPropertyDefinition> properties = introspection.findProperties();
然后通过将叶节点名称与以下Field
名称进行比较来过滤属性BeanPropertyDefinition
:
Optional<String> jsonProperty = properties.stream()
.filter(property -> nodeName.equals(property.getField().getName()))
.map(BeanPropertyDefinition::getName)
.findFirst();
使用 JAX-RS?
使用 JAX-RS(如果您正在使用它),您可以定义一个ExceptionMapper
来处理ConstraintViolationException
s:
@Provider
public class ConstraintViolationExceptionMapper
implements ExceptionMapper<ConstraintViolationException> {
@Override
public Response toResponse(ConstraintViolationException exception) {
...
}
}
要ObjectMapper
在您的 中使用ExceptionMapper
,您可以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;
}
}
Providers
将接口注入您的ExceptionMapper
:
@Context
private Providers providers;
查找您的ContextResolver<T>
然后获取ObjectMapper
实例:
ContextResolver<ObjectMapper> resolver =
providers.getContextResolver(ObjectMapper.class, MediaType.WILDCARD_TYPE);
ObjectMapper mapper = resolver.getContext(ObjectMapper.class);
如果您有兴趣获取@XxxParam
名称,请参阅此答案。