This version is still in development and is not considered stable yet. For the latest stable version, please use Spring Shell 3.3.3! |
Building
This section covers how to build a Spring Shell application.
Starters
-
Spring Shell Starters
Name | Description |
---|---|
spring-shell-starter |
Basic Spring Shell modules |
spring-shell-starter-jansi |
With JLine jansi provider |
spring-shell-starter-jni |
With JLine jni provider |
spring-shell-starter-jna |
With JLine jna provider |
spring-shell-starter-ffm |
With JLine ffm provider (requires JDK22+) |
spring-shell-starter-test |
Spring Shell testing support |
Terminal Providers
Interacting with an underlying terminal where your program is running has traditionally been relatively complex process while it may look like there’s not that much happening as it’s all just text.
Remember all those old manual typewriters or matrix printers? A character is printed where a cursor is which then need to be moved if printing in a different position. In a nutshell that’s how current terminal emulators work.
To access and understand existing terminal emulator environment better
JLine can use native code via its own shared libraries. JLine detects
which providers are present and then makes a choice which one to use.
Traditionally there’s been 3 providers, jansi
, jni
and jna
which
should all provide same functionalities.
Our starters can be used to spesifically pick some of these JLine providers.
FFM
With JDK22
a Foreign Function and Memory API came out from a preview
which is supposed to be a replacement for JNI
providing much better
and safer native API.
Starting from 3.4.x
we’ve added a support to compile Spring Shell
application with JLine
ffm
terminal provider. This obviously mean
that application needs to be run with JDK22+
. There is a new JDK
intermediate release every 6 months and long term support(LTS) release
every 2 years. Until there’s an existing LTS release Spring Shell can
align with Spring Framework we will use latest JDK release. Obviously
this means that you may need to upgrade your JDK in an inconvenient
time if you choose to use ffm
. We’re also bound to JDK version
JLine
itself uses to compile its ffm
parts.
FFM itself will cause jvm to print warnings when some part of it are used. These warnings are obviously annoying with terminal applications as it may interfere and cause a little bit of a mess. In future JDK versions these warnings will also be added for an older JNI modules and at some point these warnings will be changed into hard errors. User will be required to enable these native "unsafe" parts manually.
JVM option for this in a command line is:
--enable-native-access=ALL-UNNAMED
If you have a jar file you can have this setting in its META-INF/MANIFEST.MF
.
Enable-Native-Access: ALL-UNNAMED
Which can be added during a build i.e. if using gradle:
tasks.named("bootJar") {
manifest {
attributes 'Enable-Native-Access': 'ALL-UNNAMED'
}
}
What comes for enabling native parts in a JDK, JLine has been proactive and already has a check for this and will throw error if native access is not enabled. |
Native Support
Support for compiling Spring Shell application into a GraalVM binary mostly comes from Spring Framework and Spring Boot where feature is called AOT. Ahead of Time means that application context is prepared during the compilation time to being ready for GraalVM generation.
Building atop of AOT features from a framework Spring Shell has its own GraalVM configuration providing hints what should exist in a binary. Usually trouble comes from a 3rd party libraries which doesn’t yet contain GraalVM related configurations or those configurations are incomplete.
It is requred to use GraalVM Reachability Metadata Repository which
provides some missing hints for 3rd party libraries. Also you need to have
GraalVM installed and JAVA_HOME pointing to that.
|
For gradle add graalvm’s native plugin and configure metadata repository.
plugins {
id 'org.graalvm.buildtools.native' version '0.9.16'
}
graalvmNative {
metadataRepository {
enabled = true
}
}
When gradle build is run with ./gradlew nativeCompile
you should get binary
under build/native/nativeCompile
directory.
For maven
use spring-boot-starter-parent
as parent and you’ll get native
profile which can be used to do a compilation. You need to configure metadata repository
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<configuration>
<metadataRepository>
<enabled>true</enabled>
</metadataRepository>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
If you rely on spring-boot-starter-parent it manages native-maven-plugin
version which is kept up to date.
|
When maven build is run with ./mvnw native:compile -Pnative
you should get binary
under target
directory.
If everything went well this binary can be run as is instead of executing boot application jar via jvm.