Skip to content

Commit 2b8e445

Browse files
authored
Merge branch 'main' into search
2 parents abc6af1 + 7eedf40 commit 2b8e445

File tree

10 files changed

+186
-59
lines changed

10 files changed

+186
-59
lines changed

Sources/JExtractSwift/TranslatedType.swift

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,12 @@ extension Swift2JavaVisitor {
5555
// Translate the generic arguments to the C-compatible types.
5656
let genericArgs = try memberType.genericArgumentClause.map { genericArgumentClause in
5757
try genericArgumentClause.arguments.map { argument in
58-
try cCompatibleType(for: argument.argument)
58+
switch argument.argument {
59+
case .type(let argumentType):
60+
try cCompatibleType(for: argumentType)
61+
@unknown default:
62+
throw TypeTranslationError.unimplementedType(TypeSyntax(memberType))
63+
}
5964
}
6065
}
6166

@@ -71,7 +76,12 @@ extension Swift2JavaVisitor {
7176
// Translate the generic arguments to the C-compatible types.
7277
let genericArgs = try identifierType.genericArgumentClause.map { genericArgumentClause in
7378
try genericArgumentClause.arguments.map { argument in
74-
try cCompatibleType(for: argument.argument)
79+
switch argument.argument {
80+
case .type(let argumentType):
81+
try cCompatibleType(for: argumentType)
82+
@unknown default:
83+
throw TypeTranslationError.unimplementedType(TypeSyntax(identifierType))
84+
}
7585
}
7686
}
7787

Sources/JavaKit/AnyJavaObject.swift

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,19 @@ public protocol AnyJavaObject {
4949
var javaHolder: JavaObjectHolder { get }
5050
}
5151

52+
/// Protocol that allows Swift types to specify a custom Java class loader on
53+
/// initialization. This is useful for platforms (e.g. Android) where the default
54+
/// class loader does not make all application classes visible.
55+
public protocol CustomJavaClassLoader: AnyJavaObject {
56+
static func getJavaClassLoader(in environment: JNIEnvironment) throws -> JavaClassLoader!
57+
}
58+
59+
/// Add getClassLoader() to JavaObject as it is otherwise recursively defined
60+
extension JavaObject {
61+
@JavaMethod
62+
public func getClassLoader() throws -> JavaClassLoader!
63+
}
64+
5265
extension AnyJavaObject {
5366
/// Retrieve the underlying Java object.
5467
public var javaThis: jobject {
@@ -81,13 +94,41 @@ extension AnyJavaObject {
8194
JavaClass(javaThis: jniClass!, environment: javaEnvironment)
8295
}
8396

84-
/// Retrieve the Java class for this type.
85-
public static func getJNIClass(in environment: JNIEnvironment) throws -> jclass {
86-
try environment.translatingJNIExceptions {
97+
/// Retrieve the Java class for this type using the default class loader.
98+
private static func _withJNIClassFromDefaultClassLoader<Result>(
99+
in environment: JNIEnvironment,
100+
_ body: (jclass) throws -> Result
101+
) throws -> Result {
102+
let resolvedClass = try environment.translatingJNIExceptions {
87103
environment.interface.FindClass(
88104
environment,
89105
fullJavaClassNameWithSlashes
90106
)
91107
}!
108+
return try body(resolvedClass)
109+
}
110+
111+
/// Retrieve the Java class for this type using a specific class loader.
112+
private static func _withJNIClassFromCustomClassLoader<Result>(
113+
_ classLoader: JavaClassLoader,
114+
in environment: JNIEnvironment,
115+
_ body: (jclass) throws -> Result
116+
) throws -> Result {
117+
let resolvedClass = try classLoader.findClass(fullJavaClassName)
118+
return try body(resolvedClass!.javaThis)
119+
}
120+
121+
/// Retrieve the Java class for this type and execute body().
122+
@_spi(Testing)
123+
public static func withJNIClass<Result>(
124+
in environment: JNIEnvironment,
125+
_ body: (jclass) throws -> Result
126+
) throws -> Result {
127+
if let customJavaClassLoader = self as? CustomJavaClassLoader.Type,
128+
let customClassLoader = try customJavaClassLoader.getJavaClassLoader(in: environment) {
129+
try _withJNIClassFromCustomClassLoader(customClassLoader, in: environment, body)
130+
} else {
131+
try _withJNIClassFromDefaultClassLoader(in: environment, body)
132+
}
92133
}
93134
}

Sources/JavaKit/Exceptions/ExceptionHandling.swift

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,8 @@ extension JNIEnvironment {
3939
}
4040

4141
// Otherwise, create a exception with a message.
42-
_ = interface.ThrowNew(
43-
self,
44-
try! JavaClass<Exception>.getJNIClass(in: self),
45-
String(describing: error)
46-
)
42+
_ = try! JavaClass<Exception>.withJNIClass(in: self) { exceptionClass in
43+
interface.ThrowNew(self, exceptionClass, String(describing: error))
44+
}
4745
}
4846
}

Sources/JavaKit/Java2Swift.config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"java.lang.Byte" : "JavaByte",
66
"java.lang.Character" : "JavaCharacter",
77
"java.lang.Class" : "JavaClass",
8+
"java.lang.ClassLoader" : "JavaClassLoader",
89
"java.lang.Double" : "JavaDouble",
910
"java.lang.Error" : "JavaError",
1011
"java.lang.Exception" : "Exception",

Sources/JavaKit/JavaClass+Initialization.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ extension JavaClass {
2121
@_nonoverride
2222
public convenience init(environment: JNIEnvironment? = nil) throws {
2323
let environment = try environment ?? JavaVirtualMachine.shared().environment()
24-
self.init(
25-
javaThis: try ObjectType.getJNIClass(in: environment),
26-
environment: environment
27-
)
24+
var javaClassHolder: JavaObjectHolder!
25+
26+
javaClassHolder = try ObjectType.withJNIClass(in: environment) { javaClass in
27+
JavaObjectHolder(object: javaClass, environment: environment)
28+
}
29+
self.init(javaHolder: javaClassHolder)
2830
}
2931
}

Sources/JavaKit/JavaObject+Inheritance.swift

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,17 @@ extension AnyJavaObject {
2222
private func isInstanceOf<OtherClass: AnyJavaObject>(
2323
_ otherClass: OtherClass.Type
2424
) -> jclass? {
25-
guard let otherJavaClass = try? otherClass.getJNIClass(in: javaEnvironment) else {
26-
return nil
27-
}
25+
try? otherClass.withJNIClass(in: javaEnvironment) { otherJavaClass in
26+
if javaEnvironment.interface.IsInstanceOf(
27+
javaEnvironment,
28+
javaThis,
29+
otherJavaClass
30+
) == 0 {
31+
return nil
32+
}
2833

29-
if javaEnvironment.interface.IsInstanceOf(
30-
javaEnvironment,
31-
javaThis,
32-
otherJavaClass
33-
) == 0 {
34-
return nil
34+
return otherJavaClass
3535
}
36-
37-
return otherJavaClass
3836
}
3937

4038
/// Determine whether this object is an instance of a specific

Sources/JavaKit/JavaObject+MethodCalls.swift

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -253,23 +253,23 @@ extension AnyJavaObject {
253253
in environment: JNIEnvironment,
254254
arguments: repeat each Param
255255
) throws -> jobject {
256-
let thisClass = try Self.getJNIClass(in: environment)
257-
258-
// Compute the method signature so we can find the right method, then look up the
259-
// method within the class.
260-
let methodID = try Self.javaMethodLookup(
261-
thisClass: thisClass,
262-
methodName: javaConstructorName,
263-
parameterTypes: repeat (each Param).self,
264-
resultType: .void,
265-
in: environment
266-
)
256+
try Self.withJNIClass(in: environment) { thisClass in
257+
// Compute the method signature so we can find the right method, then look up the
258+
// method within the class.
259+
let methodID = try Self.javaMethodLookup(
260+
thisClass: thisClass,
261+
methodName: javaConstructorName,
262+
parameterTypes: repeat (each Param).self,
263+
resultType: .void,
264+
in: environment
265+
)
267266

268-
// Retrieve the constructor, then map the arguments and call it.
269-
let jniArgs = getJValues(repeat each arguments, in: environment)
270-
return try environment.translatingJNIExceptions {
271-
environment.interface.NewObjectA!(environment, thisClass, methodID, jniArgs)
272-
}!
267+
// Retrieve the constructor, then map the arguments and call it.
268+
let jniArgs = getJValues(repeat each arguments, in: environment)
269+
return try environment.translatingJNIExceptions {
270+
environment.interface.NewObjectA!(environment, thisClass, methodID, jniArgs)
271+
}!
272+
}
273273
}
274274

275275
/// Retrieve the JNI field ID for a field with the given name and type.

Sources/JavaKit/Optional+JavaObject.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,9 @@ extension Optional: JavaValue where Wrapped: AnyJavaObject {
7070

7171
public static func jniNewArray(in environment: JNIEnvironment) -> JNINewArray {
7272
return { environment, size in
73-
let jniClass = try! Wrapped.getJNIClass(in: environment)
74-
return environment.interface.NewObjectArray(environment, size, jniClass, nil)
73+
try! Wrapped.withJNIClass(in: environment) { jniClass in
74+
environment.interface.NewObjectArray(environment, size, jniClass, nil)
75+
}
7576
}
7677
}
7778

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Auto-generated by Java-to-Swift wrapper generator.
2+
import JavaRuntime
3+
4+
@JavaClass("java.lang.ClassLoader")
5+
open class JavaClassLoader: JavaObject {
6+
@JavaMethod
7+
open func getName() -> String
8+
9+
@JavaMethod
10+
open func loadClass(_ arg0: String, _ arg1: Bool) throws -> JavaClass<JavaObject>!
11+
12+
@JavaMethod
13+
open func loadClass(_ arg0: String) throws -> JavaClass<JavaObject>!
14+
15+
@JavaMethod
16+
open func setSigners(_ arg0: JavaClass<JavaObject>?, _ arg1: [JavaObject?])
17+
18+
@JavaMethod
19+
open func getClassLoadingLock(_ arg0: String) -> JavaObject!
20+
21+
@JavaMethod
22+
open func findLoadedClass(_ arg0: String) -> JavaClass<JavaObject>!
23+
24+
@JavaMethod
25+
open func findClass(_ arg0: String) throws -> JavaClass<JavaObject>!
26+
27+
@JavaMethod
28+
open func findClass(_ arg0: String, _ arg1: String) -> JavaClass<JavaObject>!
29+
30+
@JavaMethod
31+
open func resolveClass(_ arg0: JavaClass<JavaObject>?)
32+
33+
@JavaMethod
34+
open func defineClass(_ arg0: [Int8], _ arg1: Int32, _ arg2: Int32) throws -> JavaClass<JavaObject>!
35+
36+
@JavaMethod
37+
open func defineClass(_ arg0: String, _ arg1: [Int8], _ arg2: Int32, _ arg3: Int32) throws -> JavaClass<JavaObject>!
38+
39+
@JavaMethod
40+
open func findLibrary(_ arg0: String) -> String
41+
42+
@JavaMethod
43+
open func findSystemClass(_ arg0: String) throws -> JavaClass<JavaObject>!
44+
45+
@JavaMethod
46+
open func isRegisteredAsParallelCapable() -> Bool
47+
48+
@JavaMethod
49+
open func getParent() -> JavaClassLoader!
50+
51+
@JavaMethod
52+
open func setDefaultAssertionStatus(_ arg0: Bool)
53+
54+
@JavaMethod
55+
open func setPackageAssertionStatus(_ arg0: String, _ arg1: Bool)
56+
57+
@JavaMethod
58+
open func setClassAssertionStatus(_ arg0: String, _ arg1: Bool)
59+
60+
@JavaMethod
61+
open func clearAssertionStatus()
62+
}
63+
extension JavaClass<JavaClassLoader> {
64+
@JavaStaticMethod
65+
public func getPlatformClassLoader() -> JavaClassLoader!
66+
67+
@JavaStaticMethod
68+
public func getSystemClassLoader() -> JavaClassLoader!
69+
70+
@JavaStaticMethod
71+
public func registerAsParallelCapable() -> Bool
72+
}

Tests/Java2SwiftTests/Java2SwiftTests.swift

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//
1313
//===----------------------------------------------------------------------===//
1414

15+
@_spi(Testing)
1516
import JavaKit
1617
import Java2SwiftLib
1718
import XCTest // NOTE: Workaround for https://github.com/swiftlang/swift-java/issues/43
@@ -661,24 +662,27 @@ func assertTranslatedClass<JavaClassType: AnyJavaObject>(
661662
translator.translatedClasses[javaType.fullJavaClassName] = (swiftTypeName, nil)
662663
translator.nestedClasses = nestedClasses
663664
translator.startNewFile()
664-
let translatedDecls = try translator.translateClass(
665-
JavaClass<JavaObject>(
666-
javaThis: javaType.getJNIClass(in: environment),
667-
environment: environment)
668-
)
669-
let importDecls = translator.getImportDecls()
670665

671-
let swiftFileText = """
672-
// Auto-generated by Java-to-Swift wrapper generator.
673-
\(importDecls.map { $0.description }.joined())
674-
\(translatedDecls.map { $0.description }.joined(separator: "\n"))
675-
"""
666+
try javaType.withJNIClass(in: environment) { javaClass in
667+
let translatedDecls = try translator.translateClass(
668+
JavaClass<JavaObject>(
669+
javaThis: javaClass,
670+
environment: environment)
671+
)
672+
let importDecls = translator.getImportDecls()
676673

677-
for expectedChunk in expectedChunks {
678-
if swiftFileText.contains(expectedChunk) {
679-
continue
680-
}
674+
let swiftFileText = """
675+
// Auto-generated by Java-to-Swift wrapper generator.
676+
\(importDecls.map { $0.description }.joined())
677+
\(translatedDecls.map { $0.description }.joined(separator: "\n"))
678+
"""
681679

682-
XCTFail("Expected chunk '\(expectedChunk)' not found in '\(swiftFileText)'", file: file, line: line)
680+
for expectedChunk in expectedChunks {
681+
if swiftFileText.contains(expectedChunk) {
682+
continue
683+
}
684+
685+
XCTFail("Expected chunk '\(expectedChunk)' not found in '\(swiftFileText)'", file: file, line: line)
686+
}
683687
}
684688
}

0 commit comments

Comments
 (0)