Code Monkey home page Code Monkey logo

inmemoryjavacompiler's Introduction

Update 09/22/2017: I've been silent for long time (I'm into Golang lately hence putting Java aside) despite the fact that there are lots of interests to make this mini tool better. I'll kick off my effort to improve this tool from now on by reviewing outstanding issues and PRs

InMemoryJavaCompiler Build Status codecov FOSSA Status

Samples with utility classes to compile java source code in memory

After taking huge effort to look for example on the internet and found nothing work. I decided to create a very simple version.

Note: Please make sure you use JDK in your runtime

E.g.:

StringBuilder sourceCode = new StringBuilder();
sourceCode.append("package org.mdkt;\n");
sourceCode.append("public class HelloClass {\n");
sourceCode.append("   public String hello() { return \"hello\"; }");
sourceCode.append("}");

Class<?> helloClass = InMemoryJavaCompiler.newInstance().compile("org.mdkt.HelloClass", sourceCode.toString());

If you are looking for more examples, please look at unit tests in the src/test/java folder

Artifact is pushed to Sonatype OSS Releases Repository

https://oss.sonatype.org/content/repositories/releases/

Maven dependency:

<dependency>
    <groupId>org.mdkt.compiler</groupId>
    <artifactId>InMemoryJavaCompiler</artifactId>
    <version>1.3.0</version>
</dependency>

License

FOSSA Status

inmemoryjavacompiler's People

Contributors

fossabot avatar pkeidel avatar trung avatar turpid-monkey avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

inmemoryjavacompiler's Issues

Unclear README

The README for this project does not explain how to properly take advantage of this project. It looks great, but I'm not sure where to start. It looks like there is a working example included, but I don't see how to use it.

Do you have any example code you could put on the README to show users how to utilize the InMemoryJavaCompiler class?

Run compiled class in separate Java process

Hi @trung,

I'm using your library to compile code that's coming from a web interface. After compilation I'm running the compiled class to evaluate the output.

If a user inputs something like System.exit(0);, the server will crash. I tried to prevent this by running the compiled class in a separate process like this:

public static int exec(Class clazz) throws IOException,
            InterruptedException {
        String javaHome = System.getProperty("java.home");
        String javaBin = javaHome +
                File.separator + "bin" +
                File.separator + "java";
        String classpath = System.getProperty("java.class.path");
        String className = clazz.getCanonicalName();

        ProcessBuilder builder = new ProcessBuilder(
                javaBin, "-cp", classpath, className);

        Process process = builder.start();
        process.waitFor();
        return process.exitValue();
    }

The problem with this is that I'm getting a "Class not found" error everytime I try to run the compiled class like this.

Is it possible to run the compiled class in a separate process using another way?

Nested Class/Enum definitions fail

Running the following:

sourceCode.append("package org.mdkt;\n");
sourceCode.append("public class HelloClass {\n");
sourceCode.append("   public static class Nested {}\n");
sourceCode.append("}");

System.out.println(sourceCode.toString());
Class<?> helloClass = InMemoryJavaCompiler.compile("org.mdkt.HelloClass",
        sourceCode.toString());`

Results in:

java.lang.NoClassDefFoundError: org/mdkt/HelloClass (wrong name: org/mdkt/HelloClass$Nested)
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
    at org.mdkt.compiler.DynamicClassLoader.findClass(DynamicClassLoader.java:28)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at org.mdkt.compiler.InMemoryJavaCompiler.compile(InMemoryJavaCompiler.java:22)
    at uk.co.ensoft.xrm2m.codegenerator.SchemaClassGeneratorTest.testGenerateClass1(SchemaClassGeneratorTest.java:79)

Can I use this in Android?

I've a scenario where I want to create a class in runtime then use it. I tried using the code provided here but it just light up like Christmas tree. Some of the packages don't work in the Android.
Here is a list of them

  1. import javax.tools.Diagnostic;
  2. import javax.tools.DiagnosticCollector;
  3. import javax.tools.JavaCompiler;
  4. import javax.tools.JavaFileObject;
  5. import javax.tools.ToolProvider;
  6. import javax.tools.SimpleJavaFileObject;
  7. import javax.tools.FileObject;
  8. import javax.tools.ForwardingJavaFileManager;
  9. import javax.tools.JavaFileManager;

Is there is anyway where I can overcome them or use something else that exist in Android to do the same thing?

P.S
I understand that javax doesn't exist in Android. I'm just wandering if there exist something equivalent to it.

Dependency of other jars or classes

Execuse me, how can I depend on other jars and classes when using javacompiler? They are all included in my current process. Can I get the classpath variable in an elegant way?

Compile dynamic code for java web application

I had a problem with compiling code when using a java web application, as this link shows.

I would like to ask you to add a method where the user can pass the classloader and options to the java compiler task, that way the user can set your classpath and libraries.

Thank you!

Unable to compile the source on Ubuntu x64

Error executing script!
org.mdkt.compiler.CompilationException: Unable to compile the source

How I can fix it on my Ubuntu x64?
I've two versions of jdk 1.8 and 1.11, and switch it by update-alternatives --config java

Publish Snapshot

Can you publish the 1.3.0 Snapshot.

I would also recommend going to 2.0.0-SNAPSHOT with the changes that are in master.

ClassLoader failed to find class with its qualified name after compiled successfully

Problem

I try to compile the source code of a project.

All java files under the src/main/java directory is stored in to InMemoryJavaCompiler#addSource(String className, String sourceCode). And the className is qualified name, e.g. org.mdkt.compiler.CompiledCode, because there may be classes with the same simple name, e.g. CompiledCode, but in different package.

However, when I called InMemoryJavaCompiler#compileAll(), the classLoader failed to find the compiled class because the it stored it with simple name but search with the qualified name.

public Map<String, Class<?>> compileAll() throws Exception {
            ...

            Map<String, Class<?>> classes = new HashMap();
            Iterator var15 = this.sourceCodes.keySet().iterator(); //the key is qualified name

            while(var15.hasNext()) {
                String className = (String)var15.next();
                //the name stored in classLoader is simple name, therefore, it cannot find the class
                classes.put(className, this.classLoader.findClass(className)); 
            }

            return classes;
        }

ScreenShots

Screenshot 2019-05-03 at 6 41 36 PM

Related issue

#17

NullPointerException on any use

Hey, I'm getting a NullPointerException whenever I try to use the compiler. I tried it with your example:

StringBuffer sourceCode = new StringBuffer();
sourceCode.append("package org.mdkt;\n");
sourceCode.append("public class HelloClass {\n");
sourceCode.append("   public String hello() { return \"hello\"; }");
sourceCode.append("}");

try{
        Class<?> helloClass = InMemoryJavaCompiler.compile("org.mdkt.HelloClass", sourceCode.toString()); // <--- Line 16
    }catch(Exception e){
        e.printStackTrace();
    }

And it doesn't work. The exception:

java.lang.NullPointerException
    at org.mdkt.compiler.InMemoryJavaCompiler.compile(InMemoryJavaCompiler.java:19)
    at me.nonamesldev.javacompilerexample.JavaCompilerExample.main(JavaCompilerExample.java:16)

I tried it with different source codes, all don't work.

Facing NoClassDefFoundError despite jar being in classpath (dynamic compilation)

In a tomcat server, at run time, I am reading java class files and compiling them dynamically using InMemoryJavaCompiler.
Code Sample -

InMemoryJavaCompiler.newInstance()
                       .useOptions("-parameters", 
                          "-classpath", sb.toString(),  
                          "-Xlint:unchecked")
                       .compile(sourceCodeClassName,
                          sourceCode.toString());

Here sb (Stringbuilder) indicates the jars read from WEB-INF/lib directory separated by a colon.
The code works in the following scenarios :
1. If the above compilation code is kept in a standalone class file & the relevant libraries are set in the classpath, the compilation from a bash script was successful.
2. I printed the jar files i.e. I printed sb value separately & took a copy of it. I manually ran javac -classpath <sourceCode.java> in the terminal. The compilation was successful.

The code is not working in the following scenarios :

a. When the above code snippet is added as a stand alone program in IDE(Eclipse), I faced NoClassDefFound error for the interface which the sourceCode was implementing.

b. In Tomcat, the relevant jar is present in contextName/WEB-INF/lib/ and in addition to that the jar is added in -useOptions classpath. Even then, I am facing NoClassDefFound error for the the interface the sourceCode was implementing.

Note : There are no duplicate copies of the jar or multiple versions of the jar present in the lib directory or the classpath value.

NullPointerException

    ExtendedStandardJavaFileManager fileManager = new ExtendedStandardJavaFileManager(javac.getStandardFileManager(null, null, null), compiledCode, cl);

line given null pointer exception

citation to InMemoryJavaCompiler

Dear Trung,
I produced a software where I used your InMemoryJavaCompiler. I intend to publish it in a scientific journal. I would like to and I should refer to your product. Could you please inform me of the correct citation way? Thank you for your response in advance! Kind regards,
Beata Szabo-Takacs

cannot find newInstance() symbol

I try to compile my NC_writer class with
Class<?> Netcdf_writer = InMemoryJavaCompiler.newInstance().compile("meteoread.NC_writer", sourceCode.toString());

but it is not possible because newInstance() symbol cannot be found. I can use just
Class<?> Netcdf_writer = InMemoryJavaCompiler.compile("meteoread.NC_writer", sourceCode.toString());

It works in NetBeans IDE but after I built the program and I run the .jar file I get NulPointerException error. How should I fix this problem? I use InMemoryJavaCompiler-1.2

Intercepting the error stream

Hello!
This is more a question, but is it possible to intercept the compile errors and get them in a stream or string?
I am making myself an app that uses this compiler and I want it to be able to show compile errors.
Thanks in advance.

className/Class<?> pairings not necessarily same as className/sourceCode

Calling addSource("A", "class B {}"); addSource("B", "class A {}"); compileAll(); returns a Map of "A" to the class A and "B" to the class B. This is unexpected, and means that compileAll().get(className) won't necessarily return the class compiled from the source code for className.

This could cause problems if, for example, client code ensures that the source code for "A" declares a class with some property, and then expects compileAll().get("A") to return a class with that property.

A suggested fix is for the compileAll() method to check that the source code associated with each class name does declare a class of that name, and throw a CompilationException otherwise. This mirrors the behaviour of javac which requires a file named A.java to declare a class named A.

compiler does not find the NetcdfFileWriter identifiers

I would like to convert String variables to java code to build a NetCDF file from strings. I have some Strings which contain the commands to write a netCDF. For example:

String Variable contains the following strings:
'Variable time; '
'time = ncfile.addVariable(null, "time", DataType.Double, "time");'

String DataA contains:
'ArrayDouble.D1 timeData = new ArrayDouble.D1(countLinesResult); '
'Index ima = timeData.getIndex();'

String DataD contains:
'timeData.setDouble(ima.set(timeIdx),ValueD.get(timeIdx)); '

String DataNC contains:
'ncfile.write(time, timeData); '

each string is public static String. These strings are in NetCDF_writer Class static void getDataNc method. Here is the code:

package meteoread;

/**
 *
 * @author Beata
 */
;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;
import static meteoread.DownLoad_Meteo.Detected;
import static meteoread.DownLoad_Meteo.ETime;
import static meteoread.DownLoad_Meteo.STime;
import static meteoread.DownLoad_Meteo.Values;
import static meteoread.DownLoad_Meteo.Values2;
import static meteoread.DownLoad_Meteo.id1;
import static meteoread.DownLoad_Meteo.id2;
import static meteoread.DownLoad_Meteo.listString;
import static meteoread.DownLoad_Meteo.res;
import static meteoread.SelectData.result;
import org.mdkt.compiler.InMemoryJavaCompiler;

import ucar.nc2.*;

import ucar.ma2.*;

public class NetCDF_writer {
    private static String okW ="";
    private static int is;
    private static int il;
    private static int di;
    private static int countLinesResult;
    public static String TableNC  = DownLoad_Meteo.Table;
    private static ArrayList<String> s = new ArrayList<String>();
    private static ArrayList<String> s2 = new ArrayList<String>();
   private static ArrayList<String> s3 = new ArrayList<String>();
   private static ArrayList<String> s4 = new ArrayList<String>();
   private static ArrayList<String> s5 = new ArrayList<String>();
   private String[] colName;
    private static ArrayList<String> ValueS = new ArrayList<String>();
    private static ArrayList<Integer> ValueI = new ArrayList<Integer>();
    private static ArrayList<Double> ValueD = new ArrayList<Double>();
    public static String Variables;
    public static String DataA;
    public static String DataD;
    public static String DataNC;

   
 

    static void getDataNc(int id1, int id2, String listString, String location, String Stimenc, String ETimenc)throws Exception {
    
    
        try{
          Connection con = MeteoRead.getConnection();
         PreparedStatement statement= con.prepareStatement("SELECT " + listString + " FROM " +TableNC + " WHERE TIME_ID BETWEEN " +"\"" + STime + "\"" +" AND " + "\"" +ETime + "\"" + " ORDER BY ID");

         ResultSet result = statement.executeQuery();
         ResultSetMetaData rsmd = result.getMetaData();
         

            is = id1;   
      
            il = id2;
            
            di = il-is;
              
            if(is == 1){
             countLinesResult = il;
             }
             else{
             countLinesResult = di;}
            result.first();
            result.previous();
            
                
            ColName = listString.split(",");

            
            NetcdfFileWriter ncfile = NetcdfFileWriter.createNew(NetcdfFileWriter.Version.netcdf4, location, null);
            Dimension timeDim = ncfile.addUnlimitedDimension("time");
            
                       
            s = SelectData.result.get(1);
            s2 = SelectData.result.get(2);
            s3 = SelectData.result.get(3);
            s4 = SelectData.result.get(4);
            s5 = SelectData.result.get(5);


            Variables = "";
            DataA = "";
            DataD = "";
            DataNC = "";
             int n = 0;
          
              while(n < s.size()-1){
           
                 Variables = Variables +" " + s.get(n) + "\n";
                             
                 Variables = Variables +" " + s2.get(n) + "\n";
                 
                     while(result.next()){
                                       
                        Date date2 = dateConv1(result.getString("TIME"));
                 
                         double dateU = ToMATLABDate(date2);
                 
                         if(rsmd.getColumnName(n+1).equals("TIME")){
                     
                           ValueD.add(dateU);
                                    }
                 
                          if(rsmd.getColumnTypeName(n+1)== "VARCHAR" && !rsmd.getColumnName(n+1).equals("TIME")){
                      
                            ValueS.add(result.getString(ColName[n]));
                            }
                    
                          if(rsmd.getColumnTypeName(n+1)== "INTEGER"){
                           
                            ValueI.add(result.getInt(ColName[n]));
                            }
                  
                             if(rsmd.getColumnTypeName(n+1)== "DOUBLE"){
                           
                              ValueD.add(result.getDouble(ColName[n]));
                                                                     }
                                                           }
                     
                       DataA = DataA + s3.get(n) + "\n";
                       DataD = DataD + s4.get(n) + "\n";
                       DataNC = DataNC + s5.get(n) + "\n";
                 
                 
                n++; }
                
           
           
                          
               StringBuffer sourceCode = new StringBuffer();
                sourceCode.append("package meteoread;\n");
                sourceCode.append("public class NetCDF_writer {\n");
                sourceCode.append("   static void getDataNc(int id1, int id2, String listString, String location, String Stimenc, String ETimenc)throws Exception {" +Variables +" ncfile.create();" + "\n" + DataA +" for (int timeIdx = 0; timeIdx < countLinesResult; timeIdx ++){" + DataD + "}"+ DataNC + "}");
                sourceCode.append("}");      
                 Class<?> Netcdf_writer = InMemoryJavaCompiler.compile("meteoread.NetCDF_writer", sourceCode.toString());
                  
           okW = "NC FILE BUILD SUCCESSFULLY";
           okWindow o = new okWindow();
           o.okWindow(okW);
           o.setVisible(true);
           
            } catch(Exception e){
            e.printStackTrace();
            okW = e.toString();
            okWindow o = new okWindow();
            o.okWindow(okW);
            o.setVisible(true);}

            }
    
       
        public static Date dateConv1(String s){
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateInString = s;
        Date date = new Date();
        
   
        try {

             date = (Date)formatter.parse(dateInString);
        } catch (ParseException e) {
            e.printStackTrace();
        }
         return date;
    }
    
      /**
     * Converts a java.util.Date into a MATLAB Serial Date Number in the local timezone. MATLAB Serial Date Number are
     * doubles counting the number of days since January 0 0000. The time of day is represented in fractions of a whole
     * day.
     *
     * @param date the date to convert
     * @return the date as MATLAB Serial Date Number
     */
    public static double ToMATLABDate(Date date) {
        // Converts a java.util.Date into a MATLAB Serial Date Number taking into account timezones and DST.
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        double SerialDateNumber = (date.getTime() + cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET)) / 1000.0 / 3600.0 / 24.0 ;
        return SerialDateNumber;
    }

    
}

Unfortunately, I got several cannot find symbol error messages. The compiler does not find the NetcdfFileWriter identifiers even though I imported ucar.nc2.* and ucar.ma2.* packages. Could you please write to me how I should fix this issue?

InMemoryJavaCompiler.compile() returns reference to old class when compiling a new class with the same name

If I ask InMemoryJavaCompiler to compile a new class with the same name as an existing class, the compile() method returns a reference to the existing class.

Minimal example across two files, both in the default package, compiled and loaded on the classpath:

Example.java:

public class Example {
}

MinimalExample.java:

import org.mdkt.compiler.InMemoryJavaCompiler;

public class MinimalExample {

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

        Class<?> oldClass = Example.class;

        InMemoryJavaCompiler compiler = InMemoryJavaCompiler.newInstance();
        Class<?> newClass = compiler.compile("Example", "public class Example {\n }\n");

        if (oldClass.hashCode() == newClass.hashCode()) {
            System.out.println("I have two copies of the old class.");
        }

    }

}

Expected behaviour: the class returned by compile should be the result of compiling the string passed to it.

I think this is a bug.

Thanks very much for providing this library! I am very keen to use it in Gin :-)

NullPointerException

            `System.setProperty("java.home", "C:\\Program Files\\Java\\jdk-11.0.1");
	StringBuilder sourceCode = new StringBuilder();
	sourceCode.append("package me.Perzan.compileString;\n");
	sourceCode.append("class HelloClass {\n");
	sourceCode.append("   public static void hello() { System.out.println(\"hello\"); }");
	sourceCode.append("}");

	InMemoryJavaCompiler compiler = InMemoryJavaCompiler.newInstance();
	
	compiler.addSource("HelloClass", sourceCode.toString());
	
	
	
	Map<String, Class<?>> classMap = compiler.compileAll();
	
	Class<?> helloClass = classMap.get("HelloClass");
	Method m = helloClass.getMethod("hello");
	
	m.invoke(null);`

So at the line with 'Map<String, Class<?>> classMap = compiler.compileAll();' I get NullPointerException. I even set the property for JDK at the beginning. I'm not sure why this is happening, for my version is pretty much the same as your example...

(Also the '`' things are not part of it, I was just trying to insert the code)

Also here is the stack trace:

Exception in thread "main" java.lang.NullPointerException at org.mdkt.compiler.InMemoryJavaCompiler.compileAll(InMemoryJavaCompiler.java:80) at me.Perzan.compileString.CompileTest.main(CompileTest.java:26)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.