testing for a class having been loaded

Peter Levart peter.levart at gmail.com
Wed Nov 30 18:23:50 UTC 2016



On 11/30/2016 07:07 PM, Alan Snyder wrote:
> Why separately packaged? The goal would be loose coupling allowing 
> smaller images. Same goal as Jigsaw…
>
> Your solution uses Class.forName(), which will load classes. Perhaps 
> it works, but doesn’t it rely on implementation specific behavior for 
> nested static classes?
>
>   Alan

You can create a top-level class if you are worried. You don't even need 
two "Loaded" classes. One "Rendezvous" class is enough. Like this:


package pkga;

public final class Rendezvous {
     private static Class<?> aClass, bClass;

     static synchronized void aLoaded(Class<?> aCl) {
         aClass = aCl;
         if (bClass != null) {
             connect();
         }
     }

     public static synchronized void bLoaded(Class<?> bCl) {
         bClass = bCl;
         if (aClass != null) {
             connect();
         }
     }

     private static void connect() {
         System.out.println("Connecting " + aClass + " with " + bClass);
     }
}


package pkga;

public class A {

     static {
         Rendezvous.aLoaded(A.class);
     }

     public static void use() {
         System.out.println("A used.");
     }
}


package pkgb;

public class B {

     static {
         try {
             Class<?> rendezvousClass = Class.forName("pkga.Rendezvous");
B.class.getModule().addReads(rendezvousClass.getModule());
             rendezvousClass.getMethod("bLoaded", 
Class.class).invoke(null, B.class);
         } catch (ReflectiveOperationException ignore) {
             // A$Rendezvous not visible
         }
     }

     public static void use() {
         System.out.println("B used.");
     }
}


Regards, Peter

>
>
>
>> On Nov 30, 2016, at 9:52 AM, Peter Levart <peter.levart at gmail.com 
>> <mailto:peter.levart at gmail.com>> wrote:
>>
>> Hi Alan,
>>
>> On 11/29/2016 10:14 PM, Alan Snyder wrote:
>>> Prior to JDK 9, it was possible (using setAccessible) to ask a 
>>> ClassLoader whether a class with a given name had been loaded 
>>> without actually forcing it to be loaded.
>>>
>>> This hack will not work in JDK9, so I am wondering if there is a way 
>>> to do this?
>>>
>>> If not, can someone explain why it would be a bad thing to be able 
>>> to do this?
>>>
>>> Here is my use case:
>>>
>>> I have two classes, A and B, that have been designed to be aware of 
>>> each other, but are packaged in separate JAR files or modules that 
>>> can be loaded independently. My goal is for these classes to make a 
>>> runtime connection with each other, but only if both have been 
>>> loaded by the application.
>>>
>>> If each class can at load (initialization) time test whether the 
>>> other has been loaded, then they can use reflection to make that 
>>> connection.
>>>
>>> All of the other solutions I have thought of require yet a third 
>>> class/interface C that is separately packaged and loaded by both A 
>>> and B. This is feasible, but seems unnecessary.
>>
>> Why separately packaged? You could do something like the following:
>>
>>
>> package pkga;
>>
>> public class ClassA {
>>
>>    public static final class Loaded {
>>        private static boolean loaded;
>>        public static boolean isLoaded() { return loaded; }
>>    }
>>
>>    static {
>>        try {
>>            Class<?> bLoadedClass = Class.forName("pkgb.ClassB$Loaded");
>> ClassA.class.getModule().addReads(bLoadedClass.getModule());
>>            java.lang.reflect.Method bLoadedMethod = 
>> bLoadedClass.getMethod("isLoaded");
>>            synchronized (ClassA.Loaded.class) {
>>                ClassA.Loaded.loaded = true;
>>                boolean bLoaded = (Boolean) bLoadedMethod.invoke(null);
>>                if (bLoaded) {
>>                    connect();
>>                }
>>            }
>>        } catch (ReflectiveOperationException ignore) {
>>            // ClassB.Loaded not visible
>>        }
>>    }
>>
>>    private static void connect() {
>>        System.out.println("Connecting from A -> B");
>>    }
>>
>>    public static void use() {
>>        System.out.println("A used.");
>>    }
>> }
>>
>>
>> package pkgb;
>>
>> public class ClassB {
>>
>>    public static final class Loaded {
>>        private static boolean loaded;
>>        public static boolean isLoaded() { return loaded; }
>>    }
>>
>>    static {
>>        try {
>>            Class<?> aLoadedClass = Class.forName("pkga.ClassA$Loaded");
>> ClassB.class.getModule().addReads(aLoadedClass.getModule());
>>            java.lang.reflect.Method aLoadedMethod = 
>> aLoadedClass.getMethod("isLoaded");
>>            synchronized (aLoadedClass) {
>>                ClassB.Loaded.loaded = true;
>>                boolean aLoaded = (Boolean) aLoadedMethod.invoke(null);
>>                if (aLoaded) {
>>                    connect();
>>                }
>>            }
>>        } catch (ReflectiveOperationException ignore) {
>>            // ClassA.Loaded not visible
>>        }
>>    }
>>
>>    private static void connect() {
>>        System.out.println("Connecting from B -> A");
>>    }
>>
>>    public static void use() {
>>        System.out.println("B used.");
>>    }
>> }
>>
>>
>>
>>
>> Regards, Peter
>



More information about the jigsaw-dev mailing list