Interactive interpreter for Java - java

Is there a good interactive interpreter for Java, similar to Scala's? When programming, I like to try small pieces of code to see if they work like I expect before plugging them in to my main program. I would prefer an interpreter that is not based online since I often work offline.
Thanks in advance!

Since Scala runs on a JVM, why not the Scala interpreter?
That's what I do when I need to test a few Java-snippets.
It's nice to have tab completion that works.
scala> System.getPropert
getProperties getProperty
scala> System.getProperty("user.home")
res0: String = c:\Users\robert
Ok, you have to know a bit about Scala syntax when you do stuff like:
scala> val testMap = new java.util.HashMap[String, java.util.List[String]]
testMap: java.util.HashMap[String,java.util.List[String]] = {}
scala> testMap.put("planets", java.util.Arrays.asList("Mars", "Jupiter", "Pluto"
))
res0: java.util.List[String] = null
scala> testMap.get("planets")
res1: java.util.List[String] = [Mars, Jupiter, Pluto]

In the past I used beanshell. It was really light and got the job done. http://www.beanshell.org/

You can use Dr. Java. It has an interactions window that acts like an interpreter. I don't know how they developed it though, so, you better use it cautiously. E.g. if you have a class with a private method, Dr. Java's interactions will let you use this method by instance.

I used BlueJ a bit in college. It was started as a teaching tool, it's perfect for tinkering with code and the project is (was?) supported by Sun so I guess that's a feather in its cap too. It's been a while since I've used it but the nice thing I remember about it is that you can tinker with the code you write without writing a main() class. You can write a class, create an instance, call methods (it will prompt you for parameters) and so on. There's also a visual aspect to it as well, somewhat comparable to the inspector in Eclipse.
http://www.bluej.org/about/what.html

Since Java 9 the JDK comes with it's own REPL, the jshell.
If the java/bin directory is on the PATH you should be able to start it from the command line.
$ jshell
| Welcome to JShell -- Version 11.0.14
| For an introduction type: /help intro
jshell> /imports
| import java.io.*
| import java.math.*
| import java.net.*
| import java.nio.file.*
| import java.util.*
| import java.util.concurrent.*
| import java.util.function.*
| import java.util.prefs.*
| import java.util.regex.*
| import java.util.stream.*
jshell> 1 + 1
$1 ==> 2
jshell> int foo(int x) {
...> return x + 1;
...> }
| created method foo(int)
jshell> foo(5)
$3 ==> 6
You can see the current imports by calling /imports.
Jshell starts with default imports but you can always import more classes as long as they are on the classpath.
You can start the jshell and provide a classpath argument:
$ jshell --class-path /opt/libs/guava-19.0.jar:/opt/libs/commons-lang3-3.4.jar
See more regarding classpath options in this answer.

Related

Does jshell scripts support schebang? [duplicate]

Given that Java 9 is upon us and we can finally have a java REPL with jshell I was hoping there was a way to add a shebang to a script and have jshell interpret it.
I tried creating test.jsh:
#!/usr/bin/env jshell -s
System.out.println("Hello World")
/exit
However that gives:
⚡ ./test.jsh
| Error:
| illegal character: '#'
| #!/usr/bin/env jshell -s
| ^
| Error:
| illegal start of expression
| #!/usr/bin/env jshell -s
| ^
Hello World
It turns out there is an enhancement request for this in OpenJDK https://bugs.openjdk.java.net/browse/JDK-8167440.
Is there any other way to do this?
Use
//usr/bin/env jshell --show-version --execution local "$0" "$#"; exit $?
as the first line of test.jsh. The test.jsh script could look like:
//usr/bin/env jshell --show-version "$0" "$#"; exit $?
System.out.println("Hello World")
/exit
The command line option --show-version is optional, of course, but gives immediate feedback that the tool is running.
The extra command line option --execution local prevents jshell to spawn another VM. This speeds up launch time and if an exception is thrown by your script code, the local VM will exit.
Consult the output of jshell --help and jshell --help-extra for more options.
Update
Also take a look at https://github.com/jbangdev/jbang Having fun with Java scripting, which offers a neat wrapper around running .java files from the command line.
It turns out that with a bit of trickery there is a way, although I haven't fully managed to suppress the interpreted commands but pretty close to what I want.
Change test.jsh to:
#!/usr/bin/env sh
tail -n +4 "$0" | jshell -s "$#"
exit $?
System.out.println("Hello World")
/exit
Which gives us:
⚡ ./test.jsh
-> System.out.println("Hello World")
Hello World
-> /exit
Inspired by steiny answer, I came up with a more generic solution
https://gist.github.com/ffissore/012d7e32a096fde5266f49038c93dcaf
In essence: jshell-wrapper will strip the first line of the script (which is supposed to be the shebang) and will add a /exit at the end of the script
The below works too; put it into a someScript.jsh file and run it with ./someScript.jsh. All arguments received by someScript.jsh will go to String[] args.
#!/home/gigi/.sdkman/candidates/java/current/bin/java --source 11
import java.util.Arrays;
import ro.go.adrhc.*; // example of using your classes, e.g. App below
public class X {
public static void main(String[] args) {
// do whatever you want here, e.g.:
// System.out.println("Hello World");
// or
// use a class:
// App.main(args);
// e.g. from ro.go.adrhc package, by running:
// CLASSPATH="/path-to-ro.go.adrhc-classes" ./someScript.jsh
}
}
The usage of the wrapping class, here X, is a mandatory trick for this to work. Use the Java version you have by changing /home/gigi/.sdkman/candidates/java/current/bin/java.
Inspired by https://blog.codefx.org/java/scripting-java-shebang/.

How to import another script file in Jshell

I'm looking to use jshell to replace bash for command line processing.
I've created a simple class fs in the file fs.jsh (yes poor naming) that has a number of utility functions like:
// file fs.jsh
class fs
{
static void println(String line)
{
System.out.println(line);
}
}
I know want to include fs.jsh from another file:
e.g.
// helloworld.jsh
import fs.jsh
fs.println("Hello World");
The above code gives the error:
package fs does not exist
| import fs.jsh;
I've also tried:
import fs;
Which gives:
Error:
| '.' expected
| import fs;
So how do I import one script file from another.
One thing that you can make sure is to create an instance of the class before you access its method :
new fs().println("Hello World");
Another, do make sure the sequence in which the scripts are executed is fixed if one relies on the code of the other.
Scripts are run in the order in which they’re entered on the command
line. Command-line scripts are run after startup scripts. To run a
script after JShell is started, use the /open command.
Additionally, an import without a package doesn't make much sense and you cannot have packages in Jshell snippets.
The way you can do it is somewhat like:
Have one script file some.jsh
Another script file sometwo.jsh which calls it
Eventually, open the script sometwo.jsh

How to run a JShell File?

I'd like to run an entire file with JShell like:
$ jshell my-jshell-skript.java
Where e.g. the content of my my-jshell-skript.java is 40 + 2;.
Or alternatively an executable like:
#!/usr/bin/jshell
40 + 2
Is this possible now or do I still have to take the old way over a Java-Main-Class?
Edit 1: Windows-Problem
On Windows, there is still no solution for me:
C:\JDKs\jdk9.0.0.0_x64\bin>type foo.jsh
1 + 1
C:\JDKs\jdk9.0.0.0_x64\bin>jshell.exe foo.jsh
| Welcome to JShell -- Version 9
| For an introduction type: /help intro
jshell> /exit
| Goodbye
C:\JDKs\jdk9.0.0.0_x64\bin>
JShell starts ignoring my file completely. Is it a bug?
Edit 2: Solution for Windows-Problem
Turns out that it is the content of my foo. Seems like 1 + 1 does only work "on the fly", not read from a file:
C:\JDKs\jdk9.0.0.0_x64\bin>type foo.jsh
System.out.println("foo");
C:\JDKs\jdk9.0.0.0_x64\bin>jshell.exe foo.jsh
foo
| Welcome to JShell -- Version 9
| For an introduction type: /help intro
jshell> /exit
| Goodbye
C:\JDKs\jdk9.0.0.0_x64\bin>
You can create a Jshell script file named some.jsh with those statements and on the command prompt from where you run jshell, execute it as:-
jshell /path/to/some.jsh
On a MacOSX, I would do something like:
You can pipe the string to JShell:
echo 1 + 2 | jshell
Example:
:/# echo 1 + 2 | jshell
| Welcome to JShell -- Version 9
| For an introduction type: /help intro
jshell> 1 + 2
$1 ==> 3
:/#
Or, from a file:
cat myfile | jshell
Where myfile contains the line "1 + 2".
JShell is not meant to run a Java class directly. If you want to run a java class, you still need to do it the old way - java <your-class-name>.
From the docs,
The Java Shell tool (JShell) is an interactive tool for learning the
Java programming language and prototyping Java code. JShell is a
Read-Evaluate-Print Loop (REPL), which evaluates declarations,
statements, and expressions as they are entered and immediately shows
the results.
As per this quote, JShell is meant for running or trying out individual Java statements. In the traditional java way, you have to write a full Java program before you can run it and see the results. But JShell allows you a way to try out the Java statements without needing you to build the full standalone java application.
So the short answer to your question is that, no, you can't call standalone java applications like jshell my-jshell-skript.java. However, you CAN call a script file which contains individual JShell commands or Java statements. So if you copy all the statements from your Java program and paste them to a JShell script, you can run the script like:
% jshell my-jshell-skript.jsh
But this is not quite the same as running a standalone java application.
Launch jshell in concise feedback mode and filter the required content-
$echo '40 + 2' | jshell --feedback concise | sed -n '2p' |sed -En 's/[^>]*>(.+)/\1/gp'
output: 42
More details here- How to execute java jshell command as inline from shell or windows commandLine
In jshell you can save the current snippets into a file by issuing:
/save Filename
Likewise, you can load the file into the current context/session by issuing:
/open Filename
Here is one such example:
| Welcome to JShell -- Version 9.0.7.1
| For an introduction type: /help intro
jshell> String[] names={"nameone","nametwo"}
names ==> String[2] { "nameone", "nametwo" }
jshell> Arrays.toString(names);
$2 ==> "[nameone, nametwo]"
jshell> /save myExample
jshell> % sudipbhandari at sysadm-Latitude-5480 in ~ 18:22
> jshell
| Welcome to JShell -- Version 9.0.7.1
| For an introduction type: /help intro
jshell> names
| Error:
| cannot find symbol
| symbol: variable names
| names
| ^---^
jshell> /open myExample
jshell> names
names ==> String[2] { "nameone", "nametwo" }
In Windows, to see the verbose output for a jsh file
type file.jsh | jshell -v
Problem when running jshell file.jsh
D:\>type file.jsh
3 + 5
D:\>jshell file.jsh
| Welcome to JShell -- Version 13.0.2
| For an introduction type: /help intro
jshell>
Workaround:
D:\>type file.jsh
3 + 5
D:\>type file.jsh | jshell -v
| Welcome to JShell -- Version 13.0.2
| For an introduction type: /help intro
jshell> $1 ==> 8
| created scratch variable $1 : int
jshell>
Note: file should contain a blank line (/n) after the last line, else the last line is not getting executed
Pipe usage can be achieved with the "hyphen" option, absent in the initial jshell release.
echo 'System.out.print(1 + 2)' | jshell -
https://docs.oracle.com/en/java/javase/11/tools/jshell.html
https://bugs.openjdk.java.net/browse/JDK-8187439

Package name breaks JNI classpath?

I'm working on a JNI application. It is a C program that calls some Java methods.
I wrote it following some internet examples.
First I created a simple example in Eclipse Indigo (it created the Java files in a "default package"). Then I used something like this in the C code:
options.optionString = "-Djava.class.path=/home/elias/workspace/Funciones/bin";
All worked fine but then I re-made the Java proyect to have the Java code in a package called "Funciones", so I modified to:
options.optionString = "-Djava.class.path=/home/elias/workspace/Funciones/bin/Funciones";
But now I doesn't work... I supposed it is something I have wrong in the classpath.
Can someone help me please?
Thanks.
You want the class path to point at the directory (or directories, or jar files) holding the top-level packages you're using, not inside the packages. So if your code is laid out like this:
~/Funciones/bin/
|
>----Funciones
| |
| >----Funciones.class – this is the class Funciones.Funciones
|
>----some other package
|
:
you need to add ~/Funciones/bin to your classpath. To find the class, you need to use its fully qualified name – the class name prefixed with the package name:
Class clsFunciones = Class.forName("Funciones.Funciones");
or, in JNI, the class descriptor:
jclass clsFunciones = (*env)->FindClass(env, "Funciones/Funciones");

Calling clojure from java

Most of the top google hits for "calling clojure from java" are outdated and recommend using clojure.lang.RT to compile the source code. Could you help with a clear explanation of how to call Clojure from Java assuming you have already built a jar from the Clojure project and included it in the classpath?
Update: Since this answer was posted, some of the tools available have changed. After the original answer, there is an update including information on how to build the example with current tools.
It isn't quite as simple as compiling to a jar and calling the internal methods. There do seem to be a few tricks to make it all work though. Here's an example of a simple Clojure file that can be compiled to a jar:
(ns com.domain.tiny
(:gen-class
:name com.domain.tiny
:methods [#^{:static true} [binomial [int int] double]]))
(defn binomial
"Calculate the binomial coefficient."
[n k]
(let [a (inc n)]
(loop [b 1
c 1]
(if (> b k)
c
(recur (inc b) (* (/ (- a b) b) c))))))
(defn -binomial
"A Java-callable wrapper around the 'binomial' function."
[n k]
(binomial n k))
(defn -main []
(println (str "(binomial 5 3): " (binomial 5 3)))
(println (str "(binomial 10042 111): " (binomial 10042 111)))
)
If you run it, you should see something like:
(binomial 5 3): 10
(binomial 10042 111): 49068389575068144946633777...
And here's a Java program that calls the -binomial function in the tiny.jar.
import com.domain.tiny;
public class Main {
public static void main(String[] args) {
System.out.println("(binomial 5 3): " + tiny.binomial(5, 3));
System.out.println("(binomial 10042, 111): " + tiny.binomial(10042, 111));
}
}
It's output is:
(binomial 5 3): 10.0
(binomial 10042, 111): 4.9068389575068143E263
The first piece of magic is using the :methods keyword in the gen-class statement. That seems to be required to let you access the Clojure function something like static methods in Java.
The second thing is to create a wrapper function that can be called by Java. Notice that the second version of -binomial has a dash in front of it.
And of course the Clojure jar itself must be on the class path. This example used the Clojure-1.1.0 jar.
Update: This answer has been re-tested using the following tools:
Clojure 1.5.1
Leiningen 2.1.3
JDK 1.7.0 Update 25
The Clojure Part
First create a project and associated directory structure using Leiningen:
C:\projects>lein new com.domain.tiny
Now, change to the project directory.
C:\projects>cd com.domain.tiny
In the project directory, open the project.clj file and edit it such that the contents are as shown below.
(defproject com.domain.tiny "0.1.0-SNAPSHOT"
:description "An example of stand alone Clojure-Java interop"
:url "http://clarkonium.net/2013/06/java-clojure-interop-an-update/"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.5.1"]]
:aot :all
:main com.domain.tiny)
Now, make sure all of the dependencies (Clojure) are available.
C:\projects\com.domain.tiny>lein deps
You may see a message about downloading the Clojure jar at this point.
Now edit the Clojure file C:\projects\com.domain.tiny\src\com\domain\tiny.clj such that it contains the Clojure program shown in the original answer. (This file was created when Leiningen created the project.)
Much of the magic here is in the namespace declaration. The :gen-class tells the system to create a class named com.domain.tiny with a single static method called binomial, a function taking two integer arguments and returning a double. There are two similarly named functions binomial, a traditional Clojure function, and -binomial and wrapper accessible from Java. Note the hyphen in the function name -binomial. The default prefix is a hyphen, but it can be changed to something else if desired. The -main function just makes a couple of calls to the binomial function to assure that we are getting the correct results. To do that, compile the class and run the program.
C:\projects\com.domain.tiny>lein run
You should see output shown in the original answer.
Now package it up in a jar and put it someplace convenient. Copy the Clojure jar there too.
C:\projects\com.domain.tiny>lein jar
Created C:\projects\com.domain.tiny\target\com.domain.tiny-0.1.0-SNAPSHOT.jar
C:\projects\com.domain.tiny>mkdir \target\lib
C:\projects\com.domain.tiny>copy target\com.domain.tiny-0.1.0-SNAPSHOT.jar target\lib\
1 file(s) copied.
C:\projects\com.domain.tiny>copy "C:<path to clojure jar>\clojure-1.5.1.jar" target\lib\
1 file(s) copied.
The Java Part
Leiningen has a built-in task, lein-javac, that should be able to help with the Java compilation. Unfortunately, it seems to be broken in version 2.1.3. It can't find the installed JDK and it can't find the Maven repository. The paths to both have embedded spaces on my system. I assume that is the problem. Any Java IDE could handle the compilation and packaging too. But for this post, we're going old school and doing it at the command line.
First create the file Main.java with the contents shown in the original answer.
To compile java part
javac -g -cp target\com.domain.tiny-0.1.0-SNAPSHOT.jar -d target\src\com\domain\Main.java
Now create a file with some meta-information to add to the jar we want to build. In Manifest.txt, add the following text
Class-Path: lib\com.domain.tiny-0.1.0-SNAPSHOT.jar lib\clojure-1.5.1.jar
Main-Class: Main
Now package it all up into one big jar file, including our Clojure program and the Clojure jar.
C:\projects\com.domain.tiny\target>jar cfm Interop.jar Manifest.txt Main.class lib\com.domain.tiny-0.1.0-SNAPSHOT.jar lib\clojure-1.5.1.jar
To run the program:
C:\projects\com.domain.tiny\target>java -jar Interop.jar
(binomial 5 3): 10.0
(binomial 10042, 111): 4.9068389575068143E263
The output is essentially identical to that produced by Clojure alone, but the result has been converted to a Java double.
As mentioned, a Java IDE will probably take care of the messy compilation arguments and the packaging.
As of Clojure 1.6.0, there is a new preferred way to load and invoke Clojure functions. This method is now preferred to calling RT directly (and supersedes many of the other answers here). The javadoc is here - the main entry point is clojure.java.api.Clojure.
To lookup and call a Clojure function:
IFn plus = Clojure.var("clojure.core", "+");
plus.invoke(1, 2);
Functions in clojure.core are automatically loaded. Other namespaces can be loaded via require:
IFn require = Clojure.var("clojure.core", "require");
require.invoke(Clojure.read("clojure.set"));
IFns can be passed to higher order functions, e.g. the example below passes plus to read:
IFn map = Clojure.var("clojure.core", "map");
IFn inc = Clojure.var("clojure.core", "inc");
map.invoke(inc, Clojure.read("[1 2 3]"));
Most IFns in Clojure refer to functions. A few, however, refer to non-function data values. To access these, use deref instead of fn:
IFn printLength = Clojure.var("clojure.core", "*print-length*");
IFn deref = Clojure.var("clojure.core", "deref");
deref.invoke(printLength);
Sometimes (if using some other part of the Clojure runtime), you may need to ensure that the Clojure runtime is properly initialized - calling a method on the Clojure class is sufficient for this purpose. If you do not need to call a method on Clojure, then simply causing the class to load is sufficient (in the past there has been a similar recommendation to load the RT class; this is now preferred):
Class.forName("clojure.java.api.Clojure")
EDIT This answer was written in 2010, and worked at that time. See Alex Miller's answer for more modern solution.
What kind of code are calling from Java? If you have class generated with gen-class, then simply call it. If you want to call function from script, then look to following example.
If you want to evaluate code from string, inside Java, then you can use following code:
import clojure.lang.RT;
import clojure.lang.Var;
import clojure.lang.Compiler;
import java.io.StringReader;
public class Foo {
public static void main(String[] args) throws Exception {
// Load the Clojure script -- as a side effect this initializes the runtime.
String str = "(ns user) (defn foo [a b] (str a \" \" b))";
//RT.loadResourceScript("foo.clj");
Compiler.load(new StringReader(str));
// Get a reference to the foo function.
Var foo = RT.var("user", "foo");
// Call it!
Object result = foo.invoke("Hi", "there");
System.out.println(result);
}
}
EDIT: I wrote this answer almost three years ago. In Clojure 1.6 there is a proper API exactly for the purpose of calling Clojure from Java. Please Alex Miller's answer for up to date information.
Original answer from 2011:
As I see it, the simplest way (if you don't generate a class with AOT compilation) is to use clojure.lang.RT to access functions in clojure. With it you can mimic what you would have done in Clojure (no need to compile things in special ways):
;; Example usage of the "bar-fn" function from the "foo.ns" namespace from Clojure
(require 'foo.ns)
(foo.ns/bar-fn 1 2 3)
And in Java:
// Example usage of the "bar-fn" function from the "foo.ns" namespace from Java
import clojure.lang.RT;
import clojure.lang.Symbol;
...
RT.var("clojure.core", "require").invoke(Symbol.intern("foo.ns"));
RT.var("foo.ns", "bar-fn").invoke(1, 2, 3);
It is a bit more verbose in Java, but I hope it's clear that the pieces of code are equivalent.
This should work as long as Clojure and the source files (or compiled files) of your Clojure code is on the classpath.
I agree with clartaq's answer, but I felt that beginners could also use:
step-by-step information on how to actually get this running
information that's current for Clojure 1.3 and recent versions of leiningen.
a Clojure jar that also includes a main function, so it can be run standalone or linked as a library.
So I covered all that in this blog post.
The Clojure code looks like this:
(ns ThingOne.core
(:gen-class
:methods [#^{:static true} [foo [int] void]]))
(defn -foo [i] (println "Hello from Clojure. My input was " i))
(defn -main [] (println "Hello from Clojure -main." ))
The leiningen 1.7.1 project setup looks like this:
(defproject ThingOne "1.0.0-SNAPSHOT"
:description "Hello, Clojure"
:dependencies [[org.clojure/clojure "1.3.0"]]
:aot [ThingOne.core]
:main ThingOne.core)
The Java code looks like this:
import ThingOne.*;
class HelloJava {
public static void main(String[] args) {
System.out.println("Hello from Java!");
core.foo (12345);
}
}
Or you can also get all the code from this project on github.
This works with Clojure 1.5.0:
public class CljTest {
public static Object evalClj(String a) {
return clojure.lang.Compiler.load(new java.io.StringReader(a));
}
public static void main(String[] args) {
new clojure.lang.RT(); // needed since 1.5.0
System.out.println(evalClj("(+ 1 2)"));
}
}
If the use case is to include a JAR built with Clojure in a Java application, I have found having a separate namespace for the interface between the two worlds to be beneficial:
(ns example-app.interop
(:require [example-app.core :as core])
;; This example covers two-way communication: the Clojure library
;; relies on the wrapping Java app for some functionality (through
;; an interface that the Clojure library provides and the Java app
;; implements) and the Java app calls the Clojure library to perform
;; work. The latter case is covered by a class provided by the Clojure lib.
;;
;; This namespace should be AOT compiled.
;; The interface that the java app can implement
(gen-interface
:name com.example.WeatherForecast
:methods [[getTemperature [] Double]])
;; The class that the java app instantiates
(gen-class
:name com.example.HighTemperatureMailer
:state state
:init init
;; Dependency injection - take an instance of the previously defined
;; interface as a constructor argument
:constructors {[com.example.WeatherForecast] []}
:methods [[sendMails [] void]])
(defn -init [weather-forecast]
[[] {:weather-forecast weather-forecast}])
;; The actual work is done in the core namespace
(defn -sendMails
[this]
(core/send-mails (.state this)))
The core namespace can use the injected instance to accomplish its tasks:
(ns example-app.core)
(defn send-mails
[{:keys [weather-forecast]}]
(let [temp (.getTemperature weather-forecast)] ...))
For testing purposes, the interface can be stubbed:
(example-app.core/send-mails
(reify com.example.WeatherForecast (getTemperature [this] ...)))
Other technique that works also with other languages on top of JVM is to declare an interface for functions you want to call and then use 'proxy' function to create instance that implemennts them.
You can also use AOT compilation to create class files representing your clojure code. Read the documentation about compilation, gen-class and friends in the Clojure API docs for the details about how to do this, but in essence you will create a class that calls clojure functions for each method invocation.
Another alternative is to use the new defprotocol and deftype functionality, which will also require AOT compilation but provide better performance. I don't know the details of how to do this yet, but a question on the mailing list would probably do the trick.

Categories