Bug 152568 - IllegalAccessError when accessing protected method from an inner type
Summary: IllegalAccessError when accessing protected method from an inner type
Status: RESOLVED WONTFIX
Alias: None
Product: Equinox
Classification: Eclipse Project
Component: Framework (show other bugs)
Version: 3.2   Edit
Hardware: PC Linux-GTK
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: equinox.framework-inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 157381 364485 (view as bug list)
Depends on:
Blocks:
 
Reported: 2006-08-02 05:01 EDT by Tom Hofmann CLA
Modified: 2012-01-11 02:46 EST (History)
5 users (show)

See Also:


Attachments
illegal_access_plugins.zip (7.22 KB, application/zip)
2006-08-02 05:05 EDT, Tom Hofmann CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Tom Hofmann CLA 2006-08-02 05:01:23 EDT
3.2 (and I20060725)

(will attach two example plug-ins demonstrating the problem)

- have project A, exporting org.example.b, containing class SuperSamePack:

----------------- SuperSamePack.java ----------
package org.example.b;

public class SuperSamePack
{
    protected final Object method()
    {
        return null;
    }
}
----------------------------------------------

- have project B depending on A, containing class Sub:

----------------------- Sub.java -----------------
package org.example.b;

public class Sub
extends SuperSamePack
{
    Runnable fRunnable = new Runnable()
    {
        public void run()
        {
            System.out.println("Sub.fRunnable.run() before");
            Object o = method();
            System.out.println("Sub.fRunnable.run() after");
        };
    };

    public void call()
    {
        fRunnable.run();
    }
}
----------------------------------------------------------

- start an eclipse workbench containing the two plug-ins and call Sub.call().

> expected: works, console output shows the log statements in fRunnable.run()
< actual: The access to SuperSamePack::method throws an IllegalAccessError

Notes:
- the same works if the super class does not reside in the same package
- the same works if the super class resides in the same project
- callin SuperSamePack::method succeeds from a method in the body of Sub, but not from an inner class.

Since this only happens in the plug-in environment, I assume the problem stems from some access checks done by OSGi. Apparently it has to do with the package split over two plug-ins.
Comment 1 Tom Hofmann CLA 2006-08-02 05:05:17 EDT
Created attachment 47206 [details]
illegal_access_plugins.zip

Zip file containing two plug-ins, org.example.A and org.example.B.

The latter contains an application that can be launched and that will demonstrate the problem.
Comment 2 Tom Hofmann CLA 2006-08-02 05:08:08 EDT
Note: the problem showed up when developping the text plug-ins - we currently work around this by adding a private accessor method in Sub:

public class Sub
extends SuperSamePack
{
    Runnable fRunnable = new Runnable()
    {
        public void run()
        {
            System.out.println("Sub.fRunnable.run() before");
            Object o = internalMethod();
            System.out.println("Sub.fRunnable.run() after");
        };
    };

    private Object internalMethod()
    {
        return method();
    }
}
Comment 3 BJ Hargrave CLA 2006-08-10 17:41:00 EDT
(In reply to comment #0)

> > expected: works, console output shows the log statements in fRunnable.run()
> < actual: The access to SuperSamePack::method throws an IllegalAccessError

This happens because the 2 classes are loaded by 2 different classloader and are thus not part of the same package as far as the JVM is concerned. 

> 
> Notes:
> - the same works if the super class does not reside in the same package

This works because the compiler sees the classes are not part of the same package and so generates an accessor method to allow the method call. 

> - the same works if the super class resides in the same project

Same classloader.

> - callin SuperSamePack::method succeeds from a method in the body of Sub, but
> not from an inner class.

An inner class is not a subclass of the outer class and thus does not have protected access to methods from other packages.

> 
> Since this only happens in the plug-in environment, I assume the problem stems
> from some access checks done by OSGi. Apparently it has to do with the package
> split over two plug-ins.
> 

Actually just an issue with using more than one classloader. The java compiler is not aware that the super class will be loaded by a different classloader than the sub class and assumes that an accessor is not necessary.
Comment 4 Thomas Watson CLA 2006-08-10 18:00:27 EDT
There is nothing the Framework can do to help here.  Well maybe some kind of AspectJ byte code weaving could help to add the accessor method at runtime ... kinda complicated.

It may be possible for JDT to be more aware of OSGi and detect that the accessor is needed at compile time but I'm sure the JDT team would object to such a change.  You may want to try opening a bug against JDT if you really want this fixed.

Comment 5 Tom Hofmann CLA 2006-08-14 04:30:02 EDT
A simpler but equivalent case:

- Have a package visible class 'PackageVisible' in plug-in A
- In the same package in plug-in B, reference that class 
  -> compiles fine
- run it
  ->
java.lang.IllegalAccessError: tried to access class org.example.b.PackageVisible from class org.example.b.Application

Adding Philippe - can you comment on this from a compiler point-of-view? To me it seems really unfortunate to have code that compiles fine but fails with an error at run-time.
Comment 6 Thomas Watson CLA 2006-08-14 08:48:38 EDT
Keep in mind that this is the danger of split packages.  This issue has been around in one form or another since Java moved to hierarchical classloaders.  If you add a class to your own bundle in the javax.security package and then try to access a package protected class in the javax.security package from the VM you will get the same type of illegal access error.
Comment 7 BJ Hargrave CLA 2006-08-14 08:54:48 EDT
(In reply to comment #5)

Split packages, that is a package whose contents are not part of the same bundle (and hence loaded by the same classloader), is a bad design point. If you are writing new code, do not create a design with split packages.

It is understood that an exisiting package may be split across bundles but since each bundle will have its own classloader, package private visibility will be lost across the split.
Comment 8 Susan McCourt CLA 2006-09-14 17:41:46 EDT
*** Bug 157381 has been marked as a duplicate of this bug. ***
Comment 9 Susan McCourt CLA 2006-09-14 17:47:59 EDT
I would like to reiterate Tom's comment #5.
>To me
>it seems really unfortunate to have code that compiles fine but fails with an
>error at run-time.

It was very time consuming for me that the compiler does not detect this case.  I had two very similar codepaths, one working, and one not.  The reason for the failing case turned out to be the split packages, which did not occur to me.  

The fact that the compiler flagged neither, and that only one codepath failed, was very confusing.
Comment 10 Philipe Mulet CLA 2006-09-15 03:57:26 EDT
Sorry for late answering (I did miss it until now).

Basically, until this behavior is documented in the JLS, the compiler cannot really change the lookup semantics to match this particular need. It comes from the differences between compile-time classpath and runtime classpath. 

One thing we could (maybe) do once we have fine grain access rules (currently only  on a per type basis, but you could imagine on a per method/field basis in the future), PDE could tag the offending protected methods with certain access rules, and thus the compiler would get informed these methods are special.

But strictly speaking, the compiler has currently no way to know that the compile time classpath doesn't match the runtime one.
Comment 11 Thomas Watson CLA 2006-09-15 09:13:29 EDT
The issue here is a bit more subtle than a difference in the classpath at development time vs runtime.

Here the classpaths are calculated correctly at development time and runtime, but at runtime two classes from the same package are loaded by two different class loaders (a result of splitting a package).  At runtime this prohibits package access between to two classes because you are only allowed package access if you are in the same named package AND you are loaded with the same class loader.

If you add inner classes that uses a compiler generated accessor to access protected fields in the outer class then you run into more issues that can be difficult to understand.

I'm no compiler expert, but it seems like this would require the compiler to be aware of component boundaries and apply the same package access rules at compile time that the OSGi framework does at runtime.  Phillipe, is that something you think can be done with compiler access rules?  Maybe we can have an access rule that is applied to packages exported by a project that states when another project accesses it they do not have package access?
Comment 12 Thomas Watson CLA 2006-09-15 09:23:18 EDT
Keep in mind fragments actually do need package level access to their host bundles.  They are loaded with the same classloader, so we would have to have different rules for fragments.
Comment 13 BJ Hargrave CLA 2006-09-15 10:21:41 EDT
I think the compiler assumes that all classes are loaded by the same classloader. If the compiler was aware that classes would be loaded by different classloaders at runtime, then it could make better decisions regarding the generated synthetic accessor methods.
Comment 14 Philipe Mulet CLA 2006-09-18 05:19:55 EDT
Right, this is what I was trying to simplify by saying difference between compile-time and runtime CP. I hope that these subtleties could be depicted either by access rules, or by notions of component; though the latter is a bit weaker, since it really comes from classloader semantics, and this could affect a larger set of problems than components.
Comment 15 Srikanth Sankaran CLA 2012-01-11 02:46:38 EST
*** Bug 364485 has been marked as a duplicate of this bug. ***