blue-sky
blue-sky

Reputation: 53806

Run piece of code contained in a String

I have a piece of Java code in a String.

String javaCode = "if(polishScreenHeight >= 200 && " +
    "polishScreenHeight <= 235 && polishScreenWidth >= 220) { }";

Is it possible to convert this Java String to a Java statement and run it? Possibly using Java reflection?

Upvotes: 57

Views: 67456

Answers (10)

rjahn
rjahn

Reputation: 468

You could try SimpleJavaSource class of JVx framework. There's a test case in the project repository which contains something like this.

SimpleJavaSource js = new SimpleJavaSource();

js.executeScript("import java.lang.String;" +
        "strT = new String(\"true\");" +
        "strF = new String(\"false\");" +
        "System.out.println(1 == 1 ? strT : strF);" +
        "System.out.println(1 == 2 ? strT : strF);" +
        "if (1 == 2)" +
        "{" +
        "  System.out.println(\"equal\");" +
        "}" +
        "else" +
        "{" +
        "  System.out.println(\"different\");" +
        "}" +
        "if (1 == 1)" +
        "{" +
        "  System.out.println(\"equal\");" +
        "}" +
        "else" +
        "{" +
        "  System.out.println(\"different\");" +
        "}" +
        "i = 0;" +
        "while (i < 10)" +
        "{" +
        "  System.out.println(\"i=\" + i);" +
        "  i++;" +
        "}" +
        "i = 0;" +
        "do" +
        "{" +
        "  System.out.println(\"i=\" + i);" +
        "  i++;" +
        "}" +
        "while (i < 10);" +
        "for (int i = 0, size = 10; i < size; i++)" +
        "{" +
        "  System.out.println(\"i=\" + i);" +
        "}" +
        "System.out.println(\"END\");"
        );

Upvotes: 0

Peru
Peru

Reputation: 1887

  1. Please reevaluate your design and this should be your last alternative.
  2. You should validate the sanity of the String which will be executed to avoid future injection attack.

Now If you can have the String as JavaScript then below code should help,

public class EvalScript {

        public static void main(String[] args) throws Exception {
            // create a script engine manager
            ScriptEngineManager factory = new ScriptEngineManager();
            // create a JavaScript engine
            ScriptEngine engine = factory.getEngineByName("JavaScript");

            // below JS function is executed.
            /*
             * student object value will be provided by the program as the JSON String.
            function checkStudentElgibility(student){
              if(student.age >= 10 && student.currentGrade >= 5){
                return true;
              }
            }
            // student object value will be provided by the program as the JSON String

            checkStudentElgibility(student);
            */

            String studentJsonString = "{\n" + 
                    "  \"age\" : 10,\n" + 
                    "  \"currentGrade\" : 5\n" + 
                    "}";
            String javaScriptFunctionString = "function checkStudentElgibility(student){\n" + 
                    "  if(student.age >= 10 && student.currentGrade >= 5){\n" + 
                    "    return true;\n" + 
                    "  }\n" + 
                    "}\n" + 
                    "checkStudentElgibility(student);";

            StringBuilder javaScriptString = new StringBuilder();
            javaScriptString.append("student=");
                javaScriptString.append(studentJsonString);
            javaScriptString.append("\n");
            javaScriptString.append(javaScriptFunctionString);

           Object object = engine.eval(javaScriptString.toString());

           System.out.println(object);

           // You can also pass the object as follows,

           // evaluate JavaScript code that defines an object with one method
            engine.eval("var obj = new Object()");
            engine.eval("obj.hello = function(name) { print('Hello, ' + name) 
              }");

           // expose object defined in the script to the Java application
             Object obj = engine.get("obj");

         // create an Invocable object by casting the script engine object
            Invocable inv = (Invocable) engine;

      // invoke the method named "hello" on the object defined in the
     // in js Object with "Script Method" as parameter 

               inv.invokeMethod(obj, "hello", "Script Method!");





    // You can also use Java Objects as Java script object and you can also pass Objects as reference inside Java script function


                            String jsString = "    var obj = new Object()\n" + 
                        "    var ArrayList = Java.type(\"java.util.ArrayList\");\n" +
                        "    var customSizeArrayList = new ArrayList(16);\n" + 
                        "    obj.hello = function(name) { \n" + 
                        "       customSizeArrayList(name);  \n" + 
                        "       print('Hello, ' + name) \n" + 
                        "    }";
            }


}

Reference : https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/prog_guide/javascript.html#A1147187

Upvotes: 1

Lasitha Lakmal
Lasitha Lakmal

Reputation: 880

you can use this code to run method from using this code new Statement(Object target, String methodName, Object[] arguments).execute();

import java.beans.Statement;

public class HelloWorld {

  public void method_name(String name) {
      System.out.println(name);
  }

  public static void main(String[] args) throws Exception {
      HelloWorld h = new HelloWorld();
      new Statement(h, "method_name", new Object[]{"Hello world"}).execute();
  }
 }

Upvotes: 1

Joel
Joel

Reputation: 30146

As has already been suggested you can compile, save and run code on the fly using the Compiler API.

Another neat alternative would be to use beanshell. Beanshell is no longer actively developed, but I can vouch for it's reliability, I've used it successfully in multiple production projects.

Upvotes: 25

Jonas_Hess
Jonas_Hess

Reputation: 2018

It is not Java, but as pgras has already suggested you could use GrooyScript like so :

    Binding binding = new Binding();
    GroovyShell shell = new GroovyShell(binding);

    String[] strings = new String[]{"World", "Groovy"};
    shell.setVariable("args", strings);

    String script = "return \"Hello \" + args[1]";
    String value = (String) shell.evaluate(script);
    System.out.println(value); // Hello Groovy

Upvotes: -1

pgras
pgras

Reputation: 12770

Another way would be to execute your code as Groovy code, see this for an example.

Upvotes: 1

Andreas Dolk
Andreas Dolk

Reputation: 114767

Beanshell (as Boris suggested) is a way to "execute" java source code. But it looks like, you want to "execute" fragments that can interact with the compiled classes. Your example contains variabe names.

Reflection will definitly not help, because reflection targets classes ("classfiles").

You could try to define a complete class ("valid java source file"), compile it and load it (url classloader). Then you should be able to use the methods from that "live generated class". But once a class is loaded, you can't get rid of it (unload), so this will work only once (AFAIK).

Upvotes: 2

Mike
Mike

Reputation: 19697

Try the JavaCompiler API.

Someone else answered this way better than I could, though: Convert String to Code

Be careful before actually using something like this...

Upvotes: 0

Boris Pavlović
Boris Pavlović

Reputation: 64632

Use BeanShell. There's a page on how to use it from Java.

Upvotes: 10

Steve McLeod
Steve McLeod

Reputation: 52448

As far as I know there is no simple way to do this.

However, in Java 6 onwards, you can compile source code for complete classes using javax.tools.Compiler. The compiled classes can then be loaded and executed. But I don't think this will achieve what you want.

Upvotes: 1

Related Questions