dimanche 11 mars 2018

Create subclass (defined outside of library) from within base class (defined inside of library) using fully qualified sub class name and reflection

Let's say I have an abstract base class defined in a library (library.jar):

package library;

public abstract class BaseClass {
   public BaseClass() {}

   //Takes a fully qualified class name eg. library.SubClassLibrary
   //And returns a default instance via reflection
   public BaseClass createFromFullyQualifiedName(String className) {
       Class<?> clazz = null;
       BaseClass baseClass = null;
       try {
          clazz = Class.forName(className);
          baseClass = (BaseClass) clazz.newInstance();
       }
       catch(Exception ex) {
          throw new RuntimeException(ex.getMessage());
       }

       return baseClass;
   }
}

If I add a subclass to the base class in the library...

package library;

public class SubClassLibrary extends BaseClass {
   public SubClassLibrary () {}
}

...I can use createFromFullyQualifiedName without issue:

    SubClassLibrary scl = 
      (SubClassLibrary) BaseClass.createFromFullyQualifiedName("library.SubClassLibrary"); //<-- SUCCESS!

However, if I reference the library in an application and extend the base class there...

package application;
import library.BaseClass;
public class SubClassApp extends BaseClass {
   public SubClassApp() {}
}

...attempting to create this application-defined sub class fails

SubClassApp sca = 
          (SubClassApp) BaseClass.createFromFullyQualifiedName("application.SubClassApp"); //<-- RUNTIME EXCEPTION!

This is happening, presumably, because the library doesn't have SubClassApp in its classpath and has no knowledge of it existing. I am trying to allow my users to select their BaseClass implementation (including those defined outside my library) via a mutable config file that I parse out a fully qualified class name from. I don't want my users to be forced to do reflection outside of my library -- I would prefer to acquire the BaseClass instance myself just from the fully qualified class name string without asking users to pass my library a Class<?> object. Is there a way to make my library "aware" of subclass implementations outside of the library at runtime without asking my users to do reflection themselves?

PS: I am aware that newInstance() is considered evil by some. If it helps, we can pretend I'm using getConstructor() instead. The same problem remains.

Thanks for any help!





Aucun commentaire:

Enregistrer un commentaire