ClassLoader does not load inner class

Viewed 207

ClassLoader clMain -> URLClassLoader clA (class A, $B). $B is a inner class B of the class A.

  1. From clMain creating new clA with specified url to the jar file which contains class A (and class $B). Then creating new object A via clA.
  2. Another class, loaded from X ClassLoader, execute a method of the object A via interface without problems.
  3. Then, in that method, should be created new object $B, but it throws the NoClassDefFoundError.
  4. Loading the class $B in the constructor of the class A is solving the problem: this.getClass().getClassLoader().loadClass("A$B");

So, the cuestion is: "Why the definition of the class $B cannot be found for step 3 and Can be solved this porblem in another way?"

Checking the ClassLoader used in the method (this.getClass().getClassLoader()) and comparing it with the ClassLoader used in the constructor - is the same and contains the necessary url. Java 8 and 14 tried to run, jdk 8 to build.

Edit:

public class A {
 public A(){
  this.getClass().getClassLoader().loadClass("A$B"); // success
 }
 public void foo(){
  this.getClass().getClassLoader().loadClass("A$B"); // success
  new B(); // success
 }
 public static final class B {}
}
public class A {
 public A(){
 }
 public void foo(){
  this.getClass().getClassLoader().loadClass("A$B"); // throw
  new B(); // Edit: added this line to demostrate what is not the main diff between two examples
 }
 public static final class B {}
}

Edit: this behavior is not related specifically to inner class, but to every class located in the jar. In simple words, i need to iterate every class located in the jar and load them manually before they are used, or else jvm will throw the NoClassDefFoundError.

1 Answers

NoClassDefFoundError invariably means the $inner class file (in this specific case) itself could not be found. packaging or copying problem or a url referencing problem (? JNDI naming problem) but whatever, the file was not located where stated. (sometimes the filename is a typo somewhere and the location to it is correct).

unfortunately two points, 1 the sub class is static , so an extremely weird choice to invoke using reflect, 2 You simply cause a statement that does not get used or assigned (weirder) re

this.getClass().getClassLoader().loadClass("A$B"); // throw

although it may only be required inside its enclosing class to be known as "B"

e.g.

B subcab = (Class<B>).....

Your problem seems very alike "nested inner class shadowing" Its a long time back but i think that's as possible as A.B inside its enclosing class.

I would see more sense in attempting with reflect something like either... ?

A.B subcab = (Class<A.B>)((this.getClass()).getClassLoader().loadClass("A$B")); // A should have , its package name if any, also - see "binary name"

One more vague note from years back, i think when you load using classloader you require to do that inside a check

Class<?> aclss = this.getClass();
if( (Class<?>.isAssignableFrom(aclss)) && (Class<?>.isInstance(aclss)) ){
//... load here
}
Related