Hi Peter,
thanks for your explanations. I do now understand the behaviour of case [1] ..., thanks! About case [2] you wrote * Are you sure you didn't have the toString() method overridden in InternalData at time of compilation? Yes, I am sure. I agree, this should compile. At least this compiler error message is confusing. About case [3] you wrote * invokevirtual #X // Method pkginternal/InternalData.toString:()Ljava/lang/String; * ...because the compiler notices the static type of the .toString() target is InternalData which declares the toString() method (and overrides Object::toString method). So InternalData should be accessible at runtime for this invocation to succeed and at compile time for compilation to succeed. I am a bit confused here, as you mention toString() . But in case [3] getName() is not related to toString() - at least not that I can see. InternalData.getName() overwrites Data.getName() , both returning a hard-coded String as result value. So did you mean getName() instead of toString() ? I.e. did you mean: * ...because the compiler notices the static type of the ***.getName()*** target is InternalData which declares the ***getName()*** method (and overrides ***Data::getName*** method). So InternalData should be accessible at runtime for this invocation to succeed and at compile time for compilation to succeed. If you did not mean this, I would be lost here... ;-) Finally: * Note that the following should compile though (and run too): ((Data) myDataFactory.createInternalData2()).getName() Yep, indeed. Compiles and runs. Thanks again. Cheers, Martin From: Peter Levart [mailto:peter.lev...@gmail.com] Sent: Thursday, August 25, 2016 1:42 PM To: Martin Lehmann <martin.lehm...@gmx.de>; jigsaw-dev@openjdk.java.net Subject: Re: Question on returning instances of a (not exported) derived class Hi Martin, Let me try to explain why... On 08/25/2016 08:56 AM, Martin Lehmann wrote: package pkgmain; import pkgx.*; public class Main { public static void main(String[] args) { DataFactory myDataFactory = new DataFactory(); // all OK System.out.println("Factory.createData(): " + myDataFactory.createData().getName()); System.out.println("Factory.createInternalData1().toString(): " + myDataFactory.createInternalData1().toString()); System.out.println("Factory.createInternalData1(): " + myDataFactory.createInternalData1().getName()); ...these, I hope, are understandable. You are invoking the methods upon the exported type. // [1]*does* compile though return type of // 'DataFactory.createInternalData2()' is not visible here System.out.println("Factory.createInternalData2(): " + myDataFactory.createInternalData2()); "Factory.createInternalData2(): " + myDataFactory.createInternalData2() ...is (or was, until replaced with an invokedynamic which should behave the same) equivalent to calling: new StringBuilder().append("Factory.createInternalData2(): ").append(myDataFactory.createInternalData2()).toString() ...the 2nd append is StringBuilder::append(Object) method. Compiler knows that InternalData type will not be needed to invoke that method at runtime, so it doesn't require you to have access to that type at compile time either. // [2] does not compile. error: toString() in Object is // defined in an inaccessible class or interface // surprise! why is [1] OK while adding toString() is not? System.out.println("Factory.createInternalData2().toString(): " + myDataFactory.createInternalData2().toString()); I think this is to restrictive. If the compiler succeeded in compiling this code, It would compile the toString() invocation as: invokevirtual #4 // Method java/lang/Object.toString:()Ljava/lang/String; ...which doesn't need to access InternalData type at runtime. So the compile time error should not be there IMO. Are you sure you didn't have the toString() method overridden in InternalData at time of compilation? Maybe the compiler is intentionally over restrictive here so that this type of code change (adding overriding public method to the concealed class) can not break the compilation? The error message is confusing, at least: "toString() in Object is defined in an inaccessible class or interface". How can Object be inaccessible? // [3] does not compile. error: getName() in InternalData is // defined in an inaccessible class or interface // suprise! getName() is overloaded, available in exported class Data System.out.println("Factory.createInternalData2().getName(): " + myDataFactory.createInternalData2().getName()); } } This would compile down to: invokevirtual #X // Method pkginternal/InternalData.toString:()Ljava/lang/String; ...because the compiler notices the static type of the .toString() target is InternalData which declares the toString() method (and overrides Object::toString method). So InternalData should be accessible at runtime for this invocation to succeed and at compile time for compilation to succeed. Note that the following should compile though (and run too): ((Data) myDataFactory.createInternalData2()).getName() Regards, Peter