JDK-8023697 : failed class resolution reports different class name in detail message for the first and subsequent times
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: hs25,8,9
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2013-08-23
  • Updated: 2020-10-12
  • Resolved: 2014-05-06
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9 Other
8u270Fixed 9 b14Fixed openjdk8u272Fixed
Description
As shown in JDK-8023122 subsequent failed class resolution attempts have different detail messages:

$ cat ExtTest.java
class ExtTest {
    public static void main(String args[]) {
	try {
	    Property p = new Property();
	} catch (NoClassDefFoundError e) {
	    System.out.println(e);
	}
	try {
	    Property p = new Property();
	} catch (NoClassDefFoundError e) {
	    System.out.println(e);
	}
    }
}

$ java -Xint ExtTest
java.lang.NoClassDefFoundError: PropertyChild
java.lang.NoClassDefFoundError: Property

The fix would be to report the to-be resolved class in the initial exception as well:

diff -r acedd49a1bce src/share/vm/classfile/systemDictionary.cpp
--- a/src/share/vm/classfile/systemDictionary.cpp	Thu Aug 08 03:16:56 2013 +0200
+++ b/src/share/vm/classfile/systemDictionary.cpp	Fri Aug 23 16:09:04 2013 -0700
@@ -385,7 +385,7 @@ Klass* SystemDictionary::resolve_super_o
   }
   if (HAS_PENDING_EXCEPTION || superk_h() == NULL) {
     // can null superk
-    superk_h = KlassHandle(THREAD, handle_resolution_exception(class_name, class_loader, protection_domain, true, superk_h, THREAD));
+    superk_h = KlassHandle(THREAD, handle_resolution_exception(child_name, class_loader, protection_domain, true, superk_h, THREAD));
   }
 
   return superk_h();

Comments
Fix Request (8u) I would like to backport this to 8u for parity with Oracle 8u271. Original patch does not apply cleanly. Code review thread: https://mail.openjdk.java.net/pipermail/jdk8u-dev/2020-July/012201.html (reviewed)
21-07-2020

Caching the detail message is not a complicated change at all, and since for linkage errors in systemDictionary the detail message is the name of the class, in all cases but this one (where it's the name of the super class), the message is the same. If we change the system dictionary messages to something other than the class name (with more info maybe), I think that message would be better to get out of the resolution error table (rather than just the class name). My change also caches the message for MethodHandles and MethodTypes, which are not just the name if the method or signature of the type, but default to this if null.
29-04-2014

Thanks for understanding. Just to clarify - the name of the class that is not found is part of the text of the error message, it is not the error itself. Different errors have different relevant text. I don't think we want to cache the error messages for each type of LinkageError we can have (you should see the complexity of some of the VerifyError messages) - I think at this point the best I can think of is to have the error have an indirection that suggests the customer go look for an earlier error message for details.
18-04-2014

Anything than the current situation is better. In fact thinking about this again it would be better to report in both cases the class that is not found; that is PropertyChild in the above case. For future readers: PropertyChild is the super class of Property (not a good name, I know).
17-04-2014

The specification says, and Alex agrees that the vm does need to return the same error, but not the same error message, stack trace, cause, etc. I do not recommend the suggested "fix" - I believe that in general the first time this error is thrown, that we want the customer to know which class is not found, so that if a child class exists and the parent class does not, the exception message that the parent class does not exist will give them the better clue of what to look for. What if, instead of the change above, we were to modify the code that uses the stored resolution error, e.g. oops/constantPool.cpp to change the error message there to be "from previous resolution of <classname>" ? The test would still need to be fixed, since the message would still be different, but perhaps it would be a clue to the customer to look for a previous error message?
17-04-2014