From a877aa49e2e97e9e8c389f2c4d842c88ac806afe Mon Sep 17 00:00:00 2001 From: michaelknoch Date: Wed, 21 Aug 2019 18:03:11 +0200 Subject: [PATCH 1/5] allow calling static methods on JNIObjects --- Sources/JNI/JNIObjects.swift | 44 +++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/Sources/JNI/JNIObjects.swift b/Sources/JNI/JNIObjects.swift index b8a9f53..7e4b059 100644 --- a/Sources/JNI/JNIObjects.swift +++ b/Sources/JNI/JNIObjects.swift @@ -1,9 +1,21 @@ import CJNI +import Dispatch /// Designed to simplify calling a constructor and methods on a JavaClass /// Subclass this and add the methods appropriate to the object you are constructing. open class JNIObject { - public let javaClass: JavaClass + open class var className: String { + return "java.lang.object" + } + + public class var javaClass: JavaClass { + return DispatchQueue.main.sync { + let javaClassLocalRef = try! jni.FindClass(name: className.replacingFullstopsWithSlashes()) + try! checkAndThrowOnJNIError() + return jni.NewGlobalRef(javaClassLocalRef)! + } + } + public let instance: JavaObject required public init(_ instance: JavaObject) throws { @@ -11,10 +23,7 @@ open class JNIObject { throw Error.couldntCreateGlobalRef } - let javaClassLocalRef = try jni.GetObjectClass(obj: instance) - let javaClass = jni.NewGlobalRef(javaClassLocalRef) try checkAndThrowOnJNIError() - self.javaClass = javaClass! self.instance = globalInstanceRef } @@ -31,20 +40,29 @@ open class JNIObject { deinit { jni.DeleteGlobalRef(instance) - jni.DeleteGlobalRef(javaClass) } public func call(methodName: String, arguments: [JavaParameterConvertible] = []) throws { try jni.call(methodName, on: self.instance, arguments: arguments) } - public func call(methodName: String, arguments: [JavaParameterConvertible] = []) throws -> T { + public func call( + methodName: String, + arguments: [JavaParameterConvertible] = [] + ) throws -> T { return try jni.call(methodName, on: self.instance, arguments: arguments) } - public func callStatic(methodName: String, arguments: [JavaParameterConvertible] = []) throws { + public static func callStatic(methodName: String, arguments: [JavaParameterConvertible] = []) throws { try jni.callStatic(methodName, on: self.javaClass, arguments: arguments) } + + public static func callStatic( + methodName: String, + arguments: [JavaParameterConvertible] = [] + ) throws -> T { + return try jni.callStatic(methodName, on: self.javaClass, arguments: arguments) + } } extension JNIObject { @@ -64,19 +82,19 @@ extension JNI { } public extension JNI { - public func NewObject(targetClass: JavaClass, _ methodID: JavaMethodID, _ args: [JavaParameter]) throws -> JavaObject? { - let env = self._env + func NewObject(targetClass: JavaClass, _ methodID: JavaMethodID, _ args: [JavaParameter]) throws -> JavaObject? { + let env = self._env var mutableArgs = args let newObject = env.pointee.pointee.NewObject(env, targetClass, methodID, &mutableArgs) try checkAndThrowOnJNIError() return newObject - } + } - public func GetObjectClass(obj: JavaObject) throws -> JavaClass { - let env = self._env + func GetObjectClass(obj: JavaObject) throws -> JavaClass { + let env = self._env let result = env.pointee.pointee.GetObjectClass(env, obj) try checkAndThrowOnJNIError() return result! - } + } } From 07fdd3ebf4d57597127502ed1f15e2fda5af89b8 Mon Sep 17 00:00:00 2001 From: michaelknoch Date: Wed, 21 Aug 2019 18:05:14 +0200 Subject: [PATCH 2/5] reindent --- Sources/JNI/JNIObjects.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Sources/JNI/JNIObjects.swift b/Sources/JNI/JNIObjects.swift index 7e4b059..b239a92 100644 --- a/Sources/JNI/JNIObjects.swift +++ b/Sources/JNI/JNIObjects.swift @@ -73,7 +73,10 @@ extension JNIObject { } extension JNI { - func callConstructor(on targetClass: JavaClass, arguments: [JavaParameterConvertible] = []) throws -> JavaObject? { + func callConstructor( + on targetClass: JavaClass, + arguments: [JavaParameterConvertible] = [] + ) throws -> JavaObject? { let methodID = _env.pointee.pointee.GetMethodID(_env, targetClass, "", arguments.methodSignature(returnType: nil)) try checkAndThrowOnJNIError() From dc432a53014daa8708d8139dcbfc6b77b3dfc722 Mon Sep 17 00:00:00 2001 From: michaelknoch Date: Wed, 21 Aug 2019 18:22:10 +0200 Subject: [PATCH 3/5] deprecate init with explicit className --- Sources/JNI/JNIObjects.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Sources/JNI/JNIObjects.swift b/Sources/JNI/JNIObjects.swift index b239a92..9007779 100644 --- a/Sources/JNI/JNIObjects.swift +++ b/Sources/JNI/JNIObjects.swift @@ -27,6 +27,7 @@ open class JNIObject { self.instance = globalInstanceRef } + @available(*, deprecated, message: "Override Self.className instead and use the initializers that don't take className as an argument") convenience public init(_ className: String, arguments: [JavaParameterConvertible] = []) throws { let className = className.replacingFullstopsWithSlashes() let javaClassLocalRef = try jni.FindClass(name: className) @@ -38,6 +39,14 @@ open class JNIObject { try self.init(instanceLocalRef) } + convenience public init(arguments: [JavaParameterConvertible] = []) throws { + guard let instanceLocalRef = try jni.callConstructor(on: type(of: self).javaClass, arguments: arguments) else { + throw Error.couldntCallConstructor + } + + try self.init(instanceLocalRef) + } + deinit { jni.DeleteGlobalRef(instance) } From e17f110054deb4c0a8b6f8bf4d5596a2a052875e Mon Sep 17 00:00:00 2001 From: michaelknoch Date: Wed, 21 Aug 2019 19:45:29 +0200 Subject: [PATCH 4/5] implement private classInstances cache --- Sources/JNI/JNIObjects.swift | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Sources/JNI/JNIObjects.swift b/Sources/JNI/JNIObjects.swift index 9007779..2127de7 100644 --- a/Sources/JNI/JNIObjects.swift +++ b/Sources/JNI/JNIObjects.swift @@ -8,11 +8,20 @@ open class JNIObject { return "java.lang.object" } + private static var classInstances = [String: JavaClass]() + public class var javaClass: JavaClass { return DispatchQueue.main.sync { + if let classInstance = classInstances[className] { + return classInstance + } + let javaClassLocalRef = try! jni.FindClass(name: className.replacingFullstopsWithSlashes()) try! checkAndThrowOnJNIError() - return jni.NewGlobalRef(javaClassLocalRef)! + let classInstance = jni.NewGlobalRef(javaClassLocalRef)! + classInstances[className] = classInstance + + return classInstance } } @@ -39,7 +48,7 @@ open class JNIObject { try self.init(instanceLocalRef) } - convenience public init(arguments: [JavaParameterConvertible] = []) throws { + convenience public init(arguments: JavaParameterConvertible...) throws { guard let instanceLocalRef = try jni.callConstructor(on: type(of: self).javaClass, arguments: arguments) else { throw Error.couldntCallConstructor } From d0ee58d02b9b5ae60aa56158259d7849931a2a30 Mon Sep 17 00:00:00 2001 From: michaelknoch Date: Thu, 22 Aug 2019 08:47:26 +0200 Subject: [PATCH 5/5] use static getter for classinstances --- Sources/JNI/JNIObjects.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/JNI/JNIObjects.swift b/Sources/JNI/JNIObjects.swift index 2127de7..92ec789 100644 --- a/Sources/JNI/JNIObjects.swift +++ b/Sources/JNI/JNIObjects.swift @@ -10,7 +10,7 @@ open class JNIObject { private static var classInstances = [String: JavaClass]() - public class var javaClass: JavaClass { + public static var javaClass: JavaClass { return DispatchQueue.main.sync { if let classInstance = classInstances[className] { return classInstance