Dev: add expiremental API with automatic #functionName resolving

This commit is contained in:
Andrew Druk 2017-11-24 19:56:09 +02:00
parent cf0a3934b9
commit fa93e4ed20
3 changed files with 121 additions and 37 deletions

View File

@ -9,94 +9,140 @@ import Foundation
import java_swift
public protocol JNIArgumentProtocol {
func value() -> jvalue
func value(locals: UnsafeMutablePointer<[jobject]>) -> jvalue
func sig() -> String
}
public struct jnull: JNIArgumentProtocol {
public func value() -> jvalue {
let className: String
public func value(locals: UnsafeMutablePointer<[jobject]>) -> jvalue {
return jvalue()
}
public func sig() -> String {
return "L\(className);"
}
}
extension jint: JNIArgumentProtocol {
public func value() -> jvalue {
public func value(locals: UnsafeMutablePointer<[jobject]>) -> jvalue {
return jvalue(i: self)
}
public func sig() -> String {
return "I"
}
}
extension jbyte: JNIArgumentProtocol {
public func value() -> jvalue {
public func value(locals: UnsafeMutablePointer<[jobject]>) -> jvalue {
return jvalue(b: self)
}
public func sig() -> String {
return "B"
}
}
extension jchar: JNIArgumentProtocol {
public func value() -> jvalue {
public func value(locals: UnsafeMutablePointer<[jobject]>) -> jvalue {
return jvalue(c: self)
}
public func sig() -> String {
return "C"
}
}
extension jshort: JNIArgumentProtocol {
public func value() -> jvalue {
public func value(locals: UnsafeMutablePointer<[jobject]>) -> jvalue {
return jvalue(s: self)
}
public func sig() -> String {
return "S"
}
}
extension jlong: JNIArgumentProtocol {
public func value() -> jvalue {
public func value(locals: UnsafeMutablePointer<[jobject]>) -> jvalue {
return jvalue(j: self)
}
public func sig() -> String {
return "J"
}
}
extension jboolean: JNIArgumentProtocol {
public func value() -> jvalue {
public func value(locals: UnsafeMutablePointer<[jobject]>) -> jvalue {
return jvalue(z: self)
}
public func sig() -> String {
return "Z"
}
}
extension jfloat: JNIArgumentProtocol {
public func value() -> jvalue {
public func value(locals: UnsafeMutablePointer<[jobject]>) -> jvalue {
return jvalue(f: self)
}
public func sig() -> String {
return "F"
}
}
extension jdouble: JNIArgumentProtocol {
public func value() -> jvalue {
public func value(locals: UnsafeMutablePointer<[jobject]>) -> jvalue {
return jvalue(d: self)
}
public func sig() -> String {
return "D"
}
}
extension String: JNIArgumentProtocol {
public func value(locals: UnsafeMutablePointer<[jobject]>) -> jvalue {
return jvalue(l: self.localJavaObject(locals))
}
public func sig() -> String {
return "Ljava/lang/String;"
}
}
extension jobject: JNIArgumentProtocol {
public func value() -> jvalue {
public func value(locals: UnsafeMutablePointer<[jobject]>) -> jvalue {
return jvalue(l: self)
}
}
// For backward compatibility
extension jvalue: JNIArgumentProtocol {
public func value() -> jvalue {
return self
public func sig() -> String {
return "L\(JNIObject.getJavaClassname(javaObject: self));"
}
}

View File

@ -88,10 +88,6 @@ fileprivate let javaFieldLock = NSLock()
public extension JNICore {
public var NULL: JNIArgumentProtocol {
return jnull()
}
public var TRUE: jboolean {
return jboolean(JNI_TRUE)
}
@ -327,8 +323,12 @@ public extension JNICore {
private func checkArgumentAndWrap<Result>(args: [JNIArgumentProtocol], _ block: (_ argsPtr: UnsafePointer<jvalue>?) -> Result) -> Result {
if args.count > 0 {
var argsValues = args.map({ $0.value() })
var locals = [jobject]()
var argsValues = args.map({ $0.value(locals: &locals) })
return withUnsafePointer(to: &argsValues[0]) { argsPtr in
defer {
_ = JNI.check(Void.self, &locals)
}
return block(argsPtr)
}
}

View File

@ -8,35 +8,73 @@
import Foundation
import java_swift
public class JNIObjectWithClass: JNIObject {
var privateClassName: String!
public required init(javaObject: jobject?) {
super.init(javaObject: javaObject)
privateClassName = JNIObject.getJavaClassname(javaObject: self.javaObject)
}
public required init(javaObject: jobject?, className: String) {
super.init(javaObject: javaObject)
self.privateClassName = className
}
}
public extension JNIObject {
public static func getJavaClassname(javaObject: jobject?) -> String {
let cls = JNI.api.GetObjectClass(JNI.env, javaObject)
let javaClassName = JNI.api.CallObjectMethodA(JNI.env, cls, ClassGetNameMethod, nil)
return String(javaObject: javaClassName).replacingOccurrences(of: ".", with: "/")
}
public var className: String {
if let jniObject = self as? JNIObjectWithClass {
return jniObject.privateClassName
}
return JNIObject.getJavaClassname(javaObject: self.javaObject)
}
public func callVoidMethod(_ methodID: jmethodID, _ args: JNIArgumentProtocol..., locals: UnsafeMutablePointer<[jobject]>? = nil) {
public func callVoidMethod(_ methodID: jmethodID, _ args: JNIArgumentProtocol...) {
checkArgumentAndWrap(args: args, { argsPtr in
JNI.api.CallVoidMethodA(JNI.env, javaObject, methodID, argsPtr)
})
}
private func checkArgumentAndWrap<Result>(args: [JNIArgumentProtocol], _ block: (_ argsPtr: UnsafePointer<jvalue>?) -> Result, locals: UnsafeMutablePointer<[jobject]>? = nil) -> Result {
public func callStringMethod(method: String? = nil, functionName: String = #function, _ args: JNIArgumentProtocol...) -> String {
let methodName = method ?? String(functionName.split(separator: "(")[0])
return String(javaObject: self.internalcallObjectMethod(method: methodName, returnType: "Ljava/lang/String;", args))
}
public func callObjectMethod(method: String? = nil, functionName: String = #function, returnType: String, _ args: JNIArgumentProtocol...) -> jobject? {
let methodName = method ?? String(functionName.split(separator: "(")[0])
return self.internalcallObjectMethod(method: methodName, returnType: returnType, args)
}
private func internalcallObjectMethod(method: String, returnType: String, _ args: [JNIArgumentProtocol]) -> jobject? {
let sig = "(\(args.map({ $0.sig() }).joined()))\(returnType)"
let methodID = try! JNI.getJavaMethod(forClass: self.className, method: method, sig: sig)
return checkArgumentAndWrap(args: args, { argsPtr in
return JNI.api.CallObjectMethodA(JNI.env, javaObject, methodID, argsPtr)
})
}
private func checkArgumentAndWrap<Result>(args: [JNIArgumentProtocol], _ block: (_ argsPtr: UnsafePointer<jvalue>?) -> Result) -> Result {
if args.count > 0 {
var argsValues = args.map({ $0.value() })
var locals = [jobject]()
var argsValues = args.map({ $0.value(locals: &locals) })
return withUnsafePointer(to: &argsValues[0]) { argsPtr in
defer {
if let locals = locals {
_ = JNI.check(Void.self, locals)
}
_ = JNI.check(Void.self, &locals)
}
return block(argsPtr)
}
}
else {
defer {
if let locals = locals {
_ = JNI.check(Void.self, locals)
}
}
return block(nil)
}
}