Weld
  1. Weld
  2. WELD-737

Proxy instantiation fails with IllegalAccessError for Beans with package private constructor

    Details

    • Steps to Reproduce:
      Hide

      Have attached an arquillian test to reproduce the issue.

      Show
      Have attached an arquillian test to reproduce the issue.
    • Similar Issues:
      Show 10 results 

      Description

      For Beans with package private constructors, proxy instantiation fails with an Illegal access error as shown below. Since 1.1.0.Beta1 the proxy creation logic in ProxyFactory.addConstructors handles private constructors correctly but doesn't consider package private constructors.


      Caused by: java.lang.IllegalAccessError: tried to access method org.glassfish.tests.proxies.TestSessionScopedBean.<init>()V from class org.glassfish.tests.proxies.org$jboss$weld$bean-$export$work$workspaces$gfv3$v3$distributions$glassfish$target$glassfish3$glassfish$domains$domain1$applications$jsr88-1370237334428885039$-ManagedBean-class_org$glassfish$tests$proxies$TestSessionScopedBean_$$_WeldProxy
      at org.glassfish.tests.proxies.org$jboss$weld$bean-$export$work$workspaces$gfv3$v3$distributions$glassfish$target$glassfish3$glassfish$domains$domain1$applications$jsr88-1370237334428885039$ManagedBean-class_org$glassfish$tests$proxies$TestSessionScopedBean_$$WeldProxy.<init>(org$jboss$weld$bean$export$work$workspaces$gfv3$v3$distributions$glassfish$target$glassfish3$glassfish$domains$domain1$applications$jsr88-1370237334428885039$-ManagedBean-class_org$glassfish$tests$proxies$TestSessionScopedBean$$_WeldProxy.java)
      at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
      at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
      at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
      at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
      at java.lang.Class.newInstance0(Class.java:355)
      at java.lang.Class.newInstance(Class.java:308)
      at org.jboss.weld.util.reflection.SecureReflections$16.work(SecureReflections.java:396)
      at org.jboss.weld.util.reflection.SecureReflectionAccess.run(SecureReflectionAccess.java:54)
      at org.jboss.weld.util.reflection.SecureReflectionAccess.runAsInstantiation(SecureReflectionAccess.java:216)
      at org.jboss.weld.util.reflection.SecureReflections.newInstance(SecureReflections.java:391)
      at org.jboss.weld.bean.proxy.ProxyFactory.create(ProxyFactory.java:218)
      at org.jboss.weld.bean.proxy.ClientProxyProvider.createClientProxy(ClientProxyProvider.java:89)
      at org.jboss.weld.bean.proxy.ClientProxyProvider.access$000(ClientProxyProvider.java:40)
      at org.jboss.weld.bean.proxy.ClientProxyProvider$1.apply(ClientProxyProvider.java:53)
      at org.jboss.weld.bean.proxy.ClientProxyProvider$1.apply(ClientProxyProvider.java:44)
      at com.google.common.collect.ComputingConcurrentHashMap.compute(ComputingConcurrentHashMap.java:206)


      1. package-private-constructor-issue.tar.bz2
        0.8 kB
        Sivakumar Thyagarajan
      2. ProxyServicesImpl.java
        5 kB
        Sivakumar Thyagarajan

        Issue Links

          Activity

          Hide
          Sivakumar Thyagarajan
          added a comment -

          The new ProxyServicesImpl with the delegate classloader approach

          Show
          Sivakumar Thyagarajan
          added a comment - The new ProxyServicesImpl with the delegate classloader approach
          Hide
          Stuart Douglas
          added a comment -

          The problem is that this is a JVM level restriction.

          The JVM requires all constructors to call super() or another constructor on the current class, and the JVM also enforces access permissions. This means that if you try and load a subclass of the class that only has a package private constructor you must load it in the same CL as the class being proxied, as when it attempts to call super() an IllegalAccessError will be thrown. (The link you posted to Guice's bridge class loader actually states it is not used when access package-private methods, for precisely this reason).

          The support for private constructors that you mention is a non standard extension that currently only works on hotspot (as is uses com.sun.Unsafe.allocateInstance()), the CDI spec does not require proxying of classes with a private default constructor as it is not possible to do it in a portable way.

          The javassist dependencies in the proxies are going to be removed as they are no longer necessary now that we use a custom ProxyFactory, however the proxies will still be dependent on org.jboss.weld classes (although these classes should be exported from the osgi bundle).

          Show
          Stuart Douglas
          added a comment - The problem is that this is a JVM level restriction. The JVM requires all constructors to call super() or another constructor on the current class, and the JVM also enforces access permissions. This means that if you try and load a subclass of the class that only has a package private constructor you must load it in the same CL as the class being proxied, as when it attempts to call super() an IllegalAccessError will be thrown. (The link you posted to Guice's bridge class loader actually states it is not used when access package-private methods, for precisely this reason). The support for private constructors that you mention is a non standard extension that currently only works on hotspot (as is uses com.sun.Unsafe.allocateInstance()), the CDI spec does not require proxying of classes with a private default constructor as it is not possible to do it in a portable way. The javassist dependencies in the proxies are going to be removed as they are no longer necessary now that we use a custom ProxyFactory, however the proxies will still be dependent on org.jboss.weld classes (although these classes should be exported from the osgi bundle).
          Hide
          Sivakumar Thyagarajan
          added a comment -

          I understand your point about private constructors support and yes, as you point out the CDI spec states in 5.4.1 that such beans are unproxyable.

          Could you let me know when the javassist dependencies would be removed? Would ProxyFactory at
          http://bit.ly/94ghUf be replaced? If the javassist dependencies of the Proxy is removed and the closure of all class references from the generated Proxy is in the set of packages exported by the weld-osgi-bundle, then the generated proxy could be loaded using the Classloader used to load the proxied bean type to handle package-private constructors and beans.

          If this is indeed the plan, we don't need the getClassLoader() method in the ProxyServices SPI, right as to be compatible with the spec, weld should use the classloader of the proxied bean type to load the proxy as well?
          http://github.com/weld/api/blob/master/weld-spi/src/main/java/org/jboss/weld/serialization/spi/ProxyServices.java#L55

          Show
          Sivakumar Thyagarajan
          added a comment - I understand your point about private constructors support and yes, as you point out the CDI spec states in 5.4.1 that such beans are unproxyable. Could you let me know when the javassist dependencies would be removed? Would ProxyFactory at http://bit.ly/94ghUf be replaced? If the javassist dependencies of the Proxy is removed and the closure of all class references from the generated Proxy is in the set of packages exported by the weld-osgi-bundle, then the generated proxy could be loaded using the Classloader used to load the proxied bean type to handle package-private constructors and beans. If this is indeed the plan, we don't need the getClassLoader() method in the ProxyServices SPI, right as to be compatible with the spec, weld should use the classloader of the proxied bean type to load the proxy as well? http://github.com/weld/api/blob/master/weld-spi/src/main/java/org/jboss/weld/serialization/spi/ProxyServices.java#L55
          Hide
          Stuart Douglas
          added a comment -

          After some more discussion we have decided that we are not going to replace the javassist proxy classes with weld ones. Replacing the javassist classes would only move the problem from 'javassist must be accessible' to 'replacement classes must be accessible'.

          As I understand it the javassist classes should not be a major issue now that weld no longer does a partial export from the OSGI bundle. Sivakumar if this is not the case would you be able to file it under a new issue?

          Show
          Stuart Douglas
          added a comment - After some more discussion we have decided that we are not going to replace the javassist proxy classes with weld ones. Replacing the javassist classes would only move the problem from 'javassist must be accessible' to 'replacement classes must be accessible'. As I understand it the javassist classes should not be a major issue now that weld no longer does a partial export from the OSGI bundle. Sivakumar if this is not the case would you be able to file it under a new issue?
          Hide
          Sivakumar Thyagarajan
          added a comment -

          Hi Stuart: I understand the reasons for not doing this and yes, with the fixing of JASSIST-104 and WELD-570, the partial exports and the corr classloader leaks have been fixed. However I was wondering how implementations that use the weld osgi-bundle could support this package private constructor usecase. They would also need to have a fragment based approach like the one GlassFish uses [1] to make the extra javassist packages used by the proxies available to the application classloader. Is this right and recommended?

          [1] https://fisheye4.atlassian.com/changelog/glassfish-svn?cs=42968

          Show
          Sivakumar Thyagarajan
          added a comment - Hi Stuart: I understand the reasons for not doing this and yes, with the fixing of JASSIST-104 and WELD-570 , the partial exports and the corr classloader leaks have been fixed. However I was wondering how implementations that use the weld osgi-bundle could support this package private constructor usecase. They would also need to have a fragment based approach like the one GlassFish uses [1] to make the extra javassist packages used by the proxies available to the application classloader. Is this right and recommended? [1] https://fisheye4.atlassian.com/changelog/glassfish-svn?cs=42968

            People

            • Assignee:
              Stuart Douglas
              Reporter:
              Sivakumar Thyagarajan
            • Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: