Подтвердить что ты не робот

Могу ли я изменить путь свойства в аргументе ConstraintValidator для метода?

Если вы знакомы с Bean Validation Framework, вы знаете, что вы не можете получить имя аргумента метода. Поэтому, если вы выполняете ограничение @NotNull для первого аргумента метода и проверка не выполняется, getPropertyPath будет что-то вроде "arg1".

Я хотел бы создать свою собственную версию @NotNull, которая может принимать значение, например. @NamedNotNull ( "emailAddress" ). Но я не могу понять, как переопределить #getPropertyPath в моем валидаторе? Есть ли способ сделать это, или я придерживаюсь "arg1" или "arg2" и т.д.

ИЗМЕНИТЬ

Основываясь на полученном ответе, я смог придумать следующую реализацию, которая позволяет мне принять значение из аннотаций @QueryParam или @PathParam и использовать их как путь свойств для Bean аннотации проверки, такие как @NotNull.

Для Джерси вам нужно создать следующий класс. Обратите внимание на реализацию DefaultParameterNameProvider:

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 вам нужно добавить следующую строку:

register( ValidationConfigurationContextResolver.class );

Что это. Теперь ваши ConstraintValidationExceptions будут содержать имя QueryParam или PathParam, с которыми они аннотируются. Например:

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

Ответ 1

Bean В версии 1.1 был введен интерфейс ParameterNameProvider для предоставления имен параметров метода и конструктора при создании объектов нарушения ограничений.


Hibernate Validator 5.2 представил класс ReflectionParameterNameProvider, 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 @XxxParam с помощью JerseyParameterNameProvider, который должен работать с другими JAX-RS также:

/**
 * 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 name and type from it 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, вы можете использовать приведенный выше код для создания собственной реализации.


Настройка Validator, используемая для проверки классов/методов ресурса Джерси, может быть выполнена с помощью ValidationConfig и разоблачить его через ContextResolver<T> механизм:

public class ValidationConfigurationContextResolver 
        implements ContextResolver<ValidationConfig> {

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

Затем зарегистрируйте ValidationConfigurationContextResolver в ResourceConfig.

Подробнее см. документацию по документации Bean Поддержка валидации.

Ответ 2

Если вы знакомы с Bean Validation Framework, вы знаете, что вы не можете получить имя аргумента метода

Это не совсем правильно. Bean Валидация определяет концепцию ParameterNameProvider, которая позволяет вам предоставить вашу собственную реализацию. Hibernate Validator интегрируется с ParaNamer для предоставления имен параметров. Дополнительную информацию см. В веб-документах Validator онлайн. После того, как Validator поддерживает Java 8, он также будет поддерживать функцию именования параметров Java 8.

ИМО, вы должны дать ParaNamer идти.