I am running a web application in Glasshfish 5 that provides a REST endpoint using Jersey JAX-RS. It also uses bean validation. The problem I am having is that any method starting with "get" is always called when it returns something that has the @Valid annotation.
Example:
@Path("/hello")
public class HelloResource {
@GET
public @Valid HelloMessage getSomething() {
HelloMessage helloMessage = new HelloMessage();
helloMessage.setMessage("Hello World!");
return helloMessage;
}
@POST
public @Valid HelloMessage updateMessage(@Valid HelloMessage message) {
return message;
}
}
If I do a POST to /hello, you will see the getSomething method being called, before updateMessage is called. If I remove the @Valid annotation on the return type of the getSomething method, then getSomething is not called.
Is this according to specifications? Should you basically never name a method starting with "get" in a REST class?
In the past I have reported an issue for this on github, but never received a reply.
https://github.com/eclipse-ee4j/jersey/issues/3743
Other classes:
@ApplicationPath("/")
public class HelloApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
return Collections.singleton(HelloResource.class);
}
}
public class HelloMessage {
@Size(max = 100)
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
Minimal project to be found at https://github.com/robertatgh/stackoverflow-50658396/tree/develop
So this turned out to be a funny kind of an issue because of the naming convention. Debugging through the jersey source code you will see that it goes through
org.glassfish.jersey.server.validation.internal.DefaultConfiguredValidator.onValidate(ValidationInterceptorContext) line: 166
public void onValidate(final ValidationInterceptorContext ctx) {
final Object resource = ctx.getResource();
final Invocable resourceMethod = ctx.getInvocable();
final Object[] args = ctx.getArgs();
final Set<ConstraintViolation<Object>> constraintViolations = new HashSet<>();
final BeanDescriptor beanDescriptor = getConstraintsForClass(resource.getClass());
// Resource validation.
if (beanDescriptor.isBeanConstrained()) {
constraintViolations.addAll(validate(resource));
}
if (resourceMethod != null
&& configuration.getBootstrapConfiguration().isExecutableValidationEnabled()) {
final Method handlingMethod = resourceMethod.getHandlingMethod();
The interesting part is around
// Resource validation.
if (beanDescriptor.isBeanConstrained()) {
constraintViolations.addAll(validate(resource));
}
The definition of the same is
@Override
public final boolean isBeanConstrained() {
return hasConstraints() || !constrainedProperties.isEmpty();
}
Now if you look at the value of constrainedProperties
it shows below
So it thinks that getSomething
means a property something
which then inserts a validation on the property itself.
So now if we rename the method like below
@GET
public @Valid HelloMessage doGetSomething() {
System.out.println("* * * *---==** getSomething() called **==---* * * *");
HelloMessage helloMessage = new HelloMessage();
helloMessage.setMessage("H");
return helloMessage;
}
@POST
public @Valid HelloMessage updateMessage(@Valid HelloMessage message) {
message.setMessage("H");
System.out.println("* * * *---==** updateMessage() called **==---* * * *");
return message;
}
And run it again from command line
And of course if I correct the return value with valid data
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With