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 <[email protected]
<mailto:[email protected]>> 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