From 92a51f5f1797a46f4bb3719bbd9dbd7110cd5a3d Mon Sep 17 00:00:00 2001 From: jrosen081 Date: Mon, 25 Nov 2024 18:53:05 -0500 Subject: [PATCH 1/3] Add Support for Threadsafe and NotThreadSafe annotations --- .../Java2SwiftLib/JavaClassTranslator.swift | 30 +++++++++++++++++++ .../JavaClass+Reflection.swift | 3 ++ 2 files changed, 33 insertions(+) diff --git a/Sources/Java2SwiftLib/JavaClassTranslator.swift b/Sources/Java2SwiftLib/JavaClassTranslator.swift index b0b0628f..e2753790 100644 --- a/Sources/Java2SwiftLib/JavaClassTranslator.swift +++ b/Sources/Java2SwiftLib/JavaClassTranslator.swift @@ -52,6 +52,9 @@ struct JavaClassTranslator { /// The Swift names of the interfaces that this class implements. let swiftInterfaces: [String] + /// The annotations of the Java class + let annotations: [Annotation] + /// The (instance) fields of the Java class. var fields: [Field] = [] @@ -164,6 +167,8 @@ struct JavaClassTranslator { } } + self.annotations = javaClass.getAnnotations().compactMap(\.self) + // Collect all of the class members that we will need to translate. // TODO: Switch over to "declared" versions of these whenever we don't need // to see inherited members. @@ -274,6 +279,7 @@ extension JavaClassTranslator { if let nativeMethodsProtocol = renderNativeMethodsProtocol() { allDecls.append(nativeMethodsProtocol) } + allDecls.append(contentsOf: renderAnnotationExtensions()) return allDecls } @@ -483,6 +489,30 @@ extension JavaClassTranslator { return protocolDecl.formatted(using: translator.format).cast(DeclSyntax.self) } + func renderAnnotationExtensions() -> [DeclSyntax] { + var extensions: [DeclSyntax] = [] + + for annotation in annotations { + let annotationName = annotation.annotationType().getName().splitSwiftTypeName().name + if annotationName == "ThreadSafe" || annotationName == "Immutable" { // If we are threadsafe, mark as unchecked Sendable + extensions.append( + """ + extension \(raw: swiftTypeName): @unchecked Swift.Sendable { } + """ + ) + } else if annotationName == "NotThreadSafe" { // If we are _not_ threadsafe, mark sendable unavailable + extensions.append( + """ + @available(unavailable, *) + extension \(raw: swiftTypeName): Swift.Sendable { } + """ + ) + } + } + + return extensions + } + /// Render the given Java constructor as a Swift initializer. package func renderConstructor( _ javaConstructor: Constructor diff --git a/Sources/JavaKitReflection/JavaClass+Reflection.swift b/Sources/JavaKitReflection/JavaClass+Reflection.swift index e5505144..1f2120e0 100644 --- a/Sources/JavaKitReflection/JavaClass+Reflection.swift +++ b/Sources/JavaKitReflection/JavaClass+Reflection.swift @@ -43,4 +43,7 @@ extension JavaClass { @JavaMethod public func getGenericInterfaces() -> [Type?] + + @JavaMethod + public func getAnnotations() -> [Annotation?] } From fe47e589145dde2dc195c546ffd1ac2adf4cd237 Mon Sep 17 00:00:00 2001 From: jrosen081 Date: Mon, 25 Nov 2024 20:59:06 -0500 Subject: [PATCH 2/3] Add to the testing app --- .../JavaKitExample/JavaKitExample.swift | 3 +++ .../com/example/swift/ThreadSafe.java | 22 +++++++++++++++++++ .../example/swift/ThreadSafeHelperClass.java | 6 +++++ .../Sources/JavaKitExample/swift-java.config | 3 ++- 4 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 Samples/JavaKitSampleApp/Sources/JavaKitExample/com/example/swift/ThreadSafe.java create mode 100644 Samples/JavaKitSampleApp/Sources/JavaKitExample/com/example/swift/ThreadSafeHelperClass.java diff --git a/Samples/JavaKitSampleApp/Sources/JavaKitExample/JavaKitExample.swift b/Samples/JavaKitSampleApp/Sources/JavaKitExample/JavaKitExample.swift index 42a5b789..366e8894 100644 --- a/Samples/JavaKitSampleApp/Sources/JavaKitExample/JavaKitExample.swift +++ b/Samples/JavaKitSampleApp/Sources/JavaKitExample/JavaKitExample.swift @@ -76,6 +76,9 @@ extension HelloSwift: HelloSwiftNativeMethods { print("Caught Java error: \(error)") } + // Make sure that the thread safe class is sendable + let threadSafe: Sendable = ThreadSafeHelperClass(environment: javaEnvironment) + return i * j } diff --git a/Samples/JavaKitSampleApp/Sources/JavaKitExample/com/example/swift/ThreadSafe.java b/Samples/JavaKitSampleApp/Sources/JavaKitExample/com/example/swift/ThreadSafe.java new file mode 100644 index 00000000..2b1b358d --- /dev/null +++ b/Samples/JavaKitSampleApp/Sources/JavaKitExample/com/example/swift/ThreadSafe.java @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2024 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +package com.example.swift; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface ThreadSafe { +} diff --git a/Samples/JavaKitSampleApp/Sources/JavaKitExample/com/example/swift/ThreadSafeHelperClass.java b/Samples/JavaKitSampleApp/Sources/JavaKitExample/com/example/swift/ThreadSafeHelperClass.java new file mode 100644 index 00000000..14db2542 --- /dev/null +++ b/Samples/JavaKitSampleApp/Sources/JavaKitExample/com/example/swift/ThreadSafeHelperClass.java @@ -0,0 +1,6 @@ +package com.example.swift; + +@ThreadSafe +public class ThreadSafeHelperClass { + public ThreadSafeHelperClass() { } +} diff --git a/Samples/JavaKitSampleApp/Sources/JavaKitExample/swift-java.config b/Samples/JavaKitSampleApp/Sources/JavaKitExample/swift-java.config index b4e7368d..a86b5a4f 100644 --- a/Samples/JavaKitSampleApp/Sources/JavaKitExample/swift-java.config +++ b/Samples/JavaKitSampleApp/Sources/JavaKitExample/swift-java.config @@ -2,6 +2,7 @@ "classes" : { "com.example.swift.HelloSwift" : "HelloSwift", "com.example.swift.HelloSubclass" : "HelloSubclass", - "com.example.swift.JavaKitSampleMain" : "JavaKitSampleMain" + "com.example.swift.JavaKitSampleMain" : "JavaKitSampleMain", + "com.example.swift.ThreadSafeHelperClass" : "ThreadSafeHelperClass" } } From ef5397f0951eca1dc7aeed4a2e3ab9211b40acb2 Mon Sep 17 00:00:00 2001 From: jrosen081 Date: Mon, 25 Nov 2024 21:01:56 -0500 Subject: [PATCH 3/3] License --- .../com/example/swift/ThreadSafeHelperClass.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Samples/JavaKitSampleApp/Sources/JavaKitExample/com/example/swift/ThreadSafeHelperClass.java b/Samples/JavaKitSampleApp/Sources/JavaKitExample/com/example/swift/ThreadSafeHelperClass.java index 14db2542..179b8cd6 100644 --- a/Samples/JavaKitSampleApp/Sources/JavaKitExample/com/example/swift/ThreadSafeHelperClass.java +++ b/Samples/JavaKitSampleApp/Sources/JavaKitExample/com/example/swift/ThreadSafeHelperClass.java @@ -1,3 +1,17 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2024 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + package com.example.swift; @ThreadSafe