Skip to content

Commit 988b0c1

Browse files
committed
Create unsafe _jnicall to simplify error checks
1 parent 45c337c commit 988b0c1

File tree

1 file changed

+79
-133
lines changed

1 file changed

+79
-133
lines changed

src/core.jl

Lines changed: 79 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -332,166 +332,128 @@ function jnew(T::Symbol, argtypes::Tuple = () , args...)
332332
if jmethodId == C_NULL
333333
throw(JavaCallError("No constructor for $T with signature $sig"))
334334
end
335-
return _jcall(metaclass(T), jmethodId, JNI.NewObjectA, JavaObject{T}, argtypes, args...)
335+
return _jnicall(metaclass(T), jmethodId, JNI.NewObjectA, JavaObject{T}, argtypes, args...)
336336
end
337337

338+
_jcallable(typ::Type{JavaObject{T}}) where T = metaclass(T)
339+
_jcallable(obj::JavaObject) = obj
340+
338341
# Call static methods
339-
function jcall(typ::Type{JavaObject{T}}, method::AbstractString, rettype::Type, argtypes::Tuple = (),
340-
args... ) where T
342+
function jcall(ref, method::AbstractString, rettype::Type, argtypes::Tuple = (), args...)
341343
assertroottask_or_goodenv() && assertloaded()
342-
sig = method_signature(rettype, argtypes...)
343-
jmethodId = JNI.GetStaticMethodID(Ptr(metaclass(T)), String(method), sig)
344+
jmethodId = get_method_id(ref, method, rettype, argtypes)
344345
jmethodId==C_NULL && geterror(true)
345-
_jcall(metaclass(T), jmethodId, C_NULL, rettype, argtypes, args...)
346+
_jcall(_jcallable(ref), jmethodId, rettype, argtypes, args...)
346347
end
347348

348-
function jcall(typ::Type{JavaObject{T}}, method::JMethod, args...) where T
349-
assertroottask_or_goodenv() && assertloaded()
350-
jmethodId = JNI.FromReflectedMethod(method)
351-
rettype = jimport(getreturntype(method))
352-
argtypes = Tuple(jimport.(getparametertypes(method)))
353-
jmethodId==C_NULL && geterror(true)
354-
_jcall(metaclass(T), jmethodId, C_NULL, rettype, argtypes, args...)
349+
function get_method_id(typ::Type{JavaObject{T}}, method::AbstractString, rettype::Type, argtypes::Tuple) where T
350+
sig = method_signature(rettype, argtypes...)
351+
JNI.GetStaticMethodID(Ptr(metaclass(T)), String(method), sig)
355352
end
356353

357-
# Call instance methods
358-
function jcall(obj::JavaObject, method::AbstractString, rettype::Type, argtypes::Tuple = (), args... )
359-
assertroottask_or_goodenv() && assertloaded()
354+
function get_method_id(obj::JavaObject, method::AbstractString, rettype::Type, argtypes::Tuple)
355+
sig = method_signature(rettype, argtypes...)
356+
JNI.GetMethodID(Ptr(metaclass(obj)), String(method), sig)
357+
end
358+
359+
function get_method_id(obj::JavaObject, method::JMethod)
360360
sig = method_signature(rettype, argtypes...)
361-
jmethodId = JNI.GetMethodID(Ptr(metaclass(obj)), String(method), sig)
361+
JNI.FromReflectedMethod(method)
362+
end
363+
364+
function jcall(ref, method::JMethod, args...) where T
365+
jmethodId = JNI.FromReflectedMethod(method)
366+
rettype = jimport(getreturntype(method))
367+
argtypes = Tuple(jimport.(getparametertypes(method)))
362368
jmethodId==C_NULL && geterror(true)
363-
_jcall(obj, jmethodId, C_NULL, rettype, argtypes, args...)
369+
_jcall(metaclass(T), jmethodId, rettype, argtypes, args...)
364370
end
365371

366372
function jcall(obj::JavaObject, method::JMethod, args... )
367373
assertroottask_or_goodenv() && assertloaded()
374+
isnull(obj) && throw(JavaCallError("Attempt to call method on Java NULL"))
368375
jmethodId = JNI.FromReflectedMethod(method)
369376
rettype = jimport(getreturntype(method))
370377
argtypes = Tuple(jimport.(getparametertypes(method)))
371378
jmethodId==C_NULL && geterror(true)
372-
_jcall(obj, jmethodId, C_NULL, rettype, argtypes, args...)
379+
_jcall(obj, jmethodId, rettype, argtypes, args...)
373380
end
374381

375382
# JMethod invoke
376383
(m::JMethod)(obj, args...) = jcall(obj, m, args...)
377384

378385

379-
function jfield(typ::Type{JavaObject{T}}, field::AbstractString, fieldType::Type) where T
386+
function jfield(ref, field, fieldType)
380387
assertroottask_or_goodenv() && assertloaded()
381-
jfieldID = JNI.GetStaticFieldID(Ptr(metaclass(T)), String(field), signature(fieldType))
388+
jfieldID = get_field_id(ref, field, fieldType)
382389
jfieldID==C_NULL && geterror(true)
383-
_jfield(metaclass(T), jfieldID, fieldType)
390+
_jfield(_jcallable(ref), jfieldID, fieldType)
384391
end
385392

386-
function jfield(obj::Type{JavaObject{T}}, field::JField) where T
387-
assertroottask_or_goodenv() && assertloaded()
393+
function get_field_id(typ::Type{JavaObject{T}}, field::AbstractString, fieldType::Type) where T
394+
JNI.GetStaticFieldID(Ptr(metaclass(T)), String(field), signature(fieldType))
395+
end
396+
397+
function get_field_id(obj::Type{JavaObject{T}}, field::JField) where T
388398
fieldType = jimport(gettype(field))
389-
jfieldID = JNI.FromReflectedField(field)
390-
jfieldID==C_NULL && geterror(true)
391-
_jfield(metaclass(T), jfieldID, fieldType)
399+
JNI.FromReflectedField(field)
392400
end
393401

394-
function jfield(obj::JavaObject, field::AbstractString, fieldType::Type)
395-
assertroottask_or_goodenv() && assertloaded()
396-
jfieldID = JNI.GetFieldID(Ptr(metaclass(obj)), String(field), signature(fieldType))
397-
jfieldID==C_NULL && geterror(true)
398-
_jfield(obj, jfieldID, fieldType)
402+
function get_field_id(obj::JavaObject, field::AbstractString, fieldType::Type)
403+
JNI.GetFieldID(Ptr(metaclass(obj)), String(field), signature(fieldType))
399404
end
400405

401-
function jfield(obj::JavaObject, field::JField)
402-
assertroottask_or_goodenv() && assertloaded()
406+
function get_field_id(obj::JavaObject, field::JField)
403407
fieldType = jimport(gettype(field))
404-
jfieldID = JNI.FromReflectedField(field)
405-
jfieldID==C_NULL && geterror(true)
406-
_jfield(obj, jfieldID, fieldType)
408+
JNI.FromReflectedField(field)
407409
end
408410

409411
# JField invoke
410412
(f::JField)(obj) = jfield(obj, f)
411413

412-
for (x, y, z) in [(:jboolean, :(JNI.GetBooleanField), :(JNI.GetStaticBooleanField)),
413-
(:jchar, :(JNI.GetCharField), :(JNI.GetStaticCharField)) ,
414-
(:jbyte, :(JNI.GetByteField), :(JNI.GetStaticBypeField)) ,
415-
(:jshort, :(JNI.GetShortField), :(JNI.GetStaticShortField)) ,
416-
(:jint, :(JNI.GetIntField), :(JNI.GetStaticIntField)) ,
417-
(:jlong, :(JNI.GetLongField), :(JNI.GetStaticLongField)) ,
418-
(:jfloat, :(JNI.GetFloatField), :(JNI.GetStaticFloatField)) ,
419-
(:jdouble, :(JNI.GetDoubleField), :(JNI.GetStaticDoubleField)) ]
420-
421-
m = quote
422-
function _jfield(obj, jfieldID::Ptr{Nothing}, fieldType::Type{$(x)})
423-
callmethod = ifelse( typeof(obj)<:JavaObject, $y , $z )
424-
result = callmethod(Ptr(obj), jfieldID)
425-
result==C_NULL && geterror()
426-
return convert_result(fieldType, result)
427-
end
428-
end
429-
eval(m)
430-
end
431-
432414
function _jfield(obj, jfieldID::Ptr{Nothing}, fieldType::Type)
433-
callmethod = ifelse( typeof(obj)<:JavaObject, JNI.GetObjectField , JNI.GetStaticObjectField )
434-
result = callmethod(Ptr(obj), jfieldID)
415+
result = _jnifield(obj, jfieldID, fieldType)
435416
result==C_NULL && geterror()
436417
return convert_result(fieldType, result)
437418
end
438419

439-
#Generate these methods to satisfy ccall's compile time constant requirement
440-
#_jcall for primitive and Nothing return types
441-
for (x, y, z) in [(:jboolean, :(JNI.CallBooleanMethodA), :(JNI.CallStaticBooleanMethodA)),
442-
(:jchar, :(JNI.CallCharMethodA), :(JNI.CallStaticCharMethodA)) ,
443-
(:jbyte, :(JNI.CallByteMethodA), :(JNI.CallStaticByteMethodA)) ,
444-
(:jshort, :(JNI.CallShortMethodA), :(JNI.CallStaticShortMethodA)) ,
445-
(:jint, :(JNI.CallIntMethodA), :(JNI.CallStaticIntMethodA)) ,
446-
(:jlong, :(JNI.CallLongMethodA), :(JNI.CallStaticLongMethodA)) ,
447-
(:jfloat, :(JNI.CallFloatMethodA), :(JNI.CallStaticFloatMethodA)) ,
448-
(:jdouble, :(JNI.CallDoubleMethodA), :(JNI.CallStaticDoubleMethodA)) ,
449-
(:jvoid, :(JNI.CallVoidMethodA), :(JNI.CallStaticVoidMethodA)) ]
450-
m = quote
451-
function _jcall(obj, jmethodId::Ptr{Nothing}, callmethod::Ptr{Nothing}, rettype::Type{$(x)},
452-
argtypes::Tuple, args...)
453-
if callmethod == C_NULL #!
454-
callmethod = ifelse( typeof(obj)<:JavaObject, $y , $z )
455-
end
456-
@assert callmethod != C_NULL
457-
@assert jmethodId != C_NULL
458-
isnull(obj) && throw(JavaCallError("Attempt to call method on Java NULL"))
459-
savedArgs, convertedArgs = convert_args(argtypes, args...)
460-
GC.@preserve savedArgs begin
461-
result = callmethod(Ptr(obj), jmethodId, Array{JNI.jvalue}(jvalue.(convertedArgs)))
462-
end
463-
deleteref.(filter(x->isa(x,JavaObject),convertedArgs))
464-
result==C_NULL && geterror()
465-
result == nothing && (return)
466-
return convert_result(rettype, result)
467-
end
468-
end
469-
eval(m)
470-
end
471-
472-
#_jcall for Object return types
473-
#obj -- receiver - Class pointer or object prointer
474-
#jmethodId -- Java method ID
475-
#callmethod -- the C method pointer to call
476-
function _jcall(obj, jmethodId::Ptr{Nothing}, callmethod::Union{Function,Ptr{Nothing}}, rettype::Type, argtypes::Tuple,
477-
args...)
478-
if callmethod == C_NULL
479-
callmethod = ifelse(typeof(obj)<:JavaObject,
480-
JNI.CallObjectMethodA ,
481-
JNI.CallStaticObjectMethodA)
482-
end
483-
@assert callmethod != C_NULL
484-
@assert jmethodId != C_NULL
485-
isnull(obj) && error("Attempt to call method on Java NULL")
420+
function _jcall(obj, jmethodId, callmethod, rettype, argtypes, args...)
486421
savedArgs, convertedArgs = convert_args(argtypes, args...)
487422
GC.@preserve savedArgs begin
488-
result = callmethod(Ptr(obj), jmethodId, Array{JNI.jvalue}(jvalue.(convertedArgs)))
423+
result = _jnicall(obj, jmethodId, rettype, argtypes, jvalue.(convertedArgs))
489424
end
490425
deleteref.(filter(x->isa(x,JavaObject),convertedArgs))
491426
result==C_NULL && geterror()
492427
return convert_result(rettype, result)
493428
end
494429

430+
#Generate these methods to satisfy ccall's compile time constant requirement
431+
for (x, name) in [(:Type, "Object"),
432+
(:(Type{jboolean}), "Boolean"),
433+
(:(Type{jchar}), "Char" ),
434+
(:(Type{jbyte}), "Byte" ),
435+
(:(Type{jshort}), "Short" ),
436+
(:(Type{jint}), "Int" ),
437+
(:(Type{jlong}), "Long" ),
438+
(:(Type{jfloat}), "Float" ),
439+
(:(Type{jdouble}), "Double" ),
440+
(:(Type{jvoid}), "Void" )]
441+
for (t, cstr, fstr) in [(:JavaObject, "Call$(name)MethodA", "Get$(name)Field"),
442+
(:JavaMetaClass, "CallStatic$(name)MethodA", "GetStatic$(name)Field")]
443+
callmethod = :(JNI.$(Symbol(cstr)))
444+
fieldmethod = :(JNI.$(Symbol(fstr)))
445+
m = quote
446+
function _jnicall(obj::T, jmethodId::Ptr{Nothing}, rettype::$x,
447+
argtypes::Tuple, args) where T <: $t
448+
$callmethod(Ptr(obj), jmethodId, Array{JNI.jvalue}(args))
449+
end
450+
function _jnifield(obj::T, jfieldID::Ptr{Nothing}, fieldType::$x) where T <: $t
451+
$fieldmethod(Ptr(obj), jfieldID)
452+
end
453+
end
454+
eval(m)
455+
end
456+
end
495457

496458
global const _jmc_cache = [ Dict{Symbol, JavaMetaClass}() ]
497459

@@ -557,33 +519,17 @@ function method_signature(rettype, argtypes...)
557519
return String(take!(s))
558520
end
559521

560-
561522
#get the JNI signature string for a given type
562-
function signature(arg::Type)
563-
if arg === jboolean
564-
return "Z"
565-
elseif arg === jbyte
566-
return "B"
567-
elseif arg === jchar
568-
return "C"
569-
elseif arg === jshort
570-
return "S"
571-
elseif arg === jint
572-
return "I"
573-
elseif arg === jlong
574-
return "J"
575-
elseif arg === jfloat
576-
return "F"
577-
elseif arg === jdouble
578-
return "D"
579-
elseif arg === jvoid
580-
return "V"
581-
elseif arg <: Array
582-
dims = "[" ^ ndims(arg)
583-
return string(dims, signature(eltype(arg)))
584-
end
585-
end
586-
523+
signature(::Type{jboolean}) = "Z"
524+
signature(::Type{jbyte}) = "B"
525+
signature(::Type{jchar}) = "C"
526+
signature(::Type{jshort}) = "S"
527+
signature(::Type{jint}) = "I"
528+
signature(::Type{jlong}) = "J"
529+
signature(::Type{jfloat}) = "F"
530+
signature(::Type{jdouble}) = "D"
531+
signature(::Type{jvoid}) = "V"
532+
signature(::Type{Array{T,N}}) where {T,N} = string("[" ^ N, signature(T))
587533
signature(arg::Type{JavaObject{T}}) where {T} = string("L", javaclassname(T), ";")
588534
signature(arg::Type{JavaObject{T}}) where {T <: AbstractVector} = JavaCall.javaclassname(T)
589535

0 commit comments

Comments
 (0)