United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-6550655 : com.sun.tools.javac.code.Symbol$CompletionFailure

Details
Type:
Bug
Submit Date:
2007-04-26
Status:
Closed
Updated Date:
2011-05-17
Project Name:
JDK
Resolved Date:
2011-05-17
Component:
tools
OS:
windows_xp
Sub-Component:
javac
CPU:
x86
Priority:
P3
Resolution:
Fixed
Affected Versions:
6
Fixed Versions:

Related Reports
Relates:
Relates:
Relates:

Sub Tasks

Description
FULL PRODUCT VERSION :
java version "1.6.0_01"
Java(TM) SE Runtime Environment (build 1.6.0_01-b06)
Java HotSpot(TM) Client VM (build 1.6.0_01-b06, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
Compiler error when compiling a class alone that depends on another class, which has already been compiled and has a dependency on a class from persistence-api.jar

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Execute the following batch file:

cls
del *.class
rem set javac="C:\bea\jdk150_06\bin\javac"
set javac="C:\Program Files\Java\jdk1.6.0_01\bin\javac"
set jpa=C:\soft\javalib\maven2\local-repository\javax\persistence\persistence-api\1.0\persistence-api-1.0.jar
set classpath=%jpa%
%javac% AccountingContextEty.java
set classpath=.
%javac% CompletionFailureTest.java

The problem occurs as well with java5, but not one the same class:

C:\tmp\CompletionFailure>"C:\bea\jdk150_06\bin\javac" CompletionFailureTest.java
An exception has occurred in the compiler (1.5.0_06). Please file a bug at the Java Developer Connection (http://java.sun.com/webapp
com.sun.tools.javac.code.Symbol$CompletionFailure: file javax\persistence\Temporal.class not found

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
correct compilation without any warning or errors
ACTUAL -
.\AccountingContextEty.class: warning: Cannot find annotation method 'value()' in type 'javax.persistence.Temporal': class file for javax.persistence.Temporal not found
An exception has occurred in the compiler (1.6.0_01). Please file a bug at the Java Developer Connection (http://java.sun.com/webapps/bugreport)  after checking the Bug Parade for duplicates. Include your program and the following diagnostic in your report.  Thank you.
com.sun.tools.javac.code.Symbol$CompletionFailure: class file for javax.persistence.TemporalType not found


ERROR MESSAGES/STACK TRACES THAT OCCUR :
see actual results

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import javax.persistence.Table;

import java.util.Date;

import javax.persistence.Temporal;
import javax.persistence.TemporalType;

public class AccountingContextEty {
    @Temporal(TemporalType.DATE)
    private Date currentAccountingDate;
}

---------------------------------------------------------

public class CompletionFailureTest {
	AccountingContextEty ety;
}

---------- END SOURCE ----------
Here is the easily reproducible test case.
% cat genbug
#!/bin/bash

if [ "x$1" != "x" ]; then
  export JAVA_HOME=$1
fi

Ejava() {
(
  printf "public enum E {NORTH,SOUTH,EAST,WEST}\n"
) > E.java
}

Ijava() {
(
  printf "import java.lang.annotation.*;\n"
  printf "@Target(ElementType.FIELD)\n"
  printf "@Retention(RetentionPolicy.RUNTIME)\n"
  printf "    public @interface I {E value();\n"
  printf "}\n"
) > I.java
}

Cjava() {
(
  printf "public class C {\n"
  printf "    @I(E.NORTH) public String s;\n"
  printf "}\n"
) > C.java
}

Djava() {
(
  printf "public class D {C c;}\n"
) > D.java
}

rm -f *.java *.class
Ejava
Ijava
Cjava
Djava

$JAVA_HOME/bin/javac -version
$JAVA_HOME/bin/javac E.java I.java C.java
rm E.java E.class
$JAVA_HOME/bin/javac D.java

% ./genbug /usr/jdk/instances/jdk1.6.0
javac 1.6.0_07
An exception has occurred in the compiler (1.6.0_07). Please file a bug at the Java Developer Connection (http://java.sun.com/webapps/bugreport)  after checking the Bug Parade for duplicates. Include your program and the following diagnostic in your report.  Thank you.
com.sun.tools.javac.code.Symbol$CompletionFailure: class file for E not found
Reported while trying to use annotations in NetBeans development:

http://www.netbeans.org/nonav/issues/show_bug.cgi?id=152562


Simple test case, a bit different from those shown already:


package a;
public @interface A {
    E e();
    enum E {V1, V2}
}

package b;
@a.A(e=a.A.E.V1)
public @interface B {}

package c;
@b.B
public class C {}


Compile B.java against A.class, and C.java against B.class but not A.class. The compiler reports:

/tmp/test152562/b/dist/b.jar(b/B.class): warning: Cannot find annotation method 'e()' in type 'a.A': class file for a.A not found
An exception has occurred in the compiler (1.6.0_10). Please file a bug at the Java Developer Connection (http://java.sun.com/webapps/bugreport)  after checking the Bug Parade for duplicates. Include your program and the following diagnostic in your report.  Thank you.
com.sun.tools.javac.code.Symbol$CompletionFailure: class file for a.A$E not found

Clearly the compiler should not crash, but I also think it should not treat this as an error in user code. See bug #6365854 for justification:

"There doesn't seem to be any problems allowing the program to compile without the annotations. After the fix, the compiler will accept the program but issue a warning.  The rationale is that the missing annotation can cause problems when running the program."

This case seems very similar. The @A annotation in B.class cannot be resolved, but that should not prevent C.java from being compiled. The only difference here is that an enum in that annotation also cannot be resolved.
I should add that it would be better for javac to not even issue a warning in case the intermediate annotation (B in my last example) has only CLASS retention: there is no danger of the compiled class (here, C) failing to link at runtime. A warning would be appropriate in case B had RUNTIME retention.

                                    

Comments
EVALUATION

This is how we should fix this:

*) If a completion failure is thrown when entering an annotation through Annotate, a resolution diagnostic is issued - it means that some symbol could not be found.

*) If a completion failure is thrown when entering an annotation through ClassReader, a **warning** is issued. Compilation will succeed and eventually lead to ClassNotFoundError when the code is executed (only if annotation had a runtime retain policy).

This policy seems in sync with what I've been able to infer by looking at the class reader code; it seems like javac is meant to be tolerant w.r.t. problems found in annotations when reading from class files and strict when the same problems are encountered in the source file - and I can see why this policy makes sense.
                                     
2011-04-29
SUGGESTED FIX

A webrev of this fix is available at the following URL:
http://hg.openjdk.java.net/jdk7/tl/langtools/rev/dc3d9ef880a1
                                     
2011-04-29
SUGGESTED FIX

As mentioned in Description, I do not think this should be treated as a fatal error.


diff --git a/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java
--- a/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java
+++ b/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java
@@ -1377,6 +1377,7 @@
             // type.tsym.flatName() should == proxy.enumFlatName
             TypeSymbol enumTypeSym = proxy.enumType.tsym;
             VarSymbol enumerator = null;
+            try {
             for (Scope.Entry e = enumTypeSym.members().lookup(proxy.enumerator);
                  e.scope != null;
                  e = e.next()) {
@@ -1384,6 +1385,9 @@
                     enumerator = (VarSymbol)e.sym;
                     break;
                 }
+            }
+            } catch (CompletionFailure failure) {
+                return; // ignore
             }
             if (enumerator == null) {
                 log.error("unknown.enum.constant",


results in just

/tmp/test152562/b/dist/b.jar(b/B.class): warning: Cannot find annotation method 'e()' in type 'a.A': class file for a.A not found

but C.java is successfully compiled, and C.class correctly seems to contain the @B annotation. Probably some added warning is in order in case A.class could be found but A$E.class could not.

See also bug #6400041.
                                     
2008-11-24
SUGGESTED FIX

diff --git a/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java
--- a/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java
+++ b/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java
@@ -1390,17 +1390,26 @@ public class ClassReader extends ClassFi
             // type.tsym.flatName() should == proxy.enumFlatName
             TypeSymbol enumTypeSym = proxy.enumType.tsym;
             VarSymbol enumerator = null;
-            for (Scope.Entry e = enumTypeSym.members().lookup(proxy.enumerator);
-                 e.scope != null;
-                 e = e.next()) {
-                if (e.sym.kind == VAR) {
-                    enumerator = (VarSymbol)e.sym;
-                    break;
+            CompletionFailure failure = null;
+            try {
+                for (Scope.Entry e = enumTypeSym.members().lookup(proxy.enumerator);
+                        e.scope != null;
+                        e = e.next()) {
+                    if (e.sym.kind == VAR) {
+                        enumerator = (VarSymbol)e.sym;
+                        break;
+                    }
                 }
+            } catch (CompletionFailure cf) {
+                failure = cf;
             }
             if (enumerator == null) {
-                log.error("unknown.enum.constant",
-                          currentClassFile, enumTypeSym, proxy.enumerator);
+                if (failure != null) {
+                    log.error("proc.messager", failure.getMessage());
+                } else {
+                    log.error("unknown.enum.constant",
+                            currentClassFile, enumTypeSym, proxy.enumerator);                 
+                }      
                 result = new Attribute.Error(enumTypeSym.type);
             } else {
                 result = new Attribute.Enum(enumTypeSym.type, enumerator);
                                     
2008-05-22
EVALUATION

Sure enough the class is missing or atleast it is not on the classpath.
It it were not to be an Class required by annotation a similar kind of
scenario would have a created ClassNotFoundException at runtime. Needs
to dealt with from a compiler stand point and give some user friendly
diagnostics rather than the current output which is not acceptable.
                                     
2008-05-03
EVALUATION

Could reproduce the bug will look into it now.
                                     
2008-04-30
EVALUATION

Please provide a small self-contained reproducible test case.
                                     
2007-05-15



Hardware and Software, Engineered to Work Together