Skip to content

Commit fb2d5cd

Browse files
committed
Merge upstream/main
2 parents 02bf0a0 + 0c53571 commit fb2d5cd

206 files changed

Lines changed: 5821 additions & 1255 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/scripts/validate_docs.sh‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@
33
set -e
44
set -x
55

6+
swift run generate-config-docs --check
7+
8+
./scripts/generate-cli-help-snippets.sh
9+
if ! git diff --exit-code -- Snippets/SwiftJavaCLIHelp.txt; then
10+
echo "::error::Snippets/SwiftJavaCLIHelp.txt is out of date with the swift-java CLI's --help output (likely a command's flags or abstract text changed). Run scripts/generate-cli-help-snippets.sh and commit the result."
11+
exit 1
12+
fi
13+
614
DEPENDENCY='.package(url: "https://github.com/swiftlang/swift-docc-plugin", from: "1.0.0")'
715

816
if grep -q "$DEPENDENCY" Package.swift; then

‎.github/workflows/pull_request.yml‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ jobs:
3838
jdk_vendor: ['corretto']
3939
steps:
4040
- uses: actions/checkout@v7
41+
- name: Mark workspace as safe for git
42+
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
4143
- name: Prepare CI Environment
4244
uses: ./.github/actions/prepare_env
4345
- name: Cache .build

‎.licenseignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ gradlew.bat
4545
**/gradlew.bat
4646
**/ci-validate.sh
4747
**/DO_NOT_EDIT.txt
48+
Snippets/__DO_NOT_EDIT_SYMLINK_ONLY__
4849
Plugins/**/_PluginsShared
4950
Plugins/**/0_PLEASE_SYMLINK*
5051
Plugins/PluginsShared/JavaKitConfigurationShared

‎CONTRIBUTING.md‎

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Please ensure to specify the following:
1212
* Commit hash
1313
* Contextual information (e.g. what you were trying to achieve with swift-java)
1414
* Simplest possible steps to reproduce
15-
* More complex the steps are, lower the priority will be.
15+
* The more complex the steps, the lower the priority.
1616
* A pull request with failing test case is preferred, but it's just fine to paste the test case into the issue description.
1717
* Anything that might be relevant in your opinion, such as:
1818
* Swift version or the output of `swift --version`
@@ -24,7 +24,7 @@ Please ensure to specify the following:
2424
Commit hash: b17a8a9f0f814c01a56977680cb68d8a779c951f
2525
2626
Context:
27-
While testing my application that uses with swift-openapi-generator, I noticed that ...
27+
While testing my application that uses swift-java, I noticed that ...
2828
2929
Steps to reproduce:
3030
1. ...
@@ -78,7 +78,7 @@ reflected in your working directory:
7878
% act --bind workflow_call -j soundness --input format_check_enabled=true
7979
```
8080

81-
If you'd like `act` to always run with certain flags, these can be be placed in
81+
If you'd like `act` to always run with certain flags, these can be placed in
8282
an `.actrc` file either in the current working directory or your home
8383
directory, for example:
8484

@@ -88,20 +88,23 @@ directory, for example:
8888
--action-offline-mode
8989
```
9090

91-
For frequent contributors, we recommend adding the script as a [git pre-push hook](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks), which you can do via executing the following command in the project root directory:
91+
For frequent contributors, we recommend running the soundness checks before pushing. You can wire that up as a [git pre-push hook](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks):
9292

9393
```bash
94-
cat << EOF > .git/hooks/pre-push
95-
96-
if [[ -f "scripts/soundness.sh" ]]; then
97-
scripts/soundness.sh
98-
fi
94+
cat << 'EOF' > .git/hooks/pre-push
95+
#!/bin/sh
96+
exec act workflow_call -j soundness --input format_check_enabled=true --input shell_check_enabled=true
9997
EOF
98+
chmod +x .git/hooks/pre-push
10099
```
101100

102-
Which makes the script execute, and only allow the `git push` to complete if the check has passed.
101+
This only allows the `git push` to complete if the checks pass.
102+
103+
In the case of formatting issues, `git add` the formatting changes and attempt the push again.
104+
105+
### Regenerating generated docs
103106

104-
In the case of formatting issues, you can then `git add` the formatting changes, and attempt the push again.
107+
Some documentation is generated from source and checked in, so CI can catch it drifting out of date. If you changed `Configuration.swift` or a CLI command's flags/help text, run `scripts/generate-docs.sh` and commit the generated changes.
105108

106109
## How to contribute your work
107110

‎Package.swift‎

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,15 @@ if let localPath = Context.environment["SWIFT_JAVA_JNI_CORE_PATH"] {
1111
swiftJavaJNICoreDep = .package(url: "https://github.com/swiftlang/swift-java-jni-core", branch: "main")
1212
}
1313

14-
// Set SWIFTJAVA_DOCC_PLUGIN_INSTALL=1 to install the docc-plugin automatically.
14+
// Set SWIFTJAVA_DOCC_PLUGIN_INSTALL=1 to install the docc-plugin automatically,
15+
// or DOCC_PLUGIN_PATH=<path> to point at a local checkout.
1516
// This is a workaround because swift-subprocess includes the plugin explicitly,
1617
// which breaks tools trying to add `swift package add-dependency` the plugin
1718
// to swift-java because it thinks the plugin was already added, but it is not.
1819
let extraDependencies: [Package.Dependency]
19-
if Context.environment["SWIFTJAVA_DOCC_PLUGIN_INSTALL"] == "1" {
20+
if let localPath = Context.environment["DOCC_PLUGIN_PATH"] {
21+
extraDependencies = [.package(path: localPath)]
22+
} else if Context.environment["SWIFTJAVA_DOCC_PLUGIN_INSTALL"] == "1" {
2023
extraDependencies = [
2124
.package(url: "https://github.com/swiftlang/swift-docc-plugin", from: "1.5.0")
2225
]
@@ -429,6 +432,23 @@ let package = Package(
429432
]
430433
),
431434

435+
// Dev-time tool: regenerates the "Supported configuration options" table in
436+
// `Sources/SwiftJavaDocumentation/Documentation.docc/SwiftJavaConfigFile.md`
437+
// straight from the doc comments on `Configuration.swift` and the enums it
438+
// references, so the two never drift apart.
439+
//
440+
// Run manually via `swift run generate-config-docs`; CI validates freshness
441+
// with `swift run generate-config-docs --check`.
442+
.executableTarget(
443+
name: "generate-config-docs",
444+
dependencies: [
445+
.product(name: "SwiftParser", package: "swift-syntax"),
446+
.product(name: "SwiftSyntax", package: "swift-syntax"),
447+
.product(name: "ArgumentParser", package: "swift-argument-parser"),
448+
],
449+
path: "Sources/GenerateConfigDocs"
450+
),
451+
432452
.plugin(
433453
name: "_StaticBuildConfigPlugin",
434454
capability: .buildTool(),

‎README.md‎

Lines changed: 51 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ This project contains tools and libraries that facilitate **Swift & Java Interop
77

88
## Introduction
99

10-
If you'd like to check out a quick introduction to Swift & Java interoperability, you may be interested in this presentation from WWDC25: [WWDC25: Explore Swift and Java interoperability](https://www.youtube.com/watch?v=QSHO-GUGidA).
10+
For a quick introduction to Swift & Java interoperability, see the WWDC25 session [Explore Swift and Java interoperability](https://www.youtube.com/watch?v=QSHO-GUGidA).
1111

12-
While we work on more quickstarts and documentation, please refer to the Sample projects located in [Samples/](Samples/) that showcase the various ways you can use swift-java in your Swift or Java projects.
12+
While we work on more quickstarts and documentation, refer to the sample projects in [Samples/](Samples/), which showcase the various ways to use swift-java in Swift or Java projects.
1313

1414
## Dependencies
1515

@@ -42,18 +42,17 @@ sdk install java 25.0.1-amzn
4242

4343
## Self-publish supporting Java libraries
4444

45-
Swift-java relies on supporting libraries that are under active development and not yet published to Maven Central. To use the project, you'll need to self-publish these libraries locally so your Java project can depend on them.
45+
swift-java relies on supporting libraries that are under active development and not yet published to Maven Central. To use the project, you'll need to self-publish these libraries locally so your Java project can depend on them.
4646

47-
To publish the libraries to your local maven repository (`$HOME/.m2`), you can run:
47+
To publish the libraries to your local maven repository (`$HOME/.m2`), run this in `swift-java/`:
4848

49-
```
50-
// in swift-java/
49+
```bash
5150
./gradlew publishToMavenLocal
5251
```
5352

54-
To consume these libraries in your Java project built using Gradle, you can then include the local repository in the repositories to resolve dependencies from:
53+
To consume these libraries in your Java project built using Gradle, include the local repository in the repositories to resolve dependencies from:
5554

56-
```
55+
```kotlin
5756
repositories {
5857
mavenLocal()
5958
mavenCentral()
@@ -62,65 +61,66 @@ repositories {
6261

6362
We anticipate simplifying this in the future.
6463

65-
## SwiftJava macros
64+
## SwiftJava macros: calling Java from Swift
6665

67-
SwiftJava is a Swift library offering macros which simplify writing JNI code "by hand" but also calling Java code from Swift.
66+
SwiftJava is a Swift library offering macros which simplify writing JNI code "by hand", and calling Java code from Swift.
6867

69-
It is possible to generate Swift bindings to Java libraries using SwiftJava by using the `swift-java wrap-java` command.
68+
You can also generate Swift bindings to Java libraries with the `swift-java wrap-java` command.
7069

7170
Required language/runtime versions:
72-
- **JDK 17+**, any recent JDK installation should be sufficient, as only general reflection and JNI APIs are used by this integratio
71+
- **JDK 17+**, any recent JDK installation should be sufficient, as only general reflection and JNI APIs are used by this integration
7372
- **Swift 6.2.x**, because the library uses modern Swift macros
7473

75-
**swift-java jextract**
74+
## swift-java jextract: calling Swift from Java
75+
76+
`jextract` is a source generator which **generates Java bindings to existing Swift libraries**.
77+
Its inputs are Swift sources or packages, and its outputs are the generated Swift and Java code needed to call those functions efficiently from Java.
7678

77-
Is a source generator which will **generate Java bindings to existing Swift libraries**.
78-
Its inputs are Swift sources or packages, and outputs are generated Swift and Java code necessary to call these functions efficiently from Java.
79+
It has two modes, `ffm` and `jni`.
7980

80-
## swift-java jextract --mode=ffm (default)
81+
### swift-java jextract --mode=ffm (default)
8182

82-
This mode provides the most flexibility and performance, and allows to decrease the amount of data being copied between Swift and Java.
83-
This does require the use of the relatively recent [JEP-454: Foreign Function & Memory API](https://openjdk.org/jeps/454), which is only available since JDK22, and will become part of JDK LTS releases with JDK 25 (depending on your JDK vendor).
83+
This mode offers the most flexibility and performance, and can reduce the amount of data copied between Swift and Java.
84+
It requires [JEP-454: Foreign Function & Memory API](https://openjdk.org/jeps/454), which is final since JDK 22.
8485

8586
This is the primary way we envision calling Swift code from server-side Java libraries and applications.
8687

8788
Required language/runtime versions:
8889
- **Swift 6.2**, because of dependence on rich swift interface files
8990
- **JDK 25+**
90-
- We are validating the implementation using the currently supported non-LTE release, which at present means JDK-25.
91+
- We validate the implementation against the currently supported non-LTS release, which at present means JDK 25.
9192

92-
## swift-java jextract --mode=jni
93+
### swift-java jextract --mode=jni
9394

94-
In this mode, the generated sources will use the legacy JNI approach to calling native code.
95+
In this mode the generated sources use JNI to call native code.
9596

96-
This mode is more limited in some performance and flexibility that it can offer, however it is the most compatible, since even very old JVM's as well as even Android systems can be supported by this mode.
97-
We recommend this mode when FFM is not available, or wide ranging deployment compatibility is your priority. When performance is paramaunt, we recommend the FFM mode instead.
97+
This mode offers less performance and flexibility than FFM, but it is the most compatible: it works on older JVMs as well as on Android.
98+
Use it when FFM is not available, or when wide deployment compatibility is your priority. When performance is paramount, prefer FFM.
9899

99100
Required language/runtime versions:
100-
- **Swift 6.2**, because of dependence on rich swift interface files
101-
- **Java 7+**, including
102-
101+
- **Swift 6.2**, because of dependence on rich swift interface files
102+
- **JDK 17+**; the generated Java sources target the `javaSourceLevel` setting, which supports 17 through 25 (default 22)
103103

104104
## Development and Testing
105105

106106
This project contains multiple builds, living side by side together.
107107

108108
You will need to have:
109109
- Swift (6.2.x+)
110-
- Java (25+ for FFM, even though we support lower JDK targets)
110+
- Java (25+ to build this project, even though the published libraries target lower JDK versions)
111111
- Gradle (installed by "Gradle wrapper" automatically when you run gradle through `./gradlew`)
112112

113113
### Preparing your environment
114114

115-
Install **Swift**, the easiest way to do this is to use **Swiftly**: [swift.org/install/](https://www.swift.org/install/).
116-
This should automatically install a recent Swift, but you can always make sure by running:
115+
Install **Swift**; the easiest way is [Swiftly](https://www.swift.org/install/).
116+
This installs a recent Swift, but you can pin the version explicitly:
117117

118118
```bash
119119
swiftly install 6.2 --use
120120
```
121121

122-
Install a recent enough Java distribution. We validate this project using Corretto so you can choose to use that as well,
123-
however any recent enough Java distribution should work correctly. You can use sdkman to install Java:
122+
Install a recent enough Java distribution. We validate this project using Corretto, so you may want to use that as well,
123+
though any recent enough distribution should work. You can use sdkman to install Java:
124124

125125
```bash
126126
# Install sdkman from: https://sdkman.io
@@ -142,52 +142,51 @@ export JAVA_HOME="$(sdk home java current)"
142142

143143
### Testing your changes
144144

145-
Many tests, including source generation tests, are written in Swift and you can execute them all by running the
146-
swift package manager test command:
145+
Many tests, including source generation tests, are written in Swift. Run them all with:
147146

148147
```bash
149148
> swift test
150149
```
151150

152151
When adding tests in `Tests/...` targets, you can run these tests (or filter a specific test using `swift test --filter type-or-method-name`).
153152

154-
Some tests are implemented in Java and therefore need to be executed using Gradle.
155-
Please always use the gradle wrapper (`./gradlew`) to make sure to use the appropriate Gradle version
153+
Some tests are implemented in Java and need to be executed using Gradle.
154+
Always use the Gradle wrapper (`./gradlew`) so the correct Gradle version is used:
156155

157156
```bash
158157
> ./gradlew test
159158
```
160159

161-
> Tip: A lot of the **runtime tests** for code relying on `jextract` are **located in sample apps**,
162-
> so if you need to runtime test any code relying on source generation steps of jextract, consider adding the tests
163-
> to an appropriate Sample. These tests are also executed in CI (which you can check in the `ci-validate.sh` script
164-
> contained in every sample repository).
160+
> Tip: Many of the **runtime tests** for code relying on `jextract` are **located in sample apps**,
161+
> so if you need to runtime test code that depends on jextract's source generation, consider adding the tests
162+
> to an appropriate Sample. These tests also run in CI; see the `ci-validate.sh` script in each sample
163+
> that has one.
165164
166165
### Sample apps & tests
167166

168167
Sample apps are located in the `Samples/` directory, and they showcase full "roundtrip" usage of the library and/or tools.
169168

170-
Samples are build by default by Gradle. Building samples can be skipped by appending the flag `-PskipSamples=true` to a gradle command.
169+
Samples are built by default by Gradle. Building samples can be skipped by appending the flag `-PskipSamples=true` to a gradle command.
171170

172-
#### SwiftJava (Swift -> Java)
171+
#### SwiftJava (calling Java from Swift)
173172

174-
To run a simple app showcasing a Swift process calling into a Java library you can run:
173+
To run a simple app showcasing a Swift process calling into a Java library:
175174

176175
```bash
177-
cd Samples/SwiftJavaExtractFFMSampleApp
178-
./ci-validate.sh # which is just `swift build` and a `java -cp ...` invocation of the compiled program
176+
cd Samples/JavaProbablyPrime
177+
./ci-validate.sh # which is just a `swift run JavaProbablyPrime 1337`
179178
```
180179

181-
#### jextract (Java -> Swift)
180+
#### jextract (calling Swift from Java)
182181

183-
To run a simple example app showcasing the jextract (Java calling Swift) approach you can:
182+
To run a simple example app showcasing a Java program calling into Swift:
184183

185184
```bash
186185
./gradlew Samples:SwiftJavaExtractFFMSampleApp:run
187186
```
188187

189-
This will also generate the necessary sources (by invoking jextract, extracting the `Sources/ExampleSwiftLibrary`)
190-
and generating Java sources in `src/generated/java`.
188+
This also generates the necessary sources (by invoking jextract on `Sources/MySwiftLibrary`)
189+
and the Java sources in `src/generated/java`.
191190

192191
#### Other sample apps
193192

@@ -197,7 +196,7 @@ Please refer to the [Samples](Samples) directory for more sample apps which show
197196

198197
You can run Swift [ordo-one/package-benchmark](https://github.com/ordo-one/package-benchmark) and OpenJDK [JMH](https://github.com/openjdk/jmh) benchmarks in this project.
199198

200-
Swift benchmarks are located under `Benchmarks/` and JMH benchmarks are currently part of the SwiftKit sample project: `Samples/SwiftJavaExtractFFMSampleApp/src/jmh` because they depend on generated sources from the sample.
199+
Swift benchmarks are located under `Benchmarks/`. JMH benchmarks live in `Samples/SwiftJavaExtractFFMSampleApp/src/jmh`, because they depend on sources generated by that sample.
201200

202201
### Swift benchmarks
203202

@@ -217,7 +216,7 @@ cd Samples/SwiftJavaExtractFFMSampleApp
217216
./gradlew jmh
218217
```
219218

220-
Please read documentation of both performance testing tools and understand that results must be interpreted and not just taken at face value. Benchmarking is tricky and environment sensitive task, so please be careful when constructing and reading benchmarks and their results. If in doubt, please reach out on the forums.
219+
Please read the documentation of both performance testing tools, and note that results must be interpreted rather than taken at face value. Benchmarking is tricky and environment sensitive, so be careful when constructing and reading benchmarks and their results. If in doubt, reach out on the forums.
221220

222221
## User Guide
223222

@@ -241,6 +240,6 @@ xcrun docc preview Sources/SwiftJavaDocumentation/Documentation.docc
241240

242241
## Project Status
243242

244-
**This project is under active development. We welcome feedback about any issues you encounter.**
243+
**This project is under active development. We welcome feedback about any issues you encounter.**
245244

246-
There is no guarantee about API stability until the project reaches a 1.0 release.
245+
There is no guarantee of API stability until the project reaches a 1.0 release.

‎Samples/JavaDependencySampleApp/Sources/JavaDependencySample/main.swift‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ print("Start Sample app...")
2828
// TODO: locating the classpath is more complex, need to account for dependencies of our module
2929
let swiftJavaClasspath = findSwiftJavaClasspaths() // scans for .classpath files
3030

31+
// snippet.dependencyUsage
3132
// 1) Start a JVM with appropriate classpath
3233
let jvm = try JavaVirtualMachine.shared(classpath: swiftJavaClasspath)
3334

@@ -50,5 +51,6 @@ for record in try CSVFormatClass.RFC4180.parse(reader)!.getRecords()! {
5051
print("Field: \(field)")
5152
}
5253
}
54+
// snippet.end
5355

5456
print("Done.")

‎Samples/JavaKitSampleApp/Package.swift‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ let package = Package(
2222
],
2323

2424
dependencies: [
25-
.package(name: "swift-java", path: "../../")
25+
.package(name: "swift-java", path: "../../"),
26+
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.5.0"),
2627
],
2728

2829
targets: [
@@ -32,6 +33,7 @@ let package = Package(
3233
.product(name: "SwiftJava", package: "swift-java"),
3334
.product(name: "JavaUtilFunction", package: "swift-java"),
3435
.product(name: "JavaUtilJar", package: "swift-java"),
36+
.product(name: "ArgumentParser", package: "swift-argument-parser"),
3537
],
3638
swiftSettings: [
3739
.swiftLanguageMode(.v5)

0 commit comments

Comments
 (0)