You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: Sources/JavaKit/Documentation.docc/JavaKit.md
+3-251Lines changed: 3 additions & 251 deletions
Original file line number
Diff line number
Diff line change
@@ -2,11 +2,7 @@
2
2
3
3
Library and tools to make it easy to use Java libraries from Swift using the Java Native Interface (JNI).
4
4
5
-
## Getting started
6
-
7
-
Before using this package, set the `JAVA_HOME` environment variable to point at your Java installation. Failing to do so will produce errors when processing the package manifest. Alternatively, you can put the path to your Java installation in the file `~/.java_home`.
8
-
9
-
### Using Java libraries from Swift
5
+
## JavaKit: Using Java libraries from Swift
10
6
11
7
Existing Java libraries can be wrapped for use in Swift with the `swift-java`
12
8
tool. In a Swift program, the most direct way to access a Java API is to use the SwiftPM plugin to provide Swift wrappers for the Java classes. To do so, add a configuration file `swift-java.config` into the source directory for the Swift target. This is a JSON file that specifies Java classes and the Swift type name that should be generated to wrap them. For example, the following file maps `java.math.BigInteger` to a Swift type named `BigInteger`:
@@ -282,7 +278,7 @@ Java native methods that throw any checked exception should be marked as `throws
282
278
283
279
The Swift implementations of Java `native` constructors and static methods require an additional Swift parameter `environment: JNIEnvironment? = nil`, which will receive the JNI environment in which the function is being executed. In case of nil, the `JavaVirtualMachine.shared().environment()` value will be used.
284
280
285
-
## Using Java libraries from Swift
281
+
## JavaKit: Using Java libraries from Swift
286
282
287
283
This section describes how Java libraries and mapped into Swift and their use from Swift.
Java interfaces are similar to classes, and are projected into Swift in much the same way, but with the macro `JavaInterface`. The `JavaInterface` macro takes the Java interface name as well as any Java interfaces that this interface extends. As an example, here is the Swift projection of the [`java.util.Enumeration`](https://docs.oracle.com/javase/8/docs/api/java/util/Enumeration.html) generic interface:
426
422
@@ -437,247 +433,3 @@ public struct Enumeration<E: AnyJavaObject> {
437
433
publicfuncnextElement() -> JavaObject!
438
434
}
439
435
```
440
-
441
-
## Translating Java classes with `swift-java`
442
-
443
-
The `swift-java` is a Swift program that uses Java's runtime reflection facilities to translate the requested Java classes into their Swift projections. The output is a number of Swift source files, each of which corresponds to a
444
-
single Java class. The `swift-java` can be executed like this:
445
-
446
-
```
447
-
swift-java
448
-
```
449
-
450
-
to produce help output like the following:
451
-
452
-
```
453
-
OVERVIEW: Generate sources and configuration for Swift and Java interoperability.
454
-
455
-
USAGE: swift-java <options> <subcommand>
456
-
457
-
OPTIONS:
458
-
--depends-on <depends-on>
459
-
A Java2Swift configuration file for a given Swift module name on which this module depends, e.g., JavaKitJar=Sources/JavaKitJar/Java2Swift.config. There should be one of these options for each Swift module that this
460
-
module depends on (transitively) that contains wrapped Java sources.
461
-
--jar Specifies that the input is a Jar file whose public classes will be loaded. The output of Java2Swift will be a configuration file (Java2Swift.config) that can be used as input to a subsequent Java2Swift invocation to
462
-
generate wrappers for those public classes.
463
-
--fetch Fetch dependencies from given target (containing swift-java configuration) or dependency string
The names of Java classes whose declared native methods will be implemented in Swift.
466
-
--output-swift <output-swift>
467
-
The directory where generated Swift files should be written. Generally used with jextract mode.
468
-
--output-java <output-java>
469
-
The directory where generated Java files should be written. Generally used with jextract mode.
470
-
--java-package <java-package>
471
-
The Java package the generated Java code should be emitted into.
472
-
-c, --cache-directory <cache-directory>
473
-
Directory where to write cached values (e.g. swift-java.classpath files)
474
-
-o, --output-directory <output-directory>
475
-
The directory in which to output the generated Swift files or the SwiftJava configuration file.
476
-
--input-swift <input-swift>
477
-
Directory containing Swift files which should be extracted into Java bindings. Also known as 'jextract' mode. Must be paired with --output-java and --output-swift.
478
-
-l, --log-level <log-level>
479
-
Configure the level of logs that should be printed (values: trace, debug, info, notice, warning, error, critical; default: log level)
480
-
--cp, --classpath <cp> Class search path of directories and zip/jar files from which Java classes can be loaded.
481
-
-f, --filter-java-package <filter-java-package>
482
-
While scanning a classpath, inspect only types included in this package
483
-
-h, --help Show help information.
484
-
485
-
SUBCOMMANDS:
486
-
configure Configure and emit a swift-java.config file based on an input dependency or jar file
487
-
resolve Resolve dependencies and write the resulting swift-java.classpath file
488
-
489
-
See 'swift-java help <subcommand>' for detailed help.
490
-
```
491
-
492
-
For example, the `JavaKitJar` library is generated with this command line:
493
-
494
-
```swift
495
-
swift run swift-java --module-name JavaKitJar --depends-on JavaKit=Sources/JavaKit/swift-java.config-o Sources/JavaKitJar/generated Sources/JavaKitJar/swift-java.config
496
-
```
497
-
498
-
The `--swift-module JavaKitJar` parameter describes the name of the Swift module in which the code will be generated.
499
-
500
-
The `--depends-on` option is followed by the swift-java configuration files for any library on which this Swift library depends. Each `--depends-on` option is of the form `<swift library name>=<swift-java.config path>`, and tells swift-java which other Java classes have already been translated to Swift. For example, if your Java class uses `java.net.URL`, then you should include
501
-
`JavaKitNetwork`'s configuration file as a dependency here.
502
-
503
-
The `-o` option specifies the output directory. Typically, this will be `Sources/<module name>/generated` or similar to keep the generated Swift files separate from any hand-written ones. To see the output on the terminal rather than writing files to disk, pass `-` for this option.
504
-
505
-
Finally, the command line should contain the `swift-java.config` file containing the list of classes that should be translated into Swift and their corresponding Swift type names. The tool will output a single `.swift` file for each class, along with warnings for any public API that cannot be translated into Swift. The most common warnings are due to missing Swift projections for Java classes. For example, here we have not translated (or provided the translation manifests for) the Java classes
506
-
`java.util.zip.ZipOutputStream` and `java.io.OutputStream`:
507
-
508
-
```
509
-
warning: Unable to translate 'java.util.jar.JarOutputStream' superclass: Java class 'java.util.zip.ZipOutputStream' has not been translated into Swift
510
-
warning: Unable to translate 'java.util.jar.JarOutputStream' constructor: Java class 'java.io.OutputStream' has not been translated into Swift
511
-
warning: Unable to translate 'java.util.jar.JarInputStream' method 'transferTo': Java class 'java.io.OutputStream' has not been translated into Swift
512
-
```
513
-
514
-
The result of such warnings is that certain information won't be statically available in Swift, e.g., the superclass won't be known (so we will assume it is `JavaObject`), or the specified constructors or methods won't be translated. If you don't need these APIs, the warnings can be safely ignored. The APIs can still be called dynamically via JNI.
515
-
516
-
The `--jar` option changes the operation of `swift-java`. Instead of wrapping Java classes in Swift, it scans the given input Jar file to find all public classes and outputs a configuration file `swift-java.config` mapping all of the Java classes in the Jar file to Swift types. The `--jar` mode is expected to be used to help import a Java library into Swift wholesale, after which swift-java should invoked again given the generated configuration file.
517
-
518
-
### Under construction: Create a Java class to wrap the Swift library
519
-
520
-
**NOTE**: the instructions here work, but we are still smoothing out the interoperability story.
521
-
522
-
All JavaKit-based applications start execution within the Java Virtual Machine. First, define your own Java class that loads your native Swift library and provides a `native` entry point to get into the Swift code. Here is a minimal Java class that has all of the program's logic written in Swift, including `main`:
523
-
524
-
525
-
```java
526
-
packageorg.swift.javakit;
527
-
528
-
publicclassHelloSwiftMain {
529
-
static {
530
-
System.loadLibrary("HelloSwift");
531
-
}
532
-
533
-
publicnativestaticvoidmain(String[] args);
534
-
}
535
-
```
536
-
537
-
Compile this into a `.class` file with `javac` before we build the Swift half, e.g.,:
The Java class created above loads a native library `HelloSwift` that needs to contain a definition of the `main` method in the class `org.swift.javakit.HelloSwiftMain`. `HelloSwift` should be defined as a SwiftPM dynamic library product, e.g.,
546
-
547
-
```swift
548
-
products: [
549
-
.library(
550
-
name: "HelloSwift",
551
-
type: .dynamic,
552
-
targets: ["HelloSwift"]
553
-
),
554
-
]
555
-
```
556
-
557
-
with an associated target that depends on `JavaKit`:
Go ahead and build this library with `swift build`, and find the path to the directory containing the resulting shared library (e.g., `HelloSwift.dylib`, `HelloSwift.so`, or `HelloSwift.dll`, depending on platform). It is often in `.build/debug/` if you ran `swift build` on the command line.
584
-
585
-
### Putting it all together!
586
-
587
-
Finally, run this program on the command line like this:
This will prints the command-line arguments `-v` and `argument` as seen by Swift.
594
-
595
-
### Bonus: Swift argument parser
596
-
597
-
The easiest way to build a command-line program in Swift is with the [Swift argument parser library](https://github.com/apple/swift-argument-parser). We can extend our `HelloSwiftMain` type to conform to `ParsableCommand` and using the Swift argument parser to process the arguments provided by Java:
This repository also includes the `jextract-swift` tool which is similar to the JDK's [`jextract`](https://github.com/openjdk/jextract/).
634
-
635
-
This approach is using Java's most recent (stable in JDK22) Foreign function and Memory APIs, collectively known as "Project Panama". You can read more about it here: https://openjdk.org/projects/panama/ It promises much higher performance than traditional approaches using JNI, and is primarily aimed for calling native code from a Java application.
636
-
637
-
:warning: This feature requires JDK 22. The recommended way to install/manage JDKs is using [sdkman](https://sdkman.io):
638
-
639
-
```
640
-
curl -s "https://get.sdkman.io" | bash
641
-
sdk install java 22-open
642
-
643
-
export JAVA_HOME=$(sdk home java 22-open)
644
-
```
645
-
646
-
`jextract-swift` can be pointed at `*.swiftinterface` files and will generate corresponding Java files that use the (new in Java 22) Foreign Function & Memory APIs to expose efficient ways to call "down" into Swift from Java.
647
-
648
-
## JExtract: Swift <-> Java Type mapping
649
-
650
-
TODO: these are not implemented yet.
651
-
652
-
### Closures and Callbacks
653
-
654
-
A Swift function may accept a closure which is used as a callback:
655
-
656
-
```swift
657
-
funccallMe(maybe: () -> ()) {}
658
-
```
659
-
660
-
Minimal support for c-compatible closures is implemented, more documentation soon.
661
-
662
-
663
-
## `jextract-swift` importer behavior
664
-
665
-
Only `public` functions, properties and types are imported.
666
-
667
-
Global Swift functions become static functions on on a class with the same name as the Swift module in Java,
0 commit comments