Merge pull request #12 from readdle/dev/fix-local-ref-issues

Fix local ref issues
This commit is contained in:
Andriy Druk 2021-10-03 14:00:50 +03:00 committed by GitHub
commit 1758dcd711
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 165 additions and 70 deletions

View File

@ -124,7 +124,7 @@ public extension JNICore {
public func `throw`() {
switch self {
case .classNotFoundException(let message):
assert(JNI.api.ThrowNew(JNI.env, ExceptionClass, "ClassNotFoundaException: \(message)") == 0)
assert(JNI.api.ThrowNew(JNI.env, ExceptionClass, "ClassNotFoundException: \(message)") == 0)
case .methodNotFoundException(let message):
assert(JNI.api.ThrowNew(JNI.env, ExceptionClass, "MethodNotFoundException: \(message)") == 0)
case .fieldNotFoundException(let message):
@ -136,7 +136,7 @@ public extension JNICore {
public var errorDescription: String? {
switch self {
case .classNotFoundException(let message):
return "ClassNotFoundaException: \(message)"
return "ClassNotFoundException: \(message)"
case .methodNotFoundException(let message):
return "MethodNotFoundException: \(message)"
case .fieldNotFoundException(let message):

View File

@ -47,15 +47,15 @@ public extension JNIObject {
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))
return String(javaObject: self.internalCallObjectMethod(method: methodName, returnType: "Ljava/lang/String;", args))
}
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)
return self.internalCallObjectMethod(method: methodName, returnType: returnType, args)
}
private func internalcallObjectMethod(method: String, returnType: String, _ args: [JNIArgumentProtocol]) -> jobject? {
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

View File

@ -94,17 +94,16 @@ fileprivate class JavaObjectContainer<K : CodingKey> : KeyedDecodingContainerPro
let decoder: JavaDecoder
let jniStorage: JNIStorageObject
let javaObject: jobject
let javaClass: String
fileprivate init(decoder: JavaDecoder, jniStorage: JNIStorageObject) {
self.decoder = decoder
self.jniStorage = jniStorage
self.javaObject = jniStorage.javaObject
self.codingPath = jniStorage.codingPath
codingPath = jniStorage.codingPath
switch jniStorage.type {
case let .object(className):
self.javaClass = className
javaClass = className
default:
fatalError("Wrong container type")
}
@ -136,21 +135,37 @@ fileprivate class JavaObjectContainer<K : CodingKey> : KeyedDecodingContainerPro
// MARK: Decode JNI primitive fields
private func decodeBoolean(forKey key: String) throws -> Bool {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: key, sig: "Z")
let javaObject = jniStorage.javaObject
defer {
JNI.DeleteLocalRef(javaObject)
}
return JNI.api.GetBooleanField(JNI.env, javaObject, fieldID) == JNI_TRUE
}
private func decodeByte(forKey key: String) throws -> Int8 {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: key, sig: "B")
let javaObject = jniStorage.javaObject
defer {
JNI.DeleteLocalRef(javaObject)
}
return JNI.api.GetByteField(JNI.env, javaObject, fieldID)
}
private func decodeShort(forKey key: String) throws -> Int16 {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: key, sig: "S")
let javaObject = jniStorage.javaObject
defer {
JNI.DeleteLocalRef(javaObject)
}
return JNI.api.GetShortField(JNI.env, javaObject, fieldID)
}
private func decodeInteger(forKey key: String) throws -> Int32 {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: key, sig: "I")
let javaObject = jniStorage.javaObject
defer {
JNI.DeleteLocalRef(javaObject)
}
#if arch(x86_64) || arch(arm64)
return JNI.api.GetIntField(JNI.env, javaObject, fieldID)
#else
@ -160,16 +175,28 @@ fileprivate class JavaObjectContainer<K : CodingKey> : KeyedDecodingContainerPro
private func decodeLong(forKey key: String) throws -> Int64 {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: key, sig: "J")
let javaObject = jniStorage.javaObject
defer {
JNI.DeleteLocalRef(javaObject)
}
return JNI.api.GetLongField(JNI.env, javaObject, fieldID)
}
private func decodeFloat(forKey key: String) throws -> Float {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: key, sig: "F")
let javaObject = jniStorage.javaObject
defer {
JNI.DeleteLocalRef(javaObject)
}
return JNI.api.GetFloatField(JNI.env, javaObject, fieldID)
}
private func decodeDouble(forKey key: String) throws -> Double {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: key, sig: "D")
let javaObject = jniStorage.javaObject
defer {
JNI.DeleteLocalRef(javaObject)
}
return JNI.api.GetDoubleField(JNI.env, javaObject, fieldID)
}
@ -302,7 +329,10 @@ fileprivate class JavaObjectContainer<K : CodingKey> : KeyedDecodingContainerPro
let classname: String
if type == AnyCodable.self {
var locals = [jobject]()
let javaObject = jniStorage.javaObject
let cls = JNI.api.GetObjectClass(JNI.env, javaObject)!
JNI.DeleteLocalRef(javaObject)
let javaTypename = key.stringValue.localJavaObject(&locals)
guard let field = JNI.CallObjectMethod(cls, ClassGetFieldMethod, javaTypename!) else {
JNI.ExceptionReset()
@ -324,6 +354,10 @@ fileprivate class JavaObjectContainer<K : CodingKey> : KeyedDecodingContainerPro
}
let fieldID = try JNI.getJavaField(forClass: javaClass, field: key.stringValue, sig: "L\(classname);")
let javaObject = jniStorage.javaObject
defer {
JNI.api.DeleteLocalRef(JNI.env, javaObject)
}
guard let object = JNI.api.GetObjectField(JNI.env, javaObject, fieldID) else {
return nil
}
@ -360,18 +394,18 @@ fileprivate class JavaHashMapKeyedContainer<K : CodingKey>: KeyedDecodingContain
private let decoder: JavaDecoder
private let jniStorage: JNIStorageObject
private let javaObject: jobject
private var javaKeys = [AnyHashable: jobject]()
fileprivate init(decoder: JavaDecoder, jniStorage: JNIStorageObject) throws {
self.decoder = decoder
self.jniStorage = jniStorage
self.javaObject = jniStorage.javaObject
self.codingPath = jniStorage.codingPath
codingPath = jniStorage.codingPath
let javaObject = jniStorage.javaObject
let keySet = JNI.api.CallObjectMethodA(JNI.env, javaObject, HashMapKeySetMethod, nil)
let keyArray = JNI.api.CallObjectMethodA(JNI.env, keySet, SetToArrayMethod, nil)
JNI.DeleteLocalRef(javaObject)
defer {
JNI.DeleteLocalRef(keySet)
JNI.DeleteLocalRef(keyArray)
@ -436,7 +470,11 @@ fileprivate class JavaHashMapKeyedContainer<K : CodingKey>: KeyedDecodingContain
}
let javaKey = javaKeys[typeKey]
guard let object = JNI.CallObjectMethod(self.javaObject, methodID: HashMapGetMethod, args: [jvalue(l: javaKey)]) else {
let javaObject = jniStorage.javaObject
defer {
JNI.DeleteLocalRef(javaObject)
}
guard let object = JNI.CallObjectMethod(javaObject!, methodID: HashMapGetMethod, args: [jvalue(l: javaKey)]) else {
throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "Can't find object")
}
defer {
@ -480,7 +518,6 @@ fileprivate class JavaHashMapUnkeyedContainer: UnkeyedDecodingContainer {
let decoder: JavaDecoder
let jniStorage: JNIStorageObject
let javaObject: jobject
private var javaKeys: jarray
private var javaCurrentKey: jobject?
@ -488,15 +525,14 @@ fileprivate class JavaHashMapUnkeyedContainer: UnkeyedDecodingContainer {
fileprivate init(decoder: JavaDecoder, jniStorage: JNIStorageObject) throws {
self.decoder = decoder
self.jniStorage = jniStorage
self.javaObject = jniStorage.javaObject
self.codingPath = jniStorage.codingPath
self.count = Int(JNI.CallIntMethod(self.javaObject, methodID: HashMapSizeMethod)) * 2
codingPath = jniStorage.codingPath
let javaObject = jniStorage.javaObject
count = Int(JNI.CallIntMethod(javaObject!, methodID: HashMapSizeMethod)) * 2
let keySet = JNI.api.CallObjectMethodA(JNI.env, javaObject, HashMapKeySetMethod, nil)
JNI.DeleteLocalRef(javaObject)
javaKeys = JNI.api.CallObjectMethodA(JNI.env, keySet, SetToArrayMethod, nil)!
defer {
JNI.api.DeleteLocalRef(JNI.env, keySet)
}
JNI.DeleteLocalRef(keySet)
}
deinit {
@ -510,7 +546,11 @@ fileprivate class JavaHashMapUnkeyedContainer: UnkeyedDecodingContainer {
func decode<T>(_ type: T.Type) throws -> T where T : Decodable {
let codingKey = JavaKey(intValue: currentIndex)
if let javaCurrentKey = javaCurrentKey {
guard let object = JNI.CallObjectMethod(self.javaObject, methodID: HashMapGetMethod, args: [jvalue(l: javaCurrentKey)]) else {
let javaObject = jniStorage.javaObject
defer {
JNI.DeleteLocalRef(javaObject)
}
guard let object = JNI.CallObjectMethod(javaObject!, methodID: HashMapGetMethod, args: [jvalue(l: javaCurrentKey)]) else {
throw DecodingError.dataCorruptedError(in: self, debugDescription: "Can't find object")
}
currentIndex += 1
@ -568,8 +608,10 @@ fileprivate class JavaArrayContainer: UnkeyedDecodingContainer {
self.decoder = decoder
self.jniStorage = jniStorage
self.codingPath = jniStorage.codingPath
self.count = Int(JNI.CallIntMethod(jniStorage.javaObject, methodID: CollectionSizeMethod))
self.javaIterator = JNI.CallObjectMethod(jniStorage.javaObject, methodID: CollectionIteratorMethod)!
let javaObject = jniStorage.javaObject
self.count = Int(JNI.CallIntMethod(javaObject!, methodID: CollectionSizeMethod))
self.javaIterator = JNI.CallObjectMethod(javaObject!, methodID: CollectionIteratorMethod)!
JNI.DeleteLocalRef(javaObject)
}
deinit {
@ -610,17 +652,16 @@ fileprivate class JavaEnumContainer: SingleValueDecodingContainer {
let decoder: JavaDecoder
let jniStorage: JNIStorageObject
let javaObject: jobject
let javaClass: String
fileprivate init(decoder: JavaDecoder, jniStorage: JNIStorageObject) {
self.decoder = decoder
self.jniStorage = jniStorage
self.javaObject = jniStorage.javaObject
self.codingPath = jniStorage.codingPath
codingPath = jniStorage.codingPath
switch jniStorage.type {
case let .object(className):
self.javaClass = className
javaClass = className
default:
fatalError("Wrong container type")
}
@ -632,67 +673,91 @@ fileprivate class JavaEnumContainer: SingleValueDecodingContainer {
func decode(_ type: Int.Type) throws -> Int {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: "rawValue", sig: "I")
let javaObject = jniStorage.javaObject
let value = JNI.api.GetIntField(JNI.env, javaObject, fieldID)
JNI.DeleteLocalRef(javaObject)
return Int(fromJavaPrimitive: value)
}
func decode(_ type: Int8.Type) throws -> Int8 {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: "rawValue", sig: "B")
let javaObject = jniStorage.javaObject
let value = JNI.api.GetByteField(JNI.env, javaObject, fieldID)
JNI.DeleteLocalRef(javaObject)
return Int8(fromJavaPrimitive: value)
}
func decode(_ type: Int16.Type) throws -> Int16 {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: "rawValue", sig: "S")
let javaObject = jniStorage.javaObject
let value = JNI.api.GetShortField(JNI.env, javaObject, fieldID)
JNI.DeleteLocalRef(javaObject)
return Int16(fromJavaPrimitive: value)
}
func decode(_ type: Int32.Type) throws -> Int32 {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: "rawValue", sig: "I")
let javaObject = jniStorage.javaObject
let value = JNI.api.GetIntField(JNI.env, javaObject, fieldID)
JNI.DeleteLocalRef(javaObject)
return Int32(fromJavaPrimitive: value)
}
func decode(_ type: Int64.Type) throws -> Int64 {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: "rawValue", sig: "J")
let javaObject = jniStorage.javaObject
let value = JNI.api.GetLongField(JNI.env, javaObject, fieldID)
JNI.DeleteLocalRef(javaObject)
return Int64(fromJavaPrimitive: value)
}
func decode(_ type: UInt.Type) throws -> UInt {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: "rawValue", sig: "I")
let javaObject = jniStorage.javaObject
let value = JNI.api.GetIntField(JNI.env, javaObject, fieldID)
JNI.DeleteLocalRef(javaObject)
return UInt(fromJavaPrimitive: value)
}
func decode(_ type: UInt8.Type) throws -> UInt8 {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: "rawValue", sig: "B")
let javaObject = jniStorage.javaObject
let value = JNI.api.GetByteField(JNI.env, javaObject, fieldID)
JNI.DeleteLocalRef(javaObject)
return UInt8(fromJavaPrimitive: value)
}
func decode(_ type: UInt16.Type) throws -> UInt16 {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: "rawValue", sig: "S")
let javaObject = jniStorage.javaObject
let value = JNI.api.GetShortField(JNI.env, javaObject, fieldID)
JNI.DeleteLocalRef(javaObject)
return UInt16(fromJavaPrimitive: value)
}
func decode(_ type: UInt32.Type) throws -> UInt32 {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: "rawValue", sig: "I")
let javaObject = jniStorage.javaObject
let value = JNI.api.GetIntField(JNI.env, javaObject, fieldID)
JNI.DeleteLocalRef(javaObject)
return UInt32(fromJavaPrimitive: value)
}
func decode(_ type: UInt64.Type) throws -> UInt64 {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: "rawValue", sig: "J")
let javaObject = jniStorage.javaObject
let value = JNI.api.GetLongField(JNI.env, javaObject, fieldID)
JNI.DeleteLocalRef(javaObject)
return UInt64(fromJavaPrimitive: value)
}
func decode<T>(_ valueType: T.Type) throws -> T where T : Decodable {
let classname = decoder.getJavaClassname(forType: valueType)
let fieldID = try JNI.getJavaField(forClass: javaClass, field: "rawValue", sig: "L\(classname);")
let javaObject = jniStorage.javaObject
defer {
JNI.DeleteLocalRef(javaObject)
}
guard let object = JNI.api.GetObjectField(JNI.env, javaObject, fieldID) else {
throw JavaCodingError.notSupported(javaClass)
}
@ -756,7 +821,11 @@ fileprivate class JavaAnyCodableContainer<K : CodingKey> : KeyedDecodingContaine
}
}
else if key.stringValue == "value" {
return try self.decoder.unbox(type: type, javaObject: self.jniStorage.javaObject, codingPath: codingPath + [key])
let javaObject = jniStorage.javaObject
defer {
JNI.DeleteLocalRef(javaObject)
}
return try self.decoder.unbox(type: type, javaObject: javaObject!, codingPath: codingPath + [key])
}
else {
fatalError("Unknown key: \(key.stringValue)")

View File

@ -66,17 +66,28 @@ indirect enum JNIStorageType {
class JNIStorageObject {
let type: JNIStorageType
let codingPath: [CodingKey]
private var _javaObject: jobject!
var javaObject: jobject! {
didSet {
if let value = oldValue {
get {
return JNI.api.NewLocalRef(JNI.env, _javaObject)
}
set {
if let value = _javaObject {
JNI.api.DeleteLocalRef(JNI.env, value)
}
_javaObject = newValue
}
}
var hasJavaObject: Bool {
return _javaObject != nil
}
init(type: JNIStorageType, javaObject: jobject, codingPath: [CodingKey] = []) {
self.type = type
self.javaObject = javaObject
self._javaObject = javaObject
self.codingPath = codingPath
}
@ -86,7 +97,7 @@ class JNIStorageObject {
}
deinit {
if let value = javaObject {
if let value = _javaObject {
JNI.api.DeleteLocalRef(JNI.env, value)
}
}
@ -131,7 +142,7 @@ open class JavaEncoder: Encoder {
do {
let storage = try self.box(value, codingPath: codingPath)
assert(self.javaObjects.count == 0, "Missing encoding for \(self.javaObjects.count) objects")
return JNI.api.NewLocalRef(JNI.env, storage.javaObject)!
return storage.javaObject!
}
catch {
// clean all reference if failed
@ -212,45 +223,55 @@ fileprivate class JavaObjectContainer<K : CodingKey> : KeyedEncodingContainerPro
self.javaClass = javaClass
self.jniStorage = jniStorage
}
private var javaObject: jobject {
return jniStorage.javaObject
}
// MARK: Encode JNI primitive fields
func encodeBoolean(_ value: jboolean, key: String) throws {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: key, sig: "Z")
let javaObject = jniStorage.javaObject
JNI.api.SetBooleanField(JNI.env, javaObject, fieldID, value)
JNI.DeleteLocalRef(javaObject)
}
func encodeByte(_ value: jbyte, key: String) throws {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: key, sig: "B")
let javaObject = jniStorage.javaObject
JNI.api.SetByteField(JNI.env, javaObject, fieldID, value)
JNI.DeleteLocalRef(javaObject)
}
func encodeShort(_ value: jshort, key: String) throws {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: key, sig: "S")
let javaObject = jniStorage.javaObject
JNI.api.SetShortField(JNI.env, javaObject, fieldID, value)
JNI.DeleteLocalRef(javaObject)
}
func encodeInteger(_ value: jint, key: String) throws {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: key, sig: "I")
let javaObject = jniStorage.javaObject
JNI.api.SetIntField(JNI.env, javaObject, fieldID, value)
JNI.DeleteLocalRef(javaObject)
}
func encodeLong(_ value: jlong, key: String) throws {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: key, sig: "J")
let javaObject = jniStorage.javaObject
JNI.api.SetLongField(JNI.env, javaObject, fieldID, value)
JNI.DeleteLocalRef(javaObject)
}
func encodeFloat(_ value: jfloat, key: String) throws {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: key, sig: "F")
let javaObject = jniStorage.javaObject
JNI.api.SetFloatField(JNI.env, javaObject, fieldID, value)
JNI.DeleteLocalRef(javaObject)
}
func encodeDouble(_ value: jdouble, key: String) throws {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: key, sig: "D")
let javaObject = jniStorage.javaObject
JNI.api.SetDoubleField(JNI.env, javaObject, fieldID, value)
JNI.DeleteLocalRef(javaObject)
}
// MARK: - KeyedEncodingContainerProtocol Methods
@ -402,7 +423,11 @@ fileprivate class JavaObjectContainer<K : CodingKey> : KeyedEncodingContainerPro
do {
let object = try self.encoder.box(value, codingPath: codingPath + [key])
let filed = try JNI.getJavaField(forClass: self.javaClass, field: key.stringValue, sig: object.type.sig)
JNI.api.SetObjectField(JNI.env, self.javaObject, filed, object.javaObject)
let javaObject = jniStorage.javaObject
let javaField = object.javaObject
JNI.api.SetObjectField(JNI.env, javaObject, filed, javaField)
JNI.DeleteLocalRef(javaObject)
JNI.DeleteLocalRef(javaField)
}
catch {
if self.encoder.missingFieldsStrategy == .ignore {
@ -455,10 +480,6 @@ fileprivate class JavaHashMapKeyedContainer<K : CodingKey> : KeyedEncodingContai
self.jniStorage = jniStorage
}
private var javaObject: jobject {
return jniStorage.javaObject
}
// MARK: - KeyedEncodingContainerProtocol Methods
public func encodeNil(forKey key: Key) throws {
throw EncodingError.invalidValue(NSNotFound, EncodingError.Context(codingPath: codingPath, debugDescription: "Nil not supported"))
@ -474,7 +495,13 @@ fileprivate class JavaHashMapKeyedContainer<K : CodingKey> : KeyedEncodingContai
}
let valueStorage = try self.encoder.box(value, codingPath: codingPath + [key])
let result = JNI.CallObjectMethod(javaObject, methodID: HashMapPutMethod, args: [jvalue(l: keyStorage.javaObject), jvalue(l: valueStorage.javaObject)])
let javaObject = jniStorage.javaObject
let javaKey = keyStorage.javaObject
let javaValue = valueStorage.javaObject
let result = JNI.CallObjectMethod(javaObject!, methodID: HashMapPutMethod, args: [jvalue(l: javaKey), jvalue(l: javaValue)])
JNI.DeleteLocalRef(javaObject)
JNI.DeleteLocalRef(javaKey)
JNI.DeleteLocalRef(javaValue)
assert(result == nil, "Rewrite for key \(key.stringValue)")
}
@ -518,10 +545,6 @@ fileprivate class JavaHashMapUnkeyedContainer : UnkeyedEncodingContainer {
self.jniStorage = jniStorage
}
private var javaObject: jobject {
return jniStorage.javaObject
}
// MARK: - UnkeyedEncodingContainer Methods
public func encodeNil() throws {
throw EncodingError.invalidValue(NSNotFound, EncodingError.Context(codingPath: codingPath, debugDescription: "Nil not supported"))
@ -531,7 +554,13 @@ fileprivate class JavaHashMapUnkeyedContainer : UnkeyedEncodingContainer {
let indexKey = JavaKey(index: count)
let javaValue = try self.encoder.box(value, codingPath: codingPath + [indexKey])
if let javaKey = self.javaKey {
let result = JNI.CallObjectMethod(javaObject, methodID: HashMapPutMethod, args: [jvalue(l: javaKey.javaObject), jvalue(l: javaValue.javaObject)])
let javaObject = jniStorage.javaObject
let javaKey = javaKey.javaObject
let javaValue = javaValue.javaObject
let result = JNI.CallObjectMethod(javaObject!, methodID: HashMapPutMethod, args: [jvalue(l: javaKey), jvalue(l: javaValue)])
JNI.DeleteLocalRef(javaObject)
JNI.DeleteLocalRef(javaKey)
JNI.DeleteLocalRef(javaValue)
assert(result == nil, "Rewrite for key")
self.javaKey = nil
}
@ -575,10 +604,6 @@ fileprivate class JavaArrayContainer : UnkeyedEncodingContainer {
self.jniStorage = jniStorage
}
private var javaObject: jobject {
return jniStorage.javaObject
}
// MARK: - UnkeyedEncodingContainer Methods
public func encodeNil() throws {
throw EncodingError.invalidValue(NSNotFound, EncodingError.Context(codingPath: codingPath, debugDescription: "Nil not supported"))
@ -587,7 +612,11 @@ fileprivate class JavaArrayContainer : UnkeyedEncodingContainer {
public func encode<T : Encodable>(_ value: T) throws {
let indexKey = JavaKey(index: count)
let storeObject = try self.encoder.box(value, codingPath: codingPath + [indexKey])
let rewrite = JNI.CallBooleanMethod(self.javaObject, methodID: CollectionAddMethod, args: [jvalue(l: storeObject.javaObject)])
let javaObject = jniStorage.javaObject
let javaNewValue = storeObject.javaObject
let rewrite = JNI.CallBooleanMethod(javaObject!, methodID: CollectionAddMethod, args: [jvalue(l: javaNewValue!)])
JNI.DeleteLocalRef(javaObject)
JNI.DeleteLocalRef(javaNewValue)
assert(rewrite == JNI.TRUE, "ArrayList should always return true from add()")
count += 1
}
@ -667,7 +696,13 @@ class JavaEnumValueEncodingContainer: SingleValueEncodingContainer {
public func encode(_ value: jvalue, sig: String) throws {
let clazz = try JNI.getJavaClass(javaClass)
// If jniStorage.javaObject == nil its enum, else optionSet
if jniStorage.javaObject == nil {
if let javaObject = jniStorage.javaObject {
let filed = try JNI.getJavaField(forClass: self.javaClass, field: "rawValue", sig: sig)
let setterFunc = setterFuncMap[sig]
setterFunc?(javaObject, filed, value)
JNI.DeleteLocalRef(javaObject)
}
else {
let valueOfMethodID = try JNI.getStaticJavaMethod(forClass: javaClass, method: "valueOf", sig: "(\(sig))L\(javaClass);")
guard let javaObject = JNI.CallStaticObjectMethod(clazz, methodID: valueOfMethodID, args: [value]) else {
throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: codingPath,
@ -675,11 +710,6 @@ class JavaEnumValueEncodingContainer: SingleValueEncodingContainer {
}
jniStorage.javaObject = javaObject
}
else {
let filed = try JNI.getJavaField(forClass: self.javaClass, field: "rawValue", sig: sig)
let setterFunc = setterFuncMap[sig]
setterFunc?(self.jniStorage.javaObject, filed, value)
}
}
private let setterFuncMap: [String: (jobject, jfieldID, jvalue) -> Void] = [
@ -693,13 +723,13 @@ class JavaEnumValueEncodingContainer: SingleValueEncodingContainer {
let rawValue = try encoder.box(valueType, codingPath: codingPath)
let clazz = try JNI.getJavaClass(javaClass)
// If jniStorage.javaObject == nil its enum, else optionSet
if jniStorage.javaObject == nil {
if jniStorage.hasJavaObject == false {
let valueOfMethodID = try JNI.getStaticJavaMethod(forClass: javaClass, method: "valueOf", sig: "(\(rawValue.type.sig))L\(javaClass);")
JNI.SaveFatalErrorMessage("\(javaClass) valueOf \(rawValue.type.sig)")
let javaRawValue = rawValue.javaObject
defer {
JNI.RemoveFatalErrorMessage()
JNI.DeleteLocalRef(javaRawValue)
}
guard let javaObject = JNI.CallStaticObjectMethod(clazz, methodID: valueOfMethodID, args: [jvalue(l: rawValue.javaObject)]) else {
guard let javaObject = JNI.CallStaticObjectMethod(clazz, methodID: valueOfMethodID, args: [jvalue(l: javaRawValue)]) else {
throw JavaCodingError.cantCreateObject(javaClass)
}
jniStorage.javaObject = javaObject
@ -732,10 +762,6 @@ fileprivate class JavaAnyCodableContainer<K : CodingKey> : KeyedEncodingContaine
self.jniStorage = jniStorage
}
private var javaObject: jobject {
return jniStorage.javaObject
}
// MARK: - KeyedEncodingContainerProtocol Methods
public func encodeNil(forKey key: Key) throws {
throw EncodingError.invalidValue(NSNotFound, EncodingError.Context(codingPath: codingPath, debugDescription: "Nil not supported"))
@ -748,7 +774,7 @@ fileprivate class JavaAnyCodableContainer<K : CodingKey> : KeyedEncodingContaine
}
do {
let jniObject = try self.encoder.box(value, codingPath: codingPath + [key])
self.jniStorage.javaObject = JNI.api.NewLocalRef(JNI.env, jniObject.javaObject)
self.jniStorage.javaObject = jniObject.javaObject
}
catch {
if self.encoder.missingFieldsStrategy == .ignore {