Bug 185422 - [1.5][compiler] Incorrectly allows generic use of private inner classes
Summary: [1.5][compiler] Incorrectly allows generic use of private inner classes
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.2.2   Edit
Hardware: Macintosh Mac OS X - Carbon (unsup.)
: P3 normal (vote)
Target Milestone: 3.5 RC1   Edit
Assignee: Kent Johnson CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 237656 254703 273751 (view as bug list)
Depends on:
Blocks:
 
Reported: 2007-05-03 14:50 EDT by Bryan Barkley CLA
Modified: 2010-06-10 09:02 EDT (History)
8 users (show)

See Also:
Olivier_Thomann: review+


Attachments
Proposed patch and testcases (5.48 KB, patch)
2009-05-05 13:07 EDT, Kent Johnson CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Bryan Barkley CLA 2007-05-03 14:50:02 EDT
Build ID: M20070212-1330

Steps To Reproduce:
Given the following classes:

public class Foo <T>{
    private T myT;

    public T getT() {
        return myT;
    }
    
    public void setT(T aT) {
        myT = aT;
    }
}


public class Bar extends Foo<Bar.Baz> {
    public static void main(String[] args) {
        Bar myBar = new Bar();
        myBar.setT(new Baz());
        System.out.println(myBar.getT().toString());
    }
    
    private static class Baz {
        @Override
        public String toString() {
            return "Baz";
        }
    }    
}

Eclipse compiles and runs the code even though the Baz inner class is private.

javac reports:
Bar.java:1: Bar.Baz has private access in Bar
public class Bar extends Foo<Bar.Baz>
                                ^
1 error


The problem occurs in 3.2 as well as 3.3m6.
Comment 1 Olivier Thomann CLA 2007-05-03 15:12:01 EDT
We consider the access ok since we are in Bar.
If you move it to a third compilation unit, then we report an error.
Comment 2 Bryan Barkley CLA 2007-05-03 16:14:29 EDT
That pretty much makes sense to me, especially because in my actual code T is bounded by a public interface, which I'd think should be legal.

So is this a bug in javac, or just a different interpretation of the language spec?
Comment 3 Philipe Mulet CLA 2007-05-04 03:58:41 EDT
This feels a bug in javac.
Note that the following code compiles fine (note reference to Bar.Baz) moved to be a field type instead of a bound.

I suspect they improperly set the resolution context for a type variable bound to consider itself outside the current compilation unit, and hence miss the fact private access is allowed. You should report this to them.

class Foo <T>{
    private T myT;

    public T getT() {
        return myT;
    }

    public void setT(T aT) {
        myT = aT;
    }
}


class Bar extends Foo<Object> {
    Bar.Baz baz;
    public static void main(String[] args) {
        Bar myBar = new Bar();
        myBar.setT(new Baz());
        System.out.println(myBar.getT().toString());
    }

    private static class Baz {
        @Override
        public String toString() {
            return "Baz";
        }
    }    
}
Comment 4 Philipe Mulet CLA 2007-05-04 04:00:46 EDT
Closing as invalid, since working as designed.
Added GenericTypeTest#test1135.
Comment 5 Nikolay Metchev CLA 2007-11-30 12:53:36 EST
Did anybody report this to sun? If so do you have a bug number?
Comment 6 Philipe Mulet CLA 2008-06-19 07:44:33 EDT
ECJ and Javac may differ on their interpretation of the eligible context for access to private member. Javac would narrow the scope to the body of the type declaration, hence any access in extends/implements clauses, or leading annotations would be forbidden.

e.g. 
@interface Ann {
	Class value();
}

@Ann(X.Inner.class)
public class X {
    private interface Inner{}
}
Comment 7 Philipe Mulet CLA 2008-06-19 07:46:12 EDT
*** Bug 237656 has been marked as a duplicate of this bug. ***
Comment 8 Philipe Mulet CLA 2008-06-19 07:47:00 EDT
Reopening to clarify the scope for private access.
Comment 9 Philipe Mulet CLA 2008-06-19 07:47:39 EDT
Extra example:

/**
 * @see X.Inner
 */
public class X {
    private interface Inner{}
}

javadoc complains too.
Comment 10 Rémi Forax CLA 2008-06-19 10:42:06 EDT
Hi philippe,
I cut&paste my answer to openjdk compiler-dev here:
 
-------------------------------------------------------------------------
In section 6.6.1, the  next to last bullet  says:
"if the member or constructor is declared |private|, then access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor"

If body means body like in the grammar;

/NormalClassDeclaration:
/|     class|/ Identifier [/TypeParameters]/ [/|extends|/ Type] [/|implements|/ TypeList] ClassBody/


Annotations or extends/implements types are not in the body so javac is correct. 
Comment 11 Philipe Mulet CLA 2008-06-19 11:13:22 EDT
Yes, I was looking at the spec, and was coming to a similar conclusion. Thanks also Maurizio for pointing me at it.

"...if the member or constructor is declared |private|, then access is 
permitted if and only if it occurs within the body of the top level 
class (§7.6) 
<http://java.sun.com/docs/books/jls/third_edition/html/packages.html#26783> 
that encloses the declaration of the member or constructor."

This is why I reopened this issue.

Now it feels strange that the scope is only for a class body, and not entire class definition... dura lex sed lex.
Comment 12 Philipe Mulet CLA 2008-07-01 07:13:54 EDT
Added GenericTypeTest#test1357-1358
Added LookupTest#test087
Comment 13 Philipe Mulet CLA 2008-11-10 06:25:30 EST
*** Bug 254703 has been marked as a duplicate of this bug. ***
Comment 14 Philipe Mulet CLA 2009-02-09 05:18:32 EST
Srikanth - pls have a look
Comment 15 Kent Johnson CLA 2009-05-04 16:17:24 EDT
Same as bug 273751
Comment 16 Kent Johnson CLA 2009-05-05 13:06:35 EDT
*** Bug 273751 has been marked as a duplicate of this bug. ***
Comment 17 Kent Johnson CLA 2009-05-05 13:07:49 EDT
Created attachment 134470 [details]
Proposed patch and testcases
Comment 18 Kent Johnson CLA 2009-05-05 13:09:28 EDT
Olivier - please review for RC1
Comment 19 Olivier Thomann CLA 2009-05-05 20:06:22 EDT
+1
Comment 20 Olivier Thomann CLA 2009-05-06 17:25:32 EDT
Released for 3.5RC1.
Comment 21 Olivier Thomann CLA 2009-05-14 12:20:27 EDT
Verified for 3.5RC1 using I20090511-2000.
Comment 22 Christian Gossart CLA 2010-06-10 08:51:24 EDT
Hi people,

Maybe I missed something, but this is not fixed in 3.5.2.

I can reproduce the result from Bug 86291 which is marked as a duplicate of this bug (JDT allows the access of a private field outside the class body, whereas javac don't).
My personal test case was a JPA @NamedQuery annotation with the "query" attribute referencing a private static field:

@NamedQuery(name = Client.QUERY_NAME, query = Client.QUERY)
public class Client {

    public static final String QUERY_NAME = "client.query.name";
    private static final String QUERY = "from Client";
}

Both fields are visible according to JDT, but QUERY is not according to javac 1.6.0_20 (same case as Bug 254703 btw).

Environment: Windows XP, Eclipse Galileo SR2 (Build 20100218-1602 with JDT 3.5.2), Sun jdk1.6.0_20
Comment 23 Olivier Thomann CLA 2010-06-10 09:02:58 EDT
I opened bug 316456 to track this down.