diff --git a/Sources/JNI/JNIObjects.swift b/Sources/JNI/JNIObjects.swift index b8a9f53..92ec789 100644 --- a/Sources/JNI/JNIObjects.swift +++ b/Sources/JNI/JNIObjects.swift @@ -1,9 +1,30 @@ 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" + } + + private static var classInstances = [String: JavaClass]() + + public static var javaClass: JavaClass { + return DispatchQueue.main.sync { + if let classInstance = classInstances[className] { + return classInstance + } + + let javaClassLocalRef = try! jni.FindClass(name: className.replacingFullstopsWithSlashes()) + try! checkAndThrowOnJNIError() + let classInstance = jni.NewGlobalRef(javaClassLocalRef)! + classInstances[className] = classInstance + + return classInstance + } + } + public let instance: JavaObject required public init(_ instance: JavaObject) throws { @@ -11,13 +32,11 @@ 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 } + @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) @@ -29,22 +48,39 @@ 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) - 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 { @@ -55,7 +91,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() @@ -64,19 +103,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! - } + } }