1

Many Websites allow a user to type in Java code and run it. How does a program accept Java written externally/at run time and run it?

The only/closest answer i see on StackOverflow is from 5 years ago about Android development that recommended using Janino (Compile and execute arbitrary Java string in Android). Is this still the way to go? Has a better approach (like something built into Java) appeared in the last half decade?

If it helps, I'm building a training app for my students. The code is short (a few methods, maybe 20 lines max) and they must use standard libraries (no need to worry about importing things from maven, etc.).

Like similar online coding sites, I'd like to return the output of the run (or compilation failure).

An example use case:

  1. Webpage says "The code below has an error, try to fix it." A text box contains code. A semicolon is missing.
  2. User modifies the code and presses submit.
  3. The Webpage either returns a compile error message or success.

Another use case would be for me to execute unit tests on the code they submitted and return the result. The point being, I give the user feedback on the code compilation/run.

baylor
  • 99
  • 1
  • 8
  • 1
    You could just write a script to call `javac` or is this not suitable for your use case? – Jannik Oct 29 '19 at 16:09
  • 2
    There are multiple ways it could be done, including the obvious, just use `javac` and `java` to compile and run. But the JDK also has (since like Java 6?) a compiler interface. – Dave Newton Oct 29 '19 at 16:09
  • Make sure you properly set up your security. – MC Emperor Oct 29 '19 at 16:22

1 Answers1

0

Here is a small example to use the Java compiler interface

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;

public class Compiler {

    public static void main(String[] args) throws Exception {
        // compile the java file
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        int result = compiler.run(null, null, null, "D:\\development\\snippets\\Test.java");
        System.out.println("compiler result " + result);

        // load the new class
        File classesDir = new File("D:\\development\\snippets\\");
        URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { classesDir.toURI().toURL() });
        Class<?> cls = Class.forName("Test", true, classLoader);

        // invoke a method of the class via reflection
        Object instance =  cls.getDeclaredConstructors()[0].newInstance();
        Method testMethod = cls.getMethod("test");
        String testMethodResult = (String) testMethod.invoke(instance);
        System.out.println(testMethodResult);
    }
}

And here the test class

public class Test {
    public String test() {
        return "String from test.";
    }
}

Running the Compiler class returns

compiler result 0
String from test.
Jannik
  • 1,583
  • 1
  • 14
  • 22
  • This code works as written (a stand alone project). It doesn't work in my Springboot project. Is there a trick i'm missing? Error: `Request processing failed; nested exception is org.mdkt.compiler.CompilationException: Unable to compile the source [kind=WARNING, line=2, message=Can't initialize javac processor due to (most likely) a class loader problem: java.lang.NoClassDefFoundError: com/sun/tools/javac/processing/JavacProcessingEnvironment` – baylor Nov 05 '19 at 16:50
  • Is the application running in the same environment or with some different JRE? I could imagine that this class is not available if only a standalone JRE without compiler is installed. But to be fair, I am not so familiar with Springboot, so I can't really tell. – Jannik Nov 05 '19 at 22:16