Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bean Validation with JAX-RS (rest-easy): parameter name not recognized

I'm using JAX-RS resources with Bean Validation and integration between these two works as expected.

However, the default error messages generated in case of a validation error report parameter names as arg0, like so

[PARAMETER]
[login.arg0.password]
[password is required]
[]

Corresponding method definition:

@POST //and other JAX-RS annotations
public Response login(
        @NotNull
        @Valid
        LoginBody loginBody) {

   [...]

protected static class LoginBody {

    @NotNull(message =  EMAIL_REQUIRED)
    public String email;

    @NotNull(message = PASSWORD_REQUIRED)
    public String password;
}

While I'm generally fine with this message pattern, what actually is annyoing, is the fact that the original parameter name is not recognized, i. e. I'd rather like to see

login.loginBody.password instead of arg0.

Is there an easy way to fix this, e. g. somehow provide an explicit name for that parameter?

I'm using WildFly Swarm 2017.6.0. From what I found out this means I have resteasy + resteasy-validator + hibernate-validator

Thanks.

like image 713
omilke Avatar asked Jul 13 '17 16:07

omilke


1 Answers

You could try to compile your app with -parameters or instruct your IDE to do so, e.g. in case of eclipse: preferences -> java -> compiler -> "store information about method parameters (usable via reflection)"

With that in place you then need to instruct the Bean Validation infrastructure (e.g. ) hibernate-validator to use the ReflectiveParameterNamer via META-INF/validation.xml.

<parameter-name-provider>org.hibernate.validator.parameternameprovider.ReflectionParameterNameProvider</parameter-name-provider>

See also Hibernate Validator Configuration

I got something reliably working with the Paranamer library

META-INF/validation.xml:

<?xml version="1.0" encoding="UTF-8"?>
<validation-config
   xmlns="http://jboss.org/xml/ns/javax/validation/configuration"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="
                    http://jboss.org/xml/ns/javax/validation/configuration
                    validation-configuration-1.1.xsd"
   version="1.1">
   <default-provider>org.hibernate.validator.HibernateValidator
   </default-provider>
   <message-interpolator>org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator
   </message-interpolator>
   <traversable-resolver>org.hibernate.validator.internal.engine.resolver.DefaultTraversableResolver
   </traversable-resolver>
   <constraint-validator-factory>org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorFactoryImpl
   </constraint-validator-factory>
   <parameter-name-provider>org.hibernate.validator.parameternameprovider.ParanamerParameterNameProvider</parameter-name-provider>
</validation-config>

To get paranamer working with wildfly I needed to create a parameter-namer jboss-module and reference that module from the module.xml of the hibernate-validator module.

With that in place I could simply write:

@POST
public Response login(@NotNull @Valid @Named("authRequest") AuthRequest authRequest) {
    return Response.ok().build();
}
...

public class AuthRequest {

    @NotNull(message = AuthMessages.EMAIL_REQUIRED)
    public String email;

    @NotNull(message = AuthMessages.PASSWORD_REQUIRED)
    public String password;
}

which yields the following response for a request sent via curl:

curl -H "Content-Type: application/json" -H "Accept: application/json" -d '{"email":"[email protected]"}' -v http://localhost:8080/javaweb-training/resources/auth

Response:

{"exception":null,"fieldViolations":[],"propertyViolations":[],"classViolations":[],"parameterViolations":[{"constraintType":"PARAMETER","path":"login.authRequest.password","message":"password.required","value":""}],"returnValueViolations":[]}%

... note login.authRequest.password instead of just login.arg0.password

like image 63
Thomas Darimont Avatar answered Oct 11 '22 02:10

Thomas Darimont