├── .gitignore
├── src
└── main
│ └── java
│ ├── module-info.java
│ └── net
│ └── java
│ └── openjdk
│ └── shinyafox
│ └── jshell
│ └── jfxs
│ ├── JavaFXExecutionControlProvider.java
│ └── JavaFXRemoteExecutionControl.java
├── scripts
├── jfxshell.sh
└── startup.jsh
├── pom.xml
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
--------------------------------------------------------------------------------
/src/main/java/module-info.java:
--------------------------------------------------------------------------------
1 | module net.java.openjdk.shinyafox.jshell.jfxs {
2 | requires jdk.jshell;
3 | requires javafx.graphics;
4 |
5 | exports net.java.openjdk.shinyafox.jshell.jfxs;
6 |
7 | provides jdk.jshell.spi.ExecutionControlProvider
8 | with net.java.openjdk.shinyafox.jshell.jfxs.JavaFXExecutionControlProvider;
9 | }
10 |
--------------------------------------------------------------------------------
/scripts/jfxshell.sh:
--------------------------------------------------------------------------------
1 | #JAVA_HOME=
2 |
3 | PROJ_ROOT=.
4 |
5 | J_MOD_PATH=$PROJ_ROOT/target/JavaFXSupportsForJShell-1.0-SNAPSHOT.jar
6 | R_MOD_PATH=$PROJ_ROOT/target/JavaFXSupportsForJShell-1.0-SNAPSHOT.jar
7 | STARTUP=$PROJ_ROOT/scripts/startup.jsh
8 |
9 | $JAVA_HOME/bin/jshell -J--module-path -J$J_MOD_PATH -R--module-path -R$R_MOD_PATH --execution "javafx" --startup $STARTUP $@
10 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | net.java.openjdk.shinyafox
5 | JavaFXSupportsForJShell
6 | 1.0-SNAPSHOT
7 | jar
8 |
9 | UTF-8
10 | 9
11 | 9
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/main/java/net/java/openjdk/shinyafox/jshell/jfxs/JavaFXExecutionControlProvider.java:
--------------------------------------------------------------------------------
1 | package net.java.openjdk.shinyafox.jshell.jfxs;
2 |
3 | import java.util.Map;
4 | import jdk.jshell.execution.JdiExecutionControlProvider;
5 | import jdk.jshell.spi.ExecutionControl;
6 | import jdk.jshell.spi.ExecutionControlProvider;
7 | import jdk.jshell.spi.ExecutionEnv;
8 |
9 | public class JavaFXExecutionControlProvider implements ExecutionControlProvider {
10 |
11 | private ExecutionControlProvider delegate = new JdiExecutionControlProvider();
12 |
13 | public String name() {
14 | return "javafx";
15 | }
16 |
17 | public Map defaultParameters() {
18 | return delegate.defaultParameters();
19 | }
20 |
21 |
22 | public ExecutionControl generate(ExecutionEnv env, Map parameters) throws Throwable {
23 | Map delegateParams = delegate.defaultParameters();
24 | delegateParams.put(JdiExecutionControlProvider.PARAM_REMOTE_AGENT, JavaFXRemoteExecutionControl.class.getName());
25 |
26 | delegateParams.putAll(parameters);
27 |
28 | return delegate.generate(env, delegateParams);
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/scripts/startup.jsh:
--------------------------------------------------------------------------------
1 |
2 | import java.io.*;
3 | import java.math.*;
4 | import java.net.*;
5 | import java.nio.file.*;
6 | import java.util.*;
7 | import java.util.concurrent.*;
8 | import java.util.function.*;
9 | import java.util.prefs.*;
10 | import java.util.regex.*;
11 | import java.util.stream.*;
12 |
13 | import javafx.animation.*;
14 | import javafx.application.*;
15 | import javafx.beans.*;
16 | import javafx.beans.binding.*;
17 | import javafx.beans.property.*;
18 | import javafx.beans.value.*;
19 | import javafx.collections.*;
20 | import javafx.collections.transformation.*;
21 | import javafx.concurrent.*;
22 | import javafx.css.*;
23 | import javafx.embed.swing.*;
24 | import javafx.event.*;
25 | import javafx.fxml.*;
26 | import javafx.geometry.*;
27 | import javafx.print.*;
28 | import javafx.scene.*;
29 | import javafx.scene.canvas.*;
30 | import javafx.scene.chart.*;
31 | import javafx.scene.control.*;
32 | import javafx.scene.control.cell.*;
33 | import javafx.scene.effect.*;
34 | import javafx.scene.image.*;
35 | import javafx.scene.input.*;
36 | import javafx.scene.layout.*;
37 | import javafx.scene.media.*;
38 | import javafx.scene.paint.*;
39 | import javafx.scene.shape.*;
40 | import javafx.scene.text.*;
41 | import javafx.scene.transform.*;
42 | import javafx.scene.web.*;
43 | import javafx.stage.*;
44 | import javafx.util.*;
45 | import javafx.util.converter.*;
46 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JavaFXSupportsForJShell
2 |
3 | ## Overview
4 | This is a JavaFX supporting library for jshell.
5 | Include following:
6 | - ExecutionControl to allow you to run JavaFX codes in jshell
7 | - Scripts to try this repository
8 | - Useful initial startups to write your JavaFX codes in jshell
9 | - Imports all of JavaFX packages
10 |
11 | jshell is a official Java REPL-Tool.
12 | For more detail about jshell, visit http://openjdk.java.net/projects/kulla/
13 |
14 | ## Why is this necessary?
15 | As you know, JavaFX requires that JavaFX related codes must be run in JavaFX thread.
16 | But, JShell runs your code on main thread.
17 | So your JavaFX code cannot be run in jshell as usually(Instead you will get an exception).
18 |
19 | This is why you need this library to play JavaFX on jshell.
20 |
21 | ## How do work this with jshell
22 | Install JDK9: https://jdk9.java.net/
23 |
24 | I use JDK9b158 in this instruction.
25 |
26 | Clone this repository and get into the repository:
27 | ```
28 | $ git clone ...
29 | $ cd JavaFXSupportsForJShell
30 | ```
31 |
32 | Build it:
33 | ```
34 | mvn package
35 | ```
36 | (Requires Apache Mavan 3.3.9+ and JDK9/bin in your $PATH)
37 |
38 | Run it:
39 | ```
40 | $ JAVA_HOME=/path/to/your/jdk9 sh scripts/jfxshell.sh
41 | (in a few second later)
42 | jshell>
43 | ```
44 |
45 | Type your JavaFX code(in the following snippet, jshell's outputs are omitted):
46 |
47 | Note that you don't need to import anything about JavaFX package because the startup will import everything instead!
48 |
49 | ```
50 | jshell> Button button = new Button("Click me!")
51 | jshell> button.setOnAction(e -> System.out.println("HelloWorld!"))
52 | jshell> Scene scene = new Scene(button)
53 | jshell> Stage stage = new Stage()
54 | jshell> stage.setScene(scene)
55 | jshell> stage.setWidth(200)
56 | jshell> stage.setHeight(300)
57 | jshell> stage.setTitle("Hello JavaFX with JShell")
58 | jshell> stage.show()
59 | ```
60 |
61 | (prompt omitted version)
62 | ```
63 | Button button = new Button("Click me!")
64 | button.setOnAction(e -> System.out.println("HelloWorld!"))
65 | Scene scene = new Scene(button)
66 | Stage stage = new Stage()
67 | stage.setScene(scene)
68 | stage.setWidth(200)
69 | stage.setHeight(300)
70 | stage.setTitle("Hello JavaFX with JShell")
71 | stage.show()
72 | ```
73 |
74 | Enjoy your jshell&JavaFX life!!
75 |
76 | Any comments, feedbacks, issues or PRs are welcome!!
77 |
78 | ## Contributors
79 | bitter_fox(@bitter_fox) -- Owner
80 |
--------------------------------------------------------------------------------
/src/main/java/net/java/openjdk/shinyafox/jshell/jfxs/JavaFXRemoteExecutionControl.java:
--------------------------------------------------------------------------------
1 | package net.java.openjdk.shinyafox.jshell.jfxs;
2 |
3 | import java.lang.reflect.Method;
4 | import java.io.InputStream;
5 | import java.io.OutputStream;
6 | import java.io.PrintStream;
7 | import java.net.Socket;
8 | import java.util.ArrayList;
9 | import java.util.List;
10 | import java.util.Map;
11 | import java.util.HashMap;
12 | import java.util.function.Consumer;
13 |
14 | import jdk.jshell.execution.RemoteExecutionControl;
15 | import jdk.jshell.spi.ExecutionControlProvider;
16 | import static jdk.jshell.execution.Util.forwardExecutionControlAndIO;
17 |
18 | import javafx.application.Platform;
19 |
20 | public class JavaFXRemoteExecutionControl extends RemoteExecutionControl {
21 |
22 | public static void main(String[] args) throws Exception {
23 | String loopBack = null;
24 | Socket socket = new Socket(loopBack, Integer.parseInt(args[0]));
25 | InputStream inStream = socket.getInputStream();
26 | OutputStream outStream = socket.getOutputStream();
27 | Map> outputs = new HashMap<>();
28 | outputs.put("out", st -> System.setOut(new PrintStream(st, true)));
29 | outputs.put("err", st -> System.setErr(new PrintStream(st, true)));
30 | Map> input = new HashMap<>();
31 | input.put("in", System::setIn);
32 | Platform.startup(() -> {});
33 | Platform.setImplicitExit(false);
34 | forwardExecutionControlAndIO(new JavaFXRemoteExecutionControl(), inStream, outStream, outputs, input);
35 | }
36 |
37 | private static class ExceptionalValue {
38 | T value;
39 | Exception ex;
40 |
41 | static ExceptionalValue of(T value) {
42 | ExceptionalValue val = new ExceptionalValue<>();
43 | val.value = value;
44 | return val;
45 | }
46 |
47 | static ExceptionalValue failed(Exception ex) {
48 | ExceptionalValue val = new ExceptionalValue<>();
49 | val.ex = ex;
50 | return val;
51 | }
52 |
53 | T get() throws Exception {
54 | if (ex == null) {
55 | return value;
56 | } else {
57 | throw ex;
58 | }
59 | }
60 | }
61 |
62 | protected String invoke(Method doitMethod) throws Exception {
63 | List> ret = new ArrayList<>();
64 |
65 | Platform.runLater(() -> {
66 | try {
67 | String val = super.invoke(doitMethod);
68 | ret.add(ExceptionalValue.of(val));
69 | } catch (Exception e) {
70 | ret.add(ExceptionalValue.failed(e));
71 | }
72 | });
73 |
74 | return ret.isEmpty() ? "" : ret.get(0).get();
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------