Search code examples
java-compiler-apidynamic-class-loaders

Using Java Compiler API to compile multiple java files


Hi I have requirement to create ,compile and load java classes run time. Using FTL i am creating java source files , and able to compile the source if there is no dynamic dependency.

To elaborate with an instance, I have two java source file, one interface and its implementation class. I am able to compile the interface using java compiler api as follows

String classpath=System.getProperty("java.class.path");
        String testpath =classpath+";"+rootPath+"/lib/is_wls_client.jar;"+rootPath+"/rtds_wls_proxyclient.jar;.;";
        File javaFile =  new File(javaFileName+".java");
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        List<String> optionList = new ArrayList<String>();
        optionList.addAll(Arrays.asList("-classpath",testpath));
        StandardJavaFileManager sjfm = compiler.getStandardFileManager(null, null, null);
        Iterable fileObjects = sjfm.getJavaFileObjects(javaFile);
        JavaCompiler.CompilationTask task = compiler.getTask(null, null, null,optionList,null,fileObjects);
        task.call();
        sjfm.close();

I set class path for static classes which are already in the classpath , but this approach do not work for dynamically created classes? Any custom class loader will do the fix? My final implementation will be in web/app server

Any feedback will be highly appreciated

Satheesh


Solution

  • I was able to solve this issue by compiling all the java files together. Using FTL I generate the java classes, and then compile it using java compiler api and load classes with custom class loader

    Java Complier

    private  void compile(File[] files) throws IOException{
            String classpath=System.getProperty("java.class.path");
            String rootPath=getServletContext().getRealPath("/");
            System.out.println("--> root Path "+rootPath);
            String testpath=classpath+";.;xx.jar;yy.jar";
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            List<String> optionList = new ArrayList<String>();
            optionList.addAll(Arrays.asList("-classpath",testpath));
    //      optionList.addAll(Arrays.asList("-d",rootPath+"/target"));
            StandardJavaFileManager sjfm = compiler.getStandardFileManager(null, null, null);
            Iterable fileObjects = sjfm.getJavaFileObjects(files);
            JavaCompiler.CompilationTask task = compiler.getTask(null, null, null,optionList,null,fileObjects);
            task.call();
            sjfm.close();
    
        }
    

    Below code snippet shows how to use custom class loader

    class CustomClassLoader extends ClassLoader {
    
         public CustomClassLoader(ClassLoader parent) {
                super(parent);
         }
    
        public Class findClass(String className,String path) {
            byte[] classData = null;
            try {
                FileInputStream f = new FileInputStream(path);
                int num = f.available();
                classData = new byte[num];
    
                f.read(classData);
            } catch (IOException e) {
                System.out.println(e);
            }
            Class x = defineClass(className, classData, 0, classData.length);
            return x;
        }
    }
    

    thanks Satheesh