views:

2291

answers:

14

I want to know if there is any way to convert a String to Java compilable code.

Explanation:
I have a comparative expression saved in a database field.
I want to retrieve it from database, then evaluate it inside a conditional structure.

Is there any way to do this?

+8  A: 

You can't because java is a compiled language.

You, however, should use a javax.script api to execute code in runtime. JVM6 ships with Rhino (javascript interpreter) avaliable via javax.script.

http://java.sun.com/javase/6/docs/api/javax/script/package-summary.html

There are javax.script-compatible java interpreters (and bean shell) avaliable.

https://scripting.dev.java.net/

alamar
I think this answer is incorrect - generating Java source, compiling it, and using it absolutely can be done (JSPs are the perfect proof.) That doesn't make it a good idea or a good design decision, but it can be done.
Jared
Well, he can't do what he wants (he wants eval); he can do different thing which would do almost the same; albeit, with some costs attached.
alamar
This answer is totaly wrong. You can use some bytecode manipulation tools to create a new class and load it.an example with javassist: http://davidwinterfeldt.blogspot.com/2009/02/genearting-bytecode.html
elhoim
+5  A: 

You can by using something like BeanShell.

Kris
+1  A: 

It's not fair to say that this is impossible. It is a very similar problem to the problem Java Server Pages (JSPs) have - in their case, there is code embedded in HTML files that needs to be compiled into a servlet and executed. If you really wanted to use that mechanism, I'm relatively sure you could dig through the source for a servlet container and figure out how they did it (probably even reusing their mechanism to some degree.)

However; it isn't an easy problem to solve (once you solve the obvious, immediate problem, you end up having to deal with issues with classloading and related problems.)

It certainly would seem to be a better idea to go with the Java Scripting Platform in JDK6.

Jared
They use javac. You can, but you shouldn't. He should really use teh scripting.
alamar
JSPs are first transformed into a class that outputs HTML code using the HTML and Java code you write, that class is then compiled using javac like alamar said.
Jorn
Agreed, alamar. But it's not true to simply say that it can't be done. It can be done...it just seems like a really bad idea.
Jared
+9  A: 

If you are using Java 6, you could try the Java Compiler API. At its core is the JavaCompiler class. You should be able to construct the source code for your Comparator object in memory.

Warning: I have not actually tried the code below as the JavaCompiler object is not available on my platform, for some odd reason...

Warning: Compiling arbitrary Java code can be hazardous to your health.

Consider yourself warned...

String comparableClassName = ...; // the class name of the objects you wish to compare
String comparatorClassName = ...; // something random to avoid class name conflicts
String source = "public class " + comparatorClassName + " implements Comparable<" + comparableClassName + "> {" +
                "    public int compare(" + comparableClassName + " a, " + comparableClassName + " b) {" +
                "        return " + expression + ";" +
                "    }" +
                "}";

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

/*
 * Please refer to the JavaCompiler JavaDoc page for examples of the following objects (most of which can remain null)
 */
Writer out = null;
JavaFileManager fileManager = null;
DiagnosticListener<? super JavaFileObject> diagnosticListener = null;
Iterable<String> options = null;
Iterable<String> classes = null;
Iterable<? extends JavaFileObject> compilationUnits = new ArrayList<? extends JavaFileObject>();
compilationUnits.add(
    new SimpleJavaFileObject() {
        // See the JavaDoc page for more details on loading the source String
    }
);

compiler.getTask(out, fileManager, diagnosticListener, options, classes, compilationUnits).call();

Comparator comparator = (Comparator) Class.forName(comparableClassName).newInstance();

After this, you just have to store the appropriate Java expression in your database field, referencing a and b.

Adam Paynter
Well, do it if you want to be featured on TheDailyWTF.
alamar
Are you insinuating that Java Server Pages should be featured on TheDailyWTF? Oh...yeah...maybe they should...I hate dealing with them for a good reason :P
Jared
Well, JSPs use compiler for a reason; this example doesn't.
alamar
Yes , JSP belong on the daily wtf, exactly for the reason that jsp pages are compiled half-assed by the jsp-servlet at runtime. If you are hacking on your own site, in your garage, thats marginally cool, but the benefit is zero in real life.
KarlP
Well, you can precompile them if you feel extra anal.
alamar
+1  A: 

Apparently Java Scripting Platform is better for this situation but You can also use Java Compiler Api. It provides methods for compiling java source files from within java code. In your case you can make a temporary file containing a class with your comparative expression then you can load that file and use it. Off course this isn't very elegant. Check out http://www.juixe.com/techknow/index.php/2006/12/13/java-se-6-compiler-api/ for details on using Java Compiler Api

Babar
A: 

A simple way to get code snippets to executable byte code is with the Javassist library.

You can possibly adapt the techniques described in http://www.ibm.com/developerworks/java/library/j-dyn0610/ to fit your needs.

Thorbjørn Ravn Andersen
A: 

If you're getting the condition from a database, I'll wager there's a good chance that you might be wanting to use that condition to access data in that database.

If you're using an ORM such as JPA or Hibernate (traditional or JPA), you might be able to formulate a dynamic query expression that you'd pass to the createQuery() method. This isn't as good as being able to do an on-the-fly compile of arbitrary Java code, but maybe it's all you need, and that particular solution doesn't require any special inclusions or actions, since the query language compiler is part of the ORM system itself.

Of course, if you DO do dynamic queries that way, I'd recommend logging them somehow, since it can be a real pain to figure out what went wrong after the fact if your query string is now in the garbage collector.

Tim H
+1  A: 

Groovy might also be an option for you.

It integrates cleanly with the Bean Scripting Framework, can be embedded directly quite easily and might be ok, syntax-wise, for you.

Huxi
A: 

You shouldn't. Really!

Are you inventing another enterprise rules engine?. You might want to read these links.

Consider the fact that the only people that is skilled enough to write code and then insert it into a database, probably are having an editor and a compiler anyway...

The compiler will catch all those pesky syntax errors and you can even test the code! Remember that editors and compilers, and even computer languages were invented to help the programmer to comfortably write comprehensible code with a reasonable effort.

While I'm at it: read about the complicators gloves too!

KarlP
A: 

If all you really need to do is evaluate an expression stored in a database, you might want to look at JEP (Java Expression Parser)

The latest (commercial) version is here.

A slightly older, GPL version is here

Some examples for usage.

Cameron Pope
A: 

If you're willing to sacrifice the "Java code" portion of your requirement, you could use the Java Mathematic Expression Evaluator library. It allows you to specify a math expression (as a java.lang.String), add values for the variables, and then evaluate the expression.

I've used it in production code with great success.

Jared
+4  A: 

Use Groovy!

Binding binding = new Binding();
GroovyShell shell = new GroovyShell(binding);
Object value = shell.evaluate("for (x=0; x<5; x++){println "Hello"}; return x");
A: 

Yes it is possible in many ways.

As some have mentioned above, Java 6 allows you to parse, manipulate and rewrite code as it is loaded!

The solution can vary:

You could for example, write your DB expression as a Java class and insert your serialized class into the DB as a glob or blob or whatever its called.

Or, you could use a template to write a Java class to a file and insert your expression into it. Then compile the class at run-time (like a JSP to Servlet) and then dynamically load the class.

Of course you'd want to cache your compiled classes for future use if they have not been edited in the database.

Then there is also the option of using an integrated scripting engine such as most of the responses have mentioned.

Whatever you choose, maybe you'll be able to update this post with details of your choice, implementation, problems, notes, comments, etc.

Jeach
+1  A: 

use BeanShell: link text key class is bsh.Interpreter. Simple example:

Interpreter interpreter = new Interpreter();
Object res = interpreter.eval("your expresion");

it is possible even define whole class instead of expression.

vitali_y