Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java compiler fails to recognise static inner class

This is quite a complicated error, so please bear with me.

I am seeing a weird error when trying to compile some Java code. The compiler fails to recognise a static inner class. Let us say that I am working on a class MyClass. The static inner class which I need to use has an FQN of x.y.z.Parent.DesiredClass. This inner class is explicitly imported using its FQN. The parent is also imported using its FQN. Now there exists another package with (another, different FQN) which has a class DesiredClass. This other DesiredClass is on the classpath, but it is not being explicitly imported.

Before I continue I should make it clear that it is not possible to change the names of these classes.

Now when I reference Parent.DesiredClass in my code, I use the FQN of Parent.DesiredClass to avoid any possible ambiguity. But when I compile I get an error when I try to instantiate Parent.DesiredClass. My code snippet:

x.y.z.Parent.DesiredClass dc;
dc = new x.y.z.Parent.DesiredClass();

This produces the following compile time error:

MyClass.java:123: an enclosing instance that contains x.y.z.Parent.DesiredClass is required
   dc = new x.y.z.Parent.DesiredClass();
           ^

It is important to note that the classes being linked to were compiled with different Java compilers:

  • MyClass is intended to be compiled with Sun Java 1.4.2_18
  • x.y.z.Parent.DesiredClass and the other DesiredClass were compiled using Microsoft Java.

Again, unfortunately, these classes cannot be recompiled with more modern versions of Java.

Additionally, when actually trying to compile with Sun Java 1.4.2_18, the following exception occurs within the compiler:

An exception has occurred in the compiler (1.4.2_18). Please file a bug at the Java Developer Connection (http://java.sun.com/cgi-bin/bugreport.cgi)  after checking the Bug Parade for duplicates. Include your program and the following diagnostic in your report.  Thank you.
java.lang.NullPointerException
        at com.sun.tools.javac.v8.code.Type.isSubTypes(Type.java:557)
        at com.sun.tools.javac.v8.comp.Resolve.instantiate(Resolve.java:221)
        at com.sun.tools.javac.v8.comp.Resolve.selectBest(Resolve.java:317)
        at com.sun.tools.javac.v8.comp.Resolve.findMethod(Resolve.java:414)
        ...
        at com.sun.tools.javac.v8.comp.Attr.attribClass(Attr.java:1332)
        at com.sun.tools.javac.v8.JavaCompiler.compile(JavaCompiler.java:355)
        at com.sun.tools.javac.v8.Main.compile(Main.java:569)
        at com.sun.tools.javac.Main.compile(Main.java:36)
        at com.sun.tools.javac.Main.main(Main.java:27)
Error encountered running Java Compiler

Aborting compilation.

If I compile with a newer version of Java (1.5 onwards), then the compiler exception does not occur, but the abovementioned error still occurs.

Can anyone please explain this error? Why does the compiler not recognise the static inner class as static, even if it is referred to using its FQN?

Your help will be greatly appreciated.

==========

EDIT: The rabbit hole deepens. After further investigation I found that the problem is triggered by a single line of code in one of the libraries which I need to have in my path. I have access to the source code of this library, but do not compile it as part of my project. The line of code (let's say it's in class TheirClass) does exactly what I am trying to do; i.e., instantiating x.y.z.DesiredClass. If I remove this line of code in TheirClass (but not in MyClass), then I do not get the compile error.

So, in summary, the following does not work:

MyClass.java:

x.y.z.Parent.DesiredClass dc;
dc = new x.y.z.Parent.DesiredClass();

TheirClass.java:

x.y.z.Parent.DesiredClass dc;
dc = new x.y.z.Parent.DesiredClass();

The following does work:

MyClass.java:

x.y.z.Parent.DesiredClass dc;
dc = new x.y.z.Parent.DesiredClass();

TheirClass.java:

//x.y.z.Parent.DesiredClass dc;
//dc = new x.y.z.Parent.DesiredClass();

I am going to try and follow @Richard's advice and minimise the code so that I can post a sample of it.

like image 846
phantom-99w Avatar asked Jun 25 '13 15:06

phantom-99w


2 Answers

The error message "an enclosing instance that contains x.y.z.Parent.DesiredClass is required" means that the compiler thinks that DesiredClass is NOT static.

I suggest that you get hold of the Parent$DesiredClass.class file, and use javap to examine the compiled classes attributes. That should tell you if the class you are compiling against is really a static inner class.

like image 192
Stephen C Avatar answered Oct 27 '22 11:10

Stephen C


While still busy doing the low level investigations suggested by @Richard and @Stephen, I had a couple of ideas about this issue.

I first tried to extend DesiredClass with one which has a less ambiguous name and then see if it would work if I rather use the extended class. It did not and caused the same error.

I then tried to instantiate DesiredClass using Class.forName():

DesiredClass dc;
try {
    dc = (DesiredClass) Class.forName(classname).newInstance();
}
catch (Exception e) {

}

This worked!

Even though this is a bit messy, it allows me to continue with my work. I would love to know what the root cause of the error is (perhaps some problem with the class loader which the compiler uses, especially considering that there are classes which have been compiled with different "brands" of compilers?), but the cost-benefit of spending more time trying to figure this out is not worth it.

Thank you to everyone who contributed.

like image 23
phantom-99w Avatar answered Oct 27 '22 11:10

phantom-99w