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
# JavaKit Example: Using a Java library from Swift
2
+
3
+
This package contains an example program that demonstrates importing a Java library distributed as a Jar file into Swift and using some APIs from that library. It demonstrates how to:
4
+
5
+
* Use the Java2Swift tool to discover the classes in a Jar file and make them available in Swift
6
+
* Layer Swift wrappers for Java classes as separate Swift modules using Java2Swift
7
+
* Access static methods of Java classes from Swift
8
+
9
+
This example wraps an [open-source Java library](https://github.com/gazman-sdk/quadratic-sieve-Java) implementing the [Sieve of Eratosthenes](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes) algorithm for finding prime numbers, among other algorithms. To get started, clone that repository and build a Jar file containing the library:
Copy file name to clipboardExpand all lines: USER_GUIDE.md
+127-4Lines changed: 127 additions & 4 deletions
Original file line number
Diff line number
Diff line change
@@ -11,7 +11,7 @@ Before using this package, set the `JAVA_HOME` environment variable to point at
11
11
Existing Java libraries can be wrapped for use in Swift with the `Java2Swift`
12
12
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 `Java2Swift.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`:
13
13
14
-
```
14
+
```json
15
15
{
16
16
"classes" : {
17
17
"java.math.BigInteger" : "BigInteger"
@@ -91,6 +91,132 @@ if bigInt.isProbablePrime(10) {
91
91
92
92
Swift ensures that the Java garbage collector will keep the object alive until `bigInt` (and any copies of it) are been destroyed.
93
93
94
+
### Importing a Jar file into Swift
95
+
96
+
Java libraries are often distributed as Jar files. The `Java2Swift` tool can inspect a Jar file to create a `Java2Swift.config` file that will wrap all of the public classes for use in Swift. Following the example in `swift-java/Samples/JavaSieve`, we will wrap a small [Java library for computing prime numbers](https://github.com/gazman-sdk/quadratic-sieve-Java) for use in Swift. Assuming we have a Jar file `QuadraticSieve-1.0.jar` in the package directory, run the following command:
97
+
98
+
```swift
99
+
swift run Java2Swift --module-name JavaSieve --jar QuadraticSieve-1.0.jar
100
+
```
101
+
102
+
The resulting configuration file will look something like this:
As with the previous `JavaProbablyPrime` sample, the `JavaSieve` target in `Package.swift` should depend on the `swift-java` package modules (`JavaKit`, `JavaKitVM`) and apply the `Java2Swift` plugin. This makes all of the Java classes found in the Jar file available to Swift within the `JavaSieve` target.
138
+
139
+
If you inspect the build output, there are a number of warnings that look like this:
140
+
141
+
```swift
142
+
warning: Unable to translate 'com.gazman.quadratic_sieve.QuadraticSieve' method 'generateN': Java class 'java.math.BigInteger' has not been translated into Swift
143
+
```
144
+
145
+
These warnings mean that some of the APIs in the Java library aren't available in Swift because their prerequisite types are missing. To address these warnings and get access to these APIs from Swift, we can wrap those Java classes. Expanding on the prior `JavaProbablyPrime` example, we define a new SwiftPM target `JavaMath` for the various types in the `java.math` package:
Then define a a Java2Swift configuration file in `Sources/JavaMath/Java2Swift.config` to bring in the types we need:
160
+
161
+
```json
162
+
{
163
+
"classes" : {
164
+
"java.math.BigDecimal" : "BigDecimal",
165
+
"java.math.BigInteger" : "BigInteger",
166
+
"java.math.MathContext" : "MathContext",
167
+
"java.math.RoundingMode" : "RoundingMode",
168
+
"java.lang.Integer" : "JavaInteger",
169
+
}
170
+
}
171
+
```
172
+
173
+
Finally, make the `JavaSieve` target depend on `JavaMath` and rebuild: the warnings related to `java.math.BigInteger` and friends will go away, and Java APIs that depend on them will now be available in Swift!
174
+
175
+
### Calling Java static methods from Swift
176
+
177
+
There are a number of prime-generation facilities in the Java library we imported. However, we are going to focus on the simple Sieve of Eratosthenes, which is declared like this in Java:
In Java, static methods are called as members of the class itself. For Swift to call a Java static method, it needs a representation of the Java class. This is expressed as an instance of the generic type `JavaClass`, which can be created in a particular JNI environment like this:
186
+
187
+
```swift
188
+
let sieveClass =try JavaClass<SieveOfEratosthenes>(in: jvm.environment())
189
+
```
190
+
191
+
Now we can call Java's static methods on that class as instance methods on the `JavaClass` instance, e.g.,
192
+
193
+
```swift
194
+
let primes = sieveClass.findPrimes(100) // returns a List<JavaInteger>?
195
+
```
196
+
197
+
Putting it all together, we can define a main program in `Sources/JavaSieve/main.swift` that looks like this:
198
+
199
+
```swift
200
+
importJavaKit
201
+
importJavaKitVM
202
+
203
+
let jvm =try JavaVirtualMachine.shared(classPath: ["QuadraticSieve-1.0.jar"])
204
+
do {
205
+
let sieveClass =try JavaClass<SieveOfEratosthenes>(in: jvm.environment())
206
+
for prime in sieveClass.findPrimes(100)! {
207
+
print("Found prime: \(prime.intValue())")
208
+
}
209
+
} catch {
210
+
print("Failure: \(error)")
211
+
}
212
+
```
213
+
214
+
Note that we are passing the Jar file in the `classPath` argument when initializing the `JavaVirtualMachine` instance. Otherwise, the program will fail with an error because it cannot find the Java class `com.gazman.quadratic_sieve.primes.SieveOfEratosthenes`.
215
+
216
+
## Using Java libraries from Swift
217
+
218
+
This section describes how Java libraries and mapped into Swift and their use from Swift.
219
+
94
220
### Translation from Java classes into Swift
95
221
96
222
Each Java class that can be used from Swift is translated to a Swift `struct` that provides information about the Java class itself and is populated with the Swift projection of each of its constructors, methods, and fields. For example, here is an excerpt of the Swift projection of [`java.util.jar.JarFile`](https://docs.oracle.com/javase/8/docs/api/java/util/jar/JarFile.html):
@@ -521,6 +647,3 @@ public final class SomeModule ... {
0 commit comments