Just exploring new release of Java, its new module system, and playing with jshell as well. Probably my question doesn't have too much sense, but I am just curious.
So I came up with the question: Is there any way to create a module in jshell? Or module can be only created in module-info.java?
Modules cannot be created using JShell currently and it is not a Goal of JShell either.
JShell Functionality
The JShell API will provide all of JShell's evaluation functionality.
The code fragments that are input to the API are referred to as
"snippets". The jshell tool will also use the JShell completion API to
determine when input is incomplete (and the user must be prompted for
more), when it would be complete if a semicolon were added (in which
case the tool will append the semicolon) and also how to complete
input when completion is requested with a tab.
A snippet must correspond to one of the following JLS syntax productions:
Expression
Statement
ClassDeclaration
InterfaceDeclaration
MethodDeclaration
FieldDeclaration
ImportDeclaration
A snippet may not declare a package or a module. All JShell code is placed in a single package in an unnamed module. The name of the package is controlled by JShell.
In fact trying to use a ModuleDeclaration within JShell is not a recognized syntax as well both evaluating directly or using the /edit:
Yet, the following options can be made to work out effectively to make use of existing modules within JShell along with the snippet evaluations -
--module-path <path>
Specify where to find application modules
--add-modules <module>(,<module>)*
Specify modules to resolve, or all modules on the
module path if <module> is ALL-MODULE-PATHs
Related
This question already has answers here:
Accessing com.sun.tools.javac.util from Java 9
(2 answers)
Closed 3 years ago.
I've been trying to modify the AST using annotation processors. I tried extending Lombok, but that seemed too hard, so I decided to use things from com.sun.source.* and com.sun.tools.javac.* However, I am using java 11, and the document I was learning from, "The Hacker's Guide to Javac" http://scg.unibe.ch/archive/projects/Erni08b.pdf, uses Java 6. The api they used is now internal and my module cannot read it.
In IntelliJ, it gave me a few errors, but I clicked on the suggestions (which said things like "Add --Xxx-xxx to xxx" without paying attention to them. When I tried compiling with Maven, it failed, since the module does not read the internals of jdk.compiler.
These are some of my imports:
import com.sun.source.util.Trees;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.TreeTranslator;
import com.sun.tools.javac.util.Context;
My module-info file contains
requires jdk.compiler;
requires java.compiler;
I got messages like "[ERROR]package com.sun.tools.javac.util is declared in module jdk.compiler, which does not export it to module OtherAnnot" and "[ERROR] (package com.sun.tools.javac.tree is declared in module jdk.compiler, which does not export it to module OtherAnnot)"
Edit: I guess this is a duplicate, but I wanted to know if there was some alternative API for AST transformations in java 9.
With the introduction of Project Jigsaw, the JDK has been modularized, allowing users to create their own modules as well. These modules allows you to export packages of yours, allowing programs that require your module (in their module-info.java) to use the exported packages.
Ideally, you'd be prohibited from using classes that reside in packages that are not exported. However, to not break backwards compatibility, VM flags were introduced that allow you to forcefully export packages (that don't belong to you) to your module.
Given your error message, the respective VM flag to add is:
--add-exports jdk.compiler/com.sun.tools.javac.tree=OtherAnnot
The pattern here is:
--add-exports THEIR_MODULE/THEIR_PACKAGE=YOUR_MODULE
If the compiler complains that packages aren't exported to the unnamed module, then you can use the following:
--add-exports THEIR_MODULE/THEIR_PACKAGE=ALL-UNNAMED
I found this question, and this other, so intriguing that it begs several questions, at least for me:
Rather open-ended question, but where is jshell confined to? Obviously, GUI apps aren't in the domain for jshell solutions, or IDE replacement:
Out of scope are graphical interfaces and debugger support. The JShell
API is intended to allow JShell functionality in IDEs and other tools,
but the jshell tool is not intended to be an IDE.
Bonus points for Venn diagrams or other visuals.
Certainly, snippets should be limited in size. I'm more asking what sort of problems cannot be solved with snippets.
see also:
https://openjdk.java.net/jeps/222
https://openjdk.java.net/jeps/330
Answering the updated question
All problems can be solved with snippets (and with a sufficiently complicated shell script, too). But JShell is best used to debug and learn java - a full-fledged program is much more flexible for all other use-cases.
JShell, .jsh and java MyClass.java
JShell is an interactive shell for trying out java code. Essentially, it is a REPL for Java.
Since JShell is all about you typing in code snippets, which it then evaluates, and it often makes sense to put those snippets in a file instead of writing them several times, JShell supports .jsh scripts, which contain collections of snippets to be interpreted by JShell. In this sense, this is similar to bash accepting .sh files or command.com accepting .bat files -- typing them line by line is equivalent to importing them.
Single-source java-file execution is a very different beast. It is sugar that replaces, from JDK 11 onwards,
java MyClass.java arg1 arg2 arg3
by your local scripting equivalent of writing
TMPDIR=$(mktemp -d)
javac -d $TMPDIR MyClass.java
java -cp $TMPDIR MyClass arg1 arg2 arg3
rm -rf $TMPDIR
This allows single-source files to be quickly executed from the command line with a single command, and without leaving their compiled classes all over the place (no actual temporary directory needs to be created, as java can store those classes in memory). Since they already had 3 other execution modes in java (for classes, jar-files and modules), it is no great stretch to add this as a fourth one.
Since OP wanted a picture:
Java as a scripting language
Now that the distinction is clear (.jsh is for use with JShell, single-source java executables are only for, you guessed it, single-source java executables), what about using Java as a scripting language?
You have always had the option to write a launcher; for example,
#!/bin/bash
java -jar MyApp.jar
has worked for ages. It was technically possible to name a class directly, but not too useful, as jar files are far more handy when distributing binaries -- for one thing, they avoid mirroring the package structure as a bunch of folders. Having a launcher script as separate from the actual java code was, however, still somewhat unfriendly: you now need to keep both together, or at least have the launcher be able to locate the actual .jar to launch.
Now, they have also introduced the following shortcut: regardless of file name or extension, you can distribute your java source with a "shebang prefix" as follows:
#!/path/to/java --source 11
<source of MyClass.java>
mark it as executable, and launch it from the command-line just as you can launch any other executable. For example, copy and paste this into a helloworld file (and fix the jdk location before attempting to run it):
#!/opt/jdk-11.0.1/bin/java --source 11
public class Test {
public static void main(String ... args) {
System.out.println("Hello " + (args.length == 0 ? "world!" : args[0]));
}
}
After marking it as executable, you can launch it directly with
$ ./helloworld
Hello world!
and it even takes its arguments right:
$ ./helloworld Bob!
Hello bob!
For small programs, and provided you do not need to go outside of the JDK to pull in additional libraries, it will now be vastly easier to distribute java code for command-line use.
Java will still not be a "scripting language" (it will never compete with, say, python), but
it has a very nice REPL loop
you can execute short programs a lot easier
Well, of course, its confined to a bring a normal REPL utility in terms of scoping what an IDE and graphical user interfaces could provide. I would talk of more about its capabilities as compared to single source code programs. The features that keeps it apart still from single source code programs:
a history with editing
tab-completion
automatic addition of needed terminal semicolons and
configurable predefined imports and definitions
As mentioned in the alternatives to Single-File Source-Code Programs JEP as well:
We could delegate the task of "one-off runs" to the jshell tool. While
this may at first seem obvious, this was an explicit non-goal in the
design of jshell.
The jshell tool was designed to be an interactive
shell, and many design decisions were made in favor of providing a
better interactive experience.
Burdening it with the additional
constraints of being the batch runner would detract from the
interactive experience.
!!! Limitations and behavior!!!
On the other hands, few limitations(assumed functionalities) that one would mostly find while performing a hands-on using JShell rather than simply reading the docs would be :
use of final variables final variables are not functioning well in jshell
of course Debugging with JShell
integration of jshell with IDEs Java 11 JShell inside Intellij IDEA
disabling history Disable JShell history
redeclared variables should be reset In jshell-11, why does a redeclared reference variable that resets to null still have a type?
create module using jshell Create Module in JShell in Java 9
importing private package classes Importing Package-Private Classes to JShell
scope of objects Access to "parent scope" in JShell
clear jshell console How to clear Java 9 JShell Console?
!!! Features and more !!!
More details over the links that gives it an upper hand over Single File Source Code Programs :
why and how Why and how do you use JShell?
import classpath for a project In JShell, how to import classpath from a Maven project
run an application via JShell How to run a java application with jshell?
set custom feedback modes Create custom feedback mode in jshell
load scripts on startup Different ways to load script on jshell startup
list active methods List all active methods in jshell
run a jshell file How to run a JShell File?
execute javascript with jshell How to execute a java script with jshell?
how to use method references in jshell Is there a way to use method references for top-level functions in jshell?
I'm struggling trying to get remote actors setup in Scala. I'm running Scala 2.10.2 and Akka 2.2.1.
I compile using [I've shortened the paths on the classpath arg for clarity sake]:
$ scalac -classpath "akka-2.2.1/lib:akka-2.2.1/lib/scala-library.jar:akka-2.2.1/lib/akka:akka-2.2.1/lib/akka/scala-reflect-2.10.1.jar:akka-2.2.1/lib/akka/config-1.0.2.jar:akka-2.2.1/lib/akka/akka-remote_2.10-2.2.1.jar:akka-2.2.1/lib/akka/akka-kernel_2.10-2.2.1.jar:akka-2.2.1/lib/akka/akka-actor_2.10-2.2.1.jar:." [file.scala]
I've continuously added new libraries trying to debug this - I'm pretty sure all I really need to include is akka-remote, but the others shouldn't hurt.
No issues compiling.
I attempt to run like this:
$ scala -classpath "[same as above]" [application]
And I receive a NSM exception:
java.lang.NoSuchMethodException: akka.remote.RemoteActorRefProvider.<init>(java.lang.String, akka.actor.ActorSystem$Settings, akka.event.EventStream, akka.actor.Scheduler, akka.actor.DynamicAccess)
at java.lang.Class.getConstructor0(Class.java:2810)
at java.lang.Class.getDeclaredConstructor(Class.java:2053)
...
Looking into the source code, it appears that Akka 2.2.X's flavor of this constructor takes 4 arguments (the Scheduler is removed). But in Akka < 2.2.X, the constructor takes 5 args.
Thus, I'm thinking my classpath isn't setup quite right. At compile-time, Scala must be finding the <2.2.X flavor. I don't even know where it would be finding it, since I only have Akka 2.2.1 installed.
Any suggestions!? Thanks! (Please don't say to use SBT).
The problem here is that the Scala distribution contains akka-actor 2.1.0 and helpfully puts that in the boot class path for you. We very strongly recommend using a dependency manager like sbt or maven when building anything which goes beyond the most trivial projects.
As noted in another answer, the problem is that scala puts a different version of Akka into the bootclasspath.
To more directly answer your question (as you said you don't want to use sbt): you can execute your program with java instead of scala. You just have to put the appropriate Scala jars into the classpath.
Here is a spark-dev message about the problem. The important part is: "the workaround is to use java to launch the application instead of scala. All you need to do is to include the right Scala jars (scala-library and scala-compiler) in the classpath."
Is there a way to run or simulate running Java statements (kind of like IDLE - the Python GUI) without compiling and running the executable? I want to quickly test statements to see if they work. Thanks.
Yep, you can use Eclipse, create a single project, and create a Scrapbook Page in that project.
You can also specify import statements: http://www.informit.com/articles/article.aspx?p=31789&seqNum=3
Scrapbook pages get their classpath
from the containing project's build
path. If in a scrapbook page you want
to reference a Java element that is
not on the build path of the
containing Java project, you need to
add to the Java project's build path.
Scrapbook pages also allow you to
specify import statements. You do this
by selecting Set Imports from the
context menu of a scrapbook page or
Set Import Declarations for Running
Code from the toolbar. You need to set
import statements for references to
Java declarations in your projects.
This is a common oversight. If the
type or package you are attempting to
import is not listed in the Add
dialog, it means you need to add it to
the build path of the project
containing the scrapbook page. If you
are referencing an element that has
multiple declarations, you will need
to add an import statement to uniquely
identify the element.
Edit: Got another solution too: http://ideone.com. It's an online IDE and debugging tool. You can see an example here: http://ideone.com/98sA8, but it looks like you have to set up a bit more than on a scrapbook page.
Edit 2:
Nowadays in Java 11, if it's a simple app in a single file you can run it directly from the java command (on the command line) which will handle all the compilation for you behind the scenes:
java HelloWorld.java
This is useful for students, as they can get started with Java without learning all of the javac compilation routine.
As of Java 11 (JEP 330) it is now possible to run Java files directly with the java tool:
java Factorial.java 3 4 5
is informally equivalent to
javac -d <memory> Factorial.java
java -cp <memory> Factorial 3 4 5
Java also added support for "shebang" files.
For more details see:
http://openjdk.java.net/jeps/330
Using Eclipse, you can create a Scrapbook page which will allow you to do exactly this.
Caveats:
You need to use full binary class names for anything outside of java.lang
You need to select the code (standard text selection) that you want to run
There are three different methods for running -- Inspect, Display, and Run. Inspect and Display are virtually the same, showing you the result of the last statement in your code (so you don't need to print it or anything), Run runs the selected code and dumps any output to the console view.
Never used it, but BeanShell seems to do what you want
You should be able to use Beanshell to do this:
http://www.beanshell.org/download.html
Your other alternative, if you're using Eclipse, is to make use of the scrapbook functionality:
http://help.eclipse.org/helios/index.jsp?topic=/org.eclipse.jdt.doc.user/tasks/task-create_scrapbook_page.htm
You can accomplish this with Groovy and the Groovy Console, with the caveat that you'd need to know how to express whatever you are trying to express in Java in the Groovy language:
you might want to checkout janino http://docs.codehaus.org/display/JANINO/Home also ..
JGrasp is the best solution. There is a thing called interactions, that's perfectly fine.
Use JShell, which is included by default starting from JDK 9. It is command-line based Read Eval Print Loop (REPL), where you can enter Java code, and get the results immediately.
In Eclipse 3.5, say I have a package structure like this:
tom.package1
tom.package1.packageA
tom.package1.packageB
if I right click on an the tom.package1 package and go to Refactor->Rename, an option "Rename subpackages" appears as a checkbox. If I select it, and then rename tom.package1 to tom.red my package structure ends up like this:
tom.red
tom.red.packageA
tom.red.packageB
Yet I hear that Java's packages are not hierarchical. The Java Tutorials back that up (see the section on Apparent Hierarchies of Packages). It certainly seems like Eclipse is treating packages as hierarchical in this case.
I was curious why access specifiers couldn't allow/restrict access to "sub-packages" in a previous question because I KNEW I had seen "sub-packages" referenced somewhere before.
So are Eclipse's refactoring tools intentionally misleading impressionable young minds by furthering the "sub-package" myth? Or am I misinterpreting something here?
Eclipse can't possibly violate the JLS in this case, because it has nothing to do with compiling or running Java source or bytecode.
The refactoring tools behave as they do because that behaviour is useful to developers. The behaviour is useful to developers because, for many intents and purposes, we do treat packages as hierarchal (a.b.c has some kind of relationship with a.b, even if that relationship is not consistent from project to project). That doesn't mean Java treats them as hierarchal intrinsically.
One example where people treat packages as very hierarchal is in configuring a logging framework such as log4j. Again, it's not intrinsic to log4j, but that's how people use it in practice.
Java packages are not hierarchical in the sense that importing everything from package A does not import everything from package A.B.
However, Java packages do correspond directly to the directory structure on the file system, and directories are hierarchical. So Eclipse is doing the correct thing - it is renaming the directory, which automatically changes the name of the parent directory of the renamed directory's children (to state the very obvious).
even java itself has the concept of subpackage:
http://java.sun.com/j2se/1.5.0/docs/tooldocs/windows/java.html
java -ea[:<package name>"..." | :<class name> ]
Enable assertions. Assertions are disabled by default.
With no arguments, enableassertions or -ea enables assertions. With one argument ending in "...", the switch enables assertions in the specified package and any subpackages. If the argument is simply "...", the switch enables assertions in the unnamed package in the current working directory. With one argument not ending in "...", the switch enables assertions in the specified class.
If a single command line contains multiple instances of these switches, they are processed in order before loading any classes. So, for example, to run a program with assertions enabled only in package com.wombat.fruitbat (and any subpackages), the following command could be used:
java -ea:com.wombat.fruitbat... <Main Class>
Java's packages are not hierarchical, but Eclipse stores packages on your system's file structure.
tom.package1.packageA is represented on a Windows file system as tom/package1/packageA.
When you ask Eclipse to refactor a package name, you're asking Eclipse to change the name of the file system directory structure.
You can have packages in Eclipse like:
tom.package1.packageA
tom.package2.packageB
tom.package3.packageC
You'll just have different 2nd level file system directories.