1

We use some optional libraries. This libraries will only access if available. But the JIT produce already NoClassDefFoundError in the constructor of the class with optional access.

public Configuration {
    public boolean libraryAvailable() {
        return false; // some configuration that signal that the library is not available
    }
}


public class Foo {

   public Foo() {
       ... do some things
   }
   public void callLater() {
       ...
       if( libraryAvailable() ) {
           xyz();
       }
       ...
   }
   private void xyz() {
       new OptionalClass(); // available at compile time but not at runtime
   }
}

How can I prevent that the JIT will load all possible dependencies of my call before calling the constructor?

java.lang.NoClassDefFoundError: com/inet/OptionalClass
    at java.lang.Class.getDeclaredConstructors0(Native Method)
    at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
    at java.lang.Class.getConstructor0(Class.java:3075)
    at java.lang.Class.newInstance(Class.java:412)
    ...
 Caused by: java.lang.ClassNotFoundException: com.inet.OptionalClass
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at com.inet.plugin.DependencyClassLoader.loadClass(DependencyClassLoader.java:104)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at com.inet.plugin.DependencyClassLoader.loadClass(DependencyClassLoader.java:138)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 9 more
Horcrux7
  • 23,758
  • 21
  • 98
  • 156

3 Answers3

1

Instead of importing your optional class, use Class.forName

try {
    Class<?> act = Class.forName("com.bla.TestActivity");
    MyInterface driver = act.newInstance();
 } catch (ClassNotFoundException e) {
        e.printStackTrace();
}
Steven Spungin
  • 27,002
  • 5
  • 88
  • 78
  • Why should I do it. I already know that the class is not available at runtime. – Horcrux7 Jul 25 '18 at 16:55
  • 1
    Because if you import it, the runtime will try to load it when loading the Foo class itself, but if you get it dynamically, the runtime will not check until you attempt to use your optional feature. – Steven Spungin Jul 25 '18 at 17:36
  • If I use a Class.forName then I need to write thousand lines via reflection. This is not practicable. Also is it impossible to implement an interface of this way. I need a solution to prevent the class loading via demerge. – Horcrux7 Jul 25 '18 at 17:46
  • If OptionalClass is not available at Runtime, you are going to need a factory to provide you with an interface wrapper around your class' methods, or use reflection. You can't have a class in your import section that the compiler can't see. If your class implements an interface, you can cast it to the interface in the provided method. I updated the answer to show this. – Steven Spungin Jul 25 '18 at 18:19
  • You may be able to write a java agent that will scan your code as it loads, looking for references to classes that may or may not exist in your classpath, and modify your bytecode on load to remove those references. This seems like a non-trivial amount of work. Have you considered using Spring? I believe Spring boot decides whether to configure certain things based on whether the appropriate jars are in your classpath at runtime - so you could borrow their strategy. It probably requires interfaces, factories, and dummy implementations, when the libraries in question aren't there... – moilejter Jul 26 '18 at 08:17
0

You could write your own custom method as shown in below code to check if a class is available in classpath.

boolean result=false;
try {
 Class.forName( "your.test.class" );
result=true;
} catch( ClassNotFoundException e ) {
 //Class or Library is not available
}
return result;
K139
  • 3,654
  • 13
  • 17
  • I already now that the class does not exist. libraryAvailable is false. The missing class would never call but the JIT need it. – Horcrux7 Jul 25 '18 at 16:54
  • @Horcrux7 You mean, you want JIT to scan the full class bytecode to check if all required classes are available before creating an instance. isn't it kind of overkill to scan every class? AFAIK, JIT won't do that. – K139 Jul 25 '18 at 18:13
  • No, i want the inverse. I want that the JIT does not compile code that never will be run. – Horcrux7 Jul 25 '18 at 18:58
0

The decoupling of class loading for unused code with a separate method only work if the constructor empty. If there is a constructor then you need to move the unused code in a separate class. This can also be an anonymous class.

For example:

new Object () { { 
    new OptionalClass();
} };
Horcrux7
  • 23,758
  • 21
  • 98
  • 156