Dev: move java boxing to dedicated method
This commit is contained in:
parent
e6cbf47660
commit
8880665e42
|
@ -68,6 +68,7 @@ func getJavaClass(_ className: String) throws -> jclass {
|
||||||
}
|
}
|
||||||
guard let javaClass = JNI.GlobalFindClass(className) else {
|
guard let javaClass = JNI.GlobalFindClass(className) else {
|
||||||
JNI.api.ExceptionClear(JNI.env)
|
JNI.api.ExceptionClear(JNI.env)
|
||||||
|
JNI.ExceptionReset()
|
||||||
throw JNIError.classNotFoundException(className)
|
throw JNIError.classNotFoundException(className)
|
||||||
}
|
}
|
||||||
javaClasses[className] = javaClass
|
javaClasses[className] = javaClass
|
||||||
|
@ -91,6 +92,7 @@ func getJavaMethod(forClass className: String, method: String, sig: String) thro
|
||||||
}
|
}
|
||||||
guard let javaMethodID = JNI.api.GetMethodID(JNI.env, javaClass, method, sig) else {
|
guard let javaMethodID = JNI.api.GetMethodID(JNI.env, javaClass, method, sig) else {
|
||||||
JNI.api.ExceptionClear(JNI.env)
|
JNI.api.ExceptionClear(JNI.env)
|
||||||
|
JNI.ExceptionReset()
|
||||||
throw JNIError.methodNotFoundException(key)
|
throw JNIError.methodNotFoundException(key)
|
||||||
}
|
}
|
||||||
javaMethods[key] = javaMethodID
|
javaMethods[key] = javaMethodID
|
||||||
|
@ -110,6 +112,7 @@ func getJavaField(forClass className: String, field: String, sig: String) throws
|
||||||
}
|
}
|
||||||
guard let fieldID = JNI.api.GetFieldID(JNI.env, javaClass, field, sig) else {
|
guard let fieldID = JNI.api.GetFieldID(JNI.env, javaClass, field, sig) else {
|
||||||
JNI.api.ExceptionClear(JNI.env)
|
JNI.api.ExceptionClear(JNI.env)
|
||||||
|
JNI.ExceptionReset()
|
||||||
throw JNIError.fieldNotFoundException(key)
|
throw JNIError.fieldNotFoundException(key)
|
||||||
}
|
}
|
||||||
javaFields[key] = fieldID
|
javaFields[key] = fieldID
|
||||||
|
@ -135,6 +138,7 @@ extension JNICore {
|
||||||
let dump_mid = JNI.api.GetStaticMethodID(JNI.env, vm_class, "dumpReferenceTables", "()V")
|
let dump_mid = JNI.api.GetStaticMethodID(JNI.env, vm_class, "dumpReferenceTables", "()V")
|
||||||
JNI.api.CallStaticVoidMethodA(JNI.env, vm_class, dump_mid, nil)
|
JNI.api.CallStaticVoidMethodA(JNI.env, vm_class, dump_mid, nil)
|
||||||
JNI.api.ExceptionClear(JNI.env)
|
JNI.api.ExceptionClear(JNI.env)
|
||||||
|
JNI.ExceptionReset()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,16 +31,13 @@ public class JavaDecoder: Decoder {
|
||||||
public func decode<T : Decodable>(_ type: T.Type, from javaObject: jobject) throws -> T {
|
public func decode<T : Decodable>(_ type: T.Type, from javaObject: jobject) throws -> T {
|
||||||
do {
|
do {
|
||||||
let rootStorageType = try getJavaClassname(from: javaObject)
|
let rootStorageType = try getJavaClassname(from: javaObject)
|
||||||
self.storage.append(JNIStorageObject(type: rootStorageType, javaObject: javaObject))
|
self.storage.append(JNIStorageObject(type: rootStorageType, javaObject: JNI.api.NewLocalRef(JNI.env, javaObject)!))
|
||||||
let value = try T(from: self)
|
let value = try T(from: self)
|
||||||
assert(self.storage.count == 0, "Missing decoding for \(self.storage.count) objects")
|
assert(self.storage.count == 0, "Missing decoding for \(self.storage.count) objects")
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
// clean all reference if failed
|
// clean all reference if failed
|
||||||
for storageObject in self.storage {
|
|
||||||
JNI.api.DeleteLocalRef(JNI.env, storageObject.javaObject)
|
|
||||||
}
|
|
||||||
self.storage.removeAll()
|
self.storage.removeAll()
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
@ -89,11 +86,13 @@ fileprivate class JavaObjectContainer<K : CodingKey> : KeyedDecodingContainerPro
|
||||||
var allKeys = [K]()
|
var allKeys = [K]()
|
||||||
|
|
||||||
let decoder: JavaDecoder
|
let decoder: JavaDecoder
|
||||||
|
let jniStorage: JNIStorageObject
|
||||||
let javaObject: jobject
|
let javaObject: jobject
|
||||||
let javaClass: String
|
let javaClass: String
|
||||||
|
|
||||||
fileprivate init(decoder: JavaDecoder, jniStorage: JNIStorageObject) {
|
fileprivate init(decoder: JavaDecoder, jniStorage: JNIStorageObject) {
|
||||||
self.decoder = decoder
|
self.decoder = decoder
|
||||||
|
self.jniStorage = jniStorage
|
||||||
self.javaObject = jniStorage.javaObject
|
self.javaObject = jniStorage.javaObject
|
||||||
switch jniStorage.type {
|
switch jniStorage.type {
|
||||||
case let .object(className):
|
case let .object(className):
|
||||||
|
@ -103,10 +102,6 @@ fileprivate class JavaObjectContainer<K : CodingKey> : KeyedDecodingContainerPro
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
|
||||||
JNI.api.DeleteLocalRef(JNI.env, self.javaObject)
|
|
||||||
}
|
|
||||||
|
|
||||||
func contains(_ key: K) -> Bool {
|
func contains(_ key: K) -> Bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -256,12 +251,14 @@ fileprivate class JavaHashMapContainer<K : CodingKey>: KeyedDecodingContainerPro
|
||||||
var allKeys = [K]()
|
var allKeys = [K]()
|
||||||
|
|
||||||
private let decoder: JavaDecoder
|
private let decoder: JavaDecoder
|
||||||
|
private let jniStorage: JNIStorageObject
|
||||||
private let javaObject: jobject
|
private let javaObject: jobject
|
||||||
private let javaKeys: [String: jobject]
|
private let javaKeys: [String: jobject]
|
||||||
private let getMethod: jmethodID
|
private let getMethod: jmethodID
|
||||||
|
|
||||||
fileprivate init(decoder: JavaDecoder, jniStorage: JNIStorageObject) throws {
|
fileprivate init(decoder: JavaDecoder, jniStorage: JNIStorageObject) throws {
|
||||||
self.decoder = decoder
|
self.decoder = decoder
|
||||||
|
self.jniStorage = jniStorage
|
||||||
self.javaObject = jniStorage.javaObject
|
self.javaObject = jniStorage.javaObject
|
||||||
self.getMethod = try getJavaMethod(forClass: JavaHashMapClassname, method: "get", sig: "(L\(JavaObjectClassname);)L\(JavaObjectClassname);")
|
self.getMethod = try getJavaMethod(forClass: JavaHashMapClassname, method: "get", sig: "(L\(JavaObjectClassname);)L\(JavaObjectClassname);")
|
||||||
|
|
||||||
|
@ -294,7 +291,6 @@ fileprivate class JavaHashMapContainer<K : CodingKey>: KeyedDecodingContainerPro
|
||||||
for (_, value) in self.javaKeys {
|
for (_, value) in self.javaKeys {
|
||||||
JNI.api.DeleteLocalRef(JNI.env, value)
|
JNI.api.DeleteLocalRef(JNI.env, value)
|
||||||
}
|
}
|
||||||
JNI.api.DeleteLocalRef(JNI.env, self.javaObject)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func contains(_ key: K) -> Bool {
|
func contains(_ key: K) -> Bool {
|
||||||
|
@ -359,19 +355,17 @@ fileprivate class JavaUnkeyedDecodingContainer: UnkeyedDecodingContainer {
|
||||||
var currentIndex: Int = 0
|
var currentIndex: Int = 0
|
||||||
|
|
||||||
let decoder: JavaDecoder
|
let decoder: JavaDecoder
|
||||||
|
let jniStorage: JNIStorageObject
|
||||||
let javaObject: jobject
|
let javaObject: jobject
|
||||||
var unsafePointer: UnsafeMutableRawPointer? // Copied array of elements (only for primitive types)
|
var unsafePointer: UnsafeMutableRawPointer? // Copied array of elements (only for primitive types)
|
||||||
|
|
||||||
fileprivate init(decoder: JavaDecoder, jniStorage: JNIStorageObject) {
|
fileprivate init(decoder: JavaDecoder, jniStorage: JNIStorageObject) {
|
||||||
self.decoder = decoder
|
self.decoder = decoder
|
||||||
|
self.jniStorage = jniStorage
|
||||||
self.javaObject = jniStorage.javaObject
|
self.javaObject = jniStorage.javaObject
|
||||||
self.count = Int(JNI.api.GetArrayLength(JNI.env, jniStorage.javaObject))
|
self.count = Int(JNI.api.GetArrayLength(JNI.env, jniStorage.javaObject))
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
|
||||||
JNI.api.DeleteLocalRef(JNI.env, self.javaObject)
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodeNil() throws -> Bool {
|
func decodeNil() throws -> Bool {
|
||||||
throw JavaCodingError.notSupported("JavaUnkeyedDecodingContainer.decodeNil")
|
throw JavaCodingError.notSupported("JavaUnkeyedDecodingContainer.decodeNil")
|
||||||
}
|
}
|
||||||
|
@ -435,11 +429,13 @@ fileprivate class JavaEnumDecodingContainer: SingleValueDecodingContainer {
|
||||||
var codingPath: [CodingKey] = []
|
var codingPath: [CodingKey] = []
|
||||||
|
|
||||||
let decoder: JavaDecoder
|
let decoder: JavaDecoder
|
||||||
|
let jniStorage: JNIStorageObject
|
||||||
let javaObject: jobject
|
let javaObject: jobject
|
||||||
let javaClass: String
|
let javaClass: String
|
||||||
|
|
||||||
fileprivate init(decoder: JavaDecoder, jniStorage: JNIStorageObject) {
|
fileprivate init(decoder: JavaDecoder, jniStorage: JNIStorageObject) {
|
||||||
self.decoder = decoder
|
self.decoder = decoder
|
||||||
|
self.jniStorage = jniStorage
|
||||||
self.javaObject = jniStorage.javaObject
|
self.javaObject = jniStorage.javaObject
|
||||||
switch jniStorage.type {
|
switch jniStorage.type {
|
||||||
case let .object(className):
|
case let .object(className):
|
||||||
|
|
|
@ -42,9 +42,18 @@ indirect enum JNIStorageType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct JNIStorageObject {
|
class JNIStorageObject {
|
||||||
let type: JNIStorageType
|
let type: JNIStorageType
|
||||||
let javaObject: jobject
|
let javaObject: jobject
|
||||||
|
|
||||||
|
init(type: JNIStorageType, javaObject: jobject) {
|
||||||
|
self.type = type
|
||||||
|
self.javaObject = javaObject
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
JNI.api.DeleteLocalRef(JNI.env, javaObject)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `JavaEncoder` facilitates the encoding of `Encodable` values into JSON.
|
/// `JavaEncoder` facilitates the encoding of `Encodable` values into JSON.
|
||||||
|
@ -62,13 +71,15 @@ open class JavaEncoder: Encoder {
|
||||||
|
|
||||||
fileprivate let package: String
|
fileprivate let package: String
|
||||||
fileprivate var javaObjects: [JNIStorageObject]
|
fileprivate var javaObjects: [JNIStorageObject]
|
||||||
|
fileprivate let missingFieldsStrategy: MissingFieldsStrategy
|
||||||
|
|
||||||
// MARK: - Constructing a JSON Encoder
|
// MARK: - Constructing a JSON Encoder
|
||||||
/// Initializes `self` with default strategies.
|
/// Initializes `self` with default strategies.
|
||||||
public init(forPackage: String) {
|
public init(forPackage: String, missingFieldsStrategy: MissingFieldsStrategy = .throw) {
|
||||||
self.codingPath = [CodingKey]()
|
self.codingPath = [CodingKey]()
|
||||||
self.package = forPackage
|
self.package = forPackage
|
||||||
self.javaObjects = [JNIStorageObject]()
|
self.javaObjects = [JNIStorageObject]()
|
||||||
|
self.missingFieldsStrategy = missingFieldsStrategy
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Encoding Values
|
// MARK: - Encoding Values
|
||||||
|
@ -79,22 +90,17 @@ open class JavaEncoder: Encoder {
|
||||||
/// - throws: `EncodingError.invalidValue` if a non-conforming floating-point value is encountered during encoding, and the encoding strategy is `.throw`.
|
/// - throws: `EncodingError.invalidValue` if a non-conforming floating-point value is encountered during encoding, and the encoding strategy is `.throw`.
|
||||||
/// - throws: An error if any value throws an error during encoding.
|
/// - throws: An error if any value throws an error during encoding.
|
||||||
open func encode<T : Encodable>(_ value: T) throws -> jobject {
|
open func encode<T : Encodable>(_ value: T) throws -> jobject {
|
||||||
let storage = try self.pushInstance(value)
|
|
||||||
let javaObject = JNI.api.NewLocalRef(JNI.env, storage.javaObject)!
|
|
||||||
do {
|
do {
|
||||||
try value.encode(to: self)
|
let storage = try self.box(value)
|
||||||
|
assert(self.javaObjects.count == 0, "Missing encoding for \(self.javaObjects.count) objects")
|
||||||
|
return JNI.api.NewLocalRef(JNI.env, storage.javaObject)!
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
// clean all reference if failed
|
// clean all reference if failed
|
||||||
JNI.api.DeleteLocalRef(JNI.env, javaObject)
|
|
||||||
for storage in self.javaObjects {
|
|
||||||
JNI.api.DeleteLocalRef(JNI.env, storage.javaObject)
|
|
||||||
}
|
|
||||||
self.javaObjects.removeAll()
|
self.javaObjects.removeAll()
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
assert(self.javaObjects.count == 0, "Missing encoding for \(self.javaObjects.count) objects")
|
|
||||||
return javaObject
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Encoder Methods
|
// MARK: - Encoder Methods
|
||||||
|
@ -102,10 +108,10 @@ open class JavaEncoder: Encoder {
|
||||||
let storage = self.popInstance()
|
let storage = self.popInstance()
|
||||||
switch storage.type {
|
switch storage.type {
|
||||||
case .dictionary:
|
case .dictionary:
|
||||||
let container = JavaHashMapContainer<Key>(referencing: self, codingPath: self.codingPath, javaObject: storage.javaObject)
|
let container = JavaHashMapContainer<Key>(referencing: self, codingPath: self.codingPath, jniStorage: storage)
|
||||||
return KeyedEncodingContainer(container)
|
return KeyedEncodingContainer(container)
|
||||||
case let .object(className):
|
case let .object(className):
|
||||||
let container = JavaObjectContainer<Key>(referencing: self, codingPath: self.codingPath, javaClass: className, javaObject: storage.javaObject)
|
let container = JavaObjectContainer<Key>(referencing: self, codingPath: self.codingPath, javaClass: className, jniStorage: storage)
|
||||||
return KeyedEncodingContainer(container)
|
return KeyedEncodingContainer(container)
|
||||||
default:
|
default:
|
||||||
fatalError("Only keyed containers")
|
fatalError("Only keyed containers")
|
||||||
|
@ -114,14 +120,14 @@ open class JavaEncoder: Encoder {
|
||||||
|
|
||||||
public func unkeyedContainer() -> UnkeyedEncodingContainer {
|
public func unkeyedContainer() -> UnkeyedEncodingContainer {
|
||||||
let storage = self.popInstance()
|
let storage = self.popInstance()
|
||||||
return JavaArrayContainer(referencing: self, codingPath: self.codingPath, arrayObject: storage.javaObject)
|
return JavaArrayContainer(referencing: self, codingPath: self.codingPath, jniStorage: storage)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func singleValueContainer() -> SingleValueEncodingContainer {
|
public func singleValueContainer() -> SingleValueEncodingContainer {
|
||||||
let storage = self.popInstance()
|
let storage = self.popInstance()
|
||||||
switch storage.type {
|
switch storage.type {
|
||||||
case let .object(className):
|
case let .object(className):
|
||||||
return JavaEnumValueEncodingContainer(encoder: self, javaClass: className, javaObject: storage.javaObject)
|
return JavaEnumValueEncodingContainer(encoder: self, javaClass: className, jniStorage: storage)
|
||||||
default:
|
default:
|
||||||
fatalError("Only object type supported here")
|
fatalError("Only object type supported here")
|
||||||
}
|
}
|
||||||
|
@ -138,23 +144,23 @@ fileprivate class JavaObjectContainer<K : CodingKey> : KeyedEncodingContainerPro
|
||||||
/// A reference to the encoder we're writing to.
|
/// A reference to the encoder we're writing to.
|
||||||
private let encoder: JavaEncoder
|
private let encoder: JavaEncoder
|
||||||
|
|
||||||
private var javaClass: String
|
private let javaClass: String
|
||||||
private var javaObject: jobject
|
private let jniStorage: JNIStorageObject
|
||||||
|
|
||||||
/// The path of coding keys taken to get to this point in encoding.
|
/// The path of coding keys taken to get to this point in encoding.
|
||||||
private(set) public var codingPath: [CodingKey]
|
private(set) public var codingPath: [CodingKey]
|
||||||
|
|
||||||
// MARK: - Initialization
|
// MARK: - Initialization
|
||||||
/// Initializes `self` with the given references.
|
/// Initializes `self` with the given references.
|
||||||
fileprivate init(referencing encoder: JavaEncoder, codingPath: [CodingKey], javaClass: String, javaObject: jobject) {
|
fileprivate init(referencing encoder: JavaEncoder, codingPath: [CodingKey], javaClass: String, jniStorage: JNIStorageObject) {
|
||||||
self.encoder = encoder
|
self.encoder = encoder
|
||||||
self.codingPath = codingPath
|
self.codingPath = codingPath
|
||||||
self.javaClass = javaClass
|
self.javaClass = javaClass
|
||||||
self.javaObject = javaObject
|
self.jniStorage = jniStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
private var javaObject: jobject {
|
||||||
JNI.api.DeleteLocalRef(JNI.env, javaObject)
|
return jniStorage.javaObject
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - KeyedEncodingContainerProtocol Methods
|
// MARK: - KeyedEncodingContainerProtocol Methods
|
||||||
|
@ -188,6 +194,11 @@ fileprivate class JavaObjectContainer<K : CodingKey> : KeyedEncodingContainerPro
|
||||||
JNI.api.SetLongField(JNI.env, javaObject, filed, value)
|
JNI.api.SetLongField(JNI.env, javaObject, filed, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func encode(_ value: UInt, forKey key: Key) throws {
|
||||||
|
let filed = try getJavaField(forClass: javaClass, field: key.stringValue, sig: "J")
|
||||||
|
JNI.api.SetLongField(JNI.env, javaObject, filed, jlong(bitPattern: UInt64(value)))
|
||||||
|
}
|
||||||
|
|
||||||
public func encode(_ value: String, forKey key: Key) throws {
|
public func encode(_ value: String, forKey key: Key) throws {
|
||||||
let filed = try getJavaField(forClass: javaClass, field: key.stringValue, sig: "Ljava/lang/String;")
|
let filed = try getJavaField(forClass: javaClass, field: key.stringValue, sig: "Ljava/lang/String;")
|
||||||
var locals = [jobject]()
|
var locals = [jobject]()
|
||||||
|
@ -195,10 +206,19 @@ fileprivate class JavaObjectContainer<K : CodingKey> : KeyedEncodingContainerPro
|
||||||
}
|
}
|
||||||
|
|
||||||
public func encode<T : Encodable>(_ value: T, forKey key: Key) throws {
|
public func encode<T : Encodable>(_ value: T, forKey key: Key) throws {
|
||||||
let object = try self.encoder.pushInstance(value)
|
do {
|
||||||
let filed = try getJavaField(forClass: self.javaClass, field: key.stringValue, sig: object.type.sig)
|
let object = try self.encoder.box(value)
|
||||||
JNI.api.SetObjectField(JNI.env, self.javaObject, filed, object.javaObject)
|
let filed = try getJavaField(forClass: self.javaClass, field: key.stringValue, sig: object.type.sig)
|
||||||
try value.encode(to: self.encoder)
|
JNI.api.SetObjectField(JNI.env, self.javaObject, filed, object.javaObject)
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
if self.encoder.missingFieldsStrategy == .ignore {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer<NestedKey> {
|
public func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer<NestedKey> {
|
||||||
|
@ -227,7 +247,7 @@ fileprivate class JavaHashMapContainer<K : CodingKey> : KeyedEncodingContainerPr
|
||||||
/// A reference to the encoder we're writing to.
|
/// A reference to the encoder we're writing to.
|
||||||
private let encoder: JavaEncoder
|
private let encoder: JavaEncoder
|
||||||
|
|
||||||
private var javaObject: jobject
|
private let jniStorage: JNIStorageObject
|
||||||
private var javaPutMethod = try! getJavaMethod(forClass: JavaHashMapClassname, method: "put", sig: "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;")
|
private var javaPutMethod = try! getJavaMethod(forClass: JavaHashMapClassname, method: "put", sig: "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;")
|
||||||
|
|
||||||
/// The path of coding keys taken to get to this point in encoding.
|
/// The path of coding keys taken to get to this point in encoding.
|
||||||
|
@ -235,14 +255,14 @@ fileprivate class JavaHashMapContainer<K : CodingKey> : KeyedEncodingContainerPr
|
||||||
|
|
||||||
// MARK: - Initialization
|
// MARK: - Initialization
|
||||||
/// Initializes `self` with the given references.
|
/// Initializes `self` with the given references.
|
||||||
fileprivate init(referencing encoder: JavaEncoder, codingPath: [CodingKey], javaObject: jobject) {
|
fileprivate init(referencing encoder: JavaEncoder, codingPath: [CodingKey], jniStorage: JNIStorageObject) {
|
||||||
self.encoder = encoder
|
self.encoder = encoder
|
||||||
self.codingPath = codingPath
|
self.codingPath = codingPath
|
||||||
self.javaObject = javaObject
|
self.jniStorage = jniStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
private var javaObject: jobject {
|
||||||
JNI.api.DeleteLocalRef(JNI.env, javaObject)
|
return jniStorage.javaObject
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - KeyedEncodingContainerProtocol Methods
|
// MARK: - KeyedEncodingContainerProtocol Methods
|
||||||
|
@ -267,7 +287,7 @@ fileprivate class JavaHashMapContainer<K : CodingKey> : KeyedEncodingContainerPr
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let object = try self.encoder.pushInstance(value)
|
let object = try self.encoder.box(value)
|
||||||
var locals = [jobject]()
|
var locals = [jobject]()
|
||||||
var args = [jvalue]()
|
var args = [jvalue]()
|
||||||
args.append(jvalue(l: key.stringValue.localJavaObject(&locals)))
|
args.append(jvalue(l: key.stringValue.localJavaObject(&locals)))
|
||||||
|
@ -277,8 +297,6 @@ fileprivate class JavaHashMapContainer<K : CodingKey> : KeyedEncodingContainerPr
|
||||||
let result = JNI.check(JNI.api.CallObjectMethodA(JNI.env, javaObject, javaPutMethod, argsPtr), &locals)
|
let result = JNI.check(JNI.api.CallObjectMethodA(JNI.env, javaObject, javaPutMethod, argsPtr), &locals)
|
||||||
assert(result == nil, "Rewrite for key \(key.stringValue)")
|
assert(result == nil, "Rewrite for key \(key.stringValue)")
|
||||||
}
|
}
|
||||||
|
|
||||||
try value.encode(to: self.encoder)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer<NestedKey> {
|
public func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer<NestedKey> {
|
||||||
|
@ -309,18 +327,18 @@ fileprivate class JavaArrayContainer : UnkeyedEncodingContainer {
|
||||||
/// The number of elements encoded into the container.
|
/// The number of elements encoded into the container.
|
||||||
public private(set) var count: Int = 0
|
public private(set) var count: Int = 0
|
||||||
|
|
||||||
private let javaObject: jobject
|
private let jniStorage: JNIStorageObject
|
||||||
|
|
||||||
// MARK: - Initialization
|
// MARK: - Initialization
|
||||||
/// Initializes `self` with the given references.
|
/// Initializes `self` with the given references.
|
||||||
fileprivate init(referencing encoder: JavaEncoder, codingPath: [CodingKey], arrayObject: jobject) {
|
fileprivate init(referencing encoder: JavaEncoder, codingPath: [CodingKey], jniStorage: JNIStorageObject) {
|
||||||
self.encoder = encoder
|
self.encoder = encoder
|
||||||
self.codingPath = codingPath
|
self.codingPath = codingPath
|
||||||
self.javaObject = arrayObject
|
self.jniStorage = jniStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
private var javaObject: jobject {
|
||||||
JNI.api.DeleteLocalRef(JNI.env, javaObject)
|
return jniStorage.javaObject
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - UnkeyedEncodingContainer Methods
|
// MARK: - UnkeyedEncodingContainer Methods
|
||||||
|
@ -353,14 +371,12 @@ fileprivate class JavaArrayContainer : UnkeyedEncodingContainer {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let storeObject = try self.encoder.pushInstance(value)
|
let storeObject = try self.encoder.box(value)
|
||||||
JNI.api.SetObjectArrayElement(JNI.env,
|
JNI.api.SetObjectArrayElement(JNI.env,
|
||||||
self.javaObject,
|
self.javaObject,
|
||||||
jsize(self.count),
|
jsize(self.count),
|
||||||
storeObject.javaObject)
|
storeObject.javaObject)
|
||||||
|
|
||||||
try value.encode(to: self.encoder)
|
|
||||||
|
|
||||||
count += 1
|
count += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,14 +399,17 @@ class JavaEnumValueEncodingContainer: SingleValueEncodingContainer {
|
||||||
let encoder: JavaEncoder
|
let encoder: JavaEncoder
|
||||||
|
|
||||||
private var javaClass: String
|
private var javaClass: String
|
||||||
private var javaObject: jobject
|
private var jniStorage: JNIStorageObject
|
||||||
|
|
||||||
init(encoder: JavaEncoder, javaClass: String, javaObject: jobject) {
|
init(encoder: JavaEncoder, javaClass: String, jniStorage: JNIStorageObject) {
|
||||||
self.codingPath = [CodingKey]()
|
self.codingPath = [CodingKey]()
|
||||||
self.encoder = encoder
|
self.encoder = encoder
|
||||||
self.javaClass = javaClass
|
self.javaClass = javaClass
|
||||||
self.javaObject = javaObject
|
self.jniStorage = jniStorage
|
||||||
NSLog("Created \(javaClass) enum value encoding container")
|
}
|
||||||
|
|
||||||
|
private var javaObject: jobject {
|
||||||
|
return jniStorage.javaObject
|
||||||
}
|
}
|
||||||
|
|
||||||
public func encodeNil() throws {
|
public func encodeNil() throws {
|
||||||
|
@ -403,10 +422,23 @@ class JavaEnumValueEncodingContainer: SingleValueEncodingContainer {
|
||||||
JNI.api.SetLongField(JNI.env, javaObject, fieldID, jlong(value as! Int))
|
JNI.api.SetLongField(JNI.env, javaObject, fieldID, jlong(value as! Int))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
throw JavaCodingError.notSupported("JavaSingleValueEncodingContainer.encode(value: \(value)")
|
if value is UInt {
|
||||||
|
let filed = try getJavaField(forClass: javaClass, field: "rawValue", sig: "J")
|
||||||
|
JNI.api.SetLongField(JNI.env, javaObject, filed, jlong(bitPattern: UInt64(value as! UInt)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if value is UInt32 {
|
||||||
|
let filed = try getJavaField(forClass: javaClass, field: "rawValue", sig: "J")
|
||||||
|
JNI.api.SetLongField(JNI.env, javaObject, filed, jlong(value as! UInt32))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
throw JavaCodingError.notSupported("JavaSingleValueEncodingContainer.encode(value: \(value) \(type(of:value))")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var UriClass = JNI.GlobalFindClass("android/net/Uri")
|
||||||
|
private var UriConstructor = JNI.api.GetStaticMethodID(JNI.env, JNI.GlobalFindClass("android/net/Uri"), "parse", "(Ljava/lang/String;)Landroid/net/Uri;")
|
||||||
|
|
||||||
extension JavaEncoder {
|
extension JavaEncoder {
|
||||||
|
|
||||||
fileprivate func getFullClassName<T>(_ value: T) -> String{
|
fileprivate func getFullClassName<T>(_ value: T) -> String{
|
||||||
|
@ -417,15 +449,34 @@ extension JavaEncoder {
|
||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
fileprivate func pushInstance<T: Encodable>(_ value: T) throws -> JNIStorageObject {
|
fileprivate func box<T: Encodable>(_ value: T) throws -> JNIStorageObject {
|
||||||
let storage: JNIStorageObject
|
let storage: JNIStorageObject
|
||||||
if T.self == [String].self {
|
|
||||||
|
if T.self == URL.self {
|
||||||
|
var locals = [jobject]()
|
||||||
|
let javaString = (value as! URL).absoluteString.localJavaObject(&locals)
|
||||||
|
var args = [jvalue]()
|
||||||
|
args.append(jvalue(l: javaString))
|
||||||
|
|
||||||
|
let uriObject = JNIMethod.CallStaticObjectMethod(className: "android/net/Uri",
|
||||||
|
classCache: &UriClass,
|
||||||
|
methodName: "parse",
|
||||||
|
methodSig: "(Ljava/lang/String;)Landroid/net/Uri;",
|
||||||
|
methodCache: &UriConstructor,
|
||||||
|
args: &args,
|
||||||
|
locals: &locals)
|
||||||
|
|
||||||
|
storage = JNIStorageObject.init(type: .object(className: "android/net/Uri"), javaObject: uriObject!)
|
||||||
|
}
|
||||||
|
else if T.self == [String].self {
|
||||||
let value = value as! [String]
|
let value = value as! [String]
|
||||||
let javaClass = try getJavaClass(JavaStringClassname)
|
let javaClass = try getJavaClass(JavaStringClassname)
|
||||||
guard let javaObject = JNI.api.NewObjectArray(JNI.env, jsize(value.count), javaClass, nil) else {
|
guard let javaObject = JNI.api.NewObjectArray(JNI.env, jsize(value.count), javaClass, nil) else {
|
||||||
throw JavaCodingError.cantCreateObject("\(JavaStringClassname)[]")
|
throw JavaCodingError.cantCreateObject("\(JavaStringClassname)[]")
|
||||||
}
|
}
|
||||||
storage = JNIStorageObject(type: .array(type: .object(className: JavaStringClassname)), javaObject: javaObject)
|
storage = JNIStorageObject(type: .array(type: .object(className: JavaStringClassname)), javaObject: javaObject)
|
||||||
|
javaObjects.append(storage)
|
||||||
|
try value.encode(to: self)
|
||||||
}
|
}
|
||||||
else if T.self == [Int].self {
|
else if T.self == [Int].self {
|
||||||
let value = value as! [Int]
|
let value = value as! [Int]
|
||||||
|
@ -433,15 +484,19 @@ extension JavaEncoder {
|
||||||
throw JavaCodingError.cantCreateObject("long[]")
|
throw JavaCodingError.cantCreateObject("long[]")
|
||||||
}
|
}
|
||||||
storage = JNIStorageObject(type: .array(type: .primitive(name: "J")), javaObject: javaObject)
|
storage = JNIStorageObject(type: .array(type: .primitive(name: "J")), javaObject: javaObject)
|
||||||
|
javaObjects.append(storage)
|
||||||
|
try value.encode(to: self)
|
||||||
}
|
}
|
||||||
else if let value = value as? [Encodable] {
|
else if let valueEncodableArray = value as? [Encodable] {
|
||||||
let subType = String("\(T.self)".dropFirst(6)).dropLast(1)
|
let subType = String("\(T.self)".dropFirst(6)).dropLast(1)
|
||||||
let fullClassName = package + "/" + subType
|
let fullClassName = package + "/" + subType
|
||||||
let javaClass = try getJavaClass(fullClassName)
|
let javaClass = try getJavaClass(fullClassName)
|
||||||
guard let javaObject = JNI.api.NewObjectArray(JNI.env, jsize(value.count), javaClass, nil) else {
|
guard let javaObject = JNI.api.NewObjectArray(JNI.env, jsize(valueEncodableArray.count), javaClass, nil) else {
|
||||||
throw JavaCodingError.cantCreateObject("\(fullClassName)[]")
|
throw JavaCodingError.cantCreateObject("\(fullClassName)[]")
|
||||||
}
|
}
|
||||||
storage = JNIStorageObject(type: .array(type: .object(className: fullClassName)), javaObject: javaObject)
|
storage = JNIStorageObject(type: .array(type: .object(className: fullClassName)), javaObject: javaObject)
|
||||||
|
javaObjects.append(storage)
|
||||||
|
try value.encode(to: self)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let storageType: JNIStorageType
|
let storageType: JNIStorageType
|
||||||
|
@ -460,8 +515,9 @@ extension JavaEncoder {
|
||||||
throw JavaCodingError.cantCreateObject(fullClassName)
|
throw JavaCodingError.cantCreateObject(fullClassName)
|
||||||
}
|
}
|
||||||
storage = JNIStorageObject(type: storageType, javaObject: javaObject)
|
storage = JNIStorageObject(type: storageType, javaObject: javaObject)
|
||||||
|
javaObjects.append(storage)
|
||||||
|
try value.encode(to: self)
|
||||||
}
|
}
|
||||||
javaObjects.append(storage)
|
|
||||||
return storage
|
return storage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue