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
Related
In the AWS re:invent presentation on Lambda performance (highly recommend) on pp.33-34 the author lists the count of classes loaded within each library using the following command:
java -cp my.jar -verbose:class Handler | grep '\[Loaded' | grep '.jar\]' | sed -r 's/\[Loaded \([^A-Z]*\)[\$A-Za-z0-9]*from.*\]/\1/g' | sort | uniq -c | sort
This basically extracts the namespace up to but not including the first capital letter, which is the class name. The output is supposed to look something like this:
143 com.fasterxml.jackson
219 org.apache.http
373 com.google
507 com.amazonaws
However this only works with the Java 8 class loader logs, which have the following format (this example should output java.io):
[Loaded java.io.Serializable from shared objects file]
The class loader logs as of Java 9+ have this different format:
[0.041s][info][class,load] java.io.Serializable source: jrt:/java.base
How does the sed command need to be updated to produce the same output as above?
I've tried the following, but the entire line is extracted in the regex group, not just the class library. I'm also running on a Mac, so I had to add a -r flag and remove some of the escape characters:
java -cp my.jar -verbose:class Handler | grep '[class,load]' | grep '.jar' | sed -r 's/.*\[class,load\] ([^A-Z]*)[$A-Za-z0-9]*source.*/\1/g'
Since the record has fields space separated we can take advantage of cut to get the desired field and then use sed to extract the package substring. The ([a-z.]+)\.[A-Z].* regex looks for lower case letters and dots until the first dot followed by an upper case letter.
echo "[0.041s][info][class,load] java.io.Serializable source: jrt:/java.base" | cut -d ' ' -f2 | sed -E 's/([a-z.]+)\.[A-Z].*/\1/g'
Result:
java.io
If a sed only solution is preferred this command will do grep and cut jobs as well:
echo "[0.041s]..." | sed -nE '/class,load/ s/[^ ]+ ([^ ]+)/\1/ ; s/([a-z.]+)\.[A-Z].*/\1/p'
grep : /class,load/
cut : s/[^ ]+ ([^ ]+)/\1/
extract: s/([a-z.]+)\.[A-Z].*/\1/p
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/.
I have a content of compiled Java class as a binary file (named X.class). Let's assume it has some class inside with a proper main method, but I don't know original class name (and it's not X).
How can I run it with java using single command line?
You can get the name of the class using javap -c <filename>. From that point on, it's just shell games. This works on OS X:
java $(javap -c File.class | head -n 2 | tail -n1 | cut -f3 -d\ )
Note the space after the \ in the subshell - this is requires to isolate the class name.
Update based on #nikolay-vyahhi feedback:
If you're not sure at which position the class name will appear (e.g. when it's unknown whether the class is public or not), you can use tr and grep, like so:
java $(javap -c File.class | head -n2| tail -n1 | tr [:space:] \\n | grep -A1 "class\|interface" | tail -n1)
You can use javap to do that:
javap X.class
It will disassemble the class and print out the package, protected, and public fields and methods:
Compiled from "Test.java"
public class Test {
public Test();
public static void main(java.lang.String...);
}
Then you can use this to run the application:
java $(javap X.class | sed -n 's/.*class \(.*\) {/\1/p')
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.
Is it possible to generate a global call graph of an application?
Basically I am trying to find the most important class of an application.
I am looking for options for Java.
I have tried Doxy Gen, but it only generates inheritance graphs.
My current script:
#! /bin/bash
echo "digraph G
{"
find $1 -name \*.class |
sed s/\\.class$// |
while read x
do
javap -v $x | grep " = class" | sed "s%.*// *%\"$x\" -> %" | sed "s/$1\///" | sed "s/-> \(.*\)$/-> \"\1\"/"
done
echo "}"
javap -v and a bit of perl will get you dependencies between classes. You can make your parser slightly more sophisticated and get dependencies between methods.
Update: or if you have either a *nix or cygwin you can get a list of dependencies as
find com/akshor/pjt33/image -name \*.class |
sed s/\\.class$// |
while read x
do
javap -v $x | grep " = class" | sed "s%.*// *%$x -> %"
done
Add a header and a footer and you can pass it to dot to render a graph. If you just want to know which classes are used by the most other classes, as your question implies, then
find com/akshor/pjt33/image -name \*.class |
sed s/\\.class$// |
while read x
do
javap -v $x | grep " = class" | sed "s%.*// *%%"
done |
sort | uniq -c | sort -n
For advanced code analysis you might wanna have a look at http://www.moosetechnology.org/
Cheers
Thomas
(edit: moved down here by general request, See: How to generate a Java call graph)