我可以在ConstraintValidator中为Method参数更改属性路径吗?

如果您熟悉Beanvalidation框架,则您知道无法获取方法参数的名称。 因此,如果对方法的第一个参数执行@NotNull约束并且validation失败,则getPropertyPath将类似于“arg1”。

我想创建我自己的@NotNull版本,它可以取一个值,例如@NamedNotNull(“emailAddress”)。 但我无法弄清楚如何覆盖我的Validator中的#getPropertyPath? 有没有办法做到这一点,或者我坚持使用“arg1”或“arg2”等。

编辑

根据我收到的答案,我能够提出以下实现,允许我从@QueryParam或@PathParam注释中获取值,并将其用作Beanvalidation注释(如@NotNull)的属性路径。

对于Jersey,您需要创建以下类。 注意DefaultParameterNameProvider的实现:

public class ValidationConfigurationContextResolver implements ContextResolver { @Override public ValidationConfig getContext( final Class type ) { final ValidationConfig config = new ValidationConfig(); config.parameterNameProvider( new RestAnnotationParameterNameProvider() ); return config; } static class RestAnnotationParameterNameProvider extends DefaultParameterNameProvider { @Override public List getParameterNames( Method method ) { Annotation[][] annotationsByParam = method.getParameterAnnotations(); List names = new ArrayList( annotationsByParam.length ); for ( Annotation[] annotations : annotationsByParam ) { String name = getParamName( annotations ); if ( name == null ) name = "arg" + ( names.size() + 1 ); names.add( name ); } return names; } private static String getParamName( Annotation[] annotations ) { for ( Annotation annotation : annotations ) { if ( annotation.annotationType() == QueryParam.class ) { return QueryParam.class.cast( annotation ).value(); } else if ( annotation.annotationType() == PathParam.class ) { return PathParam.class.cast( annotation ).value(); } } return null; } } } 

然后在RestConfig中,您需要添加以下行:

 register( ValidationConfigurationContextResolver.class ); 

而已。 现在,您的ConstraintValidationExceptions将包含它们带有注释的QueryParam或PathParam的名称。 例如:

  public void getUser( @NotNull @QueryParam( "emailAddress" ) String emailAddress, @NotNull @QueryParam( "password" ) String password ) { ... } 

Bean Validation 1.1引入了ParameterNameProvider接口,用于在创建约束违规对象时为方法和构造函数参数提供名称。


Hibernate Validator 5.2引入了ReflectionParameterNameProvider类,这是一个ParameterNameProvider实现,它使用reflection来获取实际的参数名称(要正常工作,它需要使用-parameters编译器-parameters编译类):

 /** * Uses Java 8 reflection to get the parameter names. * 

*

For this provider to return the actual parameter names, classes must be compiled with the '-parameters' compiler * argument. Otherwise, the JDK will return synthetic names in the form {@code arg0}, {@code arg1}, etc.

*

*

See also JEP 118

* * @author Khalid Alqinyah * @since 5.2 */ public class ReflectionParameterNameProvider implements ParameterNameProvider { @Override public List getParameterNames(Constructor constructor) { return getParameterNames(constructor.getParameters()); } @Override public List getParameterNames(Method method) { return getParameterNames(method.getParameters()); } private List getParameterNames(Parameter[] parameters) { List parameterNames = newArrayList(); for (Parameter parameter : parameters) { // If '-parameters' is used at compile time, actual names will be returned. Otherwise, it will be arg0, arg1... parameterNames.add(parameter.getName()); } return parameterNames; } }

Dropwizard扩展了它,并添加了对@XxxParam JAX-RS @XxxParam注释的JerseyParameterNameProvider ,它也可以与其他JAX-RS实现一起使用:

 /** * Adds jersey support to parameter name discovery in hibernate validator. * 

*

This provider will behave like the hibernate-provided {@link ReflectionParameterNameProvider} except when a * method parameter is annotated with a jersey parameter annotation, like {@link QueryParam}. If a jersey parameter * annotation is present the value of the annotation is used as the parameter name.

*/ public class JerseyParameterNameProvider extends ReflectionParameterNameProvider { @Override public List getParameterNames(Method method) { Parameter[] parameters = method.getParameters(); Annotation[][] parameterAnnotations = method.getParameterAnnotations(); List names = new ArrayList<>(parameterAnnotations.length); for (int i = 0; i < parameterAnnotations.length; i++) { Annotation[] annotations = parameterAnnotations[i]; String name = getParameterNameFromAnnotations(annotations).orElse(parameters[i].getName()); names.add(name); } return names; } /** * Derives member's name and type from it's annotations */ public static Optional getParameterNameFromAnnotations(Annotation[] memberAnnotations) { for (Annotation a : memberAnnotations) { if (a instanceof QueryParam) { return Optional.of("query param " + ((QueryParam) a).value()); } else if (a instanceof PathParam) { return Optional.of("path param " + ((PathParam) a).value()); } else if (a instanceof HeaderParam) { return Optional.of("header " + ((HeaderParam) a).value()); } else if (a instanceof CookieParam) { return Optional.of("cookie " + ((CookieParam) a).value()); } else if (a instanceof FormParam) { return Optional.of("form field " + ((FormParam) a).value()); } else if (a instanceof Context) { return Optional.of("context"); } else if (a instanceof MatrixParam) { return Optional.of("matrix param " + ((MatrixParam) a).value()); } } return Optional.empty(); } }

如果您不使用Dropwizard,您可以使用上面的代码来创建自己的实现。


validationJersey资源类/方法时使用的Validator定制可以使用ValidationConfig类完成,并通过ContextResolver机制公开它:

 public class ValidationConfigurationContextResolver implements ContextResolver { @Override public ValidationConfig getContext(final Class type) { ValidationConfig config = new ValidationConfig(); config.parameterNameProvider(new CustomParameterNameProvider()); return config; } } 

然后在ResourceConfig注册ValidationConfigurationContextResolver

有关更多详细信息,请参阅有关Beanvalidation支持的Jersey文档 。

如果您熟悉Beanvalidation框架,则您知道无法获取方法参数的名称

那不太正确。 Bean Validation指定ParameterNameProvider的概念,它允许您提供自己的实现。 Hibernate Validator与ParaNamer集成以提供参数名称。 有关更多信息,请参阅Validator 在线文档 。 一旦Validator支持Java 8,它也将支持Java 8参数命名工具。

IMO,你应该给ParaNamer一个去吧。