├── .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 | --------------------------------------------------------------------------------