scravy.net / blog

A REPL for Java

Out of curiosity I tried to build a Read-Eval-Print-Loop in Java (let's you execute type you enter immediately). It's perfectly doable!

Get it

You can get the sources or a pre-compiled JAR-Archive. The latter can simply be started like so:

$ java -jar REPL.jar

If you want to compile it yourself, do the following:

$ javac REPL.java
$ java REPL

Use it

After you fired up the REPL (it's a CLI application, no GUI) you can simply type in any command and it will be executed immediatley:

> Java Read-Eval-Print-Loop, “help” for help.
$ System.out.println("Hello World")
> Hello World

If you need a class from a package other than java.lang, you may either spell it our or import the package:

$ random = new java.util.Random()
> java.util.Random@caf0ed
$ random.nextInt()
> 1926586976

Import:

$ import java.util.*

You can see that it's possible to assign the result of an expression to a variable which is than available later on. It's worth noting that the REPL tries to figure out the type of the expression by itself, so it's not necessary to declare a type.

A list of all imports can be obtained with the imports command. Imports can be cleared using clear imports.

The most recent non-null expression is available in a variable named “_” (underscore). If you want to figure out it's type, use the following:

$ _.getClass()

A list of all declared variables is available: Use vars to show it. Use clear vars to clear the already assigned variables.

Also have a look in the examples (help examples).

How it works

It is possible to obtain the Compiler using the Java Standard Library using a ToolProvider from the package javax.tools:

ToolProvider.getSystemJavaCompiler()

The object (of type javax.tools.JavaCompiler) that you obtain by this is a direct interface to the Compiler, as if it was invoked on the command line, i.e. you can run it by invoking the run(...) method on the JavaCompiler object which will request an InputStream and OutputStream for Standard- and Error-Outputs. The invocation I use looks like so:

OutputStream compilerError = new ByteArrayOutputStream();
int exitCode = compiler.run(null, null, compilerError,
    new String[]{tmpFile.getCanonicalPath()});

...where tmpFile is the file to compile. What happens in the REPL is the following: The Command entered by the user is wrapped in a tiny class-skeleton, stored as tmpFile, is compiled than and dynamically loaded using an URLClassLoader which allows you to load class-files from arbitrary sources.

The rest is left as an exercise to the reader ;-)

Written: 2012-02-27
Updated: 2012-03-09

^