2014-03-19 2 views
21

빈 검증 프레임 워크에 익숙하다면 메소드 인수의 이름을 얻을 수 없다는 것을 알고 있습니다. 따라서 메서드의 첫 번째 인수에서 @NotNull 제약 조건을 수행하고 유효성 검사가 실패하면 getPropertyPath는 "arg1"과 같은 형식이됩니다.Method 인수에 대한 ConstraintValidator의 속성 경로를 변경할 수 있습니까?

나는 값을 가질 수있는 @NotNull의 자체 버전을 만들고 싶습니다. @NamedNotNull ("emailAddress"). 그러나 Validator에서 #getPropertyPath를 재정의하는 방법을 알아낼 수 없습니까? 이 작업을 수행하거나 내가 "ARG1"또는 "ARG2"등

편집 붙어 오전하는 방법은 없나요 나는 다음과 같은 구현을 마련 할 수 있었다받은 답변에 따라

그 내 @QueryParam 또는 @PathParam 주석에서 값을 가져 와서 @NotNull과 같은 Bean 유효성 검사 주석의 속성 경로로 사용할 수 있습니다.

저지의 경우 다음 클래스를 만들어야합니다. DefaultParameterNameProvider의 구현을 참고 : 그거야

register(ValidationConfigurationContextResolver.class); 

:

public class ValidationConfigurationContextResolver implements ContextResolver<ValidationConfig> { 
    @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<String> getParameterNames(Method method) { 
      Annotation[][] annotationsByParam = method.getParameterAnnotations(); 
      List<String> 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 당신이 다음 줄을 추가해야합니다. 이제 ConstraintValidationExceptions에는 주석이 추가 된 QueryParam 또는 PathParam의 이름이 포함됩니다. 예를 들면 : 당신이 콩 검증 프레임 워크에 익숙하다면

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

저지를 사용하지 않으면 어떻게됩니까? – Dejell

+1

매우 유용합니다. 감사합니다. 나는 좀 더 정교함을 추가했다 : 'if (name == null) name = "payload ["+ parameterTypes [index] .getSimpleName() + "]", ""대신에 . Rest 메서드에서 검사 된 주석이없는 매개 변수 인 페이로드 유형을 제공합니다. 페이로드 DTO의 필드 (및 페이로드가 완전히 누락되어 있고 @NotNull 주석이있는 경우 페이로드 유형)의 유효성을 검사 할 때''Path ":"SomeResource.testValidation.payload [PayloadDto] .attributes "'를 제공합니다. – PhiLho

답변

1

제약 조건 위반 객체를 만들 때 Bean Validation 1.1은 메소드 및 생성자 매개 변수의 이름을 제공하기 위해 ParameterNameProvider 인터페이스를 도입했습니다.


ReflectionParameterNameProvider 클래스 도입 최대 절전 모드 검사기 5.2 실제 매개 변수 이름을 얻기 위해 반사를 사용하는 ParameterNameProvider 구현을 (제대로 작동하기 위해서는 -parameters 컴파일러 인수로 컴파일 할 클래스를 필요) :

/** 
* Uses Java 8 reflection to get the parameter names. 
* <p> 
* <p>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.</p> 
* <p> 
* <p>See also <a href="http://openjdk.java.net/jeps/118">JEP 118</a></p> 
* 
* @author Khalid Alqinyah 
* @since 5.2 
*/ 
public class ReflectionParameterNameProvider implements ParameterNameProvider { 

    @Override 
    public List<String> getParameterNames(Constructor<?> constructor) { 
     return getParameterNames(constructor.getParameters()); 
    } 

    @Override 
    public List<String> getParameterNames(Method method) { 
     return getParameterNames(method.getParameters()); 
    } 

    private List<String> getParameterNames(Parameter[] parameters) { 

     List<String> 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 그것과도 다른 JAX-RS 구현 작동한다 JerseyParameterNameProvider와 JAX-RS에 @XxxParam 주석 지원을 추가 연장 :

/** 
* Adds jersey support to parameter name discovery in hibernate validator. 
* <p> 
* <p>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.</p> 
*/ 
public class JerseyParameterNameProvider extends ReflectionParameterNameProvider { 

    @Override 
    public List<String> getParameterNames(Method method) { 
     Parameter[] parameters = method.getParameters(); 
     Annotation[][] parameterAnnotations = method.getParameterAnnotations(); 
     List<String> 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<String> 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를 사용하지 않는 경우 위의 코드를 사용하여 직접 구현할 수 있습니다./ 방법이 ValidationConfig 클래스를 사용하고 ContextResolver<T> 메커니즘을 통해 노출 할 수 있습니다 저지 자원 클래스의 검증에 사용 된 Validator


사용자 정의 :

public class ValidationConfigurationContextResolver 
     implements ContextResolver<ValidationConfig> { 

    @Override 
    public ValidationConfig getContext(final Class<?> type) { 
     ValidationConfig config = new ValidationConfig(); 
     config.parameterNameProvider(new CustomParameterNameProvider()); 
     return config; 
    } 
} 

그런 다음 ResourceConfig에서 ValidationConfigurationContextResolver를 등록합니다.

자세한 내용은 Jersey documentation about Bean Validation support을 참조하십시오.

10

당신은 당신이 아주 정확하지의 메소드 인수

의 이름을 얻을 수 것을 알고있다. Bean Validation은 사용자가 직접 구현할 수있는 ParameterNameProvider의 개념을 지정합니다. Hibernate Validator는 ParaNamer과 통합되어 매개 변수 이름을 제공합니다. 자세한 내용은 Validator online docs을 참조하십시오. Validator가 Java 8을 지원하면 Java 8 매개 변수 명명 기능도 지원합니다.

IMO, 당신은 ParaNamer에게 가야합니다.

+0

그래, 이걸 시험해 볼게. 나는 이것을 JAX-RS와 함께 사용하여 일반적으로 QueryParam이나 PathParam 주석으로부터 매개 변수 이름을 얻을 수 있습니다! 이것이 작동하면 나는 당신의 대답을 확실히 선택할 것입니다. –

+0

그것은 작동합니다 @ 하드! 귀하의 답변을 예를 들어 편집하고 답변을 표시합니다. –

+0

http://paranamer.codehaus.org/은 (는) 유효한 링크가 아닙니다 – Dejell