88
99import Foundation
1010import Dispatch
11- import CJavaVM
11+
12+ @_exported import CJavaVM
1213
1314@_silgen_name ( " JNI_OnLoad " )
14- func JNI_OnLoad( jvm: UnsafeMutablePointer < JavaVM ? > , ptr: UnsafeRawPointer ) -> jint {
15+ public func JNI_OnLoad( jvm: UnsafeMutablePointer < JavaVM ? > , ptr: UnsafeRawPointer ) -> jint {
1516 JNI . jvm = jvm
1617 let env = JNI . GetEnv ( )
17- JNI . envCache [ pthread_self ( ) ] = env
1818 JNI . api = env!. pointee!. pointee
19+ JNI . envCache [ JNI . threadKey] = env
1920#if os(Android)
2021 DispatchQueue . setThreadDetachCallback ( JNI_DetachCurrentThread )
2122#endif
@@ -24,21 +25,25 @@ func JNI_OnLoad( jvm: UnsafeMutablePointer<JavaVM?>, ptr: UnsafeRawPointer ) ->
2425
2526public func JNI_DetachCurrentThread( ) {
2627 _ = JNI . jvm? . pointee? . pointee. DetachCurrentThread ( JNI . jvm )
27- JNI . envCache [ pthread_self ( ) ] = nil
28+ JNI . envLock. lock ( )
29+ JNI . envCache [ JNI . threadKey] = nil
30+ JNI . envLock. lock ( )
2831}
2932
30- public let JNI = JavaJNI ( )
33+ public let JNI = JNICore ( )
3134
32- open class JavaJNI {
35+ open class JNICore {
3336
3437 open var jvm : UnsafeMutablePointer < JavaVM ? > ?
3538 open var api : JNINativeInterface_ !
3639
3740 open var envCache = [ pthread_t : UnsafeMutablePointer < JNIEnv ? > ? ] ( )
38- private let envLock = NSLock ( )
41+ fileprivate let envLock = NSLock ( )
42+
43+ open var threadKey : pthread_t { return pthread_self ( ) }
3944
4045 open var env : UnsafeMutablePointer < JNIEnv ? > ? {
41- let currentThread = pthread_self ( )
46+ let currentThread = threadKey
4247 if let env = envCache [ currentThread] {
4348 return env
4449 }
@@ -49,9 +54,19 @@ open class JavaJNI {
4954 return env
5055 }
5156
57+ open func AttachCurrentThread( ) -> UnsafeMutablePointer < JNIEnv ? > ? {
58+ var tenv : UnsafeMutablePointer < JNIEnv ? > ?
59+ if withPointerToRawPointer ( to: & tenv, {
60+ self . jvm? . pointee? . pointee. AttachCurrentThread ( self . jvm, $0, nil )
61+ } ) != jint ( JNI_OK) {
62+ report ( " Could not attach to background jvm " )
63+ }
64+ return tenv
65+ }
66+
5267 open func report( _ msg: String , _ file: StaticString = #file, _ line: Int = #line ) {
5368 NSLog ( " \( msg) - at \( file) : \( line) " )
54- if api. ExceptionCheck ( env ) != 0 {
69+ if api? . ExceptionCheck ( env ) != 0 {
5570 api. ExceptionDescribe ( env )
5671 }
5772 }
@@ -67,8 +82,8 @@ open class JavaJNI {
6782
6883 var options = options
6984 if options == nil {
70- var classpath = String ( cString: getenv ( " HOME " ) ) + " /.genie .jar "
71- if let CLASSPATH = getenv ( " CLASSPATH " ) {
85+ var classpath = String ( cString: getenv ( " HOME " ) ) + " /.swiftjava .jar "
86+ if let CLASSPATH = getenv ( " CLASSPATH " ) {
7287 classpath += " : " + String( cString: CLASSPATH )
7388 }
7489 options = [ " -Djava.class.path= " + classpath,
@@ -99,43 +114,35 @@ open class JavaJNI {
99114 if withPointerToRawPointer ( to: & tenv, {
100115 JNI_CreateJavaVM ( & self . jvm, $0, & vmArgs )
101116 } ) != jint ( JNI_OK) {
102- self . report ( " JNI_CreateJavaVM failed " , file, line )
117+ report ( " JNI_CreateJavaVM failed " , file, line )
103118 return false
104119 }
105120
106- self . envCache [ pthread_self ( ) ] = tenv
121+ self . envCache [ threadKey ] = tenv
107122 self . api = self . env!. pointee!. pointee
108123 return true
109124 }
110125#endif
111126 }
112127
113128 private func withPointerToRawPointer< T, Result> ( to arg: inout T , _ body: @escaping ( UnsafeMutablePointer < UnsafeMutableRawPointer ? > ) throws -> Result ) rethrows -> Result {
114- return try withUnsafePointer ( to: & arg) {
115- try body ( unsafeBitCast ( $0, to: UnsafeMutablePointer< UnsafeMutableRawPointer?> . self ) )
129+ return try withUnsafeMutablePointer ( to: & arg) {
130+ try $0. withMemoryRebound ( to: UnsafeMutableRawPointer ? . self, capacity: 1 ) {
131+ try body ( $0 )
132+ }
116133 }
117134 }
118135
119136 open func GetEnv( ) -> UnsafeMutablePointer < JNIEnv ? > ? {
120137 var tenv : UnsafeMutablePointer < JNIEnv ? > ?
121138 if withPointerToRawPointer ( to: & tenv, {
122- JNI . jvm? . pointee? . pointee. GetEnv ( JNI . jvm, $0, jint ( JNI_VERSION_1_6) ) != jint ( JNI_OK )
123- } ) {
139+ JNI . jvm? . pointee? . pointee. GetEnv ( JNI . jvm, $0, jint ( JNI_VERSION_1_6) )
140+ } ) != jint ( JNI_OK ) {
124141 report ( " Unable to get initial JNIEnv " )
125142 }
126143 return tenv
127144 }
128145
129- open func AttachCurrentThread( ) -> UnsafeMutablePointer < JNIEnv ? > ? {
130- var tenv : UnsafeMutablePointer < JNIEnv ? > ?
131- if withPointerToRawPointer ( to: & tenv, {
132- self . jvm? . pointee? . pointee. AttachCurrentThread ( self . jvm, $0, nil ) != jint ( JNI_OK)
133- } ) {
134- report ( " Could not attach to background jvm " )
135- }
136- return tenv
137- }
138-
139146 private func autoInit( ) {
140147 envLock. lock ( )
141148 if envCache. isEmpty && !initJVM( ) {
@@ -161,9 +168,9 @@ open class JavaJNI {
161168 let clazz = api. FindClass ( env, name )
162169 if clazz == nil {
163170 report ( " Could not find class \( String ( cString: name ) ) " , file, line )
164- if strncmp ( name, " org/genie / " , 10 ) == 0 {
165- report ( " \n \n Looking for a genie proxy class required for event listeners and Runnable's to work. \n " +
166- " Have you copied https://github.com/SwiftJava/SwiftJava/blob/master/genie .jar to ~/.genie .jar and/or set the CLASSPATH environment variable? \n " )
171+ if strncmp ( name, " org/swiftjava / " , 10 ) == 0 {
172+ report ( " \n \n Looking for a swiftjava proxy class required for event listeners and Runnable's to work. \n " +
173+ " Have you copied https://github.com/SwiftJava/SwiftJava/blob/master/swiftjava .jar to ~/.swiftjava .jar and/or set the CLASSPATH environment variable? \n " )
167174 }
168175 }
169176 return clazz
@@ -172,11 +179,12 @@ open class JavaJNI {
172179 open func CachedFindClass( _ name: UnsafePointer < Int8 > , _ classCache: UnsafeMutablePointer < jclass ? > ,
173180 _ file: StaticString = #file, _ line: Int = #line ) {
174181 if classCache. pointee == nil , let clazz = FindClass ( name, file, line ) {
175- classCache. pointee = api. NewGlobalRef ( JNI . env, clazz )
182+ classCache. pointee = api. NewGlobalRef ( env, clazz )
183+ api. DeleteLocalRef ( env, clazz )
176184 }
177185 }
178186
179- open func GetObjectClass( _ object: jobject ? , _ locals: UnsafeMutablePointer < [ jobject ] > ? ,
187+ open func GetObjectClass( _ object: jobject ? , _ locals: UnsafeMutablePointer < [ jobject ] > ,
180188 _ file: StaticString = #file, _ line: Int = #line ) -> jclass ? {
181189 ExceptionReset ( )
182190 if object == nil {
@@ -187,49 +195,63 @@ open class JavaJNI {
187195 report ( " GetObjectClass returns nil class " , file, line )
188196 }
189197 else {
190- locals? . pointee. append ( clazz! )
198+ locals. pointee. append ( clazz! )
191199 }
192200 return clazz
193201 }
194202
195203 private static var java_lang_ObjectClass : jclass ?
196204
197- open func NewObjectArray( _ count: Int , _ file: StaticString = #file, _ line: Int = #line ) -> jobject ? {
198- CachedFindClass ( " java/lang/Object " , & JavaJNI. java_lang_ObjectClass, file, line )
199- let array = api. NewObjectArray ( env, jsize ( count) , JavaJNI . java_lang_ObjectClass, nil )
205+ open func NewObjectArray( _ count: Int , _ array: [ jobject ? ] ? , _ locals: UnsafeMutablePointer < [ jobject ] > , _ file: StaticString = #file, _ line: Int = #line ) -> jobject ? {
206+ CachedFindClass ( " java/lang/Object " , & JNICore. java_lang_ObjectClass, file, line )
207+ var arrayClass = JNICore . java_lang_ObjectClass
208+ if array? . count != 0 {
209+ arrayClass = JNI . GetObjectClass ( array![ 0 ] , locals)
210+ }
211+ else {
212+ #if os(Android)
213+ return nil
214+ #endif
215+ }
216+ let array = api. NewObjectArray ( env, jsize ( count) , arrayClass, nil )
200217 if array == nil {
201218 report ( " Could not create array " , file, line )
202219 }
203220 return array
204221 }
205222
223+ public var inNative = false ;
224+
206225 open func DeleteLocalRef( _ local: jobject ? ) {
207- if local != nil {
226+ if local != nil { //&& !inNative {
208227 api. DeleteLocalRef ( env, local )
209228 }
210229 }
211230
212231 private var thrownCache = [ pthread_t: jthrowable] ( )
213232 private let thrownLock = NSLock ( )
214233
215- open func check< T> ( _ result: T , _ locals: UnsafePointer < [ jobject ] > ? , _ file: StaticString = #file, _ line: Int = #line ) -> T {
216- if let locals = locals {
217- for local in locals. pointee {
234+ open func check< T> ( _ result: T , _ locals: UnsafeMutablePointer < [ jobject ] > ? , removeLast: Bool = false , _ file: StaticString = #file, _ line: Int = #line ) -> T {
235+ if var locals = locals? . pointee {
236+ if removeLast && locals. count != 0 {
237+ locals. removeLast ( )
238+ }
239+ for local in locals {
218240 DeleteLocalRef ( local )
219241 }
220242 }
221243 if api. ExceptionCheck ( env ) != 0 , let throwable = api. ExceptionOccurred ( env ) {
222244 report ( " Exception occured " , file, line )
223245 thrownLock. lock ( )
224- thrownCache [ pthread_self ( ) ] = throwable
246+ thrownCache [ threadKey ] = throwable
225247 thrownLock. unlock ( )
226248 api. ExceptionClear ( env )
227249 }
228250 return result
229251 }
230252
231253 open func ExceptionCheck( ) -> jthrowable ? {
232- let currentThread = pthread_self ( )
254+ let currentThread = threadKey
233255 if let throwable = thrownCache [ currentThread] {
234256 thrownLock. lock ( )
235257 thrownCache. removeValue ( forKey: currentThread)
@@ -240,8 +262,9 @@ open class JavaJNI {
240262 }
241263
242264 open func ExceptionReset( ) {
243- if let _ = ExceptionCheck ( ) {
265+ if let throwable = ExceptionCheck ( ) {
244266 report ( " Left over exception " )
267+ Throwable ( javaObject: throwable ) . printStackTrace ( )
245268 }
246269 }
247270
0 commit comments