Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding javax.validation @Valid in JAX-RS resource method which override an interface break HibernateValidatorTemplate #2556

Closed
masini opened this issue May 22, 2019 · 5 comments

Comments

@masini
Copy link
Contributor

@masini masini commented May 22, 2019

Describe the bug

I have an interface with a single method:

public interface GreetingResourceInterface<T> {
    String hello(T pojo);
}

and a JAX-RS resource which implements it:

@Path("/hello")
public class GreetingResource implements GreetingResourceInterface<MyPojo> {

    @Override
    @POST
    @Produces(MediaType.TEXT_PLAIN)
    @Consumes(MediaType.APPLICATION_JSON)
    public String hello(@Valid MyPojo pojo) {
        return "hello";
    }
}

Expected behavior

The parameter is "validated" with javax.validation.

Actual behavior

At startup with:

mvn clean compile quarkus:dev

I got this Exception:

14:02:18,137 ERROR [io.qua.dev.DevModeMain] Failed to start quarkus: java.lang.ExceptionInInitializerError
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
        at java.lang.Class.newInstance(Class.java:442)
        at io.quarkus.runner.RuntimeRunner.run(RuntimeRunner.java:121)
        at io.quarkus.dev.DevModeMain.doStart(DevModeMain.java:159)
        at io.quarkus.dev.DevModeMain.main(DevModeMain.java:93)
Caused by: java.lang.RuntimeException: Failed to start quarkus
        at io.quarkus.runner.ApplicationImpl1.<clinit>(Unknown Source)
        ... 8 more
Caused by: java.lang.ArrayIndexOutOfBoundsException: 1
        at org.hibernate.validator.internal.properties.javabean.JavaBeanExecutable.getParameters(JavaBeanExecutable.java:213)
        at org.hibernate.validator.internal.properties.javabean.JavaBeanExecutable.<init>(JavaBeanExecutable.java:45)
        at org.hibernate.validator.internal.properties.javabean.JavaBeanConstructor.<init>(JavaBeanConstructor.java:20)
        at org.hibernate.validator.internal.properties.javabean.JavaBeanHelper.executable(JavaBeanHelper.java:109)
        at org.hibernate.validator.internal.properties.javabean.JavaBeanHelper.executable(JavaBeanHelper.java:104)
        at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.findExecutableMetaData(AnnotationMetaDataProvider.java:307)
        at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.getMetaData(AnnotationMetaDataProvider.java:292)
        at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.getConstructorMetaData(AnnotationMetaDataProvider.java:273)
        at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.retrieveBeanConfiguration(AnnotationMetaDataProvider.java:131)
        at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.getBeanConfiguration(AnnotationMetaDataProvider.java:120)
        at org.hibernate.validator.internal.metadata.PredefinedScopeBeanMetaDataManager.getBeanConfigurationForHierarchy(PredefinedScopeBeanMetaDataManager.java:165)
        at org.hibernate.validator.internal.metadata.PredefinedScopeBeanMetaDataManager.createBeanMetaData(PredefinedScopeBeanMetaDataManager.java:132)
        at org.hibernate.validator.internal.metadata.PredefinedScopeBeanMetaDataManager.<init>(PredefinedScopeBeanMetaDataManager.java:83)
        at org.hibernate.validator.internal.engine.PredefinedScopeValidatorFactoryImpl.<init>(PredefinedScopeValidatorFactoryImpl.java:175)
        at org.hibernate.validator.PredefinedScopeHibernateValidator.buildValidatorFactory(PredefinedScopeHibernateValidator.java:42)
        at org.hibernate.validator.internal.engine.AbstractConfigurationImpl.buildValidatorFactory(AbstractConfigurationImpl.java:369)
        at io.quarkus.hibernate.validator.runtime.HibernateValidatorTemplate.initializeValidatorFactory(HibernateValidatorTemplate.java:56)
        at io.quarkus.deployment.steps.HibernateValidatorProcessor$build6.deploy(Unknown Source)
        ... 9 more

When the executable of the:

org.hibernate.validator.internal.properties.javabean.JavaBeanExecutable.getParameters(java.lang.reflect.Executable) 

method is:

io.smallrye.config.ConfigSourceMap$EntrySet$Itr(io.smallrye.config.ConfigSourceMap$EntrySet,java.util.Iterator)

it does a bad calculation of "explicitlyDeclaredParameterIndex", accessing to the genericParameterTypes array with index[1] raise the
Exception.

To Reproduce

Steps to reproduce the behavior:

  1. Unzip the attached test-case
  2. mvn clean compile quarkus:dev

Configuration

None

Environment (please complete the following information):

  • Output of uname -a or ver:

    Darwin WMICTLM1P.local 18.6.0 Darwin Kernel Version 18.6.0: Thu Apr 25 23:16:27 PDT 2019; root:xnu-4903.261.4~2/RELEASE_X86_64 x86_64

  • Output of java -version:

    java version "1.8.0_152"

  • Quarkus version or git rev:

    0.15.0

Additional context
The same exact problem can be replicated from the attached test-case.

There is another issue with javax.validation and Interface, but in own opinion is not related:

#1888

test-case.zip

@masini masini added the bug label May 22, 2019
@masini masini changed the title Adding javax.validation @Valid in JAX-RS resource method which override an interface break ARC Adding javax.validation @Valid in JAX-RS resource method which override an interface break HibernateValidatorTemplate May 22, 2019
@gsmet

This comment has been minimized.

Copy link
Member

@gsmet gsmet commented May 30, 2019

I can confirm this is not fixed in current master.

@gsmet gsmet self-assigned this May 30, 2019
@gsmet gsmet added this to the 0.17.0 milestone May 30, 2019
@gsmet gsmet modified the milestones: 0.17.0, 0.18.0, 0.19.0 Jun 19, 2019
@gsmet gsmet added this to To do in Quarkus 1.0.0 Planning via automation Jul 3, 2019
@gsmet gsmet modified the milestones: 0.19.0, 0.20.0 Jul 9, 2019
@gsmet gsmet modified the milestones: 0.20.0, 0.21.0 Jul 31, 2019
@gsmet gsmet modified the milestones: 0.21.0, 0.22.0 Aug 14, 2019
@gsmet gsmet modified the milestones: 0.22.0, 0.23.0 Aug 28, 2019
@FroMage

This comment has been minimized.

Copy link
Member

@FroMage FroMage commented Oct 4, 2019

This is a bug in HV, though, no @gsmet ?

@gsmet

This comment has been minimized.

Copy link
Member

@gsmet gsmet commented Oct 4, 2019

It's a bug in HV and we have a PR open to fix it. But let's keep that open as I need the test case handy.

@gsmet gsmet modified the milestones: 0.24.0, 0.25.0 Oct 9, 2019
@gsmet gsmet added this to To do in Deprecated - Quarkus 1.0 via automation Oct 9, 2019
@yrodiere yrodiere self-assigned this Oct 9, 2019
@yrodiere

This comment has been minimized.

Copy link
Collaborator

@yrodiere yrodiere commented Oct 9, 2019

Several comments here:

  1. This is definitely caused by a bug in HV, namely HV-1730. The pending PR here fixes the problem.
  2. For some reason, the bug only occurs if the method with the annotated parameter is declared in a superinterface. If the method is declared directly in the implementing class, the bug does not occur.
  3. The @Valid annotation is irrelevant. @Digits on a parameter of type Integer (T extends Number in the superinterface) triggers the bug as well.
  4. @POST is irrelevant. The bug is triggered on a @GET method with path-params as well.
  5. Even when the bug is fixed, the code in the given test case is invalid, because the implementation of the REST endpoint adds constraints compared to the generic interface. Hibernate Validator forbids this, and will throw an exception similar to this:
Caused by: javax.validation.ConstraintDeclarationException: HV000151: A method overriding another method must not redefine the parameter constraint configuration, but method HibernateValidatorTestResource#testRestEndpointGenericMethodValidation(MyPojo) redefines the configuration of HibernateValidatorTestResourceGenericInterface#testRestEndpointGenericMethodValidation(Object).
  1. Not really related, but the implementing class has to set the @Valid annotation too in order for validation to occur. Otherwise, the @Valid annotation from the superinterface is ignored.
  2. In this particular case, the bug occurs while Hibernate Validator inspects class io.smallrye.config.ConfigSourceMap$Values$Itr, which does not appear in the user code. I wonder why Hibernate Validator inspects this class in the first place?

@gsmet I thing item 7 warrants further investigation. I added a test to my PR here: #4439
In that test, org.hibernate.validator.internal.metadata.PredefinedScopeBeanMetaDataManager#PredefinedScopeBeanMetaDataManager gets called with the following classes in beanClassesToInitialize. That seems a bit much?

0 = {Class@4376} "class io.smallrye.config.Converters$ArrayConverter"
1 = {Class@4360} "class io.quarkus.test.common.http.URLTestHTTPResourceProvider"
2 = {Class@2972} "class io.smallrye.config.SmallRyeConfigBuilder"
3 = {Class@3033} "class io.smallrye.config.SmallRyeConfig$1"
4 = {Class@4347} "class io.smallrye.config.inject.ConfigProducerUtil"
5 = {Class@4339} "class io.quarkus.it.hibernate.validator.custom.MyOtherBean"
6 = {Class@4364} "class io.smallrye.config.ImplicitConverters$StaticMethodConverter$Serialized"
7 = {Class@4372} "class io.quarkus.test.common.NativeImageLauncher$ProcessReader"
8 = {Class@4365} "class io.quarkus.test.common.http.StringTestHTTPResourceProvider"
9 = {Class@4379} "class io.quarkus.test.common.NativeImageLauncher"
10 = {Class@4340} "class io.quarkus.test.common.TestScopeManager"
11 = {Class@4344} "class io.smallrye.config.inject.ConfigInjectionBean$InjectionPointMetadataInjectionPoint"
12 = {Class@3027} "class io.smallrye.config.EnvConfigSource"
13 = {Class@4331} "interface io.quarkus.it.hibernate.validator.HibernateValidatorTestResourceGenericInterface"
14 = {Class@4378} "class io.smallrye.config.ConfigSourceMap$Values$Itr"
15 = {Class@3032} "class io.smallrye.config.SmallRyeConfig"
16 = {Class@4346} "class io.quarkus.test.common.http.TestHTTPResourceManager"
17 = {Class@4345} "class io.quarkus.it.hibernate.validator.HibernateValidatorTestResource$MyBean"
18 = {Class@4377} "class io.smallrye.config.Converters$RangeCheckConverter"
19 = {Class@3029} "class io.smallrye.config.PropertiesConfigSourceProvider"
20 = {Class@4369} "class io.quarkus.it.hibernate.validator.injection.MyService"
21 = {Class@2119} "class io.quarkus.test.common.PropertyTestUtil"
22 = {Class@3070} "class io.smallrye.config.ImplicitConverters$ConstructorConverter"
23 = {Class@2247} "class io.quarkus.test.common.QuarkusTestResourceLifecycleManagerComparator"
24 = {Class@4329} "class io.quarkus.it.hibernate.validator.HibernateValidatorTestResource$NestedBeanWithoutConstraints"
25 = {Class@2158} "class io.quarkus.test.common.TestResourceManager"
26 = {Class@4366} "class io.quarkus.test.common.TestInstantiator"
27 = {Class@4334} "class io.quarkus.it.hibernate.validator.custom.MyCustomConstraint$Validator"
28 = {Class@4352} "class io.smallrye.config.inject.ConfigInjectionBean"
29 = {Class@4382} "class io.smallrye.config.inject.ConfigExtension"
30 = {Class@4368} "class io.smallrye.config.ConfigSourceMap$EntrySet$Itr"
31 = {Class@4330} "class io.quarkus.it.hibernate.validator.HibernateValidatorTestResource$BeanWithInjectedConstraintValidatorConstraint"
32 = {Class@2161} "class io.quarkus.test.common.PathTestHelper"
33 = {Class@4375} "class io.quarkus.it.hibernate.validator.HibernateValidatorTestResource$1"
34 = {Class@3028} "class io.smallrye.config.SysPropConfigSource"
35 = {Class@2991} "class io.smallrye.config.Converters$BuiltInConverter"
36 = {Class@4374} "class io.smallrye.config.DirConfigSource"
37 = {Class@4335} "class io.smallrye.config.Converters$PatternCheckConverter"
38 = {Class@4362} "class io.quarkus.test.common.NativeImageLauncher$1"
39 = {Class@4370} "class io.quarkus.it.hibernate.validator.GreetingService"
40 = {Class@4380} "class io.quarkus.test.common.TestInjectionManager"
41 = {Class@4357} "class io.quarkus.it.hibernate.validator.injection.InjectedConstraintValidator"
42 = {Class@327} "class java.lang.Object"
43 = {Class@4361} "class io.smallrye.config.inject.ConfigProducer"
44 = {Class@4328} "class io.quarkus.it.hibernate.validator.HibernateValidatorTestResource$ResultBuilder"
45 = {Class@2989} "class io.smallrye.config.Converters"
46 = {Class@4336} "class io.smallrye.config.ImplicitConverters$ConstructorConverter$Serialized"
47 = {Class@3802} "class io.smallrye.config.ImplicitConverters$StaticMethodConverter"
48 = {Class@1200} "class io.quarkus.it.hibernate.validator.HibernateValidatorFunctionalityTest"
49 = {Class@4332} "class io.quarkus.it.hibernate.validator.HibernateValidatorTestResource"
50 = {Class@4338} "class io.smallrye.config.SmallRyeConfigBuilder$1"
51 = {Class@4371} "class io.quarkus.test.common.http.URITestHTTPResourceProvider"
52 = {Class@4358} "class io.quarkus.it.hibernate.validator.HibernateValidatorFunctionalityInGraalITCase"
53 = {Class@2166} "class io.quarkus.test.common.TestResourceManager$1"
54 = {Class@2982} "class io.smallrye.config.PropertiesConfigSource"
55 = {Class@1593} "class io.quarkus.test.common.RestAssuredURLManager"
56 = {Class@3562} "class io.smallrye.config.SecuritySupport"
57 = {Class@4373} "class io.smallrye.config.Converters$CollectionConverter"
58 = {Class@3069} "class io.smallrye.config.ImplicitConverters"
59 = {Class@4367} "class io.smallrye.config.Converters$Ser"
60 = {Class@4363} "class io.smallrye.config.inject.ConfigInjectionBean$1"
61 = {Class@4337} "class io.quarkus.it.hibernate.validator.pojo.MyPojo"
62 = {Class@3061} "class io.smallrye.config.StringUtil"
63 = {Class@3016} "class io.smallrye.config.SmallRyeConfigBuilder$ConverterWithPriority"
@gsmet

This comment has been minimized.

Copy link
Member

@gsmet gsmet commented Oct 9, 2019

Urgh, that's definitely not intended... well, except if the classes are annotated with BV/HV annotations. I'll have a closer look as soon as I can.

@gsmet gsmet modified the milestones: 0.26.0, 0.27.0 Oct 15, 2019
gsmet added a commit that referenced this issue Oct 29, 2019
Test case for issues #3284 and #2556
@gsmet gsmet closed this Oct 29, 2019
Deprecated - Quarkus 1.0 automation moved this from To do to Done Oct 29, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
5 participants
You can’t perform that action at this time.