Compare commits
5 Commits
Author | SHA1 | Date |
---|---|---|
![]() |
065a7d03a5 | |
![]() |
048b9dd595 | |
![]() |
3bd5f9bdab | |
![]() |
20e5079690 | |
![]() |
13de2eeec7 |
|
@ -17,5 +17,5 @@ let package = Package(
|
||||||
targets: [
|
targets: [
|
||||||
.target(name: "JavaCoder", dependencies: ["java_swift", "AnyCodable"], path: "Sources"),
|
.target(name: "JavaCoder", dependencies: ["java_swift", "AnyCodable"], path: "Sources"),
|
||||||
],
|
],
|
||||||
swiftLanguageVersions: [4]
|
swiftLanguageVersions: [5, 4]
|
||||||
)
|
)
|
||||||
|
|
|
@ -107,15 +107,15 @@ fileprivate let javaFieldLock = NSLock()
|
||||||
|
|
||||||
public extension JNICore {
|
public extension JNICore {
|
||||||
|
|
||||||
public var TRUE: jboolean {
|
var TRUE: jboolean {
|
||||||
return jboolean(JNI_TRUE)
|
return jboolean(JNI_TRUE)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var FALSE: jboolean {
|
var FALSE: jboolean {
|
||||||
return jboolean(JNI_FALSE)
|
return jboolean(JNI_FALSE)
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum JNIError: Error {
|
enum JNIError: Error {
|
||||||
|
|
||||||
case classNotFoundException(String)
|
case classNotFoundException(String)
|
||||||
case methodNotFoundException(String)
|
case methodNotFoundException(String)
|
||||||
|
@ -135,10 +135,7 @@ public extension JNICore {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Global cache functions
|
// MARK: Global cache functions
|
||||||
public func getJavaClass(_ className: String) throws -> jclass {
|
func getJavaClass(_ className: String) throws -> jclass {
|
||||||
if let javaClass = javaClasses[className] {
|
|
||||||
return javaClass
|
|
||||||
}
|
|
||||||
return try javaClassesLock.sync {
|
return try javaClassesLock.sync {
|
||||||
if let javaClass = javaClasses[className] {
|
if let javaClass = javaClasses[className] {
|
||||||
return javaClass
|
return javaClass
|
||||||
|
@ -153,16 +150,13 @@ public extension JNICore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getJavaEmptyConstructor(forClass className: String) throws -> jmethodID {
|
func getJavaEmptyConstructor(forClass className: String) throws -> jmethodID {
|
||||||
return try getJavaMethod(forClass: className, method: "<init>", sig: "()V")
|
return try getJavaMethod(forClass: className, method: "<init>", sig: "()V")
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getJavaMethod(forClass className: String, method: String, sig: String) throws -> jmethodID {
|
func getJavaMethod(forClass className: String, method: String, sig: String) throws -> jmethodID {
|
||||||
let key = "\(className).\(method)\(sig)"
|
let key = "\(className).\(method)\(sig)"
|
||||||
let javaClass = try getJavaClass(className)
|
let javaClass = try getJavaClass(className)
|
||||||
if let methodID = javaMethods[key] {
|
|
||||||
return methodID
|
|
||||||
}
|
|
||||||
return try javaMethodLock.sync {
|
return try javaMethodLock.sync {
|
||||||
if let methodID = javaMethods[key] {
|
if let methodID = javaMethods[key] {
|
||||||
return methodID
|
return methodID
|
||||||
|
@ -177,12 +171,9 @@ public extension JNICore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getStaticJavaMethod(forClass className: String, method: String, sig: String) throws -> jmethodID {
|
func getStaticJavaMethod(forClass className: String, method: String, sig: String) throws -> jmethodID {
|
||||||
let key = "\(className).\(method)\(sig)"
|
let key = "\(className).\(method)\(sig)"
|
||||||
let javaClass = try getJavaClass(className)
|
let javaClass = try getJavaClass(className)
|
||||||
if let methodID = javaStaticMethods[key] {
|
|
||||||
return methodID
|
|
||||||
}
|
|
||||||
return try javaStaticMethodLock.sync {
|
return try javaStaticMethodLock.sync {
|
||||||
if let methodID = javaStaticMethods[key] {
|
if let methodID = javaStaticMethods[key] {
|
||||||
return methodID
|
return methodID
|
||||||
|
@ -197,12 +188,9 @@ public extension JNICore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getJavaField(forClass className: String, field: String, sig: String) throws -> jfieldID {
|
func getJavaField(forClass className: String, field: String, sig: String) throws -> jfieldID {
|
||||||
let key = "\(className).\(field)\(sig)"
|
let key = "\(className).\(field)\(sig)"
|
||||||
let javaClass = try getJavaClass(className)
|
let javaClass = try getJavaClass(className)
|
||||||
if let fieldID = javaFields[key] {
|
|
||||||
return fieldID
|
|
||||||
}
|
|
||||||
return try javaFieldLock.sync({
|
return try javaFieldLock.sync({
|
||||||
if let fieldID = javaFields[key] {
|
if let fieldID = javaFields[key] {
|
||||||
return fieldID
|
return fieldID
|
||||||
|
@ -218,7 +206,7 @@ public extension JNICore {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public func GlobalFindClass( _ name: UnsafePointer<Int8>,
|
func GlobalFindClass( _ name: UnsafePointer<Int8>,
|
||||||
_ file: StaticString = #file, _ line: Int = #line ) -> jclass? {
|
_ file: StaticString = #file, _ line: Int = #line ) -> jclass? {
|
||||||
guard let clazz: jclass = FindClass(name, file, line ) else {
|
guard let clazz: jclass = FindClass(name, file, line ) else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -229,87 +217,87 @@ public extension JNICore {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Constructors
|
// MARK: Constructors
|
||||||
public func NewObject(_ clazz: jclass, methodID: jmethodID, args: [jvalue] = []) -> jobject? {
|
func NewObject(_ clazz: jclass, methodID: jmethodID, args: [jvalue] = []) -> jobject? {
|
||||||
return checkArgument(args: args, { argsPtr in
|
return checkArgument(args: args, { argsPtr in
|
||||||
api.NewObjectA(env, clazz, methodID, argsPtr)
|
api.NewObjectA(env, clazz, methodID, argsPtr)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Object methods
|
// MARK: Object methods
|
||||||
public func CallBooleanMethod(_ object: jobject, methodID: jmethodID, args: [jvalue] = []) -> jboolean {
|
func CallBooleanMethod(_ object: jobject, methodID: jmethodID, args: [jvalue] = []) -> jboolean {
|
||||||
return checkArgument(args: args, { argsPtr in
|
return checkArgument(args: args, { argsPtr in
|
||||||
api.CallBooleanMethodA(env, object, methodID, argsPtr)
|
api.CallBooleanMethodA(env, object, methodID, argsPtr)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public func CallByteMethod(_ object: jobject, methodID: jmethodID, args: [jvalue] = []) -> jbyte {
|
func CallByteMethod(_ object: jobject, methodID: jmethodID, args: [jvalue] = []) -> jbyte {
|
||||||
return checkArgument(args: args, { argsPtr in
|
return checkArgument(args: args, { argsPtr in
|
||||||
api.CallByteMethodA(env, object, methodID, argsPtr)
|
api.CallByteMethodA(env, object, methodID, argsPtr)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public func CallShortMethod(_ object: jobject, methodID: jmethodID, args: [jvalue] = []) -> jshort {
|
func CallShortMethod(_ object: jobject, methodID: jmethodID, args: [jvalue] = []) -> jshort {
|
||||||
return checkArgument(args: args, { argsPtr in
|
return checkArgument(args: args, { argsPtr in
|
||||||
api.CallShortMethodA(env, object, methodID, argsPtr)
|
api.CallShortMethodA(env, object, methodID, argsPtr)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public func CallIntMethod(_ object: jobject, methodID: jmethodID, args: [jvalue] = []) -> jint {
|
func CallIntMethod(_ object: jobject, methodID: jmethodID, args: [jvalue] = []) -> jint {
|
||||||
return checkArgument(args: args, { argsPtr in
|
return checkArgument(args: args, { argsPtr in
|
||||||
api.CallIntMethodA(env, object, methodID, argsPtr)
|
api.CallIntMethodA(env, object, methodID, argsPtr)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public func CallLongMethod(_ object: jobject, methodID: jmethodID, args: [jvalue] = []) -> jlong {
|
func CallLongMethod(_ object: jobject, methodID: jmethodID, args: [jvalue] = []) -> jlong {
|
||||||
return checkArgument(args: args, { argsPtr in
|
return checkArgument(args: args, { argsPtr in
|
||||||
api.CallLongMethodA(env, object, methodID, argsPtr)
|
api.CallLongMethodA(env, object, methodID, argsPtr)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public func CallObjectMethod(_ object: jobject, methodID: jmethodID, args: [jvalue] = []) -> jobject? {
|
func CallObjectMethod(_ object: jobject, methodID: jmethodID, args: [jvalue] = []) -> jobject? {
|
||||||
return checkArgument(args: args, { argsPtr in
|
return checkArgument(args: args, { argsPtr in
|
||||||
api.CallObjectMethodA(env, object, methodID, argsPtr)
|
api.CallObjectMethodA(env, object, methodID, argsPtr)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Static methods
|
// MARK: Static methods
|
||||||
public func CallStaticBooleanMethod(_ clazz: jclass, methodID: jmethodID, args: [jvalue] = []) -> jboolean {
|
func CallStaticBooleanMethod(_ clazz: jclass, methodID: jmethodID, args: [jvalue] = []) -> jboolean {
|
||||||
return checkArgument(args: args, { argsPtr in
|
return checkArgument(args: args, { argsPtr in
|
||||||
api.CallStaticBooleanMethodA(env, clazz, methodID, argsPtr)
|
api.CallStaticBooleanMethodA(env, clazz, methodID, argsPtr)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public func CallStaticByteMethod(_ clazz: jclass, methodID: jmethodID, args: [jvalue] = []) -> jbyte {
|
func CallStaticByteMethod(_ clazz: jclass, methodID: jmethodID, args: [jvalue] = []) -> jbyte {
|
||||||
return checkArgument(args: args, { argsPtr in
|
return checkArgument(args: args, { argsPtr in
|
||||||
api.CallStaticByteMethodA(env, clazz, methodID, argsPtr)
|
api.CallStaticByteMethodA(env, clazz, methodID, argsPtr)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public func CallStaticShortMethod(_ clazz: jclass, methodID: jmethodID, args: [jvalue] = []) -> jshort {
|
func CallStaticShortMethod(_ clazz: jclass, methodID: jmethodID, args: [jvalue] = []) -> jshort {
|
||||||
return checkArgument(args: args, { argsPtr in
|
return checkArgument(args: args, { argsPtr in
|
||||||
api.CallStaticShortMethodA(env, clazz, methodID, argsPtr)
|
api.CallStaticShortMethodA(env, clazz, methodID, argsPtr)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public func CallStaticIntMethod(_ clazz: jclass, methodID: jmethodID, args: [jvalue] = []) -> jint {
|
func CallStaticIntMethod(_ clazz: jclass, methodID: jmethodID, args: [jvalue] = []) -> jint {
|
||||||
return checkArgument(args: args, { argsPtr in
|
return checkArgument(args: args, { argsPtr in
|
||||||
api.CallStaticIntMethodA(env, clazz, methodID, argsPtr)
|
api.CallStaticIntMethodA(env, clazz, methodID, argsPtr)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public func CallStaticLongMethod(_ clazz: jclass, methodID: jmethodID, args: [jvalue] = []) -> jlong {
|
func CallStaticLongMethod(_ clazz: jclass, methodID: jmethodID, args: [jvalue] = []) -> jlong {
|
||||||
return checkArgument(args: args, { argsPtr in
|
return checkArgument(args: args, { argsPtr in
|
||||||
api.CallStaticLongMethodA(env, clazz, methodID, argsPtr)
|
api.CallStaticLongMethodA(env, clazz, methodID, argsPtr)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public func CallStaticObjectMethod(_ clazz: jclass, methodID: jmethodID, args: [jvalue] = []) -> jobject? {
|
func CallStaticObjectMethod(_ clazz: jclass, methodID: jmethodID, args: [jvalue] = []) -> jobject? {
|
||||||
return checkArgument(args: args, { argsPtr in
|
return checkArgument(args: args, { argsPtr in
|
||||||
api.CallStaticObjectMethodA(env, clazz, methodID, argsPtr)
|
api.CallStaticObjectMethodA(env, clazz, methodID, argsPtr)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public func dumpReferenceTables() {
|
func dumpReferenceTables() {
|
||||||
JNI.api.CallStaticVoidMethodA(JNI.env, VMDebugClass, VMDebugDumpReferenceTablesMethod, nil)
|
JNI.api.CallStaticVoidMethodA(JNI.env, VMDebugClass, VMDebugDumpReferenceTablesMethod, nil)
|
||||||
JNI.api.ExceptionClear(JNI.env)
|
JNI.api.ExceptionClear(JNI.env)
|
||||||
JNI.ExceptionReset()
|
JNI.ExceptionReset()
|
||||||
|
@ -335,25 +323,25 @@ public extension JNICore {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: New API
|
// MARK: New API
|
||||||
public func CallObjectMethod(_ object: jobject, _ methodID: jmethodID, _ args: JNIArgumentProtocol...) -> jobject? {
|
func CallObjectMethod(_ object: jobject, _ methodID: jmethodID, _ args: JNIArgumentProtocol...) -> jobject? {
|
||||||
return checkArgumentAndWrap(args: args, { argsPtr in
|
return checkArgumentAndWrap(args: args, { argsPtr in
|
||||||
api.CallObjectMethodA(env, object, methodID, argsPtr)
|
api.CallObjectMethodA(env, object, methodID, argsPtr)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public func CallStaticObjectMethod(_ clazz: jclass, _ methodID: jmethodID, _ args: JNIArgumentProtocol...) -> jobject? {
|
func CallStaticObjectMethod(_ clazz: jclass, _ methodID: jmethodID, _ args: JNIArgumentProtocol...) -> jobject? {
|
||||||
return checkArgumentAndWrap(args: args, { argsPtr in
|
return checkArgumentAndWrap(args: args, { argsPtr in
|
||||||
api.CallStaticObjectMethodA(env, clazz, methodID, argsPtr)
|
api.CallStaticObjectMethodA(env, clazz, methodID, argsPtr)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public func CallVoidMethod(_ object: jobject, _ methodID: jmethodID, _ args: JNIArgumentProtocol...) {
|
func CallVoidMethod(_ object: jobject, _ methodID: jmethodID, _ args: JNIArgumentProtocol...) {
|
||||||
checkArgumentAndWrap(args: args, { argsPtr in
|
checkArgumentAndWrap(args: args, { argsPtr in
|
||||||
api.CallVoidMethodA(env, object, methodID, argsPtr)
|
api.CallVoidMethodA(env, object, methodID, argsPtr)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public func CallStaticVoidMethod(_ clazz: jclass, _ methodID: jmethodID, _ args: JNIArgumentProtocol...) {
|
func CallStaticVoidMethod(_ clazz: jclass, _ methodID: jmethodID, _ args: JNIArgumentProtocol...) {
|
||||||
checkArgumentAndWrap(args: args, { argsPtr in
|
checkArgumentAndWrap(args: args, { argsPtr in
|
||||||
api.CallStaticVoidMethodA(env, clazz, methodID, argsPtr)
|
api.CallStaticVoidMethodA(env, clazz, methodID, argsPtr)
|
||||||
})
|
})
|
||||||
|
|
|
@ -26,31 +26,31 @@ public class JNIObjectWithClass: JNIObject {
|
||||||
|
|
||||||
public extension JNIObject {
|
public extension JNIObject {
|
||||||
|
|
||||||
public static func getJavaClassname(javaObject: jobject?) -> String {
|
static func getJavaClassname(javaObject: jobject?) -> String {
|
||||||
let cls = JNI.api.GetObjectClass(JNI.env, javaObject)
|
let cls = JNI.api.GetObjectClass(JNI.env, javaObject)
|
||||||
let javaClassName = JNI.api.CallObjectMethodA(JNI.env, cls, ClassGetNameMethod, nil)
|
let javaClassName = JNI.api.CallObjectMethodA(JNI.env, cls, ClassGetNameMethod, nil)
|
||||||
return String(javaObject: javaClassName).replacingOccurrences(of: ".", with: "/")
|
return String(javaObject: javaClassName).replacingOccurrences(of: ".", with: "/")
|
||||||
}
|
}
|
||||||
|
|
||||||
public var className: String {
|
var className: String {
|
||||||
if let jniObject = self as? JNIObjectWithClass {
|
if let jniObject = self as? JNIObjectWithClass {
|
||||||
return jniObject.privateClassName
|
return jniObject.privateClassName
|
||||||
}
|
}
|
||||||
return JNIObject.getJavaClassname(javaObject: self.javaObject)
|
return JNIObject.getJavaClassname(javaObject: self.javaObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func callVoidMethod(_ methodID: jmethodID, _ args: JNIArgumentProtocol...) {
|
func callVoidMethod(_ methodID: jmethodID, _ args: JNIArgumentProtocol...) {
|
||||||
checkArgumentAndWrap(args: args, { argsPtr in
|
checkArgumentAndWrap(args: args, { argsPtr in
|
||||||
JNI.api.CallVoidMethodA(JNI.env, javaObject, methodID, argsPtr)
|
JNI.api.CallVoidMethodA(JNI.env, javaObject, methodID, argsPtr)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public func callStringMethod(method: String? = nil, functionName: String = #function, _ args: JNIArgumentProtocol...) -> String {
|
func callStringMethod(method: String? = nil, functionName: String = #function, _ args: JNIArgumentProtocol...) -> String {
|
||||||
let methodName = method ?? String(functionName.split(separator: "(")[0])
|
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))
|
||||||
}
|
}
|
||||||
|
|
||||||
public func callObjectMethod(method: String? = nil, functionName: String = #function, returnType: String, _ args: JNIArgumentProtocol...) -> jobject? {
|
func callObjectMethod(method: String? = nil, functionName: String = #function, returnType: String, _ args: JNIArgumentProtocol...) -> jobject? {
|
||||||
let methodName = method ?? String(functionName.split(separator: "(")[0])
|
let methodName = method ?? String(functionName.split(separator: "(")[0])
|
||||||
return self.internalcallObjectMethod(method: methodName, returnType: returnType, args)
|
return self.internalcallObjectMethod(method: methodName, returnType: returnType, args)
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,13 +176,17 @@ public struct JavaCoderConfig {
|
||||||
|
|
||||||
RegisterType(type: Data.self, javaClassname: ByteBufferClassname, encodableClosure: {
|
RegisterType(type: Data.self, javaClassname: ByteBufferClassname, encodableClosure: {
|
||||||
let valueData = $0 as! Data
|
let valueData = $0 as! Data
|
||||||
let byteArray = JNI.api.NewByteArray(JNI.env, Int32(valueData.count))
|
let byteArray = JNI.api.NewByteArray(JNI.env, jint(valueData.count))
|
||||||
if let throwable = JNI.ExceptionCheck() {
|
if let throwable = JNI.ExceptionCheck() {
|
||||||
throw EncodingError.invalidValue($0, EncodingError.Context(codingPath: [],
|
throw EncodingError.invalidValue($0, EncodingError.Context(codingPath: [],
|
||||||
debugDescription: "Can't create NewByteArray \(valueData.count)"))
|
debugDescription: "Can't create NewByteArray \(valueData.count)"))
|
||||||
}
|
}
|
||||||
valueData.withUnsafeBytes({ (pointer: UnsafePointer<Int8>) -> Void in
|
try valueData.withUnsafeBytes({ pointer in
|
||||||
JNI.api.SetByteArrayRegion(JNI.env, byteArray, 0, Int32(valueData.count), pointer)
|
guard let bytes = pointer.baseAddress?.assumingMemoryBound(to: Int8.self) else {
|
||||||
|
throw EncodingError.invalidValue(valueData, EncodingError.Context(codingPath: [],
|
||||||
|
debugDescription: "Can't get unsafeBytes \(valueData.count)"))
|
||||||
|
}
|
||||||
|
JNI.api.SetByteArrayRegion(JNI.env, byteArray, 0, jint(valueData.count), bytes)
|
||||||
})
|
})
|
||||||
if let throwable = JNI.ExceptionCheck() {
|
if let throwable = JNI.ExceptionCheck() {
|
||||||
throw EncodingError.invalidValue($0, EncodingError.Context(codingPath: [],
|
throw EncodingError.invalidValue($0, EncodingError.Context(codingPath: [],
|
||||||
|
@ -195,6 +199,9 @@ public struct JavaCoderConfig {
|
||||||
return JNI.CallStaticObjectMethod(ByteBufferClass, methodID: ByteBufferWrap, args: [jvalue(l: byteArray)])!
|
return JNI.CallStaticObjectMethod(ByteBufferClass, methodID: ByteBufferWrap, args: [jvalue(l: byteArray)])!
|
||||||
}, decodableClosure: {
|
}, decodableClosure: {
|
||||||
let byteArray = JNI.CallObjectMethod($0, methodID: ByteBufferArray)
|
let byteArray = JNI.CallObjectMethod($0, methodID: ByteBufferArray)
|
||||||
|
defer {
|
||||||
|
JNI.api.DeleteLocalRef(JNI.env, byteArray)
|
||||||
|
}
|
||||||
guard let pointer = JNI.api.GetByteArrayElements(JNI.env, byteArray, nil) else {
|
guard let pointer = JNI.api.GetByteArrayElements(JNI.env, byteArray, nil) else {
|
||||||
throw JavaCodingError.cantFindObject("ByteBuffer")
|
throw JavaCodingError.cantFindObject("ByteBuffer")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue