Search code examples
javaclassloader

Can't Find the Dynamic loaded Class


I am trying to load the Class using Class.forName() but it gives me Exceptionjava.lang.ClassNotFoundException: Test.

actually Test is created in the eclipse working directory here is the image but it created outside the bin folder. If i try to run using command prompt it working properly.

below the code:

public class CompileString {

public static void main(String arges[]) throws Exception{

    JavaCompiler compiler=ToolProvider.getSystemJavaCompiler();
     String program = " class Test{" + "   public static void main (String [] args){"
                + "      System.out.println (\"Hello, World\");"
                + "      System.out.println (args.length);" + "   }" + "}"
                +"interface demo{}"         
                ;

     Iterable<? extends JavaFileObject> fileObjects;
        fileObjects = getJavaSourceFromString(program);

        Boolean result=compiler.getTask(null, null, null, null, null, fileObjects).call();
        System.out.println(result);


        Class<?> clazz=null;
        try {
            clazz = Class.forName("Test");
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
              System.out.println(clazz);
            e.printStackTrace();

        }
        Method m = clazz.getMethod("main", new Class[] { String[].class });
        Object[] _args = new Object[] { new String[0] };
        m.invoke(null, _args);
      }

      static Iterable<JavaSourceFromString> getJavaSourceFromString(String code) {
        final JavaSourceFromString jsfs;
        jsfs = new JavaSourceFromString("demo", code);
        return new Iterable<JavaSourceFromString>() {
          public Iterator<JavaSourceFromString> iterator() {
            return new Iterator<JavaSourceFromString>() {
              boolean isNext = true;

              public boolean hasNext() {
                return isNext;
              }

              public JavaSourceFromString next() {
                if (!isNext)
                  throw new NoSuchElementException();
                isNext = false;
                return jsfs;
              }

              public void remove() {
                throw new UnsupportedOperationException();
              }
            };
          }
        };
      } 

}

Another Class:

class JavaSourceFromString extends SimpleJavaFileObject {
  final String code;

  JavaSourceFromString(String name, String code) {
    super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
    this.code = code;
  }

  public CharSequence getCharContent(boolean ignoreEncodingErrors) {
    return code;
  }
}

it gives me Run time Exception

java.lang.ClassNotFoundException: Test

Everything working correctly compiler JavaCompiler compiler=ToolProvider.getSystemJavaCompiler() gives true but why i am not able to find the Test.class.


Solution

  • Why this code is not working

    Eclipse generates class files in a different directory to the one where the program runs, whereas when you run it from the command line you are using the same value.

    How to fix

    The easiest way to fix this would be to use a URLClassLoader to load the classes, so you can specify the directory to use to find the class files.

    Example code (Uses List.of from Java 9)

    import java.io.File;
    import java.io.IOException;
    import java.lang.reflect.*;
    import java.net.MalformedURLException;
    import java.net.URI;
    import java.net.URLClassLoader;
    import java.util.*;
    import java.util.logging.Logger;
    import javax.tools.*;
    
    public final class CompileString {
    
        static class JavaSourceFromString extends SimpleJavaFileObject {
            private final String code;
    
            JavaSourceFromString(final String name, final String code) {
                super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
                this.code = code;
            }
    
            @Override
            public CharSequence getCharContent(final boolean ignoreEncodingErrors) {
                return code;
            }
        }
    
        private CompileString() {}
    
        private static final Logger LOG = Logger.getLogger(CompileString.class.getCanonicalName());
    
        private static final JavaCompiler COMPILER = ToolProvider.getSystemJavaCompiler();
        public static void main(final String...args) {
    
            final String program =
                "public class Test{" +
                "   public static void main (String [] args) {" +
                "      System.out.println (\"Hello, World\");" +
                "      System.out.println (args.length);" +
                "   }" +
                "}";
    
            final List <JavaSourceFromString> fileObjects = List.of(new JavaSourceFromString("Test", program));
    
            final boolean result = COMPILER.getTask(null, null, null, null, null, fileObjects).call();
            LOG.info("Compilation result was: " + result);
    
            final URL url;
            try {
                url = new File("./").toURI().toURL();
            } catch (final MalformedURLException ex) {
                throw new AssertionError("Bad URL? (Really shouldn't happen)", ex);
            }
    
            try (URLClassLoader loader = new URLClassLoader(new URL[] {url})) {
                final Class<?> clazz = loader.loadClass("Test");
                final Method main = clazz.getMethod("main", String[].class);
                final Object[] invocationArguments = {new String[] {}};
                main.invoke(null, invocationArguments);
            } catch (final ClassNotFoundException ex) {
                throw new AssertionError("Bad class name", ex);
            } catch (final IOException ex) {
                throw new AssertionError("IO Error", ex);
            } catch (final NoSuchMethodException ex) {
                throw new AssertionError("Missing main method", ex);
            } catch (final IllegalAccessException ex) {
                throw new AssertionError("Class or main method not public", ex);
            } catch (final InvocationTargetException ex) {
                throw new AssertionError("Exception thrown by main method", ex);
            }
        }
    
    }