11

Similar to dynamic SQL, wherein a String is executed as an SQL at runtime, can we have Java code run dynamically? Like I return a String which is a Java code and then I execute at runtime. Is this possible?

skaffman
  • 398,947
  • 96
  • 818
  • 769
Sid
  • 4,893
  • 14
  • 55
  • 110

6 Answers6

16

For real Java code, this is possible using the JavaCompiler interface. However, it's very inconvenient to use since it's just an interface to a real Java compiler that expects to compile entire class definitions found in files.

The easiest way to execute code supplied at runtime would be to use the Rhino JavaScript engine.

Both of these options have been only in Java 6, though I believe the scripting interface existed before, so you could use Rhino in an earlier JRE if you download and add it to the classpath.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
  • +1 on this, I've added Javascript interpreting to a few apps, it's fairly painless and very powerful. – Sam Barnum Nov 12 '10 at 16:11
  • 1
    The Rhino JavaScript engine can't execute Java code at runtime. – Anderson Green May 07 '13 at 21:57
  • @AndersonGreen: you actually can import Java classes and use them as JavaScript objects, but I wrote that mainly for cases where the focus is on being able to easily run code dynamically, not that it must be Java code. – Michael Borgwardt May 07 '13 at 22:57
6

Javassist

You would need to use a bytecode manipulation library such as Javassist (Wikipedia), in order to run an arbitrary string that is provided at runtime. Javassist allows you to create a CtClass based on a string representing source code; and can then turn this into compiled Class object via a particular classloader, so that the class is then available to your application. Other libraries would need to do something similar to these two steps in order to achieve the same thing.

So it is possible, but it's very heavyweight and is likely to make your application very hard to reason about. If at all possible, consider designing a very flexible class statically, and having it accept parameters that control its behaviour.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
Andrzej Doyle
  • 102,507
  • 33
  • 189
  • 228
  • 3
    +1 -- for a comprehensive list of possible libraries: http://java-source.net/open-source/bytecode-libraries – Kirk Woll Nov 12 '10 at 15:43
4

If you want to do more than invoke an existing method dynamically, you may need to compile your String into bytecode. An easy way to do this is to include the Eclipse/JDT compiler jar in your classpath, and then you can use that to compile your String into a Class, which can then be loaded.

This type of dynamic code generation and execution is used to convert JSP files into Servlets and is used in other packages such as JasperReports to turn a report specification into a Class that is then invoked.

Remember that just as with SQL you must be careful to prevent code injection security problems if any of the String contains user-specified data.

jbindel
  • 5,535
  • 2
  • 25
  • 38
  • 1
    Good point to mention the "injection" problems, though I dare say this entire architecture is injection by definition - you're *trying* to execute this arbitrary code, so I would hope it goes without saying that the source should be trusted implicitly. – Andrzej Doyle Nov 12 '10 at 15:50
  • A nice thing with Java is that you can run the injected code with limited privileges, too. – jbindel Dec 02 '10 at 15:47
4

You also may want to look at Java 6 scripting support: http://download.oracle.com/javase/6/docs/technotes/guides/scripting/programmer_guide/index.htm

Here is a version of hello world that creates array of strings and prints a first one:


import javax.script.*;
public class EvalScript { 
    public static void main(String[] args) throws Exception {
        ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
        engine.eval("var a=java.lang.reflect.Array.newInstance(java.lang.String, 1);a[0]='Hello World';print(a[0])");
    }
}
Yuriy
  • 151
  • 1
3

Have a look at Beanshell. It provides an interpreter with java like syntax.

Anderson Green
  • 30,230
  • 67
  • 195
  • 328
ordnungswidrig
  • 3,140
  • 1
  • 18
  • 29
3

Yes it is possible. Look at the Java Compiler API. Have a look here:

http://download.oracle.com/javase/6/docs/api/javax/tools/JavaCompiler.html

Travis Webb
  • 14,688
  • 7
  • 55
  • 109