Uploaded image for project: 'RESTEasy'
  1. RESTEasy
  2. RESTEASY-3520

ArrayIndexOutOfBoundsException when using eclipsemicroprofile REST client with custom ContextResolver

XMLWordPrintable

    • Hide

      Deploying these classes to WildFly 29.0.0.Final will trigger the exception:

      MyContextResolver.java
      import jakarta.ws.rs.ext.ContextResolver;
      import jakarta.ws.rs.ext.Provider;
      
      @Provider
      public class MyContextResolver implements ContextResolver<Object> {
        @Override
        public MyContext getContext(Class<?> type) {
          return new MyContext();
        }
      }
      
      MyContext.java
      public class MyContext {}
      
      MyRestClient.java
      import org.eclipse.microprofile.rest.client.annotation.RegisterProvider;
      import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
      import de.sanacorp.wedesk.server.base.jackson.MyContextResolver;
      import jakarta.ws.rs.GET;
      
      @RegisterRestClient(baseUri = "whatever")
      @RegisterProvider(MyContextResolver.class)
      public interface MyRestClient {
        @GET
        void ping();
      }
      
      MyStartupEjb.java
      import org.eclipse.microprofile.rest.client.inject.RestClient;
      import jakarta.annotation.PostConstruct;
      import jakarta.ejb.Singleton;
      import jakarta.ejb.Startup;
      import jakarta.inject.Inject;
      
      @Startup
      @Singleton
      public class MyStartupEjb {
        @Inject
        @RestClient
        private MyRestClient client;
      
        @PostConstruct
        public void postConstruct() {
          System.out.println("MyStartup.postConstruct()");
          client.ping();
        }
      }
      
      Show
      Deploying these classes to WildFly 29.0.0.Final will trigger the exception: MyContextResolver.java import jakarta.ws.rs.ext.ContextResolver; import jakarta.ws.rs.ext.Provider; @Provider public class MyContextResolver implements ContextResolver< Object > { @Override public MyContext getContext( Class <?> type) { return new MyContext(); } } MyContext.java public class MyContext {} MyRestClient.java import org.eclipse.microprofile. rest .client.annotation.RegisterProvider; import org.eclipse.microprofile. rest .client.inject.RegisterRestClient; import de.sanacorp.wedesk.server.base.jackson.MyContextResolver; import jakarta.ws.rs.GET; @RegisterRestClient(baseUri = "whatever" ) @RegisterProvider(MyContextResolver.class) public interface MyRestClient { @GET void ping(); } MyStartupEjb.java import org.eclipse.microprofile. rest .client.inject.RestClient; import jakarta.annotation.PostConstruct; import jakarta.ejb.Singleton; import jakarta.ejb.Startup; import jakarta.inject.Inject; @Startup @Singleton public class MyStartupEjb { @Inject @RestClient private MyRestClient client; @PostConstruct public void postConstruct() { System .out.println( "MyStartup.postConstruct()" ); client.ping(); } }
    • Workaround Exists
    • Hide

      Workaround 1

      Annotate the ContextResolver with @Dependent to prevent Weld from using a proxy.

      Workaround 2

      Don't use @Provider or CDI scope annotations such as @ApplicationScoped or @RequestScoped on the ContextResolver that is registered via @RegisterProvider. To make the provider work with REST resources you can then create an empty subclass of the context resolver and annotate that subclass with @Provider.

      Show
      Workaround 1 Annotate the ContextResolver with @Dependent to prevent Weld from using a proxy. Workaround 2 Don't use @Provider or CDI scope annotations such as @ApplicationScoped or @RequestScoped on the ContextResolver that is registered via @RegisterProvider . To make the provider work with REST resources you can then create an empty subclass of the context resolver and annotate that subclass with @Provider .

      When registering a custom context resolver class via @org.eclipse.microprofile.rest.client.annotation.RegisterProvider you get an ArrayIndexOutOfBoundsException if the context resolver class ist annotated with @Provider.
      In my example I have an ObjectMapperProvider to register a custom Jackson ObjectMapper and i want to annotate it with @Provider so that it gets picked up by my REST resources. To also make it available to my rest clients i use @RegisterProvider:

      @Provider
      @Produces(MediaType.APPLICATION_JSON)
      public class JsonObjectMapperProvider implements ContextResolver<ObjectMapper> {
        // ...
      }
      
      @RegisterProvider(MyContextResolver.class)
      public interface MyRestClient {
       // ...
      }
      

      The issue is that when using @Provider the provider is an instance of WeldProxy for some reason (probably @Provider implies a non-dependent scope) and this causes org.jboss.resteasy.spi.util.Types.findInterfaceParameterizedTypes(Class<?>, ParameterizedType, Class<?>) to get a non-parameterized class object when calling root.getGenericInterfaces() in line 535 in version 6.2.4.Final. In the Javadoc of java.lang.Class.getGenericInterfaces() I read:

      Returns the Types representing the interfaces directly implemented by the class or interface represented bythis Class object.

      So my guess is that maybe the Weld proxy reimplements the ContextResolver interface without generic type parameters. So i would propose to make Types.findInterfaceParameterizedTypes check the superclass in case the generic type parameter cannot be determined from the subclass, similar to how the superclass is already used when the interface is not present on the subclass.

      Exception

      13:55:08,408 ERROR [org.jboss.msc.service.fail] (ServerService Thread Pool -- 364) MSC000001: Failed to start service jboss.deployment.unit."my-app.war".component.MyStartupEjb.START: org.jboss.msc.service.StartException in service jboss.deployment.unit."my-app.war".component.MyStartupEjb.START: java.lang.IllegalStateException: WFLYEE0042: Failed to construct component instance
      	at org.jboss.as.ee@29.0.0.Final//org.jboss.as.ee.component.ComponentStartService$1.run(ComponentStartService.java:57)
      	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
      	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
      	at org.jboss.threads@2.4.0.Final//org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
      	at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1990)
      	at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
      	at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1377)
      	at java.base/java.lang.Thread.run(Thread.java:1583)
      	at org.jboss.threads@2.4.0.Final//org.jboss.threads.JBossThread.run(JBossThread.java:513)
      Caused by: java.lang.IllegalStateException: WFLYEE0042: Failed to construct component instance
      	at org.jboss.as.ee@29.0.0.Final//org.jboss.as.ee.component.BasicComponent.constructComponentInstance(BasicComponent.java:170)
      	at org.jboss.as.ee@29.0.0.Final//org.jboss.as.ee.component.BasicComponent.constructComponentInstance(BasicComponent.java:141)
      	at org.jboss.as.ee@29.0.0.Final//org.jboss.as.ee.component.BasicComponent.createInstance(BasicComponent.java:88)
      	at org.jboss.as.ejb3@29.0.0.Final//org.jboss.as.ejb3.component.singleton.SingletonComponent.getComponentInstance(SingletonComponent.java:127)
      	at org.jboss.as.ejb3@29.0.0.Final//org.jboss.as.ejb3.component.singleton.SingletonComponent.start(SingletonComponent.java:141)
      	at org.jboss.as.ee@29.0.0.Final//org.jboss.as.ee.component.ComponentStartService$1.run(ComponentStartService.java:54)
      	... 8 more
      Caused by: jakarta.ejb.EJBException: java.lang.RuntimeException: RESTEASY003920: Unable to instantiate ContextResolver
      	at org.jboss.as.ejb3@29.0.0.Final//org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInOurTx(CMTTxInterceptor.java:268)
      	at org.jboss.as.ejb3@29.0.0.Final//org.jboss.as.ejb3.tx.CMTTxInterceptor.requiresNew(CMTTxInterceptor.java:416)
      	at org.jboss.as.ejb3@29.0.0.Final//org.jboss.as.ejb3.tx.LifecycleCMTTxInterceptor.processInvocation(LifecycleCMTTxInterceptor.java:68)
      	at org.jboss.invocation@2.0.0.Final//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
      	at org.jboss.as.weld@29.0.0.Final//org.jboss.as.weld.injection.WeldInjectionContextInterceptor.processInvocation(WeldInjectionContextInterceptor.java:43)
      	at org.jboss.invocation@2.0.0.Final//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
      	at org.jboss.as.ejb3@29.0.0.Final//org.jboss.as.ejb3.component.interceptors.CurrentInvocationContextInterceptor.processInvocation(CurrentInvocationContextInterceptor.java:41)
      	at org.jboss.invocation@2.0.0.Final//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
      	at org.jboss.as.ee@29.0.0.Final//org.jboss.as.ee.concurrent.ConcurrentContextInterceptor.processInvocation(ConcurrentContextInterceptor.java:45)
      	at org.jboss.invocation@2.0.0.Final//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
      	at org.jboss.invocation@2.0.0.Final//org.jboss.invocation.ContextClassLoaderInterceptor.processInvocation(ContextClassLoaderInterceptor.java:60)
      	at org.jboss.invocation@2.0.0.Final//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
      	at org.jboss.as.ejb3@29.0.0.Final//org.jboss.as.ejb3.component.singleton.StartupCountDownInterceptor.processInvocation(StartupCountDownInterceptor.java:25)
      	at org.jboss.invocation@2.0.0.Final//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
      	at org.jboss.invocation@2.0.0.Final//org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:53)
      	at org.jboss.as.ee@29.0.0.Final//org.jboss.as.ee.component.BasicComponent.constructComponentInstance(BasicComponent.java:168)
      	... 13 more
      Caused by: java.lang.RuntimeException: RESTEASY003920: Unable to instantiate ContextResolver
      	at org.jboss.resteasy.resteasy-core@6.2.4.Final//org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl.processProviderInstanceContracts(ResteasyProviderFactoryImpl.java:945)
      	at org.jboss.resteasy.resteasy-core@6.2.4.Final//org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl.registerProviderInstance(ResteasyProviderFactoryImpl.java:921)
      	at org.jboss.resteasy.resteasy-core@6.2.4.Final//org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl.register(ResteasyProviderFactoryImpl.java:1398)
      	at org.jboss.resteasy.resteasy-core@6.2.4.Final//org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl.register(ResteasyProviderFactoryImpl.java:119)
      	at org.jboss.resteasy.resteasy-client@6.2.4.Final//org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl.register(ResteasyClientBuilderImpl.java:479)
      	at org.jboss.resteasy.resteasy-client-microprofile@2.1.2.Final//org.jboss.resteasy.microprofile.client.RestClientBuilderImpl.register(RestClientBuilderImpl.java:765)
      	at org.jboss.resteasy.resteasy-client-microprofile@2.1.2.Final//org.jboss.resteasy.microprofile.client.RestClientBuilderImpl.register(RestClientBuilderImpl.java:707)
      	at org.jboss.resteasy.resteasy-client-microprofile@2.1.2.Final//org.jboss.resteasy.microprofile.client.RestClientBuilderImpl.build(RestClientBuilderImpl.java:261)
      	at org.jboss.resteasy.resteasy-client-microprofile@2.1.2.Final//org.jboss.resteasy.microprofile.client.RestClientBuilderImpl.build(RestClientBuilderImpl.java:396)
      	at org.jboss.resteasy.resteasy-client-microprofile@2.1.2.Final//org.jboss.resteasy.microprofile.client.RestClientDelegateBean.create(RestClientDelegateBean.java:163)
      	at org.jboss.weld.core@5.1.1.SP1//org.jboss.weld.contexts.unbound.DependentContextImpl.get(DependentContextImpl.java:64)
      	at org.jboss.weld.core@5.1.1.SP1//org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.get(ContextualInstanceStrategy.java:100)
      	at org.jboss.weld.core@5.1.1.SP1//org.jboss.weld.bean.ContextualInstance.get(ContextualInstance.java:50)
      	at org.jboss.weld.core@5.1.1.SP1//org.jboss.weld.manager.BeanManagerImpl.getReference(BeanManagerImpl.java:680)
      	at org.jboss.weld.core@5.1.1.SP1//org.jboss.weld.manager.BeanManagerImpl.getInjectableReference(BeanManagerImpl.java:780)
      	at org.jboss.weld.core@5.1.1.SP1//org.jboss.weld.injection.FieldInjectionPoint.inject(FieldInjectionPoint.java:92)
      	at org.jboss.weld.core@5.1.1.SP1//org.jboss.weld.util.Beans.injectBoundFields(Beans.java:345)
      	at org.jboss.weld.core@5.1.1.SP1//org.jboss.weld.util.Beans.injectFieldsAndInitializers(Beans.java:356)
      	at org.jboss.weld.core@5.1.1.SP1//org.jboss.weld.injection.producer.DefaultInjector$1.proceed(DefaultInjector.java:71)
      	at org.jboss.weld.core@5.1.1.SP1//org.jboss.weld.injection.InjectionContextImpl.run(InjectionContextImpl.java:48)
      	at org.jboss.weld.core@5.1.1.SP1//org.jboss.weld.injection.producer.DefaultInjector.inject(DefaultInjector.java:73)
      	at org.jboss.weld.core@5.1.1.SP1//org.jboss.weld.module.ejb.DynamicInjectionPointInjector.inject(DynamicInjectionPointInjector.java:61)
      	at org.jboss.weld.core@5.1.1.SP1//org.jboss.weld.module.ejb.SessionBeanInjectionTarget.inject(SessionBeanInjectionTarget.java:138)
      	at org.jboss.as.weld@29.0.0.Final//org.jboss.as.weld.injection.WeldInjectionContext.inject(WeldInjectionContext.java:39)
      	at org.jboss.as.weld@29.0.0.Final//org.jboss.as.weld.injection.WeldInjectionInterceptor.processInvocation(WeldInjectionInterceptor.java:51)
      	at org.jboss.invocation@2.0.0.Final//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
      	at org.jboss.as.ee@29.0.0.Final//org.jboss.as.ee.component.AroundConstructInterceptorFactory$1.processInvocation(AroundConstructInterceptorFactory.java:28)
      	at org.jboss.invocation@2.0.0.Final//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
      	at org.jboss.as.weld@29.0.0.Final//org.jboss.as.weld.injection.WeldInterceptorInjectionInterceptor.processInvocation(WeldInterceptorInjectionInterceptor.java:56)
      	at org.jboss.invocation@2.0.0.Final//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
      	at org.jboss.as.weld@29.0.0.Final//org.jboss.as.weld.interceptors.Jsr299BindingsCreateInterceptor.processInvocation(Jsr299BindingsCreateInterceptor.java:111)
      	at org.jboss.invocation@2.0.0.Final//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
      	at org.jboss.as.ee@29.0.0.Final//org.jboss.as.ee.component.NamespaceContextInterceptor.processInvocation(NamespaceContextInterceptor.java:50)
      	at org.jboss.invocation@2.0.0.Final//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
      	at org.jboss.as.ejb3@29.0.0.Final//org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInOurTx(CMTTxInterceptor.java:254)
      	... 28 more
      Caused by: java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0
      	at org.jboss.resteasy.resteasy-core@6.2.4.Final//org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl.addContextResolver(ResteasyProviderFactoryImpl.java:626)
      	at org.jboss.resteasy.resteasy-core@6.2.4.Final//org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl.processProviderInstanceContracts(ResteasyProviderFactoryImpl.java:942)
      	... 62 more
      

              jperkins-rhn James Perkins
              adrodoc Adrodoc 55 (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

                Created:
                Updated:
                Resolved: