Ron,
I realised that after I sent my email.
The issue happens when the rest endpoint is an ejb managed bean,
org.jboss.resteasy.cdi.JaxrsInjectionTarget.inject() only gets called in
the first invocation of the endpoint. On subsequent invocations,
JaxrsInjectionTarget.inject() is not called, so the validation exceptions
are not handled and I see a http 500 cause by a wrapped validation
exception being thrown in the ejb subsystem.
John
On Fri, Oct 27, 2017 at 5:03 PM, Ron Sigal <rsigal(a)redhat.com> wrote:
It's me again.
John, what you're describing is the behavior I wrote about on Wednesday.
Discussion inline:
On 10/27/2017 03:03 AM, John O'Hara wrote:
Thank you for your responses. If I fill you in on a bit of background
about what I have experienced, then it might help clarify the issue I see.
Background
I am running a JEE benchmark on EAP7.1 (using resteasy 3.0.24.Final). One
of rest endpoints has a @Valid annotation on a method parameter for a
complex object.
@POST
@Path("/foo")
@Consumes(MediaType.APPLICATION_JSON)
public void addFoo(@Valid Foo bar) throws Exception {
The Foo class contains different validation annotations, such as @NotNull,
@Size, @Pattern and a custom validation annotation.
One test determines how WF/EAP handles invalid requests. When I invoke
the endpoint above I see a non-deterministic response from the app server.
If I invoke the endpoint with an invalid json object I receive a HTTP 400
exception as expected, but if I invoke the endpoint with a valid object,
and *then* invoke the endpoint with an invalid object I receive a HTTP
500 error.
This exception only occurs on some property validation annotations and not
all (e.g. @NotNull works as expected)
The test is being run in the context of CDI, and the HTTP 500 error is
coming from the ejb3 subsystem. The ejb3 subsystem is wrapping the
ConstraintValidationException raised by hibernate-validator.
Observations
In the call stack I capture [1], and WF thread dump [2] I can see;
1.
The test is run in the context of CDI. The HTTP 500 response code
message is caused by the ejb3 subsystem wrapping a
ConstraintValidationException raised by hibernate-validator
1.
The validator is not called in ResourceMethodInvoker.invokeOnTarget()
[3] as isValidatable is false [4], a ResteasyViolationException is not
thrown
1.
The request is validated again here [5], the validation exceptions are
not acted upon in this method call and the reflected method (which happens
to be the Foo class constructor) is called here [6]
Questions
1.
Why is ResourceMethodInvoker.isValidatable false in WF/EAP?
In the context of CDI, field and property injections are not carried out
until a method is called on an object. I don't know why, but that's how it
is. So it's possible to do parameter validation inline in
MethodInjectorImpl.invoke(), but it's premature to do field/parameter
validation in ResourceMethodInvoker.invokeOnTargetAfterFilter().
1.
If isValidatable is false, and validation occurs again at
MethodInjectorImpl.invoke() can we not check for validation errors and
raise the correct exception there as well?
In effect, that's what is happening, but it's buried in
org.jboss.resteasy.cdi.JaxrsInjectionTarget.inject(). In particular:
private void validate(HttpRequest request, T instance)
{
if (GetRestful.isRootResource(clazz))
{
ResteasyProviderFactory providerFactory = ResteasyProviderFactory.
getInstance();
ContextResolver<GeneralValidatorCDI> resolver = providerFactory.
getContextResolver(GeneralValidatorCDI.class, MediaType.WILDCARD_TYPE);
if (resolver != null)
{
validator = providerFactory.getContextResolver(GeneralValidatorCDI.class,
MediaType.WILDCARD_TYPE).getContext(null); /// Hmmm, this looks
redundant ...
}
if (validator != null && validator.isValidatableFromCDI(clazz))
{
validator.validate(request, instance);
validator.checkViolationsfromCDI(request);
}
}
}
Note that validator.checkViolationsfromCDI(request) will throw a
ResteasyViolationException if any field/property/parameter violations have
been detected.
-Ron
I have a standalone test that I will clean up and push out. There are some
aspects of the test that can not be published publicly, so I need to modify
them first.
Thanks,
John
[1] - see failing_4.stack
[2] - see WF_stackTrace.out
[3] -
https://github.com/resteasy/Resteasy/blob/master/resteasy-
jaxrs/src/main/java/org/jboss/resteasy/core/ResourceMethodInvoker.java#
L305
[4] -
https://github.com/resteasy/Resteasy/blob/master/
providers/resteasy-validator-provider-11/src/main/java/org/
jboss/resteasy/plugins/validation/GeneralValidatorImpl.java#L223
[5] -
https://github.com/resteasy/Resteasy/blob/master/resteasy-
jaxrs/src/main/java/org/jboss/resteasy/core/MethodInjectorImpl.java#L119
[6] -
https://github.com/resteasy/Resteasy/blob/master/resteasy-
jaxrs/src/main/java/org/jboss/resteasy/core/MethodInjectorImpl.java#L140
_______________________________________________
resteasy-dev mailing
listresteasy-dev@lists.jboss.orghttps://lists.jboss.org/mailman/listinfo/resteasy-dev
--
My company's smarter than your company (unless you work for Red Hat)
_______________________________________________
resteasy-dev mailing list
resteasy-dev(a)lists.jboss.org
https://lists.jboss.org/mailman/listinfo/resteasy-dev
TRIED. TESTED. TRUSTED. <