UCL's are siblings and have the NoAnnotationClassLoader as a parent classloader.
The point to think here is how does the classloaded by one of the UCL's is made VISIBLE to the classes loaded in another UCL?
How the class which is loaded by UCL1 is made visible to the UCL2 when UCL1 and UCL2 are siblings, does this not break the VISIBILITY principle of the classloader and result in the ClassCastException?
I assume that the readers must have understanding of the Delegation, Uniqueness and Visibility principle of classloading. Please refer here to get the insights about these principles
Let us discuss this in detail .
Considering the scenario
1) Classloader1 loading test.classloader.A
2) Classloader2 loading test.classloader.B
A is having the reference of the class B .Please look at the source codes .
Couple of more classes which will be used here are
1) Cache this will store the loaded class as the key,value pair in the Map .
2) MyCLWithCache will load the class first from the cache and if it does not get then it loads from the URL .
Let us do this now
1) Create ClassLoader Classloader1 to load test.classloader.A
2) Create ClassLoader Classloader2 to load test.classloader.B
So we have
So we have Classloader1 and Classloader2 as the siblings .....
Let us move ahead now
I am going to load A using Classloader1 and B with Classloader2 which means in terms Of VISIBILITY principle that
B will be visible to the Classloader1 and its Children's not to the SIBLINGS .
Similarly Classloader2 will load A and classloading VISIBILITY principle will let Classloader2 and its Child to view this class .
Using reflection I will make setB invocation of the class A
which will result in the ClassCastException as we are trying to cast the classloaded by sibling's which voilates the VISIBILITY principle .
Shouldn't this appear in the UCL's too ? Let us dig more now .
Now if I use the Cached Version of the ClassLoader ie MyCLWithCache it would work , this is how the classes get shared in UCL's although UCL's are siblings .
So when we are casting the classes the loading classloader should be same , it means
Class A = (A) obj ;
which can eventually be interpreted as
class<A,Ci>Cd = class<obj,Ci1>Cd1
This will work only if the Cd and Cd1 points to the same classloader . These are the defining Classloader , these classloaders actually should be same . Please note here that the initiating classloaders are different , Ci is not same as Ci1 .
For more details about the Initiating/Defining Classloader please refer the famous paper
So the Cache class is storing the class which is loaded by various classloader.
This is how the UCL's too work , they have the ULR as the Cache to store the classes .
So you don't get the ClassCastException when using the classes loaded across the UCL's since the defining classloaders are same for the loading classes .
Please run the ClassLoaderDemo2 and ClassLoaderDemo2 to have more insights .
Look at the Jboss ClassLoader usecases here