Skip to content

Commit c4f0019

Browse files
committed
Merge branch 'main' into implement-protocols
2 parents 662d76d + 2ed85e2 commit c4f0019

File tree

15 files changed

+643
-86
lines changed

15 files changed

+643
-86
lines changed

Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/AsyncTest.java

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,31 +26,32 @@
2626
import java.util.OptionalLong;
2727
import java.util.concurrent.CompletableFuture;
2828
import java.util.concurrent.ExecutionException;
29+
import java.util.concurrent.Future;
2930

3031
import static org.junit.jupiter.api.Assertions.*;
3132

3233
public class AsyncTest {
3334
@Test
34-
void asyncSum() {
35-
CompletableFuture<Long> future = MySwiftLibrary.asyncSum(10, 12);
35+
void asyncSum() throws Exception {
36+
Future<Long> future = MySwiftLibrary.asyncSum(10, 12);
3637

37-
Long result = future.join();
38+
Long result = future.get();
3839
assertEquals(22, result);
3940
}
4041

4142
@Test
42-
void asyncSleep() {
43-
CompletableFuture<Void> future = MySwiftLibrary.asyncSleep();
44-
future.join();
43+
void asyncSleep() throws Exception {
44+
Future<Void> future = MySwiftLibrary.asyncSleep();
45+
future.get();
4546
}
4647

4748
@Test
48-
void asyncCopy() {
49+
void asyncCopy() throws Exception {
4950
try (var arena = SwiftArena.ofConfined()) {
5051
MySwiftClass obj = MySwiftClass.init(10, 5, arena);
51-
CompletableFuture<MySwiftClass> future = MySwiftLibrary.asyncCopy(obj, arena);
52+
Future<MySwiftClass> future = MySwiftLibrary.asyncCopy(obj, arena);
5253

53-
MySwiftClass result = future.join();
54+
MySwiftClass result = future.get();
5455

5556
assertEquals(10, result.getX());
5657
assertEquals(5, result.getY());
@@ -59,7 +60,7 @@ void asyncCopy() {
5960

6061
@Test
6162
void asyncThrows() {
62-
CompletableFuture<Void> future = MySwiftLibrary.asyncThrows();
63+
Future<Void> future = MySwiftLibrary.asyncThrows();
6364

6465
ExecutionException ex = assertThrows(ExecutionException.class, future::get);
6566

@@ -70,14 +71,14 @@ void asyncThrows() {
7071
}
7172

7273
@Test
73-
void asyncOptional() {
74-
CompletableFuture<OptionalLong> future = MySwiftLibrary.asyncOptional(42);
75-
assertEquals(OptionalLong.of(42), future.join());
74+
void asyncOptional() throws Exception {
75+
Future<OptionalLong> future = MySwiftLibrary.asyncOptional(42);
76+
assertEquals(OptionalLong.of(42), future.get());
7677
}
7778

7879
@Test
79-
void asyncString() {
80-
CompletableFuture<String> future = MySwiftLibrary.asyncString("hey");
81-
assertEquals("hey", future.join());
80+
void asyncString() throws Exception {
81+
Future<String> future = MySwiftLibrary.asyncString("hey");
82+
assertEquals("hey", future.get());
8283
}
8384
}

Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/MySwiftClassTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,10 @@ void addXWithJavaLong() {
165165
}
166166

167167
@Test
168-
void getAsyncVariable() {
168+
void getAsyncVariable() throws Exception {
169169
try (var arena = SwiftArena.ofConfined()) {
170170
MySwiftClass c1 = MySwiftClass.init(20, 10, arena);
171-
assertEquals(42, c1.getGetAsync().join());
171+
assertEquals(42, c1.getGetAsync().get());
172172
}
173173
}
174174
}

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -509,40 +509,55 @@ extension JNISwift2JavaGenerator {
509509
originalFunctionSignature: SwiftFunctionSignature,
510510
mode: JExtractAsyncFuncMode
511511
) {
512+
// Update translated function
513+
let nativeFutureType: JavaType
514+
let translatedFutureType: JavaType
515+
let completeMethodID: String
516+
let completeExceptionallyMethodID: String
517+
512518
switch mode {
513519
case .completableFuture:
514-
// Update translated function
515-
516-
let nativeFutureType = JavaType.completableFuture(nativeFunctionSignature.result.javaType)
520+
nativeFutureType = .completableFuture(nativeFunctionSignature.result.javaType)
521+
translatedFutureType = .completableFuture(translatedFunctionSignature.resultType.javaType)
522+
completeMethodID = "_JNIMethodIDCache.CompletableFuture.complete"
523+
completeExceptionallyMethodID = "_JNIMethodIDCache.CompletableFuture.completeExceptionally"
524+
525+
case .legacyFuture:
526+
nativeFutureType = .simpleCompletableFuture(nativeFunctionSignature.result.javaType)
527+
translatedFutureType = .future(translatedFunctionSignature.resultType.javaType)
528+
completeMethodID = "_JNIMethodIDCache.SimpleCompletableFuture.complete"
529+
completeExceptionallyMethodID = "_JNIMethodIDCache.SimpleCompletableFuture.completeExceptionally"
530+
}
517531

518-
let futureOutParameter = OutParameter(
519-
name: "$future",
520-
type: nativeFutureType,
521-
allocation: .new
522-
)
532+
let futureOutParameter = OutParameter(
533+
name: "future$",
534+
type: nativeFutureType,
535+
allocation: .new
536+
)
523537

524-
let result = translatedFunctionSignature.resultType
525-
translatedFunctionSignature.resultType = TranslatedResult(
526-
javaType: .completableFuture(translatedFunctionSignature.resultType.javaType),
527-
annotations: result.annotations,
528-
outParameters: result.outParameters + [futureOutParameter],
529-
conversion: .aggregate(variable: nil, [
530-
.print(.placeholder), // Make the downcall
531-
.method(.constant("$future"), function: "thenApply", arguments: [
532-
.lambda(args: ["futureResult$"], body: .replacingPlaceholder(result.conversion, placeholder: "futureResult$"))
533-
])
538+
let result = translatedFunctionSignature.resultType
539+
translatedFunctionSignature.resultType = TranslatedResult(
540+
javaType: translatedFutureType,
541+
annotations: result.annotations,
542+
outParameters: result.outParameters + [futureOutParameter],
543+
conversion: .aggregate(variable: nil, [
544+
.print(.placeholder), // Make the downcall
545+
.method(.constant("future$"), function: "thenApply", arguments: [
546+
.lambda(args: ["futureResult$"], body: .replacingPlaceholder(result.conversion, placeholder: "futureResult$"))
534547
])
535-
)
548+
])
549+
)
536550

537-
// Update native function
538-
nativeFunctionSignature.result.conversion = .asyncCompleteFuture(
539-
swiftFunctionResultType: originalFunctionSignature.result.type,
540-
nativeFunctionSignature: nativeFunctionSignature,
541-
isThrowing: originalFunctionSignature.isThrowing
542-
)
543-
nativeFunctionSignature.result.javaType = .void
544-
nativeFunctionSignature.result.outParameters.append(.init(name: "result_future", type: nativeFutureType))
545-
}
551+
// Update native function
552+
nativeFunctionSignature.result.conversion = .asyncCompleteFuture(
553+
swiftFunctionResultType: originalFunctionSignature.result.type,
554+
nativeFunctionSignature: nativeFunctionSignature,
555+
isThrowing: originalFunctionSignature.isThrowing,
556+
completeMethodID: completeMethodID,
557+
completeExceptionallyMethodID: completeExceptionallyMethodID
558+
)
559+
nativeFunctionSignature.result.javaType = .void
560+
nativeFunctionSignature.result.outParameters.append(.init(name: "result_future", type: nativeFutureType))
546561
}
547562

548563
func translateProtocolParameter(

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,9 @@ extension JNISwift2JavaGenerator {
714714
indirect case asyncCompleteFuture(
715715
swiftFunctionResultType: SwiftType,
716716
nativeFunctionSignature: NativeFunctionSignature,
717-
isThrowing: Bool
717+
isThrowing: Bool,
718+
completeMethodID: String,
719+
completeExceptionallyMethodID: String
718720
)
719721

720722
/// `{ (args) -> return body }`
@@ -1006,7 +1008,9 @@ extension JNISwift2JavaGenerator {
10061008
case .asyncCompleteFuture(
10071009
let swiftFunctionResultType,
10081010
let nativeFunctionSignature,
1009-
let isThrowing
1011+
let isThrowing,
1012+
let completeMethodID,
1013+
let completeExceptionallyMethodID
10101014
):
10111015
var globalRefs: [String] = ["globalFuture"]
10121016

@@ -1033,7 +1037,7 @@ extension JNISwift2JavaGenerator {
10331037
printer.print("environment = try! JavaVirtualMachine.shared().environment()")
10341038
let inner = nativeFunctionSignature.result.conversion.render(&printer, "swiftResult$")
10351039
if swiftFunctionResultType.isVoid {
1036-
printer.print("environment.interface.CallBooleanMethodA(environment, globalFuture, _JNIMethodIDCache.CompletableFuture.complete, [jvalue(l: nil)])")
1040+
printer.print("environment.interface.CallBooleanMethodA(environment, globalFuture, \(completeMethodID), [jvalue(l: nil)])")
10371041
} else {
10381042
let result: String
10391043
if nativeFunctionSignature.result.javaType.requiresBoxing {
@@ -1043,7 +1047,7 @@ extension JNISwift2JavaGenerator {
10431047
result = inner
10441048
}
10451049

1046-
printer.print("environment.interface.CallBooleanMethodA(environment, globalFuture, _JNIMethodIDCache.CompletableFuture.complete, [jvalue(l: \(result))])")
1050+
printer.print("environment.interface.CallBooleanMethodA(environment, globalFuture, \(completeMethodID), [jvalue(l: \(result))])")
10471051
}
10481052
}
10491053

@@ -1065,7 +1069,7 @@ extension JNISwift2JavaGenerator {
10651069
"""
10661070
let catchEnvironment = try! JavaVirtualMachine.shared().environment()
10671071
let exception = catchEnvironment.interface.NewObjectA(catchEnvironment, _JNIMethodIDCache.Exception.class, _JNIMethodIDCache.Exception.constructWithMessage, [String(describing: error).getJValue(in: catchEnvironment)])
1068-
catchEnvironment.interface.CallBooleanMethodA(catchEnvironment, globalFuture, _JNIMethodIDCache.CompletableFuture.completeExceptionally, [jvalue(l: exception)])
1072+
catchEnvironment.interface.CallBooleanMethodA(catchEnvironment, globalFuture, \(completeExceptionallyMethodID), [jvalue(l: exception)])
10691073
"""
10701074
)
10711075
}

Sources/JExtractSwiftLib/JavaTypes/JavaType+JDK.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,9 @@ extension JavaType {
5050
static func completableFuture(_ T: JavaType) -> JavaType {
5151
.class(package: "java.util.concurrent", name: "CompletableFuture", typeParameters: [T.boxedType])
5252
}
53+
54+
/// The description of the type java.util.concurrent.Future<T>
55+
static func future(_ T: JavaType) -> JavaType {
56+
.class(package: "java.util.concurrent", name: "Future", typeParameters: [T.boxedType])
57+
}
5358
}

Sources/JExtractSwiftLib/JavaTypes/JavaType+SwiftKit.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,9 @@ extension JavaType {
8585
}
8686
}
8787

88+
/// The description of the type org.swift.swiftkit.core.SimpleCompletableFuture<T>
89+
static func simpleCompletableFuture(_ T: JavaType) -> JavaType {
90+
.class(package: "org.swift.swiftkit.core", name: "SimpleCompletableFuture", typeParameters: [T.boxedType])
91+
}
92+
8893
}

Sources/SwiftJava/AnyJavaObject.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ extension AnyJavaObject {
6666
javaHolder.object
6767
}
6868

69-
/// Retrieve the environment in which this Java object resides.
69+
/// Retrieve the environment in which this Java object was created.
7070
public var javaEnvironment: JNIEnvironment {
7171
javaHolder.environment
7272
}

Sources/SwiftJava/JavaObject+MethodCalls.swift

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ extension AnyJavaObject {
104104
resultType: Result.Type
105105
) throws -> jmethodID {
106106
// Retrieve the Java class instance from the object.
107-
let environment = javaEnvironment
107+
let environment = try JavaVirtualMachine.shared().environment()
108+
108109
let thisClass = try environment.translatingJNIExceptions {
109110
environment.interface.GetObjectClass(environment, javaThis)
110111
}!
@@ -115,7 +116,7 @@ extension AnyJavaObject {
115116
methodName: methodName,
116117
parameterTypes: repeat each parameterTypes,
117118
resultType: Result.javaType,
118-
in: javaEnvironment
119+
in: environment
119120
)
120121
}
121122
}
@@ -126,7 +127,8 @@ extension AnyJavaObject {
126127
parameterTypes: repeat (each Param).Type
127128
) throws -> jmethodID {
128129
// Retrieve the Java class instance from the object.
129-
let environment = javaEnvironment
130+
let environment = try JavaVirtualMachine.shared().environment()
131+
130132
let thisClass = try environment.translatingJNIExceptions {
131133
environment.interface.GetObjectClass(environment, javaThis)
132134
}!
@@ -137,7 +139,7 @@ extension AnyJavaObject {
137139
methodName: methodName,
138140
parameterTypes: repeat each parameterTypes,
139141
resultType: .void,
140-
in: javaEnvironment
142+
in: environment
141143
)
142144
}
143145
}
@@ -167,8 +169,10 @@ extension AnyJavaObject {
167169
method: jmethodID,
168170
args: repeat each Param
169171
) throws -> Result {
172+
let environment = try JavaVirtualMachine.shared().environment()
173+
170174
return try Self.javaMethodCall(
171-
in: javaEnvironment,
175+
in: environment,
172176
this: javaThis,
173177
method: method,
174178
args: repeat each args
@@ -229,8 +233,10 @@ extension AnyJavaObject {
229233
method: jmethodID,
230234
args: repeat each Param
231235
) throws {
236+
let environment = try JavaVirtualMachine.shared().environment()
237+
232238
try Self.javaMethodCall(
233-
in: javaEnvironment,
239+
in: environment,
234240
this: javaThis,
235241
method: method,
236242
args: repeat each args
@@ -276,7 +282,7 @@ extension AnyJavaObject {
276282
private func getJNIFieldID<FieldType: JavaValue>(_ fieldName: String, fieldType: FieldType.Type) -> jfieldID?
277283
where FieldType: ~Copyable {
278284
let this = javaThis
279-
let environment = javaEnvironment
285+
let environment = try! JavaVirtualMachine.shared().environment()
280286

281287
// Retrieve the Java class instance from the object.
282288
let thisClass = environment.interface.GetObjectClass(environment, this)!
@@ -289,15 +295,19 @@ extension AnyJavaObject {
289295
fieldType fieldType: FieldType.Type
290296
) -> FieldType where FieldType: ~Copyable {
291297
get {
298+
let environment = try! JavaVirtualMachine.shared().environment()
299+
292300
let fieldID = getJNIFieldID(fieldName, fieldType: fieldType)!
293-
let jniMethod = FieldType.jniFieldGet(in: javaEnvironment)
294-
return FieldType(fromJNI: jniMethod(javaEnvironment, javaThis, fieldID), in: javaEnvironment)
301+
let jniMethod = FieldType.jniFieldGet(in: environment)
302+
return FieldType(fromJNI: jniMethod(environment, javaThis, fieldID), in: environment)
295303
}
296304

297305
nonmutating set {
306+
let environment = try! JavaVirtualMachine.shared().environment()
307+
298308
let fieldID = getJNIFieldID(fieldName, fieldType: fieldType)!
299-
let jniMethod = FieldType.jniFieldSet(in: javaEnvironment)
300-
jniMethod(javaEnvironment, javaThis, fieldID, newValue.getJNIValue(in: javaEnvironment))
309+
let jniMethod = FieldType.jniFieldSet(in: environment)
310+
jniMethod(environment, javaThis, fieldID, newValue.getJNIValue(in: environment))
301311
}
302312
}
303313
}
@@ -311,7 +321,7 @@ extension JavaClass {
311321
resultType: Result.Type
312322
) throws -> Result {
313323
let thisClass = javaThis
314-
let environment = javaEnvironment
324+
let environment = try! JavaVirtualMachine.shared().environment()
315325

316326
// Compute the method signature so we can find the right method, then look up the
317327
// method within the class.
@@ -345,7 +355,7 @@ extension JavaClass {
345355
arguments: repeat each Param
346356
) throws {
347357
let thisClass = javaThis
348-
let environment = javaEnvironment
358+
let environment = try JavaVirtualMachine.shared().environment()
349359

350360
// Compute the method signature so we can find the right method, then look up the
351361
// method within the class.
@@ -372,7 +382,7 @@ extension JavaClass {
372382

373383
/// Retrieve the JNI field ID for a field with the given name and type.
374384
private func getJNIStaticFieldID<FieldType: JavaValue>(_ fieldName: String, fieldType: FieldType.Type) -> jfieldID? {
375-
let environment = javaEnvironment
385+
let environment = try! JavaVirtualMachine.shared().environment()
376386

377387
return environment.interface.GetStaticFieldID(environment, javaThis, fieldName, FieldType.jniMangling)
378388
}
@@ -382,15 +392,19 @@ extension JavaClass {
382392
fieldType fieldType: FieldType.Type
383393
) -> FieldType {
384394
get {
395+
let environment = try! JavaVirtualMachine.shared().environment()
396+
385397
let fieldID = getJNIStaticFieldID(fieldName, fieldType: fieldType)!
386-
let jniMethod = FieldType.jniStaticFieldGet(in: javaEnvironment)
387-
return FieldType(fromJNI: jniMethod(javaEnvironment, javaThis, fieldID), in: javaEnvironment)
398+
let jniMethod = FieldType.jniStaticFieldGet(in: environment)
399+
return FieldType(fromJNI: jniMethod(environment, javaThis, fieldID), in: environment)
388400
}
389401

390402
set {
403+
let environment = try! JavaVirtualMachine.shared().environment()
404+
391405
let fieldID = getJNIStaticFieldID(fieldName, fieldType: fieldType)!
392-
let jniMethod = FieldType.jniStaticFieldSet(in: javaEnvironment)
393-
jniMethod(javaEnvironment, javaThis, fieldID, newValue.getJNIValue(in: javaEnvironment))
406+
let jniMethod = FieldType.jniStaticFieldSet(in: environment)
407+
jniMethod(environment, javaThis, fieldID, newValue.getJNIValue(in: environment))
394408
}
395409
}
396410
}

0 commit comments

Comments
 (0)