Compare commits

...

8 Commits

Author SHA1 Message Date
Andrew Druk 328decd147 Dev: fix primitive encode/decode for 32 bit 2021-03-26 00:43:23 +02:00
Andrew Druk 677cf1a463 Dev: restore 32-bit support in Java Coder 2021-02-17 01:18:30 +02:00
Andrew Druk b708c7527a Dev: restore enum with object encode / decode 2021-01-28 00:47:32 +02:00
Andrew Druk e4b105dc83 Dev: fix support of primitive and support of optional primitives
improve support of Encoding&Decoding errors
2020-04-19 17:29:06 +03:00
Andrew Druk e4a9fc7ff7 Dev: add errorDescription for JavaCodingError 2020-03-11 00:53:06 +02:00
Andrew Druk 20c43bb6ec Dev: fix primitive encoding 2020-03-11 00:52:43 +02:00
Andrew Druk ca0014b6eb Dev: fix optional encoding of primitives 2020-03-06 17:56:21 +02:00
Andrew Druk 5b7dd458e6 Dev: add java primitive support 2020-02-25 14:10:18 +02:00
6 changed files with 989 additions and 175 deletions

View File

@ -115,7 +115,7 @@ public extension JNICore {
return jboolean(JNI_FALSE)
}
enum JNIError: Error {
enum JNIError: Error, LocalizedError {
case classNotFoundException(String)
case methodNotFoundException(String)
@ -132,6 +132,17 @@ public extension JNICore {
}
}
public var errorDescription: String? {
switch self {
case .classNotFoundException(let message):
return "ClassNotFoundaException: \(message)"
case .methodNotFoundException(let message):
return "MethodNotFoundException: \(message)"
case .fieldNotFoundException(let message):
return "FieldNotFoundException: \(message)"
}
}
}
// MARK: Global cache functions
@ -254,6 +265,18 @@ public extension JNICore {
})
}
func CallFloatMethod(_ object: jobject, methodID: jmethodID, args: [jvalue] = []) -> jfloat {
return checkArgument(args: args, { argsPtr in
api.CallFloatMethodA(env, object, methodID, argsPtr)
})
}
func CallDoubleMethod(_ object: jobject, methodID: jmethodID, args: [jvalue] = []) -> jdouble {
return checkArgument(args: args, { argsPtr in
api.CallDoubleMethodA(env, object, methodID, argsPtr)
})
}
func CallObjectMethod(_ object: jobject, methodID: jmethodID, args: [jvalue] = []) -> jobject? {
return checkArgument(args: args, { argsPtr in
api.CallObjectMethodA(env, object, methodID, argsPtr)
@ -335,6 +358,78 @@ public extension JNICore {
})
}
func CallBooleanMethod(_ object: jobject, _ methodID: jmethodID, _ args: JNIArgumentProtocol...) -> jboolean {
return checkArgumentAndWrap(args: args, { argsPtr in
api.CallBooleanMethodA(env, object, methodID, argsPtr)
})
}
func CallByteMethod(_ object: jobject, _ methodID: jmethodID, _ args: JNIArgumentProtocol...) -> jbyte {
return checkArgumentAndWrap(args: args, { argsPtr in
api.CallByteMethodA(env, object, methodID, argsPtr)
})
}
func CallShortMethod(_ object: jobject, _ methodID: jmethodID, _ args: JNIArgumentProtocol...) -> jshort {
return checkArgumentAndWrap(args: args, { argsPtr in
api.CallShortMethodA(env, object, methodID, argsPtr)
})
}
func CallIntMethod(_ object: jobject, _ methodID: jmethodID, _ args: JNIArgumentProtocol...) -> jint {
return checkArgumentAndWrap(args: args, { argsPtr in
api.CallIntMethodA(env, object, methodID, argsPtr)
})
}
func CallLongMethod(_ object: jobject, _ methodID: jmethodID, _ args: JNIArgumentProtocol...) -> jlong {
return checkArgumentAndWrap(args: args, { argsPtr in
api.CallLongMethodA(env, object, methodID, argsPtr)
})
}
func CallFloatMethod(_ object: jobject, _ methodID: jmethodID, _ args: JNIArgumentProtocol...) -> jfloat {
return checkArgumentAndWrap(args: args, { argsPtr in
api.CallFloatMethodA(env, object, methodID, argsPtr)
})
}
func CallDoubleMethod(_ object: jobject, _ methodID: jmethodID, _ args: JNIArgumentProtocol...) -> jdouble {
return checkArgumentAndWrap(args: args, { argsPtr in
api.CallDoubleMethodA(env, object, methodID, argsPtr)
})
}
func CallStaticBooleanMethod(_ clazz: jclass, _ methodID: jmethodID, _ args: JNIArgumentProtocol...) -> jboolean {
return checkArgumentAndWrap(args: args, { argsPtr in
api.CallStaticBooleanMethodA(env, clazz, methodID, argsPtr)
})
}
func CallStaticByteMethod(_ clazz: jclass, _ methodID: jmethodID, _ args: JNIArgumentProtocol...) -> jbyte {
return checkArgumentAndWrap(args: args, { argsPtr in
api.CallStaticByteMethodA(env, clazz, methodID, argsPtr)
})
}
func CallStaticShortMethod(_ clazz: jclass, _ methodID: jmethodID, _ args: JNIArgumentProtocol...) -> jshort {
return checkArgumentAndWrap(args: args, { argsPtr in
api.CallStaticShortMethodA(env, clazz, methodID, argsPtr)
})
}
func CallStaticIntMethod(_ clazz: jclass, _ methodID: jmethodID, _ args: JNIArgumentProtocol...) -> jint {
return checkArgumentAndWrap(args: args, { argsPtr in
api.CallStaticIntMethodA(env, clazz, methodID, argsPtr)
})
}
func CallStaticLongMethod(_ clazz: jclass, _ methodID: jmethodID, _ args: JNIArgumentProtocol...) -> jlong {
return checkArgumentAndWrap(args: args, { argsPtr in
api.CallStaticLongMethodA(env, clazz, methodID, argsPtr)
})
}
func CallVoidMethod(_ object: jobject, _ methodID: jmethodID, _ args: JNIArgumentProtocol...) {
checkArgumentAndWrap(args: args, { argsPtr in
api.CallVoidMethodA(env, object, methodID, argsPtr)

View File

@ -6,8 +6,8 @@ import Foundation
import java_swift
import CJavaVM
public typealias JavaEncodableClosure = (Any) throws -> jobject
public typealias JavaDecodableClosure = (jobject) throws -> Decodable
public typealias JavaEncodableClosure = (Any, [CodingKey]) throws -> jobject
public typealias JavaDecodableClosure = (jobject, [CodingKey]) throws -> Decodable
public struct JavaCoderConfig {
@ -43,153 +43,170 @@ public struct JavaCoderConfig {
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))]
RegisterType(type: Int.self, javaClassname: IntegerClassname, encodableClosure: { any, codingPath in
let value = any as! Int
let primitive = try value.javaPrimitive(codingPath: codingPath)
let args = [jvalue(i: primitive)]
return JNI.NewObject(IntegerClass, methodID: IntegerConstructor, args: args)!
}, decodableClosure: {
return Int(JNI.CallIntMethod($0, methodID: NumberIntValueMethod))
}, decodableClosure: { value, _ in
Int(fromJavaPrimitive: JNI.CallIntMethod(value, methodID: NumberIntValueMethod))
})
RegisterType(type: Int8.self, javaClassname: ByteClassname, encodableClosure: {
let args = [jvalue(b: $0 as! Int8)]
RegisterType(type: Int8.self, javaClassname: ByteClassname, encodableClosure: { any, _ in
let value = any as! Int8
let primitive = try value.javaPrimitive()
let args = [jvalue(b: primitive)]
return JNI.NewObject(ByteClass, methodID: ByteConstructor, args: args)!
}, decodableClosure: {
return JNI.CallByteMethod($0, methodID: NumberByteValueMethod)
}, decodableClosure: { value, _ in
Int8(fromJavaPrimitive: JNI.CallByteMethod(value, methodID: NumberByteValueMethod))
})
RegisterType(type: Int16.self, javaClassname: ShortClassname, encodableClosure: {
let args = [jvalue(s: $0 as! Int16)]
RegisterType(type: Int16.self, javaClassname: ShortClassname, encodableClosure: { any, _ in
let value = any as! Int16
let primitive = try value.javaPrimitive()
let args = [jvalue(s: primitive)]
return JNI.NewObject(ShortClass, methodID: ShortConstructor, args: args)!
}, decodableClosure: {
return JNI.CallShortMethod($0, methodID: NumberShortValueMethod)
}, decodableClosure: { value, _ in
Int16(fromJavaPrimitive: JNI.CallShortMethod(value, methodID: NumberShortValueMethod))
})
RegisterType(type: Int32.self, javaClassname: IntegerClassname, encodableClosure: {
let args = [jvalue(i: jint($0 as! Int32))]
RegisterType(type: Int32.self, javaClassname: IntegerClassname, encodableClosure: { any, _ in
let value = any as! Int32
let primitive = try value.javaPrimitive()
let args = [jvalue(i: primitive)]
return JNI.NewObject(IntegerClass, methodID: IntegerConstructor, args: args)!
}, decodableClosure: {
return Int32(JNI.CallIntMethod($0, methodID: NumberIntValueMethod))
}, decodableClosure: { value, _ in
Int32(fromJavaPrimitive: JNI.CallIntMethod(value, methodID: NumberIntValueMethod))
})
RegisterType(type: Int64.self, javaClassname: LongClassname, encodableClosure: {
let args = [jvalue(j: $0 as! Int64)]
RegisterType(type: Int64.self, javaClassname: LongClassname, encodableClosure: { any, _ in
let value = any as! Int64
let primitive = try value.javaPrimitive()
let args = [jvalue(j: primitive)]
return JNI.NewObject(LongClass, methodID: LongConstructor, args: args)!
}, decodableClosure: {
return JNI.CallLongMethod($0, methodID: NumberLongValueMethod)
}, decodableClosure: { value, _ in
Int64(fromJavaPrimitive: JNI.CallLongMethod(value, 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: UInt.self, javaClassname: IntegerClassname, encodableClosure: { any, codingPath in
let value = any as! UInt
let primitive = try value.javaPrimitive(codingPath: codingPath)
let args = [jvalue(i: primitive)]
return JNI.NewObject(IntegerClass, methodID: IntegerConstructor, args: args)!
}, decodableClosure: { value, _ in
UInt(fromJavaPrimitive: JNI.CallIntMethod(value, methodID: NumberIntValueMethod))
})
RegisterType(type: UInt8.self, javaClassname: ShortClassname, encodableClosure: {
let args = [jvalue(s: Int16($0 as! UInt8))]
RegisterType(type: UInt8.self, javaClassname: ByteClassname, encodableClosure: { any, _ in
let value = any as! UInt8
let primitive = try value.javaPrimitive()
let args = [jvalue(b: primitive)]
return JNI.NewObject(ByteClass, methodID: ByteConstructor, args: args)!
}, decodableClosure: { value, _ in
UInt8(fromJavaPrimitive: JNI.CallByteMethod(value, methodID: NumberByteValueMethod))
})
RegisterType(type: UInt16.self, javaClassname: ShortClassname, encodableClosure: { any, _ in
let value = any as! UInt16
let primitive = try value.javaPrimitive()
let args = [jvalue(s: primitive)]
return JNI.NewObject(ShortClass, methodID: ShortConstructor, args: args)!
}, decodableClosure: {
return UInt8(JNI.CallShortMethod($0, methodID: NumberShortValueMethod))
}, decodableClosure: { value, _ in
UInt16(fromJavaPrimitive: JNI.CallShortMethod(value, methodID: NumberShortValueMethod))
})
RegisterType(type: UInt16.self, javaClassname: IntegerClassname, encodableClosure: {
let args = [jvalue(i: jint($0 as! UInt16))]
RegisterType(type: UInt32.self, javaClassname: IntegerClassname, encodableClosure: { any, _ in
let value = any as! UInt32
let primitive = try value.javaPrimitive()
let args = [jvalue(i: primitive)]
return JNI.NewObject(IntegerClass, methodID: IntegerConstructor, args: args)!
}, decodableClosure: {
return UInt16(JNI.CallIntMethod($0, methodID: NumberIntValueMethod))
}, decodableClosure: { value, _ in
UInt32(fromJavaPrimitive: JNI.CallIntMethod(value, methodID: NumberIntValueMethod))
})
RegisterType(type: UInt32.self, javaClassname: LongClassname, encodableClosure: {
let args = [jvalue(j: Int64($0 as! UInt32))]
RegisterType(type: UInt64.self, javaClassname: LongClassname, encodableClosure: { any, _ in
let value = any as! UInt64
let primitive = try value.javaPrimitive()
let args = [jvalue(j: primitive)]
return JNI.NewObject(LongClass, methodID: LongConstructor, args: args)!
}, decodableClosure: {
return UInt32(JNI.CallLongMethod($0, methodID: NumberLongValueMethod))
}, decodableClosure: { value, _ in
UInt64(fromJavaPrimitive: JNI.CallLongMethod(value, 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: Float.self, javaClassname: FloatClassname, encodableClosure: {
let args = [jvalue(f: $0 as! Float)]
RegisterType(type: Float.self, javaClassname: FloatClassname, encodableClosure: { any, _ in
let value = any as! Float
let primitive = try value.javaPrimitive()
let args = [jvalue(f: primitive)]
return JNI.NewObject(FloatClass, methodID: FloatConstructor, args: args)!
}, decodableClosure: {
return JNI.api.CallFloatMethodA(JNI.env, $0, NumberFloatValueMethod, nil)
}, decodableClosure: { value, _ in
Float(fromJavaPrimitive: JNI.CallFloatMethod(value, methodID: NumberFloatValueMethod))
})
RegisterType(type: Double.self, javaClassname: DoubleClassname, encodableClosure: {
let args = [jvalue(d: $0 as! Double)]
RegisterType(type: Double.self, javaClassname: DoubleClassname, encodableClosure: { any, _ in
let value = any as! Double
let primitive = try value.javaPrimitive()
let args = [jvalue(d: primitive)]
return JNI.NewObject(DoubleClass, methodID: DoubleConstructor, args: args)!
}, decodableClosure: {
return JNI.api.CallDoubleMethodA(JNI.env, $0, NumberDoubleValueMethod, nil)
}, decodableClosure: { value, _ in
Double(fromJavaPrimitive: JNI.CallDoubleMethod(value, methodID: NumberDoubleValueMethod))
})
RegisterType(type: Bool.self, javaClassname: BooleanClassname, encodableClosure: {
let args = [jvalue(z: $0 as! Bool ? JNI.TRUE : JNI.FALSE)]
RegisterType(type: Bool.self, javaClassname: BooleanClassname, encodableClosure: { value, _ in
let args = [jvalue(z: value as! Bool ? JNI.TRUE : JNI.FALSE)]
return JNI.NewObject(BooleanClass, methodID: BooleanConstructor, args: args)!
}, decodableClosure: {
return (JNI.CallBooleanMethod($0, methodID: NumberBooleanValueMethod) == JNI.TRUE)
}, decodableClosure: { value, _ in
JNI.CallBooleanMethod(value, methodID: NumberBooleanValueMethod) == JNI.TRUE
})
RegisterType(type: String.self, javaClassname: StringClassname, encodableClosure: {
let valueString = $0 as! String
RegisterType(type: String.self, javaClassname: StringClassname, encodableClosure: { value, _ in
let valueString = value as! String
var locals = [jobject]()
// Locals ignored because JNIStorageObject take ownership of LocalReference
return valueString.localJavaObject(&locals)!
}, decodableClosure: {
return String(javaObject: $0)
}, decodableClosure: { value, _ in
String(javaObject: value)
})
RegisterType(type: Date.self, javaClassname: DateClassname, encodableClosure: {
let valueDate = $0 as! Date
RegisterType(type: Date.self, javaClassname: DateClassname, encodableClosure: { value, _ in
let valueDate = value 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)
}, decodableClosure: { value, _ in
let timeInterval = JNI.api.CallLongMethodA(JNI.env, value, DateGetTimeMethod, nil)
// Java save TimeInterval in UInt64 milliseconds
return Date(timeIntervalSince1970: TimeInterval(timeInterval) / 1000.0)
})
RegisterType(type: URL.self, javaClassname: UriClassname, encodableClosure: {
RegisterType(type: URL.self, javaClassname: UriClassname, encodableClosure: { value, _ in
var locals = [jobject]()
let javaString = ($0 as! URL).absoluteString.localJavaObject(&locals)
let javaString = (value as! URL).absoluteString.localJavaObject(&locals)
let args = [jvalue(l: javaString)]
JNI.SaveFatalErrorMessage("UriConstructor")
defer {
JNI.RemoveFatalErrorMessage()
}
return JNI.check(JNI.CallStaticObjectMethod(UriClass, methodID: UriConstructor!, args: args)!, &locals)
}, decodableClosure: {
let pathString = JNI.api.CallObjectMethodA(JNI.env, $0, ObjectToStringMethod, nil)
}, decodableClosure: { value, _ in
let pathString = JNI.api.CallObjectMethodA(JNI.env, value, ObjectToStringMethod, nil)
return URL(string: String(javaObject: pathString))
})
RegisterType(type: Data.self, javaClassname: ByteBufferClassname, encodableClosure: {
let valueData = $0 as! Data
RegisterType(type: Data.self, javaClassname: ByteBufferClassname, encodableClosure: { data, codingPath in
let valueData = data as! Data
let byteArray = JNI.api.NewByteArray(JNI.env, jint(valueData.count))
if let throwable = JNI.ExceptionCheck() {
throw EncodingError.invalidValue($0, EncodingError.Context(codingPath: [],
throw EncodingError.invalidValue(data, EncodingError.Context(codingPath: codingPath,
debugDescription: "Can't create NewByteArray \(valueData.count)"))
}
try valueData.withUnsafeBytes({ pointer in
guard let bytes = pointer.baseAddress?.assumingMemoryBound(to: Int8.self) else {
throw EncodingError.invalidValue(valueData, EncodingError.Context(codingPath: [],
throw EncodingError.invalidValue(valueData, EncodingError.Context(codingPath: codingPath,
debugDescription: "Can't get unsafeBytes \(valueData.count)"))
}
JNI.api.SetByteArrayRegion(JNI.env, byteArray, 0, jint(valueData.count), bytes)
})
if let throwable = JNI.ExceptionCheck() {
throw EncodingError.invalidValue($0, EncodingError.Context(codingPath: [],
throw EncodingError.invalidValue(data, EncodingError.Context(codingPath: codingPath,
debugDescription: "SetByteArrayRegion failed \(valueData.count)"))
}
JNI.SaveFatalErrorMessage("java/nio/ByteBuffer wrap")
@ -197,8 +214,8 @@ public struct JavaCoderConfig {
JNI.RemoveFatalErrorMessage()
}
return JNI.CallStaticObjectMethod(ByteBufferClass, methodID: ByteBufferWrap, args: [jvalue(l: byteArray)])!
}, decodableClosure: {
let byteArray = JNI.CallObjectMethod($0, methodID: ByteBufferArray)
}, decodableClosure: { value, _ in
let byteArray = JNI.CallObjectMethod(value, methodID: ByteBufferArray)
defer {
JNI.api.DeleteLocalRef(JNI.env, byteArray)
}

View File

@ -0,0 +1,78 @@
//
// Created by Andriy Druk on 19.04.2020.
//
import Foundation
public enum JavaCodingError: LocalizedError {
case notSupported(String)
case cantCreateObject(String)
case cantFindObject(String)
public var errorDescription: String? {
switch self {
case .notSupported(let message):
return "Not supported: \(message)"
case .cantCreateObject(let message):
return "Can't create object: \(message)"
case .cantFindObject(let message):
return "Can't find object: \(message)"
}
}
}
// We need one more protocol, because we can't override description func in EncodingError & DecodingError
public protocol JavaCodingErrorDescription {
var detailedDescription: String { get }
}
fileprivate func contextDescription(codingPath: [CodingKey],
debugDescription: String,
underlyingError: Error?) -> String {
var underlyingErrorDescription = ""
if let underlyingError = underlyingError {
underlyingErrorDescription = " with underlying error: \(underlyingError.localizedDescription)"
}
let path = codingPath.map({ $0.stringValue }).joined(separator: "/")
return "\(debugDescription) [\(path)]" + underlyingErrorDescription
}
extension EncodingError.Context: JavaCodingErrorDescription {
public var detailedDescription: String {
return contextDescription(codingPath: codingPath, debugDescription: debugDescription, underlyingError: underlyingError)
}
}
extension DecodingError.Context: JavaCodingErrorDescription {
public var detailedDescription: String {
return contextDescription(codingPath: codingPath, debugDescription: debugDescription, underlyingError: underlyingError)
}
}
extension EncodingError: JavaCodingErrorDescription {
public var detailedDescription: String {
switch self {
case .invalidValue(let value, let context):
return "Invalid value \"\(value)\": \(context.detailedDescription)"
@unknown default:
return "Not supported encoding error"
}
}
}
extension DecodingError: JavaCodingErrorDescription {
public var detailedDescription: String {
switch self {
case .typeMismatch(let value, let context):
return "Type mismatch \"\(value)\": \(context.detailedDescription)"
case .valueNotFound(let value, let context):
return "Value not found \"\(value)\": \(context.detailedDescription)"
case .keyNotFound(let codingKey, let context):
return "Key not found \"\(codingKey)\": \(context.detailedDescription)"
case .dataCorrupted(let context):
return "Data corrupted: \(context.detailedDescription)"
@unknown default:
return "Not supported decoding error"
}
}
}

View File

@ -11,7 +11,7 @@ import AnyCodable
public class JavaDecoder: Decoder {
public var codingPath = [CodingKey]()
public var codingPath: [CodingKey]
public var userInfo = [CodingUserInfoKey : Any]()
@ -19,14 +19,17 @@ public class JavaDecoder: Decoder {
fileprivate let package: String
fileprivate let missingFieldsStrategy: MissingFieldsStrategy
public init(forPackage package: String, missingFieldsStrategy: MissingFieldsStrategy = .throw) {
public init(forPackage package: String,
missingFieldsStrategy: MissingFieldsStrategy = .throw,
codingPath: [CodingKey] = []) {
self.package = package
self.missingFieldsStrategy = missingFieldsStrategy
self.codingPath = codingPath
}
public func decode<T : Decodable>(_ type: T.Type, from javaObject: jobject) throws -> T {
do {
let value = try unbox(type: type, javaObject: javaObject)
let value = try unbox(type: type, javaObject: javaObject, codingPath: codingPath)
assert(self.storage.count == 0, "Missing decoding for \(self.storage.count) objects")
return value
}
@ -86,7 +89,7 @@ public class JavaDecoder: Decoder {
fileprivate class JavaObjectContainer<K : CodingKey> : KeyedDecodingContainerProtocol {
typealias Key = K
var codingPath = [CodingKey]()
var codingPath: [CodingKey]
var allKeys = [K]()
let decoder: JavaDecoder
@ -98,6 +101,7 @@ fileprivate class JavaObjectContainer<K : CodingKey> : KeyedDecodingContainerPro
self.decoder = decoder
self.jniStorage = jniStorage
self.javaObject = jniStorage.javaObject
self.codingPath = jniStorage.codingPath
switch jniStorage.type {
case let .object(className):
self.javaClass = className
@ -111,7 +115,7 @@ fileprivate class JavaObjectContainer<K : CodingKey> : KeyedDecodingContainerPro
}
func decodeNil(forKey key: K) throws -> Bool {
throw JavaCodingError.notSupported("JavaObjectContainer.decodeNil(forKey: \(key)")
throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "Nil not supported")
}
private func decodeWithMissingStrategy<T>(defaultValue: T, block: () throws -> T) throws -> T {
@ -129,12 +133,102 @@ 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")
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")
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")
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")
#if arch(x86_64) || arch(arm64)
return JNI.api.GetIntField(JNI.env, javaObject, fieldID)
#else
return Int32(JNI.api.GetIntField(JNI.env, javaObject, fieldID))
#endif
}
private func decodeLong(forKey key: String) throws -> Int64 {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: key, sig: "J")
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")
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")
return JNI.api.GetDoubleField(JNI.env, javaObject, fieldID)
}
// MARK: KeyedDecodingContainerProtocol protocol
public func decode(_ type: Bool.Type, forKey key: K) throws -> Bool {
// TODO: WTF? Delete decodeWithMissingStrategy with default false -> CRASH
return try decodeWithMissingStrategy(defaultValue: false) {
return try decodeJava(type, forKey: key) ?? false
return try self.decodeBoolean(forKey: key.stringValue)
}
}
public func decode(_ type: Int.Type, forKey key: K) throws -> Int {
return Int(try decodeInteger(forKey: key.stringValue))
}
public func decode(_ type: Int8.Type, forKey key: K) throws -> Int8 {
return try decodeByte(forKey: key.stringValue)
}
public func decode(_ type: Int16.Type, forKey key: K) throws -> Int16 {
return try decodeShort(forKey: key.stringValue)
}
public func decode(_ type: Int32.Type, forKey key: K) throws -> Int32 {
return try decodeInteger(forKey: key.stringValue)
}
public func decode(_ type: Int64.Type, forKey key: K) throws -> Int64 {
return try decodeLong(forKey: key.stringValue)
}
public func decode(_ type: UInt.Type, forKey key: K) throws -> UInt {
return UInt(UInt32(bitPattern: try decodeInteger(forKey: key.stringValue)))
}
public func decode(_ type: UInt8.Type, forKey key: K) throws -> UInt8 {
return UInt8(bitPattern: try decodeByte(forKey: key.stringValue))
}
public func decode(_ type: UInt16.Type, forKey key: K) throws -> UInt16 {
return UInt16(bitPattern: try decodeShort(forKey: key.stringValue))
}
public func decode(_ type: UInt32.Type, forKey key: K) throws -> UInt32 {
return UInt32(bitPattern: try decodeInteger(forKey: key.stringValue))
}
public func decode(_ type: UInt64.Type, forKey key: K) throws -> UInt64 {
return UInt64(bitPattern: try decodeLong(forKey: key.stringValue))
}
public func decode(_ type: Float.Type, forKey key: K) throws -> Float {
return try decodeFloat(forKey: key.stringValue)
}
public func decode(_ type: Double.Type, forKey key: K) throws -> Double {
return try decodeDouble(forKey: key.stringValue)
}
// override all decodeIfPresent to prevent calling decodeNil(forKey:)
public func decodeIfPresent(_ type: Int.Type, forKey key: K) throws -> Int? {
return try self.decodeJava(type, forKey: key)
@ -176,6 +270,14 @@ fileprivate class JavaObjectContainer<K : CodingKey> : KeyedDecodingContainerPro
return try self.decodeJava(type, forKey: key)
}
public func decodeIfPresent(_ type: Float.Type, forKey key: K) throws -> Float? {
return try self.decodeJava(type, forKey: key)
}
public func decodeIfPresent(_ type: Double.Type, forKey key: K) throws -> Double? {
return try self.decodeJava(type, forKey: key)
}
public func decodeIfPresent(_ type: Bool.Type, forKey key: K) throws -> Bool? {
return try self.decodeJava(type, forKey: key)
}
@ -190,7 +292,7 @@ fileprivate class JavaObjectContainer<K : CodingKey> : KeyedDecodingContainerPro
func decode<T>(_ type: T.Type, forKey key: K) throws -> T where T : Decodable {
guard let result = try self.decodeJava(type, forKey: key) else {
throw JavaCodingError.nilNotSupported("\(javaClass).\(key.stringValue)")
throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "Nil not supported: \(javaClass).\(key.stringValue)")
}
return result
}
@ -206,7 +308,7 @@ fileprivate class JavaObjectContainer<K : CodingKey> : KeyedDecodingContainerPro
JNI.ExceptionReset()
let errorMessage = "\(javaClass).\(key.stringValue): JavaDecoder uses reflection for AnyCodable, " +
"probably \(key.stringValue) field not public"
throw JavaCodingError.cantFindObject(errorMessage)
throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: errorMessage)
}
let fieldClass = JNI.CallObjectMethod(field, methodID: FieldGetTypedMethod, args: [])!
let javaClassName = JNI.api.CallObjectMethodA(JNI.env, fieldClass, ClassGetNameMethod, nil)!
@ -228,16 +330,16 @@ fileprivate class JavaObjectContainer<K : CodingKey> : KeyedDecodingContainerPro
defer {
JNI.DeleteLocalRef(object)
}
return try self.decoder.unbox(type: type, javaObject: object)
return try self.decoder.unbox(type: type, javaObject: object, codingPath: codingPath + [key])
}
}
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: K) throws -> KeyedDecodingContainer<NestedKey> where NestedKey : CodingKey {
throw JavaCodingError.notSupported("JavaObjectContainer.nestedContainer(keyedBy: \(type), forKey: \(key))")
throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "Nested keyed container not supported")
}
func nestedUnkeyedContainer(forKey key: K) throws -> UnkeyedDecodingContainer {
throw JavaCodingError.notSupported("JavaObjectContainer.nestedUnkeyedContainer(forKey: \(key))")
throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "Nested unkeyed container not supported")
}
func superDecoder() throws -> Decoder {
@ -246,14 +348,14 @@ fileprivate class JavaObjectContainer<K : CodingKey> : KeyedDecodingContainerPro
}
func superDecoder(forKey key: K) throws -> Decoder {
throw JavaCodingError.notSupported("JavaObjectContainer.superDecoder(forKey: \(key)")
throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "Super decoder not supported")
}
}
fileprivate class JavaHashMapKeyedContainer<K : CodingKey>: KeyedDecodingContainerProtocol {
typealias Key = K
var codingPath = [CodingKey]()
var codingPath: [CodingKey]
var allKeys = [K]()
private let decoder: JavaDecoder
@ -266,6 +368,7 @@ fileprivate class JavaHashMapKeyedContainer<K : CodingKey>: KeyedDecodingContain
self.decoder = decoder
self.jniStorage = jniStorage
self.javaObject = jniStorage.javaObject
self.codingPath = jniStorage.codingPath
let keySet = JNI.api.CallObjectMethodA(JNI.env, javaObject, HashMapKeySetMethod, nil)
let keyArray = JNI.api.CallObjectMethodA(JNI.env, keySet, SetToArrayMethod, nil)
@ -283,21 +386,24 @@ fileprivate class JavaHashMapKeyedContainer<K : CodingKey>: KeyedDecodingContain
var keySig: String?
for i in 0 ..< size {
guard let indexKey = K(intValue: Int(i)) else {
throw DecodingError.dataCorruptedError(forKey: K(stringValue: "init()")!, in: self, debugDescription: "Wrong array length")
}
guard let object = JNI.api.GetObjectArrayElement(JNI.env, keyArray, i) else {
throw JavaCodingError.wrongArrayLength
throw DecodingError.dataCorruptedError(forKey: K(stringValue: "init()")!, in: self, debugDescription: "Wrong array length")
}
if keySig == nil {
keySig = self.decoder.getJavaClassname(from: object).sig
}
if keySig == "Ljava/lang/String;" {
let stringKey = try self.decoder.unbox(type: String.self, javaObject: object)
let stringKey = try self.decoder.unbox(type: String.self, javaObject: object, codingPath: codingPath + [indexKey])
if let key = K(stringValue: stringKey) {
javaKeys[stringKey] = object
allKeys.append(key)
}
}
else {
let intKey = try self.decoder.unbox(type: Int.self, javaObject: object)
let intKey = try self.decoder.unbox(type: Int.self, javaObject: object, codingPath: codingPath + [indexKey])
if let key = K(intValue: intKey) {
javaKeys[intKey] = object
allKeys.append(key)
@ -317,7 +423,7 @@ fileprivate class JavaHashMapKeyedContainer<K : CodingKey>: KeyedDecodingContain
}
func decodeNil(forKey key: K) throws -> Bool {
throw JavaCodingError.notSupported("JavaHashMapContainer.decodeNil(forKey: \(key))")
throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "Nil not supported")
}
func decode<T>(_ type: T.Type, forKey key: K) throws -> T where T : Decodable {
@ -331,20 +437,20 @@ fileprivate class JavaHashMapKeyedContainer<K : CodingKey>: KeyedDecodingContain
let javaKey = javaKeys[typeKey]
guard let object = JNI.CallObjectMethod(self.javaObject, methodID: HashMapGetMethod, args: [jvalue(l: javaKey)]) else {
throw JavaCodingError.cantFindObject("HashMap[\(key.stringValue)]")
throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "Can't find object")
}
defer {
JNI.DeleteLocalRef(object)
}
return try self.decoder.unbox(type: type, javaObject: object)
return try self.decoder.unbox(type: type, javaObject: object, codingPath: codingPath + [key])
}
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: K) throws -> KeyedDecodingContainer<NestedKey> where NestedKey : CodingKey {
throw JavaCodingError.notSupported("JavaHashMapContainer.nestedContainer(keyedBy: \(type), forKey: \(key))")
throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "Nested keyed container not supported")
}
func nestedUnkeyedContainer(forKey key: K) throws -> UnkeyedDecodingContainer {
throw JavaCodingError.notSupported("JavaHashMapContainer.nestedUnkeyedContainer(forKey: \(key))")
throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "Nested unkeyed container not supported")
}
func superDecoder() throws -> Decoder {
@ -352,13 +458,13 @@ fileprivate class JavaHashMapKeyedContainer<K : CodingKey>: KeyedDecodingContain
}
func superDecoder(forKey key: K) throws -> Decoder {
throw JavaCodingError.notSupported("JavaHashMapContainer.superDecoder(forKey: \(key))")
throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "Super decoder not supported")
}
}
fileprivate class JavaHashMapUnkeyedContainer: UnkeyedDecodingContainer {
var codingPath = [CodingKey]()
var codingPath: [CodingKey]
var count: Int?
@ -383,6 +489,7 @@ fileprivate class JavaHashMapUnkeyedContainer: UnkeyedDecodingContainer {
self.decoder = decoder
self.jniStorage = jniStorage
self.javaObject = jniStorage.javaObject
self.codingPath = jniStorage.codingPath
self.count = Int(JNI.CallIntMethod(self.javaObject, methodID: HashMapSizeMethod)) * 2
let keySet = JNI.api.CallObjectMethodA(JNI.env, javaObject, HashMapKeySetMethod, nil)
@ -397,13 +504,14 @@ fileprivate class JavaHashMapUnkeyedContainer: UnkeyedDecodingContainer {
}
func decodeNil() throws -> Bool {
throw JavaCodingError.notSupported("JavaUnkeyedDecodingContainer.decodeNil")
throw DecodingError.dataCorruptedError(in: self, debugDescription: "Nil not supported")
}
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 {
throw JavaCodingError.cantFindObject("HashMap[]")
throw DecodingError.dataCorruptedError(in: self, debugDescription: "Can't find object")
}
currentIndex += 1
defer {
@ -411,34 +519,34 @@ fileprivate class JavaHashMapUnkeyedContainer: UnkeyedDecodingContainer {
JNI.DeleteLocalRef(self.javaCurrentKey)
self.javaCurrentKey = nil
}
return try self.decoder.unbox(type: type, javaObject: object)
return try self.decoder.unbox(type: type, javaObject: object, codingPath: codingPath + [codingKey])
}
else {
guard let object = JNI.api.GetObjectArrayElement(JNI.env, javaKeys, jsize(self.currentIndex / 2)) else {
throw JavaCodingError.wrongArrayLength
throw DecodingError.dataCorruptedError(in: self, debugDescription: "Wrong array length")
}
self.javaCurrentKey = object
currentIndex += 1
return try self.decoder.unbox(type: type, javaObject: object)
return try self.decoder.unbox(type: type, javaObject: object, codingPath: codingPath + [codingKey])
}
}
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type) throws -> KeyedDecodingContainer<NestedKey> where NestedKey : CodingKey {
throw JavaCodingError.notSupported("JavaUnkeyedDecodingContainer.nestedContainer(keyedBy: \(type))")
throw DecodingError.dataCorruptedError(in: self, debugDescription: "Nested keyed container not supported")
}
func nestedUnkeyedContainer() throws -> UnkeyedDecodingContainer {
throw JavaCodingError.notSupported("JavaUnkeyedDecodingContainer.nestedUnkeyedContainer")
throw DecodingError.dataCorruptedError(in: self, debugDescription: "Nested unkeyed container not supported")
}
func superDecoder() throws -> Decoder {
throw JavaCodingError.notSupported("JavaUnkeyedDecodingContainer.superDecoder")
throw DecodingError.dataCorruptedError(in: self, debugDescription: "Super decoder not supported")
}
}
fileprivate class JavaArrayContainer: UnkeyedDecodingContainer {
var codingPath = [CodingKey]()
var codingPath: [CodingKey]
var count: Int?
@ -459,6 +567,7 @@ fileprivate class JavaArrayContainer: UnkeyedDecodingContainer {
fileprivate init(decoder: JavaDecoder, jniStorage: JNIStorageObject) {
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)!
}
@ -468,35 +577,36 @@ fileprivate class JavaArrayContainer: UnkeyedDecodingContainer {
}
func decodeNil() throws -> Bool {
throw JavaCodingError.notSupported("JavaUnkeyedDecodingContainer.decodeNil")
throw DecodingError.dataCorruptedError(in: self, debugDescription: "Nil not supported")
}
func decode<T>(_ type: T.Type) throws -> T where T : Decodable {
let codingKey = JavaKey(intValue: currentIndex)
guard let object = JNI.CallObjectMethod(self.javaIterator, methodID: IteratorNextMethod) else {
throw JavaCodingError.cantFindObject("Array out of range: \(self.currentIndex)")
throw DecodingError.dataCorruptedError(in: self, debugDescription: "Array out of range: \(self.currentIndex)")
}
defer {
JNI.DeleteLocalRef(object)
}
currentIndex += 1
return try self.decoder.unbox(type: type, javaObject: object)
return try self.decoder.unbox(type: type, javaObject: object, codingPath: codingPath + [codingKey])
}
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type) throws -> KeyedDecodingContainer<NestedKey> where NestedKey : CodingKey {
throw JavaCodingError.notSupported("JavaUnkeyedDecodingContainer.nestedContainer(keyedBy: \(type))")
throw DecodingError.dataCorruptedError(in: self, debugDescription: "Nested keyed container not supported")
}
func nestedUnkeyedContainer() throws -> UnkeyedDecodingContainer {
throw JavaCodingError.notSupported("JavaUnkeyedDecodingContainer.nestedUnkeyedContainer")
throw DecodingError.dataCorruptedError(in: self, debugDescription: "Nested unkeyed container not supported")
}
func superDecoder() throws -> Decoder {
throw JavaCodingError.notSupported("JavaUnkeyedDecodingContainer.superDecoder")
throw DecodingError.dataCorruptedError(in: self, debugDescription: "Super decoder not supported")
}
}
fileprivate class JavaEnumContainer: SingleValueDecodingContainer {
var codingPath: [CodingKey] = []
var codingPath: [CodingKey]
let decoder: JavaDecoder
let jniStorage: JNIStorageObject
@ -507,6 +617,7 @@ fileprivate class JavaEnumContainer: SingleValueDecodingContainer {
self.decoder = decoder
self.jniStorage = jniStorage
self.javaObject = jniStorage.javaObject
self.codingPath = jniStorage.codingPath
switch jniStorage.type {
case let .object(className):
self.javaClass = className
@ -519,23 +630,83 @@ fileprivate class JavaEnumContainer: SingleValueDecodingContainer {
fatalError("Unsupported: JavaEnumDecodingContainer.decodeNil")
}
func decode<T>(_ type: T.Type) throws -> T where T : Decodable {
let classname = self.decoder.getJavaClassname(forType: type)
func decode(_ type: Int.Type) throws -> Int {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: "rawValue", sig: "I")
let value = JNI.api.GetIntField(JNI.env, javaObject, fieldID)
return Int(fromJavaPrimitive: value)
}
func decode(_ type: Int8.Type) throws -> Int8 {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: "rawValue", sig: "B")
let value = JNI.api.GetByteField(JNI.env, javaObject, fieldID)
return Int8(fromJavaPrimitive: value)
}
func decode(_ type: Int16.Type) throws -> Int16 {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: "rawValue", sig: "S")
let value = JNI.api.GetShortField(JNI.env, javaObject, fieldID)
return Int16(fromJavaPrimitive: value)
}
func decode(_ type: Int32.Type) throws -> Int32 {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: "rawValue", sig: "I")
let value = JNI.api.GetIntField(JNI.env, javaObject, fieldID)
return Int32(fromJavaPrimitive: value)
}
func decode(_ type: Int64.Type) throws -> Int64 {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: "rawValue", sig: "J")
let value = JNI.api.GetLongField(JNI.env, javaObject, fieldID)
return Int64(fromJavaPrimitive: value)
}
func decode(_ type: UInt.Type) throws -> UInt {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: "rawValue", sig: "I")
let value = JNI.api.GetIntField(JNI.env, javaObject, fieldID)
return UInt(fromJavaPrimitive: value)
}
func decode(_ type: UInt8.Type) throws -> UInt8 {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: "rawValue", sig: "B")
let value = JNI.api.GetByteField(JNI.env, javaObject, fieldID)
return UInt8(fromJavaPrimitive: value)
}
func decode(_ type: UInt16.Type) throws -> UInt16 {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: "rawValue", sig: "S")
let value = JNI.api.GetShortField(JNI.env, javaObject, fieldID)
return UInt16(fromJavaPrimitive: value)
}
func decode(_ type: UInt32.Type) throws -> UInt32 {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: "rawValue", sig: "I")
let value = JNI.api.GetIntField(JNI.env, javaObject, fieldID)
return UInt32(fromJavaPrimitive: value)
}
func decode(_ type: UInt64.Type) throws -> UInt64 {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: "rawValue", sig: "J")
let value = JNI.api.GetLongField(JNI.env, javaObject, fieldID)
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);")
guard let object = JNI.api.GetObjectField(JNI.env, javaObject, fieldID) else {
throw JavaCodingError.nilNotSupported("\(javaClass).rawValue")
throw JavaCodingError.notSupported(javaClass)
}
defer {
JNI.DeleteLocalRef(object)
}
return try self.decoder.unbox(type: type, javaObject: object)
return try decoder.unbox(type: valueType, javaObject: object, codingPath: codingPath)
}
}
fileprivate class JavaAnyCodableContainer<K : CodingKey> : KeyedDecodingContainerProtocol {
typealias Key = K
var codingPath = [CodingKey]()
var codingPath: [CodingKey]
var allKeys = [K]()
let decoder: JavaDecoder
@ -545,6 +716,7 @@ fileprivate class JavaAnyCodableContainer<K : CodingKey> : KeyedDecodingContaine
fileprivate init(decoder: JavaDecoder, jniStorage: JNIStorageObject) {
self.decoder = decoder
self.jniStorage = jniStorage
self.codingPath = jniStorage.codingPath
switch jniStorage.type {
case let .anyCodable(codable):
self.jniCodableType = codable
@ -558,7 +730,7 @@ fileprivate class JavaAnyCodableContainer<K : CodingKey> : KeyedDecodingContaine
}
func decodeNil(forKey key: K) throws -> Bool {
throw JavaCodingError.notSupported("JavaObjectContainer.decodeNil(forKey: \(key)")
throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "Nil not supported")
}
func decode<T>(_ type: T.Type, forKey key: K) throws -> T where T : Decodable {
@ -584,7 +756,7 @@ fileprivate class JavaAnyCodableContainer<K : CodingKey> : KeyedDecodingContaine
}
}
else if key.stringValue == "value" {
return try self.decoder.unbox(type: type, javaObject: self.jniStorage.javaObject)
return try self.decoder.unbox(type: type, javaObject: self.jniStorage.javaObject, codingPath: codingPath + [key])
}
else {
fatalError("Unknown key: \(key.stringValue)")
@ -592,7 +764,7 @@ fileprivate class JavaAnyCodableContainer<K : CodingKey> : KeyedDecodingContaine
}
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: K) throws -> KeyedDecodingContainer<NestedKey> where NestedKey : CodingKey {
throw JavaCodingError.notSupported("JavaAnyCodableContainer.nestedContainer(keyedBy: \(type), forKey: \(key))")
throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "Nested keyed container not supported")
}
func nestedUnkeyedContainer(forKey key: K) throws -> UnkeyedDecodingContainer {
@ -602,7 +774,7 @@ fileprivate class JavaAnyCodableContainer<K : CodingKey> : KeyedDecodingContaine
case .dictionary:
return try JavaHashMapUnkeyedContainer(decoder: self.decoder, jniStorage: self.jniStorage)
default:
fatalError("Unsupported type here")
throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "Nested unkeyed container not supported")
}
}
@ -611,16 +783,16 @@ fileprivate class JavaAnyCodableContainer<K : CodingKey> : KeyedDecodingContaine
}
func superDecoder(forKey key: K) throws -> Decoder {
throw JavaCodingError.notSupported("JavaAnyCodableContainer.superDecoder(forKey: \(key)")
throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "Super decoder not supported")
}
}
extension JavaDecoder {
fileprivate func unbox<T: Decodable>(type: T.Type, javaObject: jobject) throws -> T {
fileprivate func unbox<T: Decodable>(type: T.Type, javaObject: jobject, codingPath: [CodingKey]) throws -> T {
let typeName = String(describing: type)
if let decodableClosure = JavaCoderConfig.decodableClosures[typeName] {
return try decodableClosure(javaObject) as! T
return try decodableClosure(javaObject, codingPath) as! T
}
else if type == AnyCodable.self {
let cls = JNI.api.GetObjectClass(JNI.env, javaObject)
@ -642,7 +814,9 @@ extension JavaDecoder {
codableType = .object(className: className)
}
let obj = JNI.api.NewLocalRef(JNI.env, javaObject)!
let storageObject = JNIStorageObject(type: .anyCodable(codable: codableType), javaObject: obj)
let storageObject = JNIStorageObject(type: .anyCodable(codable: codableType),
javaObject: obj,
codingPath: codingPath)
self.storage.append(storageObject)
return try T.init(from: self)
}
@ -652,13 +826,19 @@ extension JavaDecoder {
let obj = JNI.api.NewLocalRef(JNI.env, javaObject)!
switch stringType {
case _ where stringType.starts(with: "Array<"):
storageObject = JNIStorageObject(type: .array(className: ArrayListClassname), javaObject: obj)
storageObject = JNIStorageObject(type: .array(className: ArrayListClassname),
javaObject: obj,
codingPath: codingPath)
case _ where stringType.starts(with: "Set<"):
storageObject = JNIStorageObject(type: .array(className: HashSetClassname), javaObject: obj)
storageObject = JNIStorageObject(type: .array(className: HashSetClassname),
javaObject: obj,
codingPath: codingPath)
case _ where stringType.starts(with: "Dictionary<"):
storageObject = JNIStorageObject(type: .dictionary, javaObject: obj)
default:
storageObject = JNIStorageObject(type: .object(className: "\(package)/\(type)"), javaObject: obj)
storageObject = JNIStorageObject(type: .object(className: "\(package)/\(type)"),
javaObject: obj,
codingPath: codingPath)
}
self.storage.append(storageObject)
return try T.init(from: self)

View File

@ -15,12 +15,32 @@ public enum MissingFieldsStrategy: Error {
case ignore
}
public enum JavaCodingError: Error {
case notSupported(String)
case cantCreateObject(String)
case cantFindObject(String)
case nilNotSupported(String)
case wrongArrayLength
internal struct JavaKey : CodingKey {
public var stringValue: String
public var intValue: Int?
public init(stringValue: String) {
self.stringValue = stringValue
self.intValue = nil
}
public init(intValue: Int) {
self.stringValue = "\(intValue)"
self.intValue = intValue
}
public init(stringValue: String, intValue: Int?) {
self.stringValue = stringValue
self.intValue = intValue
}
init(index: Int) {
self.stringValue = "Index \(index)"
self.intValue = index
}
static let `super` = JavaKey(stringValue: "super")
}
indirect enum JNIStorageType {
@ -45,6 +65,7 @@ indirect enum JNIStorageType {
class JNIStorageObject {
let type: JNIStorageType
let codingPath: [CodingKey]
var javaObject: jobject! {
didSet {
if let value = oldValue {
@ -53,13 +74,15 @@ class JNIStorageObject {
}
}
init(type: JNIStorageType, javaObject: jobject) {
init(type: JNIStorageType, javaObject: jobject, codingPath: [CodingKey] = []) {
self.type = type
self.javaObject = javaObject
self.codingPath = codingPath
}
init(type: JNIStorageType) {
init(type: JNIStorageType, codingPath: [CodingKey] = []) {
self.type = type
self.codingPath = codingPath
}
deinit {
@ -88,8 +111,10 @@ open class JavaEncoder: Encoder {
// MARK: - Constructing a JSON Encoder
/// Initializes `self` with default strategies.
public init(forPackage: String, missingFieldsStrategy: MissingFieldsStrategy = .throw) {
self.codingPath = [CodingKey]()
public init(forPackage: String,
missingFieldsStrategy: MissingFieldsStrategy = .throw,
codingPath: [CodingKey] = []) {
self.codingPath = codingPath
self.package = forPackage
self.javaObjects = [JNIStorageObject]()
self.missingFieldsStrategy = missingFieldsStrategy
@ -104,7 +129,7 @@ open class JavaEncoder: Encoder {
/// - throws: An error if any value throws an error during encoding.
open func encode<T : Encodable>(_ value: T) throws -> jobject {
do {
let storage = try self.box(value)
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)!
}
@ -192,14 +217,190 @@ fileprivate class JavaObjectContainer<K : CodingKey> : KeyedEncodingContainerPro
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")
JNI.api.SetBooleanField(JNI.env, javaObject, fieldID, value)
}
func encodeByte(_ value: jbyte, key: String) throws {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: key, sig: "B")
JNI.api.SetByteField(JNI.env, javaObject, fieldID, value)
}
func encodeShort(_ value: jshort, key: String) throws {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: key, sig: "S")
JNI.api.SetShortField(JNI.env, javaObject, fieldID, value)
}
func encodeInteger(_ value: jint, key: String) throws {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: key, sig: "I")
JNI.api.SetIntField(JNI.env, javaObject, fieldID, value)
}
func encodeLong(_ value: jlong, key: String) throws {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: key, sig: "J")
JNI.api.SetLongField(JNI.env, javaObject, fieldID, value)
}
func encodeFloat(_ value: jfloat, key: String) throws {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: key, sig: "F")
JNI.api.SetFloatField(JNI.env, javaObject, fieldID, value)
}
func encodeDouble(_ value: jdouble, key: String) throws {
let fieldID = try JNI.getJavaField(forClass: javaClass, field: key, sig: "D")
JNI.api.SetDoubleField(JNI.env, javaObject, fieldID, value)
}
// MARK: - KeyedEncodingContainerProtocol Methods
public func encodeNil(forKey key: Key) throws {
throw JavaCodingError.notSupported("JavaObjectContainer.encodeNil(forKey: \(key)")
throw EncodingError.invalidValue(NSNotFound, EncodingError.Context(codingPath: codingPath, debugDescription: "Nil not supported"))
}
func encode(_ value: Bool, forKey key: K) throws {
try encodeBoolean(try value.javaPrimitive(), key: key.stringValue)
}
func encode(_ value: Double, forKey key: K) throws {
try encodeDouble(try value.javaPrimitive(), key: key.stringValue)
}
func encode(_ value: Float, forKey key: K) throws {
try encodeFloat(try value.javaPrimitive(), key: key.stringValue)
}
func encode(_ value: Int, forKey key: K) throws {
try encodeInteger(try value.javaPrimitive(codingPath: codingPath + [key]), key: key.stringValue)
}
func encode(_ value: Int8, forKey key: K) throws {
try encodeByte(try value.javaPrimitive(), key: key.stringValue)
}
func encode(_ value: Int16, forKey key: K) throws {
try encodeShort(try value.javaPrimitive(), key: key.stringValue)
}
func encode(_ value: Int32, forKey key: K) throws {
try encodeInteger(try value.javaPrimitive(), key: key.stringValue)
}
func encode(_ value: Int64, forKey key: K) throws {
try encodeLong(try value.javaPrimitive(), key: key.stringValue)
}
func encode(_ value: UInt, forKey key: K) throws {
try encodeInteger(try value.javaPrimitive(codingPath: codingPath + [key]), key: key.stringValue)
}
func encode(_ value: UInt8, forKey key: K) throws {
try encodeByte(try value.javaPrimitive(), key: key.stringValue)
}
func encode(_ value: UInt16, forKey key: K) throws {
try encodeShort(try value.javaPrimitive(), key: key.stringValue)
}
func encode(_ value: UInt32, forKey key: K) throws {
try encodeInteger(try value.javaPrimitive(), key: key.stringValue)
}
func encode(_ value: UInt64, forKey key: K) throws {
try encodeLong(try value.javaPrimitive(), key: key.stringValue)
}
func encodeIfPresent(_ value: Bool?, forKey key: K) throws {
if let value = value {
try encodeObject(value, forKey: key)
}
}
func encodeIfPresent(_ value: String?, forKey key: K) throws {
if let value = value {
try encodeObject(value, forKey: key)
}
}
func encodeIfPresent(_ value: Double?, forKey key: K) throws {
if let value = value {
try encodeObject(value, forKey: key)
}
}
func encodeIfPresent(_ value: Float?, forKey key: K) throws {
if let value = value {
try encodeObject(value, forKey: key)
}
}
func encodeIfPresent(_ value: Int?, forKey key: K) throws {
if let value = value {
try encodeObject(value, forKey: key)
}
}
func encodeIfPresent(_ value: Int8?, forKey key: K) throws {
if let value = value {
try encodeObject(value, forKey: key)
}
}
func encodeIfPresent(_ value: Int16?, forKey key: K) throws {
if let value = value {
try encodeObject(value, forKey: key)
}
}
func encodeIfPresent(_ value: Int32?, forKey key: K) throws {
if let value = value {
try encodeObject(value, forKey: key)
}
}
func encodeIfPresent(_ value: Int64?, forKey key: K) throws {
if let value = value {
try encodeObject(value, forKey: key)
}
}
func encodeIfPresent(_ value: UInt?, forKey key: K) throws {
if let value = value {
try encodeObject(value, forKey: key)
}
}
func encodeIfPresent(_ value: UInt8?, forKey key: K) throws {
if let value = value {
try encodeObject(value, forKey: key)
}
}
func encodeIfPresent(_ value: UInt16?, forKey key: K) throws {
if let value = value {
try encodeObject(value, forKey: key)
}
}
func encodeIfPresent(_ value: UInt32?, forKey key: K) throws {
if let value = value {
try encodeObject(value, forKey: key)
}
}
func encodeIfPresent(_ value: UInt64?, forKey key: K) throws {
if let value = value {
try encodeObject(value, forKey: key)
}
}
public func encode<T : Encodable>(_ value: T, forKey key: Key) throws {
try self.encodeObject(value, forKey: key)
}
private func encodeObject<T : Encodable>(_ value: T, forKey key: Key) throws {
do {
let object = try self.encoder.box(value)
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)
}
@ -260,19 +461,19 @@ fileprivate class JavaHashMapKeyedContainer<K : CodingKey> : KeyedEncodingContai
// MARK: - KeyedEncodingContainerProtocol Methods
public func encodeNil(forKey key: Key) throws {
throw JavaCodingError.notSupported("JavaHashMapContainer.encodeNil(forKey: \(key))")
throw EncodingError.invalidValue(NSNotFound, EncodingError.Context(codingPath: codingPath, debugDescription: "Nil not supported"))
}
public func encode<T : Encodable>(_ value: T, forKey key: Key) throws {
let keyStorage: JNIStorageObject
if let intValue = key.intValue {
keyStorage = try self.encoder.box(intValue)
keyStorage = try self.encoder.box(intValue, codingPath: codingPath + [key])
}
else {
keyStorage = try self.encoder.box(key.stringValue)
keyStorage = try self.encoder.box(key.stringValue, codingPath: codingPath + [key])
}
let valueStorage = try self.encoder.box(value)
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)])
assert(result == nil, "Rewrite for key \(key.stringValue)")
}
@ -323,11 +524,12 @@ fileprivate class JavaHashMapUnkeyedContainer : UnkeyedEncodingContainer {
// MARK: - UnkeyedEncodingContainer Methods
public func encodeNil() throws {
throw JavaCodingError.notSupported("JavaArrayContainer.encodeNil")
throw EncodingError.invalidValue(NSNotFound, EncodingError.Context(codingPath: codingPath, debugDescription: "Nil not supported"))
}
public func encode<T : Encodable>(_ value: T) throws {
let javaValue = try self.encoder.box(value)
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)])
assert(result == nil, "Rewrite for key")
@ -379,11 +581,12 @@ fileprivate class JavaArrayContainer : UnkeyedEncodingContainer {
// MARK: - UnkeyedEncodingContainer Methods
public func encodeNil() throws {
throw JavaCodingError.notSupported("JavaArrayContainer.encodeNil")
throw EncodingError.invalidValue(NSNotFound, EncodingError.Context(codingPath: codingPath, debugDescription: "Nil not supported"))
}
public func encode<T : Encodable>(_ value: T) throws {
let storeObject = try self.encoder.box(value)
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)])
assert(rewrite == JNI.TRUE, "ArrayList should always return true from add()")
count += 1
@ -418,11 +621,76 @@ class JavaEnumValueEncodingContainer: SingleValueEncodingContainer {
}
public func encodeNil() throws {
throw JavaCodingError.notSupported("JavaSingleValueEncodingContainer.encodeNil")
throw EncodingError.invalidValue(NSNotFound, EncodingError.Context(codingPath: codingPath, debugDescription: "Nil not supported"))
}
public func encode<T : Encodable>(_ value: T) throws {
let rawValue = try self.encoder.box(value)
public func encode(_ value: Int8) throws {
try encode(jvalue(b: value.javaPrimitive()), sig: "B")
}
public func encode(_ value: Int16) throws {
try encode(jvalue(s: value.javaPrimitive()), sig: "S")
}
public func encode(_ value: Int32) throws {
try encode(jvalue(i: value.javaPrimitive()), sig: "I")
}
public func encode(_ value: Int64) throws {
try encode(jvalue(j: value.javaPrimitive()), sig: "J")
}
public func encode(_ value: Int) throws {
try encode(jvalue(i: value.javaPrimitive(codingPath: codingPath)), sig: "I")
}
public func encode(_ value: UInt8) throws {
try encode(jvalue(b: value.javaPrimitive()), sig: "B")
}
public func encode(_ value: UInt16) throws {
try encode(jvalue(s: value.javaPrimitive()), sig: "S")
}
public func encode(_ value: UInt32) throws {
try encode(jvalue(i: value.javaPrimitive()), sig: "I")
}
public func encode(_ value: UInt64) throws {
try encode(jvalue(j: value.javaPrimitive()), sig: "J")
}
public func encode(_ value: UInt) throws {
try encode(jvalue(i: value.javaPrimitive(codingPath: codingPath)), sig: "I")
}
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 {
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,
debugDescription: "Nil not supported: \\(javaClass).valueOf()"))
}
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] = [
"B": { _ = JNI.api.SetByteField(JNI.env, $0, $1, $2.b) },
"S": { _ = JNI.api.SetShortField(JNI.env, $0, $1, $2.s) },
"I": { _ = JNI.api.SetIntField(JNI.env, $0, $1, $2.i) },
"J": { _ = JNI.api.SetLongField(JNI.env, $0, $1, $2.j) }
]
public func encode<T : Encodable>(_ valueType: T) throws {
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 {
@ -432,13 +700,13 @@ class JavaEnumValueEncodingContainer: SingleValueEncodingContainer {
JNI.RemoveFatalErrorMessage()
}
guard let javaObject = JNI.CallStaticObjectMethod(clazz, methodID: valueOfMethodID, args: [jvalue(l: rawValue.javaObject)]) else {
throw JavaCodingError.nilNotSupported("\(javaClass).valueOf()")
throw JavaCodingError.cantCreateObject(javaClass)
}
jniStorage.javaObject = javaObject
}
else {
let filed = try JNI.getJavaField(forClass: self.javaClass, field: "rawValue", sig: rawValue.type.sig)
JNI.api.SetObjectField(JNI.env, self.jniStorage.javaObject, filed, rawValue.javaObject)
let context = EncodingError.Context(codingPath: codingPath, debugDescription: "Unsupported: type \(type(of: valueType))")
throw EncodingError.invalidValue(valueType, context)
}
}
}
@ -470,7 +738,7 @@ fileprivate class JavaAnyCodableContainer<K : CodingKey> : KeyedEncodingContaine
// MARK: - KeyedEncodingContainerProtocol Methods
public func encodeNil(forKey key: Key) throws {
throw JavaCodingError.notSupported("JavaObjectContainer.encodeNil(forKey: \(key)")
throw EncodingError.invalidValue(NSNotFound, EncodingError.Context(codingPath: codingPath, debugDescription: "Nil not supported"))
}
public func encode<T : Encodable>(_ value: T, forKey key: Key) throws {
@ -479,7 +747,7 @@ fileprivate class JavaAnyCodableContainer<K : CodingKey> : KeyedEncodingContaine
return
}
do {
let jniObject = try self.encoder.box(value)
let jniObject = try self.encoder.box(value, codingPath: codingPath + [key])
self.jniStorage.javaObject = JNI.api.NewLocalRef(JNI.env, jniObject.javaObject)
}
catch {
@ -523,18 +791,18 @@ fileprivate class JavaAnyCodableContainer<K : CodingKey> : KeyedEncodingContaine
extension JavaEncoder {
fileprivate func box<T: Encodable>(_ value: T) throws -> JNIStorageObject {
fileprivate func box<T: Encodable>(_ value: T, codingPath: [CodingKey]) throws -> JNIStorageObject {
let storage: JNIStorageObject
let typeName = String(describing: type(of: value))
if let encodableClosure = JavaCoderConfig.encodableClosures[typeName] {
let javaObject = try encodableClosure(value)
let javaObject = try encodableClosure(value, codingPath)
storage = JNIStorageObject(type: .object(className: JavaCoderConfig.codableClassNames[typeName]!), javaObject: javaObject)
}
else if T.self == AnyCodable.self {
let anyCodableValue = value as! AnyCodable
if let javaClassname = JavaCoderConfig.codableClassNames[anyCodableValue.typeName] {
let encodableClosure = JavaCoderConfig.encodableClosures[anyCodableValue.typeName]!
let javaObject = try encodableClosure(anyCodableValue.value)
let javaObject = try encodableClosure(anyCodableValue.value, codingPath)
storage = JNIStorageObject(type: .object(className: javaClassname), javaObject: javaObject)
}
else {

176
Sources/JavaPrimitive.swift Normal file
View File

@ -0,0 +1,176 @@
//
// Created by Andriy Druk on 24.01.2020.
//
import Foundation
import java_swift
import CJavaVM
extension Bool {
public init(fromJavaPrimitive javaPrimitive: jboolean) {
self.init(javaPrimitive == JNI_TRUE)
}
public func javaPrimitive() throws -> jboolean {
return jboolean(self ? JNI_TRUE : JNI_FALSE)
}
}
extension Int {
public init(fromJavaPrimitive javaPrimitive: jint) {
self.init(javaPrimitive)
}
public func javaPrimitive(codingPath: [CodingKey] = []) throws -> jint {
if self < Int(Int32.min) || self > Int(Int32.max) {
let errorDescription = "Not enough bits to represent Int"
let context = EncodingError.Context(codingPath: codingPath, debugDescription: errorDescription)
throw EncodingError.invalidValue(self, context)
}
return jint(self)
}
}
extension Int8 {
public init(fromJavaPrimitive javaPrimitive: jbyte) {
self.init(javaPrimitive)
}
public func javaPrimitive() throws -> jbyte {
return jbyte(self)
}
}
extension Int16 {
public init(fromJavaPrimitive javaPrimitive: jshort) {
self.init(javaPrimitive)
}
public func javaPrimitive() throws -> jshort {
return jshort(self)
}
}
extension Int32 {
public init(fromJavaPrimitive javaPrimitive: jint) {
self.init(javaPrimitive)
}
public func javaPrimitive() throws -> jint {
return jint(self)
}
}
extension Int64 {
public init(fromJavaPrimitive javaPrimitive: jlong) {
self.init(javaPrimitive)
}
public func javaPrimitive() throws -> jlong {
return jlong(self)
}
}
extension UInt {
public init(fromJavaPrimitive javaPrimitive: jint) {
#if arch(x86_64) || arch(arm64)
self.init(UInt32(bitPattern: javaPrimitive))
#else
self.init(bitPattern: javaPrimitive)
#endif
}
public func javaPrimitive(codingPath: [CodingKey] = []) throws -> jint {
if self < UInt(UInt32.min) || self > UInt(UInt32.max) {
let errorDescription = "Not enough bits to represent UInt"
let context = EncodingError.Context(codingPath: codingPath, debugDescription: errorDescription)
throw EncodingError.invalidValue(self, context)
}
#if arch(x86_64) || arch(arm64)
return jint(bitPattern: UInt32(self))
#else
return jint(bitPattern: self)
#endif
}
}
extension UInt8 {
public init(fromJavaPrimitive javaPrimitive: jbyte) {
self.init(bitPattern: javaPrimitive)
}
public func javaPrimitive() throws -> jbyte {
return jbyte(bitPattern: self)
}
}
extension UInt16 {
public init(fromJavaPrimitive javaPrimitive: jshort) {
self.init(bitPattern: javaPrimitive)
}
public func javaPrimitive() throws -> jshort {
return jshort(bitPattern: self)
}
}
extension UInt32 {
public init(fromJavaPrimitive javaPrimitive: jint) {
#if arch(x86_64) || arch(arm64)
self.init(bitPattern: javaPrimitive)
#else
self.init(UInt(bitPattern: javaPrimitive))
#endif
}
public func javaPrimitive() throws -> jint {
#if arch(x86_64) || arch(arm64)
return jint(bitPattern: self)
#else
return jint(bitPattern: UInt(self))
#endif
}
}
extension UInt64 {
public init(fromJavaPrimitive javaPrimitive: jlong) {
self.init(bitPattern: javaPrimitive)
}
public func javaPrimitive() throws -> jlong {
return jlong(bitPattern: self)
}
}
extension Float {
public init(fromJavaPrimitive javaPrimitive: jfloat) {
self.init(javaPrimitive)
}
public func javaPrimitive() throws -> jfloat {
return jfloat(self)
}
}
extension Double {
public init(fromJavaPrimitive javaPrimitive: jdouble) {
self.init(javaPrimitive)
}
public func javaPrimitive() throws -> jdouble {
return jdouble(self)
}
}