Uploaded image for project: 'WildFly Core'
  1. WildFly Core
  2. WFCORE-4514

ProxyMetadataSource breaks contract of ClassMetadataSource#getDeclaredMethods (resulting in "illegal reflective access operation" in Java 11)

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: Major Major
    • None
    • 9.0.1.Final
    • Server
    • None

      While investigating this issue reported in the forum thread[1], where the user states that using Java 11 shows up a warning about illegal reflective access:

      WARNING: An illegal reflective access operation has occurred
      
      WARNING: Illegal reflective access by org.jboss.invocation.proxy.AbstractProxyFactory$1 (jar:file:/C:/wildfly-16.0.0.Final/modules/system/layers/base/org/jboss/invocation/main/jboss-invocation-1.5.2.Final.jar!/) to method java.lang.Object.clone()
      
      WARNING: Please consider reporting this to the maintainers of org.jboss.invocation.proxy.AbstractProxyFactory$1
      
      WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
      
      WARNING: All illegal access operations will be denied in a future release
      

      I realized that, that issue is in fact triggered by, what I believe, is a bug and a violation of an (internal) API contract in WildFly.

      What seems to be happening is - when the proxy class is being defined for (EJB) component, in the jboss-invocation library here[2], the implementation there overrides the component classes' methods. It does that for the entire class hierarchy of the component class and stops at the Object.class (rightly so) through the use of this check[3] (currentClass != Object.class). In this implementation, within the loop, it then calls:

      ClassMetadataSource data = reflectionMetadataSource.getClassMetadata(currentClass);
      

      which is an API exposed by the org.jboss.invocation.proxy.reflection.ReflectionMetadataSource interface. The returned ClassMetadataSource is then used within that loop as follows:

      for (Method method : data.getDeclaredMethods()) {
      ....
      

      The getDeclaredMethods() API, exposed by ClassMetadataSource[5] is expected to (only) return the methods that are declared by that class. Turns out, the implementation in WildFly[6], for this interface, doesn't honour that contract and instead returns all methods (including the ones that are in the super class) on that class:

      public Collection<Method> getDeclaredMethods() {
          return index.getClassMethods();
      }
      

      The index.getClassMethods() is a call to the ClassReflectionIndex#getClassMethods() whose implementation[7] walks through the entire class hierarchy and returns all the methods on that class.

      This (unexpected) implemetation of ProxyMetadataSource#getDeclaredMethods()[6] causes the check in [3] to end up being irrelevant and as a result the code in [2] ends up trying to take control over methods on the Object class (by calling method.setAccessible(true)[8]) and one such method is the "clone" method. This ultimately results in that illegal reflective access warning.

      Looking at the history of ProxyMetadataSource#getDeclaredMethods() in WildFly, it looks like the implementation was changed to accomodate/fix this issue https://issues.jboss.org/browse/WFCORE-579 in this commit https://github.com/wildfly/wildfly-core/commit/4382f0c28dab2d0494926b8a34582dc9a3813875. The previous implementation was returning the correct methods (only the declared ones). Looking at that JIRA and linked bugzilla to it, I think the original issue might need a different fix. I haven't yet had a chance to look more into that issue.

      Of course, one way to solve the current issue at hand (the illegal reflective access one) would be to add a check in
      jboss-invocation's AbstractProxyFactory similar to this https://github.com/wildfly/wildfly-core/blob/master/server/src/main/java/org/jboss/as/server/deployment/reflect/ClassReflectionIndex.java#L84, but IMO, that would be more of a hack than an actual fix since the API contract violation in ProxyMetadataSource will still be an issue and can (and probably does) cause some unexpected problems.

      [1] https://developer.jboss.org/message/989623#989623
      [2] https://github.com/jbossas/jboss-invocation/blob/master/src/main/java/org/jboss/invocation/proxy/AbstractSubclassFactory.java#L209
      [3] https://github.com/jbossas/jboss-invocation/blob/master/src/main/java/org/jboss/invocation/proxy/AbstractSubclassFactory.java#L211
      [4] https://github.com/jbossas/jboss-invocation/blob/master/src/main/java/org/jboss/invocation/proxy/reflection/ReflectionMetadataSource.java
      [5] https://github.com/jbossas/jboss-invocation/blob/master/src/main/java/org/jboss/invocation/proxy/reflection/ClassMetadataSource.java
      [6] https://github.com/wildfly/wildfly-core/blob/5391b40b79f72d2a57d4e32234af7c4ad585acab/server/src/main/java/org/jboss/as/server/deployment/reflect/ProxyMetadataSource.java#L47
      [7] https://github.com/wildfly/wildfly-core/blob/master/server/src/main/java/org/jboss/as/server/deployment/reflect/ClassReflectionIndex.java#L389
      [8] https://github.com/jbossas/jboss-invocation/blob/master/src/main/java/org/jboss/invocation/proxy/AbstractProxyFactory.java#L120

              jmesnil1@redhat.com Jeff Mesnil
              jaikiran Jaikiran Pai (Inactive)
              Votes:
              4 Vote for this issue
              Watchers:
              7 Start watching this issue

                Created:
                Updated: