Skip to content

Commit 9809404

Browse files
committed
Introduce the @JavaStaticMethod and use it for calling static Java methods
The use of the `@JavaMethod` macro within an extension of `JavaClass` to represent static Java methods on that class didn't quite work, because JavaClass is itself an AnyJavaObject with its own methods. Introduce a `@JavaStaticMethod` macro that will be used for this purpose, and have it call through a separate API (`dynamicJavaStaticMethodCall`). Thank you to Lokesh for reporting this bug!
1 parent 080c2ae commit 9809404

File tree

6 files changed

+35
-10
lines changed

6 files changed

+35
-10
lines changed

Sources/Java2Swift/JavaTranslator.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,8 +416,9 @@ extension JavaTranslator {
416416

417417
let throwsStr = javaMethod.throwsCheckedException ? "throws" : ""
418418

419+
let methodAttribute: AttributeSyntax = javaMethod.isStatic ? "@JavaStaticMethod" : "@JavaMethod";
419420
return """
420-
@JavaMethod
421+
\(methodAttribute)
421422
public func \(raw: javaMethod.getName())\(raw: genericParameterClause)(\(raw: parametersStr))\(raw: throwsStr)\(raw: resultTypeStr)\(raw: whereClause)
422423
"""
423424
}

Sources/JavaKit/JavaObject+MethodCalls.swift

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -301,9 +301,10 @@ extension AnyJavaObject {
301301
extension JavaClass {
302302
/// Call a Java static method with the given name and arguments, which must be
303303
/// of the correct type, that produces the given result type.
304-
public func dynamicJavaMethodCall<each Param: JavaValue, Result: JavaValue>(
304+
public func dynamicJavaStaticMethodCall<each Param: JavaValue, Result: JavaValue>(
305305
methodName: String,
306-
args: repeat each Param
306+
arguments: repeat each Param,
307+
resultType: Result.Type
307308
) throws -> Result {
308309
let thisClass = javaThis
309310
let environment = javaEnvironment
@@ -325,7 +326,7 @@ extension JavaClass {
325326

326327
// Retrieve the method that performs this call, then
327328
let jniMethod = Result.jniStaticMethodCall(in: environment)
328-
let jniArgs = getJValues(repeat each args, in: environment)
329+
let jniArgs = getJValues(repeat each arguments, in: environment)
329330
let jniResult = try environment.translatingJNIExceptions {
330331
jniMethod(environment, thisClass, methodID, jniArgs)
331332
}
@@ -335,9 +336,9 @@ extension JavaClass {
335336

336337
/// Call a Java static method with the given name and arguments, which must be
337338
/// of the correct type, that produces the given result type.
338-
public func dynamicJavaMethodCall<each Param: JavaValue>(
339+
public func dynamicJavaStaticMethodCall<each Param: JavaValue>(
339340
methodName: String,
340-
args: repeat each Param
341+
arguments: repeat each Param
341342
) throws {
342343
let thisClass = javaThis
343344
let environment = javaEnvironment
@@ -359,7 +360,7 @@ extension JavaClass {
359360

360361
// Retrieve the method that performs this call, then
361362
let jniMethod = environment.interface.CallStaticVoidMethodA
362-
let jniArgs = getJValues(repeat each args, in: environment)
363+
let jniArgs = getJValues(repeat each arguments, in: environment)
363364
try environment.translatingJNIExceptions {
364365
jniMethod!(environment, thisClass, methodID, jniArgs)
365366
}

Sources/JavaKit/Macros.swift

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public macro JavaField(_ javaFieldName: String? = nil) = #externalMacro(module:
9595

9696
/// Attached macro that turns a Swift method into one that wraps a Java method on the underlying Java object.
9797
///
98-
/// The macro must be used within either a AnyJavaObject-conforming type or a specific JavaClass instance.
98+
/// The macro must be used in an AnyJavaObject-conforming type.
9999
///
100100
/// ```swift
101101
/// @JavaMethod
@@ -115,6 +115,18 @@ public macro JavaField(_ javaFieldName: String? = nil) = #externalMacro(module:
115115
@attached(body)
116116
public macro JavaMethod() = #externalMacro(module: "JavaKitMacros", type: "JavaMethodMacro")
117117

118+
/// Attached macro that turns a Swift method on JavaClass into one that wraps
119+
/// a Java static method on the underlying Java class object.
120+
///
121+
/// The macro must be used within a specific JavaClass instance.
122+
///
123+
/// ```swift
124+
/// @JavaMethod
125+
/// func sayHelloBack(_ i: Int32) -> Double
126+
/// ```
127+
@attached(body)
128+
public macro JavaStaticMethod() = #externalMacro(module: "JavaKitMacros", type: "JavaMethodMacro")
129+
118130
/// Macro that exposes the given Swift method as a native method in Java.
119131
///
120132
/// The macro must be used within a struct type marked with `@JavaClass`, and there

Sources/JavaKitMacros/JavaMethodMacro.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ extension JavaMethodMacro: BodyMacro {
3434
fatalError("not a function")
3535
}
3636

37+
let isStatic = node.attributeName.trimmedDescription == "JavaStaticMethod"
3738
let funcName = funcDecl.name.text
3839
let params = funcDecl.signature.parameterClause.parameters
3940
let resultType: String =
@@ -54,7 +55,7 @@ extension JavaMethodMacro: BodyMacro {
5455
? "try" : "try!"
5556

5657
return [
57-
"return \(raw: tryKeyword) dynamicJavaMethodCall(methodName: \(literal: funcName)\(raw: parametersAsArgs)\(raw: resultType))"
58+
"return \(raw: tryKeyword) dynamicJava\(raw: isStatic ? "Static" : "")MethodCall(methodName: \(literal: funcName)\(raw: parametersAsArgs)\(raw: resultType))"
5859
]
5960
}
6061

Sources/JavaKitNetwork/generated/URLConnection.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ extension JavaClass<URLConnection> {
146146
@JavaMethod
147147
public func setDefaultAllowUserInteraction(_ arg0: Bool)
148148

149-
@JavaMethod
149+
@JavaStaticMethod
150150
public func getDefaultAllowUserInteraction() -> Bool
151151

152152
@JavaMethod

Tests/JavaKitTests/BasicRuntimeTests.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,14 @@ struct BasicRuntimeTests {
6666
#expect(String(describing: error) == "no protocol: bad url")
6767
}
6868
}
69+
70+
@Test("Static methods")
71+
func staticMethods() {
72+
let urlConnectionClass = JavaClass<URLConnection>(
73+
javaThis: URLConnection.getJNIClass(in: jvm.environment)!,
74+
environment: jvm.environment
75+
)
76+
77+
#expect(urlConnectionClass.getDefaultAllowUserInteraction() == false)
78+
}
6979
}

0 commit comments

Comments
 (0)