Skip to content

Commit 0391fe7

Browse files
authored
Merge pull request #3 from mrsarm/rc2-improvements
Release 1.0.0
2 parents 714560a + 343e9f9 commit 0391fe7

File tree

3 files changed

+158
-23
lines changed

3 files changed

+158
-23
lines changed

README.md

Lines changed: 118 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Hosted on _(release candidate)_: https://plugins.gradle.org/plugin/com.github.mr
99

1010
- [Getting started](#getting-started)
1111
- [Startup options](#startup-options)
12+
- [Spring Boot applications](#spring-boot-applications)
1213
- [Troubleshooting](#troubleshooting)
1314
- [System Requirements](#system-requirements)
1415
- [Build and Publish](#build-an-publish)
@@ -22,7 +23,7 @@ To use this plugin, add the following to your `build.gradle`:
2223

2324
```groovy
2425
plugins {
25-
id "com.github.mrsarm.jshell.plugin" version "1.0.0-RC1"
26+
id "com.github.mrsarm.jshell.plugin" version "1.0.0"
2627
}
2728
```
2829

@@ -36,7 +37,7 @@ buildscript {
3637
}
3738
}
3839
dependencies {
39-
classpath "gradle.plugin.com.github.mrsarm:jshell-plugin:1.0.0-RC1"
40+
classpath "gradle.plugin.com.github.mrsarm:jshell-plugin:1.0.0"
4041
}
4142
}
4243
@@ -86,6 +87,109 @@ arguments, like:
8687

8788
$ gradle --console plain jshell -Pjshell.startup=/path/to/run.jsh
8889

90+
If you have a `startup.jsh` script at the root of the project
91+
but at some point you don't want to execute it nor any other
92+
startup script, just pass the `jshell.startup` property with an empty
93+
value: `gradle --console plain jshell -Pjshell.startup=`.
94+
95+
Spring Boot applications
96+
------------------------
97+
98+
The JShell plugin allows to startup a Spring Boot application
99+
within the console and access to the business object from there,
100+
but you will need to do some extra configurations, and add
101+
a dependency to the project to make easier to access
102+
to the Spring beans.
103+
104+
1. Setup the plugin following the steps in the
105+
[Getting started](#getting-started) section.
106+
107+
2. Add the library [spring-ctx](https://github.com/mrsarm/spring-ctx)
108+
to your dependencies as follows:
109+
110+
- Add the following dependency to your `dependencies` section:
111+
112+
```groovy
113+
implementation 'com.github.mrsarm:spring-ctx:1.0.0'
114+
```
115+
116+
- At the end of the `repositories` section:
117+
118+
```groovy
119+
maven { url 'https://jitpack.io' }
120+
```
121+
122+
3. Any Spring Boot application has a class annotated with
123+
`@SpringBootApplication` that is the starting point of
124+
the application, with a `public static void main(String[] args)`
125+
method, you need to create a [startup.jsh](#startup-options) file
126+
at the root of your project calling that method, eg:
127+
128+
```java
129+
com.my.package.MyApplication.main(new String).main(new String[]{})
130+
```
131+
132+
You can also add the imports of the business classes you are going
133+
to play with, as many as you have, otherwise you can import them
134+
once the JShell started:
135+
136+
```java
137+
import com.my.package.services.MyUserService
138+
```
139+
140+
4. Done. You can start playing with your Spring application, you can
141+
access to the bean objects once the JShell started as
142+
following:
143+
144+
```
145+
./gradlew --console plain jshell
146+
147+
. ____ _ __ _ _
148+
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
149+
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
150+
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
151+
' |____| .__|_| |_|_| |_\__, | / / / /
152+
=========|_|==============|___/=/_/_/_/
153+
:: Spring Boot :: (v2.2.4.RELEASE)
154+
155+
14:43:28.320 INFO com.my.package.MyApplication : Starting Application on kubu1910 with PID 5225 (/projects/...
156+
14:43:28.323 DEBUG com.my.package.MyApplication : Running with Spring Boot v2.2.4.RELEASE, Spring v5.2.3.RELEASE
157+
14:43:28.324 INFO com.my.package.MyApplication : The following profiles are active: ...
158+
14:43:30.229 INFO boot.web.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8010 (http)
159+
160+
...
161+
...
162+
163+
14:43:33.729 INFO tuate.endpoint.web.EndpointLinksResolver : Exposing 3 endpoint(s) beneath base path ''
164+
14:43:33.811 INFO boot.web.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8010 (http) with context path ''
165+
14:43:33.816 INFO com.my.package.MyApplication : Started Application in 6.995 seconds (JVM running for 10.524)
166+
167+
> Task :jshell
168+
| Welcome to JShell -- Version 11.0.6
169+
| For an introduction type: /help intro
170+
171+
jshell> var myUserService = ctx.App.getBean(MyUserService.class)
172+
173+
jshell> ctx.App.ppjson(myUserService.getByUsername("admin"))
174+
{
175+
"name" : "Jhon",
176+
"lastName" : "Due",
177+
"username" : "admin",
178+
"age" : null
179+
}
180+
```
181+
182+
You can add to the `startup.jsh` not just the call to the `main` method
183+
and useful imports, but also adds the bean declarations you are
184+
going to use most likely, eg.
185+
`var myUserService = ctx.App.getBean(MyUserService.class)`, or any other
186+
snippet of Java code that may save you time running each time the JShell.
187+
188+
The class `ctx.App` comes from the `spring-ctx` dependency added, checkout the
189+
[documentation](https://github.com/mrsarm/spring-ctx/blob/master/README.md)
190+
of all the useful methods it has to help you to play with
191+
the Spring framework.
192+
89193

90194
Troubleshooting
91195
---------------
@@ -104,7 +208,7 @@ Gradle command:
104208

105209
$ gradle --console plain classes jshell
106210

107-
### I have a JDK 9+ installation but my default JDK is the JDK 8 or below
211+
### I have a JDK 9+ installation, but my default JDK is the JDK 8 or below
108212

109213
In that case Gradle will try to use the default JDK, and `jshell` is
110214
not available in Java 8 and above. Moreover the steps to change the
@@ -124,9 +228,9 @@ not have effect anymore.
124228
You can even create an alias in your `~/.profile` / `~/.bashrc`
125229
file like: `alias setjava9='export JAVA_HOME=/System/Library/Java/...'`
126230
to later switch easily to the other distribution calling
127-
`setjava9`.
231+
`setjava9`, or `setjava8` to switch back.
128232

129-
### Gradle output is print with the jshell output in the console
233+
### Gradle output is mixed with the jshell output in the console
130234

131235
If content like `<-------------> 0% EXECUTING [16s]` is mixed
132236
in the console with the jshell output each time you try
@@ -137,6 +241,13 @@ adding the option `--no-daemon` to start up the jshell:
137241

138242
$ gradle --no-daemon --console plain jshell
139243

244+
### Tab completion not working
245+
246+
Auto-completion does not work, and pressing arrow keys triggers
247+
weird characters in the console. Unfortunately, with the
248+
current console support from Gradle, there is no
249+
solution for this [bug](https://github.com/mrsarm/jshell-plugin/issues/2).
250+
140251

141252
System Requirements
142253
-------------------
@@ -169,10 +280,10 @@ I forked it because the original project is not receiving patches
169280
and this version solves some issues and adds the following features:
170281

171282
- It works with **multi-module projects**
172-
- There is no need to set the env variable `JAVA_OPTS` with a bunch of
283+
- There is no need to set the env variable `JAVA_OPTS` with a bunch
173284
of arguments _"--add-exports jdk.jshell/jdk.intern..."_
174285
- It allows to run at the beginning of the session a _.jsh_ startup script
175-
- _Coming soon_: special support to the **Spring Framework**
286+
- Special support to the **Spring Framework**
176287

177288
Project: https://github.com/mrsarm/jshell-plugin
178289

build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ plugins {
22
id 'com.gradle.plugin-publish' version '0.11.0'
33
id 'maven-publish'
44
id 'groovy'
5+
id 'java-library'
56
}
67

78
group 'com.github.mrsarm'
8-
version '1.0.0-RC1'
9+
version '1.0.0'
910

1011
sourceCompatibility = 9
1112
targetCompatibility = 9

src/main/groovy/com/github/mrsarm/jshell/plugin/JShellPlugin.groovy

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,56 +18,79 @@ package com.github.mrsarm.jshell.plugin
1818
import jdk.jshell.tool.JavaShellToolBuilder
1919
import org.gradle.api.Plugin
2020
import org.gradle.api.Project
21+
import org.gradle.api.Task
2122
import org.gradle.api.tasks.JavaExec
2223

2324
class JShellPlugin implements Plugin<Project> {
2425

25-
@Override
26-
void apply(Project project) {
27-
def jshellTask = project.tasks.create('jshell')
26+
private String[] shellArgs
27+
28+
// This task could be merged with the main task in just one,
29+
// the problem is that the main task is a JavaExec one,
30+
// and at least for now I couldn't find a way
31+
// to get the dependencies list with this type
32+
private Task createJshellSetupTask(Project project) {
33+
Task jshellTask = project.tasks.create('jshellSetup')
2834
def classesTask = project.tasks.find { it.name == "classes" }
2935
if (classesTask) {
3036
jshellTask.dependsOn classesTask
31-
} else {
32-
// Some multi-module projects may not have the :classes task
33-
jshellTask.logger.warn ":jshell task :classes not found, be sure to compile the project first"
3437
}
3538
jshellTask.doLast {
39+
if (!jshellTask.dependsOn) {
40+
// Some multi-module projects may not have the :classes task
41+
jshellTask.logger.warn ":jshell task :classes not found, be sure to compile the project first"
42+
}
3643
Set pathSet = []
3744
project.tasks.withType(JavaExec) {
38-
pathSet.addAll(classpath.findAll{ it.exists() })
45+
pathSet.addAll(classpath.findAll { it.exists() })
3946
}
4047
project.subprojects.each {
4148
it.tasks.withType(JavaExec) {
42-
pathSet.addAll(classpath.findAll{ it.exists() })
49+
pathSet.addAll(classpath.findAll { it.exists() })
4350
}
4451
}
45-
Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader()) // promote class loader
4652
def path = pathSet.join(System.properties['os.name'].toLowerCase().contains('windows') ? ';' : ':')
4753
jshellTask.logger.info(":jshell executing with --class-path \"{}\"", path)
48-
String[] args = [
54+
shellArgs = [
4955
"--class-path", path,
5056
"--startup", "DEFAULT",
5157
"--startup", "PRINTING"
5258
]
53-
if (project.findProperty("jshell.startup")) {
59+
if (project.findProperty("jshell.startup") == "") {
60+
// Nothing, just avoid to run the startup.jsh if exists
61+
}
62+
else if (project.findProperty("jshell.startup")) {
5463
def jshellStartup = project.findProperty("jshell.startup")
5564
jshellTask.logger.info(":jshell executing with --startup DEFAULT --startup PRINTING " +
5665
"--startup \"{}\"", jshellStartup)
57-
args = args + (String[]) ["--startup", jshellStartup]
58-
} else {
66+
shellArgs = shellArgs + (String[]) ["--startup", jshellStartup]
67+
}
68+
else {
5969
def startupJsh = new File("${project.projectDir}/startup.jsh")
6070
if (startupJsh.exists()) {
6171
def startupJshPath = startupJsh.absolutePath
6272
jshellTask.logger.info(":jshell executing with --startup DEFAULT --startup PRINTING" +
6373
" --startup \"{}\"", startupJshPath)
64-
args = args + (String[]) ["--startup", startupJshPath]
74+
shellArgs = shellArgs + (String[]) ["--startup", startupJshPath]
6575
} else {
6676
jshellTask.logger.info(":jshell did not find a startup.jsh script at the project dir " +
6777
"nor a `jshell.startup` configuration")
6878
}
6979
}
70-
JavaShellToolBuilder.builder().run(args)
80+
}
81+
return jshellTask
82+
}
83+
84+
@Override
85+
void apply(Project project) {
86+
Task jshellSetupTask = createJshellSetupTask(project)
87+
Task jshellTask = project.tasks.create('jshell')
88+
jshellTask.group = 'application'
89+
jshellTask.description = 'Runs a JShell session with all the code and dependencies.'
90+
jshellTask.dependsOn jshellSetupTask
91+
jshellTask.doLast {
92+
Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader()) // promote class loader
93+
JavaShellToolBuilder.builder().run(shellArgs)
7194
}
7295
}
7396
}

0 commit comments

Comments
 (0)