Skip to content

Introduce the @JavaStaticMethod and use it for calling static Java methods #37

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Sources/Java2Swift/JavaTranslator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -416,8 +416,9 @@ extension JavaTranslator {

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

let methodAttribute: AttributeSyntax = javaMethod.isStatic ? "@JavaStaticMethod" : "@JavaMethod";
return """
@JavaMethod
\(methodAttribute)
public func \(raw: javaMethod.getName())\(raw: genericParameterClause)(\(raw: parametersStr))\(raw: throwsStr)\(raw: resultTypeStr)\(raw: whereClause)
"""
}
Expand Down
13 changes: 7 additions & 6 deletions Sources/JavaKit/JavaObject+MethodCalls.swift
Original file line number Diff line number Diff line change
Expand Up @@ -301,9 +301,10 @@ extension AnyJavaObject {
extension JavaClass {
/// Call a Java static method with the given name and arguments, which must be
/// of the correct type, that produces the given result type.
public func dynamicJavaMethodCall<each Param: JavaValue, Result: JavaValue>(
public func dynamicJavaStaticMethodCall<each Param: JavaValue, Result: JavaValue>(
methodName: String,
args: repeat each Param
arguments: repeat each Param,
resultType: Result.Type
) throws -> Result {
let thisClass = javaThis
let environment = javaEnvironment
Expand All @@ -325,7 +326,7 @@ extension JavaClass {

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

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

// Retrieve the method that performs this call, then
let jniMethod = environment.interface.CallStaticVoidMethodA
let jniArgs = getJValues(repeat each args, in: environment)
let jniArgs = getJValues(repeat each arguments, in: environment)
try environment.translatingJNIExceptions {
jniMethod!(environment, thisClass, methodID, jniArgs)
}
Expand Down
14 changes: 13 additions & 1 deletion Sources/JavaKit/Macros.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public macro JavaField(_ javaFieldName: String? = nil) = #externalMacro(module:

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

/// Attached macro that turns a Swift method on JavaClass into one that wraps
/// a Java static method on the underlying Java class object.
///
/// The macro must be used within a specific JavaClass instance.
///
/// ```swift
/// @JavaMethod
/// func sayHelloBack(_ i: Int32) -> Double
/// ```
@attached(body)
public macro JavaStaticMethod() = #externalMacro(module: "JavaKitMacros", type: "JavaMethodMacro")

/// Macro that exposes the given Swift method as a native method in Java.
///
/// The macro must be used within a struct type marked with `@JavaClass`, and there
Expand Down
3 changes: 2 additions & 1 deletion Sources/JavaKitMacros/JavaMethodMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ extension JavaMethodMacro: BodyMacro {
fatalError("not a function")
}

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

return [
"return \(raw: tryKeyword) dynamicJavaMethodCall(methodName: \(literal: funcName)\(raw: parametersAsArgs)\(raw: resultType))"
"return \(raw: tryKeyword) dynamicJava\(raw: isStatic ? "Static" : "")MethodCall(methodName: \(literal: funcName)\(raw: parametersAsArgs)\(raw: resultType))"
]
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/JavaKitNetwork/generated/URI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,6 @@ public struct URI {
public func wait() throws
}
extension JavaClass<URI> {
@JavaMethod
@JavaStaticMethod
public func create(_ arg0: String) -> URI?
}
6 changes: 3 additions & 3 deletions Sources/JavaKitNetwork/generated/URLClassLoader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,12 @@ public struct URLClassLoader {
public func wait() throws
}
extension JavaClass<URLClassLoader> {
@JavaMethod
@JavaStaticMethod
public func newInstance(_ arg0: [URL?]) -> URLClassLoader?

@JavaMethod
@JavaStaticMethod
public func getSystemResource(_ arg0: String) -> URL?

@JavaMethod
@JavaStaticMethod
public func getSystemResources(_ arg0: String) throws -> Enumeration<URL>?
}
2 changes: 1 addition & 1 deletion Sources/JavaKitNetwork/generated/URLConnection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ extension JavaClass<URLConnection> {
@JavaMethod
public func setDefaultAllowUserInteraction(_ arg0: Bool)

@JavaMethod
@JavaStaticMethod
public func getDefaultAllowUserInteraction() -> Bool

@JavaMethod
Expand Down
2 changes: 1 addition & 1 deletion Sources/JavaKitReflection/generated/AccessibleObject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,6 @@ public struct AccessibleObject {
public func wait() throws
}
extension JavaClass<AccessibleObject> {
@JavaMethod
@JavaStaticMethod
public func setAccessible(_ arg0: [AccessibleObject?], _ arg1: Bool)
}
2 changes: 1 addition & 1 deletion Sources/JavaKitReflection/generated/Constructor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,6 @@ public struct Constructor<T: AnyJavaObject> {
public func wait() throws
}
extension JavaClass {
@JavaMethod
@JavaStaticMethod
public func setAccessible<T: AnyJavaObject>(_ arg0: [AccessibleObject?], _ arg1: Bool) where ObjectType == Constructor<T>
}
2 changes: 1 addition & 1 deletion Sources/JavaKitReflection/generated/Executable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,6 @@ public struct Executable {
public func wait() throws
}
extension JavaClass<Executable> {
@JavaMethod
@JavaStaticMethod
public func setAccessible(_ arg0: [AccessibleObject?], _ arg1: Bool)
}
2 changes: 1 addition & 1 deletion Sources/JavaKitReflection/generated/Method.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,6 @@ public struct Method {
public func wait() throws
}
extension JavaClass<Method> {
@JavaMethod
@JavaStaticMethod
public func setAccessible(_ arg0: [AccessibleObject?], _ arg1: Bool)
}
8 changes: 4 additions & 4 deletions Sources/_Subprocess/Subprocess+IO.swift
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,10 @@ extension Subprocess {
case fileDescriptor(FileDescriptor?, Bool)
}

let storage: Mutex<Storage>
let storage: LockedState<Storage>

internal init(storage: Storage) {
self.storage = .init(storage)
self.storage = .init(initialState: storage)
}

internal func getReadFileDescriptor() -> FileDescriptor? {
Expand Down Expand Up @@ -250,10 +250,10 @@ extension Subprocess {
case collected(Int, FileDescriptor?, FileDescriptor?)
}

private let storage: Mutex<Storage>
private let storage: LockedState<Storage>

internal init(storage: Storage) {
self.storage = .init(storage)
self.storage = .init(initialState: storage)
}

internal func getWriteFileDescriptor() -> FileDescriptor? {
Expand Down
10 changes: 10 additions & 0 deletions Tests/JavaKitTests/BasicRuntimeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,14 @@ struct BasicRuntimeTests {
#expect(String(describing: error) == "no protocol: bad url")
}
}

@Test("Static methods")
func staticMethods() {
let urlConnectionClass = JavaClass<URLConnection>(
javaThis: URLConnection.getJNIClass(in: jvm.environment)!,
environment: jvm.environment
)

#expect(urlConnectionClass.getDefaultAllowUserInteraction() == false)
}
}
Loading