Dev: add registration external type via JavaCoderConfig
This commit is contained in:
parent
e72d52c36c
commit
0d15cf94df
|
@ -0,0 +1,150 @@
|
||||||
|
//
|
||||||
|
// Created by Andrew on 12/22/17.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import java_swift
|
||||||
|
|
||||||
|
public typealias JavaDecodableClosure = (jobject) throws -> Decodable
|
||||||
|
public typealias JavaEncodableClosure = (Encodable) throws -> jobject
|
||||||
|
|
||||||
|
public struct JavaCoderConfig {
|
||||||
|
|
||||||
|
private static let closuresLock = NSRecursiveLock()
|
||||||
|
|
||||||
|
static var decodableClosures = [String: JavaDecodableClosure]()
|
||||||
|
static var encodableClosures = [String: JavaEncodableClosure]()
|
||||||
|
static var codableClassNames = [String: String]()
|
||||||
|
|
||||||
|
public static func RegisterType<T: Codable>(type: T.Type,
|
||||||
|
javaClassname: String,
|
||||||
|
encodableClosure: @escaping JavaEncodableClosure,
|
||||||
|
decodableClosure: @escaping JavaDecodableClosure) {
|
||||||
|
closuresLock.lock()
|
||||||
|
defer {
|
||||||
|
closuresLock.unlock()
|
||||||
|
}
|
||||||
|
let typeName = String(reflecting: type)
|
||||||
|
NSLog("JavaCoderConfig register: \(typeName)")
|
||||||
|
codableClassNames[typeName] = javaClassname
|
||||||
|
encodableClosures[typeName] = encodableClosure
|
||||||
|
decodableClosures[typeName] = decodableClosure
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func RegisterBasicJavaTypes() {
|
||||||
|
|
||||||
|
RegisterType(type: Int.self, javaClassname: IntegerClassname, encodableClosure: {
|
||||||
|
// jint for macOS and Android different, that's why we make cast to jint() here
|
||||||
|
let args = [jvalue(i: jint($0 as! Int))]
|
||||||
|
return JNI.NewObject(IntegerClass, methodID: IntegerConstructor, args: args)!
|
||||||
|
}, decodableClosure: {
|
||||||
|
return Int(JNI.CallIntMethod($0, methodID: NumberIntValueMethod))
|
||||||
|
})
|
||||||
|
|
||||||
|
RegisterType(type: Int8.self, javaClassname: ByteClassname, encodableClosure: {
|
||||||
|
let args = [jvalue(b: $0 as! Int8)]
|
||||||
|
return JNI.NewObject(ByteClass, methodID: ByteConstructor, args: args)!
|
||||||
|
}, decodableClosure: {
|
||||||
|
return JNI.CallByteMethod($0, methodID: NumberByteValueMethod)
|
||||||
|
})
|
||||||
|
|
||||||
|
RegisterType(type: Int16.self, javaClassname: ShortClassname, encodableClosure: {
|
||||||
|
let args = [jvalue(s: $0 as! Int16)]
|
||||||
|
return JNI.NewObject(ShortClass, methodID: ShortConstructor, args: args)!
|
||||||
|
}, decodableClosure: {
|
||||||
|
return JNI.CallShortMethod($0, methodID: NumberShortValueMethod)
|
||||||
|
})
|
||||||
|
|
||||||
|
RegisterType(type: Int32.self, javaClassname: IntegerClassname, encodableClosure: {
|
||||||
|
let args = [jvalue(i: jint($0 as! Int32))]
|
||||||
|
return JNI.NewObject(IntegerClass, methodID: IntegerConstructor, args: args)!
|
||||||
|
}, decodableClosure: {
|
||||||
|
return Int32(JNI.CallIntMethod($0, methodID: NumberIntValueMethod))
|
||||||
|
})
|
||||||
|
|
||||||
|
RegisterType(type: Int64.self, javaClassname: LongClassname, encodableClosure: {
|
||||||
|
let args = [jvalue(j: $0 as! Int64)]
|
||||||
|
return JNI.NewObject(LongClass, methodID: LongConstructor, args: args)!
|
||||||
|
}, decodableClosure: {
|
||||||
|
return JNI.CallLongMethod($0, methodID: NumberLongValueMethod)
|
||||||
|
})
|
||||||
|
|
||||||
|
RegisterType(type: UInt.self, javaClassname: LongClassname, encodableClosure: {
|
||||||
|
let args = [jvalue(j: Int64($0 as! UInt))]
|
||||||
|
return JNI.NewObject(LongClass, methodID: LongConstructor, args: args)!
|
||||||
|
}, decodableClosure: {
|
||||||
|
return UInt(JNI.CallLongMethod($0, methodID: NumberLongValueMethod))
|
||||||
|
})
|
||||||
|
|
||||||
|
RegisterType(type: UInt8.self, javaClassname: ShortClassname, encodableClosure: {
|
||||||
|
let args = [jvalue(s: Int16($0 as! UInt8))]
|
||||||
|
return JNI.NewObject(ShortClass, methodID: ShortConstructor, args: args)!
|
||||||
|
}, decodableClosure: {
|
||||||
|
return UInt8(JNI.CallShortMethod($0, methodID: NumberShortValueMethod))
|
||||||
|
})
|
||||||
|
|
||||||
|
RegisterType(type: UInt16.self, javaClassname: IntegerClassname, encodableClosure: {
|
||||||
|
let args = [jvalue(i: jint($0 as! UInt16))]
|
||||||
|
return JNI.NewObject(IntegerClass, methodID: IntegerConstructor, args: args)!
|
||||||
|
}, decodableClosure: {
|
||||||
|
return UInt16(JNI.CallIntMethod($0, methodID: NumberIntValueMethod))
|
||||||
|
})
|
||||||
|
|
||||||
|
RegisterType(type: UInt32.self, javaClassname: LongClassname, encodableClosure: {
|
||||||
|
let args = [jvalue(j: Int64($0 as! UInt32))]
|
||||||
|
return JNI.NewObject(LongClass, methodID: LongConstructor, args: args)!
|
||||||
|
}, decodableClosure: {
|
||||||
|
return UInt32(JNI.CallLongMethod($0, methodID: NumberLongValueMethod))
|
||||||
|
})
|
||||||
|
|
||||||
|
RegisterType(type: UInt64.self, javaClassname: BigIntegerClassname, encodableClosure: {
|
||||||
|
var locals = [jobject]()
|
||||||
|
let args = [jvalue(l: String($0 as! UInt64).localJavaObject(&locals))]
|
||||||
|
return JNI.check(JNI.NewObject(BigIntegerClass, methodID: BigIntegerConstructor, args: args)!, &locals)
|
||||||
|
}, decodableClosure: {
|
||||||
|
let javaString = JNI.CallObjectMethod($0, methodID: ObjectToStringMethod)
|
||||||
|
defer {
|
||||||
|
JNI.api.DeleteLocalRef(JNI.env, javaString)
|
||||||
|
}
|
||||||
|
let stringRepresentation = String(javaObject: javaString)
|
||||||
|
return UInt64(stringRepresentation)
|
||||||
|
})
|
||||||
|
|
||||||
|
RegisterType(type: Bool.self, javaClassname: BooleanClassname, encodableClosure: {
|
||||||
|
let args = [jvalue(z: $0 as! Bool ? JNI.TRUE : JNI.FALSE)]
|
||||||
|
return JNI.NewObject(BooleanClass, methodID: BooleanConstructor, args: args)!
|
||||||
|
}, decodableClosure: {
|
||||||
|
return (JNI.CallBooleanMethod($0, methodID: NumberBooleanValueMethod) == JNI.TRUE)
|
||||||
|
})
|
||||||
|
|
||||||
|
RegisterType(type: String.self, javaClassname: StringClassname, encodableClosure: {
|
||||||
|
let valueString = $0 as! String
|
||||||
|
var locals = [jobject]()
|
||||||
|
// Locals ignored because JNIStorageObject take ownership of LocalReference
|
||||||
|
return valueString.localJavaObject(&locals)!
|
||||||
|
}, decodableClosure: {
|
||||||
|
return String(javaObject: $0)
|
||||||
|
})
|
||||||
|
|
||||||
|
RegisterType(type: Date.self, javaClassname: DateClassname, encodableClosure: {
|
||||||
|
let valueDate = $0 as! Date
|
||||||
|
let args = [jvalue(j: jlong(valueDate.timeIntervalSince1970 * 1000))]
|
||||||
|
return JNI.NewObject(DateClass, methodID: DateConstructor, args: args)!
|
||||||
|
}, decodableClosure: {
|
||||||
|
let timeInterval = JNI.api.CallLongMethodA(JNI.env, $0, DateGetTimeMethod, nil)
|
||||||
|
// Java save TimeInterval in UInt64 milliseconds
|
||||||
|
return Date(timeIntervalSince1970: TimeInterval(timeInterval) / 1000.0)
|
||||||
|
})
|
||||||
|
|
||||||
|
RegisterType(type: URL.self, javaClassname: UriClassname, encodableClosure: {
|
||||||
|
var locals = [jobject]()
|
||||||
|
let javaString = ($0 as! URL).absoluteString.localJavaObject(&locals)
|
||||||
|
let args = [jvalue(l: javaString)]
|
||||||
|
return JNI.check(JNI.CallStaticObjectMethod(UriClass, methodID: UriConstructor!, args: args)!, &locals)
|
||||||
|
}, decodableClosure: {
|
||||||
|
let pathString = JNI.api.CallObjectMethodA(JNI.env, $0, ObjectToStringMethod, nil)
|
||||||
|
return URL(string: String(javaObject: pathString))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -605,55 +605,9 @@ fileprivate class JavaAnyCodableContainer<K : CodingKey> : KeyedDecodingContaine
|
||||||
extension JavaDecoder {
|
extension JavaDecoder {
|
||||||
|
|
||||||
fileprivate func unbox<T: Decodable>(type: T.Type, javaObject: jobject) throws -> T {
|
fileprivate func unbox<T: Decodable>(type: T.Type, javaObject: jobject) throws -> T {
|
||||||
if type == Int.self {
|
let typeName = String(reflecting: type)
|
||||||
return Int(JNI.CallIntMethod(javaObject, methodID: NumberIntValueMethod)) as! T
|
if let decodableClosure = JavaCoderConfig.decodableClosures[typeName] {
|
||||||
}
|
return try decodableClosure(javaObject) as! T
|
||||||
else if type == Int8.self {
|
|
||||||
return JNI.CallByteMethod(javaObject, methodID: NumberByteValueMethod) as! T
|
|
||||||
}
|
|
||||||
else if type == Int16.self {
|
|
||||||
return JNI.CallShortMethod(javaObject, methodID: NumberShortValueMethod) as! T
|
|
||||||
}
|
|
||||||
else if type == Int32.self {
|
|
||||||
return Int32(JNI.CallIntMethod(javaObject, methodID: NumberIntValueMethod)) as! T
|
|
||||||
}
|
|
||||||
else if type == Int64.self {
|
|
||||||
return JNI.CallLongMethod(javaObject, methodID: NumberLongValueMethod) as! T
|
|
||||||
}
|
|
||||||
else if type == UInt.self {
|
|
||||||
return UInt(JNI.CallLongMethod(javaObject, methodID: NumberLongValueMethod)) as! T
|
|
||||||
}
|
|
||||||
else if type == UInt8.self {
|
|
||||||
return UInt8(JNI.CallShortMethod(javaObject, methodID: NumberShortValueMethod)) as! T
|
|
||||||
}
|
|
||||||
else if type == UInt16.self {
|
|
||||||
return UInt16(JNI.CallIntMethod(javaObject, methodID: NumberIntValueMethod)) as! T
|
|
||||||
}
|
|
||||||
else if type == UInt32.self {
|
|
||||||
return UInt32(JNI.CallLongMethod(javaObject, methodID: NumberLongValueMethod)) as! T
|
|
||||||
}
|
|
||||||
else if type == UInt64.self {
|
|
||||||
let javaString = JNI.CallObjectMethod(javaObject, methodID: ObjectToStringMethod)
|
|
||||||
defer {
|
|
||||||
JNI.api.DeleteLocalRef(JNI.env, javaString)
|
|
||||||
}
|
|
||||||
let stringRepresentation = String(javaObject: javaString)
|
|
||||||
return UInt64(stringRepresentation) as! T
|
|
||||||
}
|
|
||||||
else if type == Bool.self {
|
|
||||||
return (JNI.CallBooleanMethod(javaObject, methodID: NumberBooleanValueMethod) == JNI.TRUE) as! T
|
|
||||||
}
|
|
||||||
else if type == String.self {
|
|
||||||
return String(javaObject: javaObject) as! T
|
|
||||||
}
|
|
||||||
else if type == Date.self {
|
|
||||||
let timeInterval = JNI.api.CallLongMethodA(JNI.env, javaObject, DateGetTimeMethod, nil)
|
|
||||||
// Java save TimeInterval in UInt64 milliseconds
|
|
||||||
return Date(timeIntervalSince1970: TimeInterval(timeInterval) / 1000.0) as! T
|
|
||||||
}
|
|
||||||
else if type == URL.self {
|
|
||||||
let pathString = JNI.api.CallObjectMethodA(JNI.env, javaObject, ObjectToStringMethod, nil)
|
|
||||||
return URL(string: String(javaObject: pathString)) as! T
|
|
||||||
}
|
}
|
||||||
else if type == AnyCodable.self {
|
else if type == AnyCodable.self {
|
||||||
let cls = JNI.api.GetObjectClass(JNI.env, javaObject)
|
let cls = JNI.api.GetObjectClass(JNI.env, javaObject)
|
||||||
|
@ -699,47 +653,9 @@ extension JavaDecoder {
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func getJavaClassname<T>(forType: T.Type) -> String {
|
fileprivate func getJavaClassname<T>(forType: T.Type) -> String {
|
||||||
if T.self == Int.self {
|
let typeName = String(reflecting: forType)
|
||||||
return IntegerClassname
|
if let className = JavaCoderConfig.codableClassNames[typeName] {
|
||||||
}
|
return className
|
||||||
else if T.self == Int8.self {
|
|
||||||
return ByteClassname
|
|
||||||
}
|
|
||||||
else if T.self == Int16.self {
|
|
||||||
return ShortClassname
|
|
||||||
}
|
|
||||||
else if T.self == Int32.self {
|
|
||||||
return IntegerClassname
|
|
||||||
}
|
|
||||||
else if T.self == Int64.self {
|
|
||||||
return LongClassname
|
|
||||||
}
|
|
||||||
else if T.self == UInt.self {
|
|
||||||
return LongClassname
|
|
||||||
}
|
|
||||||
else if T.self == UInt8.self {
|
|
||||||
return ShortClassname
|
|
||||||
}
|
|
||||||
else if T.self == UInt16.self {
|
|
||||||
return IntegerClassname
|
|
||||||
}
|
|
||||||
else if T.self == UInt32.self {
|
|
||||||
return LongClassname
|
|
||||||
}
|
|
||||||
else if T.self == UInt64.self {
|
|
||||||
return BigIntegerClassname
|
|
||||||
}
|
|
||||||
else if T.self == Bool.self {
|
|
||||||
return BooleanClassname
|
|
||||||
}
|
|
||||||
else if T.self == String.self {
|
|
||||||
return StringClassname
|
|
||||||
}
|
|
||||||
else if T.self == Date.self {
|
|
||||||
return DateClassname
|
|
||||||
}
|
|
||||||
else if T.self == URL.self {
|
|
||||||
return UriClassname
|
|
||||||
}
|
}
|
||||||
else if "\(forType)".starts(with: "Array<") {
|
else if "\(forType)".starts(with: "Array<") {
|
||||||
return ArrayListClassname
|
return ArrayListClassname
|
||||||
|
|
|
@ -513,94 +513,10 @@ extension JavaEncoder {
|
||||||
|
|
||||||
fileprivate func box<T: Encodable>(_ value: T) throws -> JNIStorageObject {
|
fileprivate func box<T: Encodable>(_ value: T) throws -> JNIStorageObject {
|
||||||
let storage: JNIStorageObject
|
let storage: JNIStorageObject
|
||||||
|
let typeName = String(reflecting: type(of: value))
|
||||||
if T.self == Int.self {
|
if let encodableClosure = JavaCoderConfig.encodableClosures[typeName] {
|
||||||
let valueInt = value as! Int
|
let javaObject = try encodableClosure(value)
|
||||||
// jint for macOS and Android defferent, that's why we make cast to jint() here
|
storage = JNIStorageObject(type: .object(className: JavaCoderConfig.codableClassNames[typeName]!), javaObject: javaObject)
|
||||||
let args = [jvalue(i: jint(valueInt))]
|
|
||||||
let javaObject = JNI.NewObject(IntegerClass, methodID: IntegerConstructor, args: args)
|
|
||||||
storage = JNIStorageObject.init(type: .object(className: IntegerClassname), javaObject: javaObject!)
|
|
||||||
}
|
|
||||||
else if T.self == Int8.self {
|
|
||||||
let valueInt8 = value as! Int8
|
|
||||||
let args = [jvalue(b: valueInt8)]
|
|
||||||
let javaObject = JNI.NewObject(ByteClass, methodID: ByteConstructor, args: args)
|
|
||||||
storage = JNIStorageObject.init(type: .object(className: ByteClassname), javaObject: javaObject!)
|
|
||||||
}
|
|
||||||
else if T.self == Int16.self {
|
|
||||||
let valueInt16 = value as! Int16
|
|
||||||
let args = [jvalue(s: valueInt16)]
|
|
||||||
let javaObject = JNI.NewObject(ShortClass, methodID: ShortConstructor, args: args)
|
|
||||||
storage = JNIStorageObject.init(type: .object(className: ShortClassname), javaObject: javaObject!)
|
|
||||||
}
|
|
||||||
else if T.self == Int32.self {
|
|
||||||
let valueInt32 = value as! Int32
|
|
||||||
let args = [jvalue(i: jint(valueInt32))]
|
|
||||||
let javaObject = JNI.NewObject(IntegerClass, methodID: IntegerConstructor, args: args)
|
|
||||||
storage = JNIStorageObject.init(type: .object(className: IntegerClassname), javaObject: javaObject!)
|
|
||||||
}
|
|
||||||
else if T.self == Int64.self {
|
|
||||||
let valueInt64 = value as! Int64
|
|
||||||
let args = [jvalue(j: valueInt64)]
|
|
||||||
let javaObject = JNI.NewObject(LongClass, methodID: LongConstructor, args: args)
|
|
||||||
storage = JNIStorageObject.init(type: .object(className: LongClassname), javaObject: javaObject!)
|
|
||||||
}
|
|
||||||
else if T.self == UInt.self {
|
|
||||||
let valueUInt = value as! UInt
|
|
||||||
let args = [jvalue(j: Int64(valueUInt))]
|
|
||||||
let javaObject = JNI.NewObject(LongClass, methodID: LongConstructor, args: args)
|
|
||||||
storage = JNIStorageObject.init(type: .object(className: LongClassname), javaObject: javaObject!)
|
|
||||||
}
|
|
||||||
else if T.self == UInt8.self {
|
|
||||||
let valueUInt8 = value as! UInt8
|
|
||||||
let args = [jvalue(s: Int16(valueUInt8))]
|
|
||||||
let javaObject = JNI.NewObject(ShortClass, methodID: ShortConstructor, args: args)
|
|
||||||
storage = JNIStorageObject.init(type: .object(className: ShortClassname), javaObject: javaObject!)
|
|
||||||
}
|
|
||||||
else if T.self == UInt16.self {
|
|
||||||
let valueUInt16 = value as! UInt16
|
|
||||||
let args = [jvalue(i: jint(valueUInt16))]
|
|
||||||
let javaObject = JNI.NewObject(IntegerClass, methodID: IntegerConstructor, args: args)
|
|
||||||
storage = JNIStorageObject.init(type: .object(className: IntegerClassname), javaObject: javaObject!)
|
|
||||||
}
|
|
||||||
else if T.self == UInt32.self {
|
|
||||||
let valueUInt32 = value as! UInt32
|
|
||||||
let args = [jvalue(j: Int64(valueUInt32))]
|
|
||||||
let javaObject = JNI.NewObject(LongClass, methodID: LongConstructor, args: args)
|
|
||||||
storage = JNIStorageObject.init(type: .object(className: LongClassname), javaObject: javaObject!)
|
|
||||||
}
|
|
||||||
else if T.self == UInt64.self {
|
|
||||||
let valueInt64 = value as! UInt64
|
|
||||||
var locals = [jobject]()
|
|
||||||
let args = [jvalue(l: String(valueInt64).localJavaObject(&locals))]
|
|
||||||
let javaObject = JNI.check(JNI.NewObject(BigIntegerClass, methodID: BigIntegerConstructor, args: args), &locals)
|
|
||||||
storage = JNIStorageObject.init(type: .object(className: BigIntegerClassname), javaObject: javaObject!)
|
|
||||||
}
|
|
||||||
else if T.self == Bool.self {
|
|
||||||
let valueBool = value as! Bool
|
|
||||||
let args = [jvalue(z: valueBool ? JNI.TRUE : JNI.FALSE)]
|
|
||||||
let javaObject = JNI.NewObject(BooleanClass, methodID: BooleanConstructor, args: args)
|
|
||||||
storage = JNIStorageObject.init(type: .object(className: BooleanClassname), javaObject: javaObject!)
|
|
||||||
}
|
|
||||||
else if T.self == String.self {
|
|
||||||
let valueString = value as! String
|
|
||||||
var locals = [jobject]()
|
|
||||||
let javaObject = valueString.localJavaObject(&locals)
|
|
||||||
// Locals ignored because JNIStorageObject take ownership of LocalReference
|
|
||||||
storage = JNIStorageObject.init(type: .object(className: StringClassname), javaObject: javaObject!)
|
|
||||||
}
|
|
||||||
else if T.self == Date.self {
|
|
||||||
let valueDate = value as! Date
|
|
||||||
let args = [jvalue(j: jlong(valueDate.timeIntervalSince1970 * 1000))]
|
|
||||||
let dateObject = JNI.NewObject(DateClass, methodID: DateConstructor, args: args)
|
|
||||||
storage = JNIStorageObject.init(type: .object(className: DateClassname), javaObject: dateObject!)
|
|
||||||
}
|
|
||||||
else if T.self == URL.self {
|
|
||||||
var locals = [jobject]()
|
|
||||||
let javaString = (value as! URL).absoluteString.localJavaObject(&locals)
|
|
||||||
let args = [jvalue(l: javaString)]
|
|
||||||
let uriObject = JNI.check(JNI.CallStaticObjectMethod(UriClass, methodID: UriConstructor!, args: args), &locals)
|
|
||||||
storage = JNIStorageObject.init(type: .object(className: UriClassname), javaObject: uriObject!)
|
|
||||||
}
|
}
|
||||||
else if T.self == AnyCodable.self {
|
else if T.self == AnyCodable.self {
|
||||||
let anyCodableValue = value as! AnyCodable
|
let anyCodableValue = value as! AnyCodable
|
||||||
|
|
Loading…
Reference in New Issue