13

For debug reasons, I want to be able to run code that is typed in through the console. For example:

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while(true){
    String str = br.readLine(); //This can return 'a = 5;','b = "Text";' or 'pckg.example.MyClass.run(5);'
    if(str == null)
        return;
    runCode(str); //How would I do this?
}
PureGero
  • 937
  • 2
  • 8
  • 16
  • 7
    the real question is: **why** would you like to do this... – Dariusz Jul 12 '13 at 06:04
  • 1
    Let us assume for a split second this is possible... but just think how would Java compile your runtime code ? – AurA Jul 12 '13 at 06:04
  • 2
    What you need is maybe a [Java interpreter](http://stackoverflow.com/questions/3504396/java-interpreter). – LaurentG Jul 12 '13 at 06:05
  • +1 An interactive java console? I kind of like that idea. – Alex Gittemeier Jul 12 '13 at 06:05
  • @Dariusz the OP has explained why in the question. "For Debug". There are other methods, not all other methods will work in every context you can get java to work. – Philip Couling Jul 12 '13 at 06:05
  • In linux there's something called a "Bean Shell" which allows you to run code using the console. http://www.beanshell.org/ Maybe this could be of some assistance to you? – JREN Jul 12 '13 at 06:11
  • 1
    @couling it shouldn't be *why?*, it shoyld be *why oh why would someone do something like that ever?* Please, this seems like an atrocity. – Dariusz Jul 12 '13 at 06:16
  • If you succeed, you might then find this helpful http://docs.oracle.com/javase/tutorial/reflect/ – gpalex Jul 12 '13 at 06:17
  • @Dariusz Not really. If your testing code on an embedded device you sometimes need to tweak the values at runtime without re-compiling and then spending 10 minutes pressing the buttons on the device to get back to where you were. There's plenty of examples where this is useful as long as it's not left in the production code and is strictly "for debug reasons". – Philip Couling Jul 12 '13 at 06:18
  • @Dariusz The alternative is that you spend weeks and weeks developing an API which exposes every layer of your code just for debug. It's a complete waste of time. – Philip Couling Jul 12 '13 at 06:20
  • @couling it's Java, just use Eclipse debugger and change whatever you wish whenever you wish to whatever you want! – Dariusz Jul 12 '13 at 06:31
  • @couling: Alternatively, one could use one of the [many](http://logback.qos.ch/) [available](http://logging.apache.org/log4j/1.2/manual.html) [logging](http://logging.apache.org/log4j/2.x/) [libraries](http://docs.oracle.com/javase/6/docs/technotes/guides/logging/) instead, and provide meaningful debug-level log statements, instead of jury-rigging something like this into the working application, which just ***screams*** security hole. – Makoto Jul 12 '13 at 06:46
  • You essentially want what the Lisp world knows as the REPL loop. java does not have that, unfortunately. So, the question is what you want to be able to, because people have found a way to do most things anyway. – Thorbjørn Ravn Andersen Jul 12 '13 at 07:17
  • Better duplicate candidate: http://stackoverflow.com/questions/2946338/how-do-i-programmatically-compile-and-instantiate-a-java-class – Zhanger Jul 12 '13 at 07:34

5 Answers5

6

PLEASE DON'T ACTUALLY USE THIS

I was under the assumption you wanted to evaluate a string as Java code, not some scripting engine like Javascript, so I created this on a whim after reading this, using the compiler API mark mentioned. It's probably very bad practice but it (somewhat) works like you wanted it to. I doubt it'll be much use in debugging since it runs the code in the context of a new class. Sample usage is included at the bottom.

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;

public class main {
    public static void runCode(String s) throws Exception{
        JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager sjfm = jc.getStandardFileManager(null, null, null);
        File jf = new File("test.java"); //create file in current working directory
        PrintWriter pw = new PrintWriter(jf);
        pw.println("public class test {public static void main(){"+s+"}}");
        pw.close();
        Iterable fO = sjfm.getJavaFileObjects(jf);
        if(!jc.getTask(null,sjfm,null,null,null,fO).call()) { //compile the code
            throw new Exception("compilation failed");
        }
        URL[] urls = new URL[]{new File("").toURI().toURL()}; //use current working directory
        URLClassLoader ucl = new URLClassLoader(urls);
        Object o= ucl.loadClass("test").newInstance();
        o.getClass().getMethod("main").invoke(o);

    }
    public static void main(String[] args) {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        while(true){
            try {
            String str = br.readLine(); //This can return 'a = 5;','b = "Text";' or 'pckg.example.MyClass.run(5);'
            if(str == null)
                return;

            runCode(str); //How would I do this?
            } catch(Exception e) {
                e.printStackTrace();
            }
        }

    }
}
//command line
>  System.out.println("hello");
hello
>  System.out.println(3+2+3+4+5+2);
19
>  for(int i = 0; i < 10; i++) {System.out.println(i);}
0
1
2
3
4
5
6
7
8
9

With the SimpleJavaFileObject you could actually avoid using a file, as shown here, but the syntax seems a bit cumbersome so I just opted for a file in the current working directory.

EDIT: Convert String to Code offers a similar approach but it's not fully fleshed out

Community
  • 1
  • 1
Zhanger
  • 1,290
  • 14
  • 19
5

If the code is in JavaScript then you can run it with JavaScript engine:

Object res = new ScriptEngineManager().getEngineByName("js").eval(str);

JavaScript engine is part of Java SE since 1.6. See this guide http://download.java.net/jdk8/docs/technotes/guides/scripting/programmer_guide/index.html for details

Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275
  • There are also other scripting languages, like BeanShell, java subset. – Joop Eggen Jul 12 '13 at 07:15
  • If script is the option then why stray afar java? There is Scala, Groovy also JRuby and everyone seems to love JRuby performance wise. – Bnrdo Jul 12 '13 at 07:24
  • if you are on java8 I'd use nudge4j https://lorenzoongithub.github.io/nudge4j/ – Zo72 Feb 28 '17 at 13:31
3

You can use the Java scripting API which is located in the Package javax.script. There you can include several scripting languages like bsh for example.

You can find a programmer's guide on the web page of Oracle.

Rhino, which is some kind of JavaScript is already included with the Oracle JVM.

рüффп
  • 5,172
  • 34
  • 67
  • 113
Uwe Plonus
  • 9,803
  • 4
  • 41
  • 48
0

For this you may want to look into Java Compiler API. I haven't studied much as to how this works, but it allows you to load a java file, compile and load the class in an already running system. Maybe it can be repurposed into accepting input from console.

Mark M
  • 1,580
  • 10
  • 22
  • This method will mean making a file, writing class and code to it, compiling it, opening it, running the code... Doesn't seem the best way to run a line of code... – PureGero Jul 12 '13 at 06:18
0

For a general compiler you could use Janino which will allow you to compile and run Java code. The expression evaluator may help with your example.

If you are just looking to evaluate expressions while debugging then Eclispe has the Display view which allows you to execute expressions. See this question.

Community
  • 1
  • 1
Leesrus
  • 1,095
  • 2
  • 11
  • 19