jeudi 4 avril 2019

NoSuchMethodException when attempting to instantiate a dynamically loaded class with a constructor that includes a custom class

I am attempting to instantiate a dynamically loaded class (with a custom class loader) with a constructor that contains both a String object and a custom class I have created.

I have re-created the issue outside of my project, this is assuming that A.class is already in the target folder.

Main method:

public class simplifiedMainMethod {

static boolean propagate = false;
static Class<?> projectActions = null;
static Object oInstance;

public static void main (String[] args)
{
    String projectName = "A";
    String baseUrl = "https://www.google.com/";
    simplifiedReport reporter = new simplifiedReport();

    try 
    {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        Reloader r = new Reloader(cl);

        if (propagate) 
            Thread.currentThread().setContextClassLoader(r);

        projectActions = r.loadClass("autobots_framework."+projectName);
        Constructor<?> c = projectActions.getConstructor(String.class, simplifiedReport.class);

        oInstance = c.newInstance(baseUrl, reporter);
    }
    catch (Exception e) {
        e.printStackTrace();
    }
}
}

simplifiedReport.java:

public class simplifiedReport 
{
   public simplifiedReport()
   {

   }
   public void testMethod()
   {
            System.out.println("Hello World");
   }
}

A.java:

public class A
{
        public A(String testString, simplifiedReport testReport) 
            { 
                   System.out.println(testString);
                   testReport.testMethod();
            }
}

Here is the CustomClassLoader I am using:

public class ClassLoaderCompiler
{
    public ClassLoaderCompiler()
{}

public static boolean compileCode(String fileDirectory, String projectName) throws IOException
{   
    JavaCompiler compiler = new EclipseCompiler();
    DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
    StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
    Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromStrings(Arrays.asList(fileDirectory));
    JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, null, null, compilationUnits);
    try
    {
        task.call();
        fileManager.close();
        return true;
    }
    catch(Exception e)
    {
        fileManager.close();
        return false;
    }
}

public static void moveClassFile(String projectName)
{
    try
    {
        Files.deleteIfExists(new File(System.getProperty("user.dir")+"/target/classes/autobots_framework/"+projectName+".class").toPath());
        Files.deleteIfExists(new File(System.getProperty("user.dir")+"/target/classes/autobots_framework/L_"+projectName+".class").toPath());

        if (Files.exists(Paths.get(System.getProperty("user.dir")+"/projects/"+projectName+"/"+projectName+".class")))
        {
            Path temp = Files.move (Paths.get(System.getProperty("user.dir")+"/projects/"+projectName+"/"+projectName+".class"),Paths.get(System.getProperty("user.dir")+"/target/classes/autobots_framework/"+projectName+".class")); 
            Path tempLocator = Files.move (Paths.get(System.getProperty("user.dir")+"/projects/"+projectName+"/L_"+projectName+".class"),Paths.get(System.getProperty("user.dir")+"/target/classes/autobots_framework/L_"+projectName+".class"));
        }
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
}

}

/**
 * adapted from http://stackoverflow.com/a/3971771/7849
 */
class Reloader extends ClassLoader {

static URL url;
ClassLoader orig;

Reloader(ClassLoader orig) {
    this.orig = orig;
}

@Override
public Class<?> loadClass(String s) {
    return findClass(s);
}

@Override
public Class<?> findClass(String s) {
    try {
        byte[] bytes = loadClassData(s);
        return defineClass(s, bytes, 0, bytes.length);
    } catch (IOException ioe) {
        try {
            return super.loadClass(s);
        } catch (ClassNotFoundException ignore) {
            ignore.printStackTrace(System.out);
        }
        ioe.printStackTrace(System.out);
        return null;
    }
}

private byte[] loadClassData(String className) throws IOException {
    try {
        /*
         * get the actual path using the original classloader 
         */
        Class<?> clazz = orig.loadClass(className);
        url = clazz.getResource(clazz.getSimpleName() + ".class");

        /*
         * force reload
         */
        File f = new File(url.toURI());
        int size = (int) f.length();
        byte buff[] = new byte[size];
        FileInputStream fis = new FileInputStream(f);
        DataInputStream dis = new DataInputStream(fis);
        dis.readFully(buff);
        dis.close();
        return buff;
    } catch (Exception ex) {
        throw new IOException(ex);
    }
}
}

I am getting this error as a result:

java.lang.NoSuchMethodException: autobots_framework.A.<init>(java.lang.String, autobots_framework.simplifiedReport)
at java.lang.Class.getConstructor0(Unknown Source)
at java.lang.Class.getConstructor(Unknown Source)

I figured this was due to the parameters not matching, so to confirm I tried finding what the constructor is implicitly looking for:

for (Constructor c : projectActions.getDeclaredConstructors())
{
      System.out.print(c.toGenericString());
}

Yielding this result:

 public autobots_framework.A(java.lang.String,autobots_framework.simplifiedReport)

Which is frustratingly looking alot like what I have put here:

Constructor<?> c = projectActions.getConstructor(String.class, simplifiedReport.class);
oInstance = c.newInstance(baseUrl, reporter);

I understand that this has something to do with my class, as when I leave out simplifiedReport in the constructor and only instantiate it with String.class, I am successful. What modifier am I missing in my class to make this work?

This is all a function of my application to dynamically compile code and then instantiate them to run custom code and methods.

Thanks a lot in advance.





Aucun commentaire:

Enregistrer un commentaire