From ba404a7f2554966215743bf862f1438d08d2a205 Mon Sep 17 00:00:00 2001 From: Avik Sengupta Date: Wed, 21 Oct 2015 18:29:56 +0100 Subject: [PATCH 01/21] Remove 0.4 deprecations --- src/convert.jl | 8 ++++---- src/core.jl | 24 ++++++++++++------------ src/jvm.jl | 12 ++++++------ src/reflect.jl | 4 ++-- test/runtests.jl | 7 +++---- 5 files changed, 27 insertions(+), 28 deletions(-) diff --git a/src/convert.jl b/src/convert.jl index 1a0daa0..10a7887 100644 --- a/src/convert.jl +++ b/src/convert.jl @@ -1,5 +1,5 @@ -convert{T<:String}(::Type{JString}, str::T) = JString(str) -convert{T<:String}(::Type{JObject}, str::T) = convert(JObject, JString(str)) +convert{T<:AbstractString}(::Type{JString}, str::T) = JString(str) +convert{T<:AbstractString}(::Type{JObject}, str::T) = convert(JObject, JString(str)) #Cast java object from S to T . Needed for polymorphic calls function convert{T,S}(::Type{JavaObject{T}}, obj::JavaObject{S}) @@ -164,8 +164,8 @@ convert{X,Y}(::Type{@jimport(java.util.Map)}, K::Type{JavaObject{X}}, V::Type{Ja function bytestring(jstr::JString) #jstr must be a jstring obtained via a JNI call if isnull(jstr); return ""; end #Return empty string to keep type stability. But this is questionable pIsCopy = Array(jboolean, 1) - buf::Ptr{Uint8} = ccall(jnifunc.GetStringUTFChars, Ptr{Uint8}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{jboolean}), penv, jstr.ptr, pIsCopy) + buf::Ptr{UInt8} = ccall(jnifunc.GetStringUTFChars, Ptr{UInt8}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{jboolean}), penv, jstr.ptr, pIsCopy) s=bytestring(buf) - ccall(jnifunc.ReleaseStringUTFChars, Void, (Ptr{JNIEnv}, Ptr{Void}, Ptr{Uint8}), penv, jstr.ptr, buf) + ccall(jnifunc.ReleaseStringUTFChars, Void, (Ptr{JNIEnv}, Ptr{Void}, Ptr{UInt8}), penv, jstr.ptr, buf) return s end diff --git a/src/core.jl b/src/core.jl index 612f387..db2eb94 100644 --- a/src/core.jl +++ b/src/core.jl @@ -14,7 +14,7 @@ typealias jshort Cshort typealias jfloat Cfloat typealias jdouble Cdouble typealias jsize jint -jprimitive = Union(jboolean, jchar, jshort, jfloat, jdouble, jint, jlong) +jprimitive = @compat Union{jboolean, jchar, jshort, jfloat, jdouble, jint, jlong} immutable JavaMetaClass{T} ptr::Ptr{Void} @@ -56,8 +56,8 @@ typealias JObject JavaObject{symbol("java.lang.Object")} typealias JMethod JavaObject{symbol("java.lang.reflect.Method")} typealias JString JavaObject{symbol("java.lang.String")} -function JString(str::String) - jstring = ccall(jnifunc.NewStringUTF, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Uint8}), penv, utf8(str)) +function JString(str::AbstractString) + jstring = ccall(jnifunc.NewStringUTF, Ptr{Void}, (Ptr{JNIEnv}, Ptr{UInt8}), penv, utf8(str)) if jstring == C_NULL geterror() else @@ -78,7 +78,7 @@ macro jimport(class) juliaclass=sprint(Base.show_unquoted, class) elseif isa(class, Symbol) juliaclass=string(class) - elseif isa(class, String) + elseif isa(class, AbstractString) juliaclass=class else error("Macro parameter is of type $(typeof(class))!\nShould be Expr, Symbol or String") @@ -91,7 +91,7 @@ end function jnew(T::Symbol, argtypes::Tuple, args...) sig = method_signature(Void, argtypes...) - jmethodId = ccall(jnifunc.GetMethodID, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{Uint8}, Ptr{Uint8}), penv, metaclass(T), utf8(""), sig) + jmethodId = ccall(jnifunc.GetMethodID, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{UInt8}, Ptr{UInt8}), penv, metaclass(T), utf8(""), sig) if (jmethodId == C_NULL) error("No constructor for $T with signature $sig") end @@ -99,12 +99,12 @@ function jnew(T::Symbol, argtypes::Tuple, args...) end # Call static methods -function jcall{T}(typ::Type{JavaObject{T}}, method::String, rettype::Type, argtypes::Tuple, args... ) +function jcall{T}(typ::Type{JavaObject{T}}, method::AbstractString, rettype::Type, argtypes::Tuple, args... ) try gc_enable(false) sig = method_signature(rettype, argtypes...) - jmethodId = ccall(jnifunc.GetStaticMethodID, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{Uint8}, Ptr{Uint8}), penv, metaclass(T), utf8(method), sig) + jmethodId = ccall(jnifunc.GetStaticMethodID, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{UInt8}, Ptr{UInt8}), penv, metaclass(T), utf8(method), sig) if jmethodId==C_NULL; geterror(true); end _jcall(metaclass(T), jmethodId, C_NULL, rettype, argtypes, args...) @@ -115,11 +115,11 @@ function jcall{T}(typ::Type{JavaObject{T}}, method::String, rettype::Type, argty end # Call instance methods -function jcall(obj::JavaObject, method::String, rettype::Type, argtypes::Tuple, args... ) +function jcall(obj::JavaObject, method::AbstractString, rettype::Type, argtypes::Tuple, args... ) try gc_enable(false) sig = method_signature(rettype, argtypes...) - jmethodId = ccall(jnifunc.GetMethodID, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{Uint8}, Ptr{Uint8}), penv, metaclass(obj), utf8(method), sig) + jmethodId = ccall(jnifunc.GetMethodID, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{UInt8}, Ptr{UInt8}), penv, metaclass(obj), utf8(method), sig) if jmethodId==C_NULL; geterror(true); end _jcall(obj, jmethodId, C_NULL, rettype, argtypes, args...) finally @@ -177,7 +177,7 @@ end @memoize function metaclass(class::Symbol) jclass=javaclassname(class) - jclassptr = ccall(jnifunc.FindClass, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Uint8}), penv, jclass) + jclassptr = ccall(jnifunc.FindClass, Ptr{Void}, (Ptr{JNIEnv}, Ptr{UInt8}), penv, jclass) if jclassptr == C_NULL; error("Class Not Found $jclass"); end return JavaMetaClass(class, jclassptr) end @@ -195,9 +195,9 @@ function geterror(allow=false) if jthrow==C_NULL ; error("Java Exception thrown, but no details could be retrieved from the JVM"); end ccall(jnifunc.ExceptionDescribe, Void, (Ptr{JNIEnv},), penv ) #Print java stackstrace to stdout ccall(jnifunc.ExceptionClear, Void, (Ptr{JNIEnv},), penv ) - jclass = ccall(jnifunc.FindClass, Ptr{Void}, (Ptr{JNIEnv},Ptr{Uint8}), penv, "java/lang/Throwable") + jclass = ccall(jnifunc.FindClass, Ptr{Void}, (Ptr{JNIEnv},Ptr{UInt8}), penv, "java/lang/Throwable") if jclass==C_NULL; error("Java Exception thrown, but no details could be retrieved from the JVM"); end - jmethodId=ccall(jnifunc.GetMethodID, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{Uint8}, Ptr{Uint8}), penv, jclass, "toString", "()Ljava/lang/String;") + jmethodId=ccall(jnifunc.GetMethodID, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{UInt8}, Ptr{UInt8}), penv, jclass, "toString", "()Ljava/lang/String;") if jmethodId==C_NULL; error("Java Exception thrown, but no details could be retrieved from the JVM"); end res = ccall(jnifunc.CallObjectMethodA, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{Void}, Ptr{Void}), penv, jthrow, jmethodId,C_NULL) if res==C_NULL; error("Java Exception thrown, but no details could be retrieved from the JVM"); end diff --git a/src/jvm.jl b/src/jvm.jl index 0cda063..05ab7fa 100644 --- a/src/jvm.jl +++ b/src/jvm.jl @@ -70,7 +70,7 @@ end immutable JavaVMOption - optionString::Ptr{Uint8} + optionString::Ptr{UInt8} extraInfo::Ptr{Void} end @@ -84,10 +84,10 @@ end @unix_only const sep = ":" @windows_only const sep = ";" -cp=Array(String, 0) -opts=Array(String, 0) -addClassPath(s::String) = isloaded()?warn("JVM already initialised. This call has no effect"): push!(cp, s) -addOpts(s::String) = isloaded()?warn("JVM already initialised. This call has no effect"): push!(opts, s) +cp=Array(ByteString, 0) +opts=Array(ByteString, 0) +addClassPath(s::ByteString) = isloaded()?warn("JVM already initialised. This call has no effect"): push!(cp, s) +addOpts(s::ByteString) = isloaded()?warn("JVM already initialised. This call has no effect"): push!(opts, s) init() = init(vcat(opts, reduce((x,y)->string(x,sep,y),"-Djava.class.path=$(cp[1])",cp[2:end]) )) @@ -97,7 +97,7 @@ assertloaded() = isloaded()?nothing:error("JVM not initialised. Please run init( assertnotloaded() = isloaded()?error("JVM already initialised"):nothing # Pointer to pointer to pointer to pointer alert! Hurrah for unsafe load -function init{T<:String}(opts::Array{T, 1}) +function init{T<:AbstractString}(opts::Array{T, 1}) assertnotloaded() opt = Array(JavaVMOption, length(opts)) for i in 1:length(opts) diff --git a/src/reflect.jl b/src/reflect.jl index d69c120..7ced8c8 100644 --- a/src/reflect.jl +++ b/src/reflect.jl @@ -3,7 +3,7 @@ function getclass(obj::JavaObject) jcall(obj, "getClass", JClass, ()) end -function conventional_name(name::String) +function conventional_name(name::AbstractString) if @compat startswith(name, "[") return conventional_name(name[2:end]) * "[]" elseif name == "Z" @@ -43,7 +43,7 @@ function listmethods(obj::JavaObject) jcall(cls, "getMethods", Vector{JMethod}, ()) end -function listmethods(obj::JavaObject, name::String) +function listmethods(obj::JavaObject, name::AbstractString) allmethods = listmethods(obj) filter(m -> getname(m) == name, allmethods) end diff --git a/test/runtests.jl b/test/runtests.jl index 85ffb50..3c7e3ad 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -11,7 +11,7 @@ JavaCall.init(["-verbose:jni", "-verbose:gc","-Djava.class.path=$(joinpath(Pkg.d a=JString("how are you") @test a.ptr != C_NULL @test 11==ccall(JavaCall.jnifunc.GetStringUTFLength, jint, (Ptr{JavaCall.JNIEnv}, Ptr{Void}), JavaCall.penv, a.ptr) -b=ccall(JavaCall.jnifunc.GetStringUTFChars, Ptr{Uint8}, (Ptr{JavaCall.JNIEnv}, Ptr{Void}, Ptr{Void}), JavaCall.penv, a.ptr, C_NULL) +b=ccall(JavaCall.jnifunc.GetStringUTFChars, Ptr{UInt8}, (Ptr{JavaCall.JNIEnv}, Ptr{Void}, Ptr{Void}), JavaCall.penv, a.ptr, C_NULL) @test bytestring(b) == "how are you" # Test parameter passing @@ -76,8 +76,7 @@ a=jcall(j_u_arrays, "copyOf", Array{JObject, 1}, (Array{JObject, 1}, jint), ["a" jd = @jimport(java.util.Date)(()) jcal = @jimport(java.util.GregorianCalendar)(()) -jsd = @jimport(java.sql.Date)((jlong,),int(time())) - +jsd = @jimport(java.sql.Date)((jlong,),round(jlong, time())) @assert typeof(convert(Dates.DateTime, jd)) == Dates.DateTime @assert typeof(convert(Dates.DateTime, jcal)) == Dates.DateTime @@ -85,8 +84,8 @@ jsd = @jimport(java.sql.Date)((jlong,),int(time())) nulldate = @jimport(java.util.Date)(C_NULL) Dates.year(convert(Dates.DateTime, nulldate)) == 1970 nullcal = @jimport(java.util.GregorianCalendar)(C_NULL) -Dates.year(convert(Dates.DateTime, nullcal)) == 1970 +Dates.year(convert(Dates.DateTime, nullcal)) == 1970 #Test for Map conversion JHashMap = @jimport(java.util.HashMap) From 8bf25d09c0ba1abadcc53a3c0830cea1a2bfed4a Mon Sep 17 00:00:00 2001 From: Avik Sengupta Date: Wed, 21 Oct 2015 18:52:05 +0100 Subject: [PATCH 02/21] Remove OSX on travis due to JVM bug --- .travis.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index d67b621..94487fd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,9 @@ language: julia os: -- osx -- linux + - linux julia: -- release -- nightly + - 0.3 + - 0.4 + - nightly notifications: -email: false + email: false From a028bc0b98c3c7f585ce1b562f70e721338cf9e6 Mon Sep 17 00:00:00 2001 From: Avik Sengupta Date: Wed, 21 Oct 2015 22:15:29 +0100 Subject: [PATCH 03/21] add path for windows jre appveyor config for 0.4 --- appveyor.yml | 8 ++++++-- src/jvm.jl | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index e94600f..eeb8fb1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,11 +1,15 @@ environment: matrix: - JULIAVERSION: "julialang/bin/winnt/x86/0.3/julia-0.3-latest-win32.exe" - JAVA_HOME: C:\Program Files (x86)\Java\jdk1.7.0\bin + JAVA_HOME: C:\Program Files (x86)\Java\jdk1.7.0\ - JULIAVERSION: "julialang/bin/winnt/x64/0.3/julia-0.3-latest-win64.exe" JAVA_HOME: C:\Program Files\Java\jdk1.7.0\ + - JULIAVERSION: "julialang/bin/winnt/x86/0.4/julia-0.4-latest-win32.exe" + JAVA_HOME: C:\Program Files (x86)\Java\jdk1.7.0\ + - JULIAVERSION: "julialang/bin/winnt/x64/0.4/julia-0.4-latest-win64.exe" + JAVA_HOME: C:\Program Files\Java\jdk1.7.0\ - JULIAVERSION: "julianightlies/bin/winnt/x86/julia-latest-win32.exe" - JAVA_HOME: C:\Program Files (x86)\Java\jdk1.7.0\bin + JAVA_HOME: C:\Program Files (x86)\Java\jdk1.7.0\ - JULIAVERSION: "julianightlies/bin/winnt/x64/julia-latest-win64.exe" JAVA_HOME: C:\Program Files\Java\jdk1.7.0\ diff --git a/src/jvm.jl b/src/jvm.jl index 05ab7fa..3fe90a7 100644 --- a/src/jvm.jl +++ b/src/jvm.jl @@ -37,6 +37,7 @@ function findjvm() push!(libpaths,pwd()) for n in javahomes @windows_only push!(libpaths, joinpath(n, "jre", "bin", "server")) + @windows_only push!(libpaths, joinpath(n, "bin", "client")) @linux_only if WORD_SIZE==64; push!(libpaths, joinpath(n, "jre", "lib", "amd64", "server")); end @linux_only if WORD_SIZE==32; push!(libpaths, joinpath(n, "jre", "lib", "i386", "server")); end push!(libpaths, joinpath(n, "jre", "lib", "server")) From f5a5cae411b723a1927dd99b92af75b6650ca94f Mon Sep 17 00:00:00 2001 From: Avik Sengupta Date: Tue, 27 Oct 2015 18:01:43 +0000 Subject: [PATCH 04/21] Put badges in one line [ci skip] --- README.md | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 03b0d22..c52f362 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,7 @@ # JavaCall +[![Build Status](https://travis-ci.org/aviks/JavaCall.jl.png)](https://travis-ci.org/aviks/JavaCall.jl) [![Build status](https://ci.appveyor.com/api/projects/status/xdkfd0t8r3oqeio9?svg=true)](https://ci.appveyor.com/project/aviks/javacall-jl) [![JavaCall](http://pkg.julialang.org/badges/JavaCall_0.3.svg)](http://pkg.julialang.org/?pkg=JavaCall&ver=release) [![JavaCall](http://pkg.julialang.org/badges/JavaCall_0.4.svg)](http://pkg.julialang.org/?pkg=JavaCall&ver=nightly) + Call Java programs from Julia. Documentation is available at http://aviks.github.io/JavaCall.jl - -[![Build Status](https://travis-ci.org/aviks/JavaCall.jl.png)](https://travis-ci.org/aviks/JavaCall.jl) - -[![Build status](https://ci.appveyor.com/api/projects/status/xdkfd0t8r3oqeio9?svg=true)](https://ci.appveyor.com/project/aviks/javacall-jl) - -[![JavaCall](http://pkg.julialang.org/badges/JavaCall_0.3.svg)](http://pkg.julialang.org/?pkg=JavaCall&ver=release) - -[![JavaCall](http://pkg.julialang.org/badges/JavaCall_0.4.svg)](http://pkg.julialang.org/?pkg=JavaCall&ver=nightly) - - From ea9bcb40c37f52e23caeb9e0f5b693aa2780da9f Mon Sep 17 00:00:00 2001 From: Avik Sengupta Date: Thu, 3 Dec 2015 16:06:57 +0530 Subject: [PATCH 05/21] make tests less brittle for different JDK versions --- test/runtests.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 3c7e3ad..6951286 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -115,8 +115,8 @@ end @test_throws ErrorException jcall(jlm, "sinx", jdouble, (jdouble,), 1.0) @test_throws ErrorException jcall(jlm, "sinx", jdouble, (jdouble,), 1.0) -@test length(listmethods(JString("test"))) == 72 -@test length(listmethods(JString("test"), "indexOf")) == 4 +@test length(listmethods(JString("test"))) >= 72 +@test length(listmethods(JString("test"), "indexOf")) >= 3 m = listmethods(JString("test"), "indexOf")[1] @test getname(getreturntype(m)) == "int" @test [getname(typ) for typ in getparametertypes(m)] == ["java.lang.String", "int"] From 5abae1901a1148bf114e46fc717aa09432cdb6db Mon Sep 17 00:00:00 2001 From: Avik Sengupta Date: Mon, 12 Oct 2015 11:06:07 +0100 Subject: [PATCH 06/21] Access fields --- src/JavaCall.jl | 2 +- src/core.jl | 37 +++++++++++++++++++++++++++++++++++++ test/Test$TestInner.class | Bin 392 -> 392 bytes test/Test.class | Bin 1501 -> 1625 bytes test/Test.java | 3 +++ test/runtests.jl | 15 ++++++++++++++- 6 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src/JavaCall.jl b/src/JavaCall.jl index 10e37c6..4123028 100644 --- a/src/JavaCall.jl +++ b/src/JavaCall.jl @@ -2,7 +2,7 @@ module JavaCall export JavaObject, JavaMetaClass, jint, jlong, jbyte, jboolean, jchar, jshort, jfloat, jdouble, JObject, JClass, JMethod, JString, - @jimport, jcall, isnull, + @jimport, jcall, jfield, isnull, getname, listmethods, getreturntype, getparametertypes # using Debug diff --git a/src/core.jl b/src/core.jl index db2eb94..dbaacbc 100644 --- a/src/core.jl +++ b/src/core.jl @@ -127,7 +127,44 @@ function jcall(obj::JavaObject, method::AbstractString, rettype::Type, argtypes: end end +function jfield{T}(typ::Type{JavaObject{T}}, field::AbstractString, fieldType::Type) + jfieldID = ccall(jnifunc.GetStaticFieldID, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{UInt8}, Ptr{UInt8}), penv, metaclass(T), utf8(field), signature(fieldType)) + if jfieldID==C_NULL; geterror(true); end + _jfield(metaclass(T), jfieldID, fieldType) +end + +function jfield(obj::JavaObject, field::AbstractString, fieldType::Type) + jfieldID = ccall(jnifunc.GetFieldID, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{UInt8}, Ptr{UInt8}), penv, metaclass(obj), utf8(field), signature(fieldType)) + if jfieldID==C_NULL; geterror(true); end + _jfield(obj, jfieldID, fieldType) +end +for (x, y, z) in [ (:jboolean, :(jnifunc.GetBooleanField), :(jnifunc.GetStaticBooleanField)), + (:jchar, :(jnifunc.GetCharField), :(jnifunc.GetStaticCharField)), + (:jbyte, :(jnifunc.GetByteField), :(jnifunc.GetStaticBypeField)), + (:jshort, :(jnifunc.GetShortField), :(jnifunc.GetStaticShortField)), + (:jint, :(jnifunc.GetIntField), :(jnifunc.GetStaticIntField)), + (:jlong, :(jnifunc.GetLongField), :(jnifunc.GetStaticLongField)), + (:jfloat, :(jnifunc.GetFloatField), :(jnifunc.GetStaticFloatField)), + (:jdouble, :(jnifunc.GetDoubleField), :(jnifunc.GetStaticDoubleField)) ] + + m = quote + function _jfield(obj, jfieldID::Ptr{Void}, fieldType::Type{$(x)}) + callmethod = ifelse( typeof(obj)<:JavaObject, $y , $z ) + result = ccall(callmethod, $x, (Ptr{JNIEnv}, Ptr{Void}, Ptr{Void}), penv, obj.ptr, jfieldID) + if result==C_NULL; geterror(); end + return convert_result(fieldType, result) + end + end + eval(m) +end + +function _jfield(obj, jfieldID::Ptr{Void}, fieldType::Type) + callmethod = ifelse( typeof(obj)<:JavaObject, jnifunc.GetObjectField , jnifunc.GetStaticObjectField ) + result = ccall(callmethod, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{Void}), penv, obj.ptr, jfieldID) + if result==C_NULL; geterror(); end + return convert_result(fieldType, result) +end #Generate these methods to satisfy ccall's compile time constant requirement #_jcall for primitive and Void return types diff --git a/test/Test$TestInner.class b/test/Test$TestInner.class index bbc42c0ad16553a1ecaeaa22c7431bb0c80435f6..6a1b0e8d0fd6c1a9fba710cc2b75d19c995c782b 100644 GIT binary patch delta 19 acmeBR?qJ^F!pLYf*_Ba)(PnZUqZ9x#X9S@D delta 19 acmeBR?qJ^F!pLYo*_Ba)(Q`YiX|zQrTA5fk`&i9tQZ)?Yzk$mS5vrQkgiB^Q;M||Zb^Mx!yOHGHB<%k zn$wEPzVCzrrqWBE-D){4zPf(oG@Y>II$lFSlm!m8qR{o5u_aS^ZvSByJ=<>;z;8-y)mn`smAt@KV96@QV7DZJ>HNVut%IgG^jh2V1jh2Q zM>}%8;)>mRcGG^r+YQR>i(zQLthg=aJF>^GcR)|Q>Nb5lYKOe*xzBseA1q>lWOB=P zeSvKL;lXp+QllEQ!%e5;sy5bG&;>aM6FHnTaSX?Klf_)McDKBC-NYnLXsDUE2cqe+ zpIfExOfGab8?!kLbrbioZsGwRO7XiCkED1k#k#<#nz3p_?|K6LD~{&{CZ6CaU+O{V zHB3z7tce+%H<5?MI+c&gXW{~iyqPRkV0dS3Zf!hwHfb7?C#R)|cX5|b^<^t^wzyD1 zo1SCcrno`zHdis?kR5xAUF+7l*UZvhNGCbZ&-YSO=N{Xg%$L=^a?9k}aLg=`RD{lQ+nx8DR`pNnce_f5bP`a`ldKF?pZ=0Hzly-~a#s literal 1501 zcmb7EZBx@|6g>}ZNgE@DD%C~Biik}GyNa%>AiD}yiWPLrZhiR_Xa?hi#7Wbg@jt2S z?uWwYj6Yz1)Xtv!kO3`@Gv>p&?S0O<_qi|0zyE#s1Yi~|6Qh{T;To=I@so)g_*vkl zz%79}fq8-31{O@1n9brBvAPwUQ)=4uMq}YB3rRnl1Mc_bhNN$*Aihfjy$1Fl^ZXeKb@-Y z1Y6ZT=bU}mm4sgH`o6+wIbn2T&#x{!ofi+CS91zSCHtKya$YyQ4)dM(g13J_X0GXN z1y0b%(CnIp@rYU+?iGw z`E3hlQL=CWQx?u)f>+WUozKEWlv#w_OJVq+^J^O~-A%fNi5FxBTh2r=v-%;4cfcsmu_C|m5^j~UvHbC&wX|_U9RiZ5~p34}(&6`+KEFD77f%c=n|!<^?{_I@QDA)L(sBhbbMQ^gJfN zAsz3*7=PO*9i_BLDK}$Zdbrk!9RTOLK3l<-bKD;?P9o<-^Iw2LSYxjS_ivPM26}s#H;f4Wz1__t?N`@(NVAB NB(1DjkxO?1>VJr*4qpHO diff --git a/test/Test.java b/test/Test.java index ba03e58..c10ff54 100644 --- a/test/Test.java +++ b/test/Test.java @@ -2,6 +2,9 @@ public class Test { + public int integerField = 100; + public String stringField = "A STRING"; + public static short testShort(short i) { System.out.print("In Java, recd: ");System.out.println(i); return i; diff --git a/test/runtests.jl b/test/runtests.jl index 6951286..386c67b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -82,8 +82,9 @@ jsd = @jimport(java.sql.Date)((jlong,),round(jlong, time())) @assert typeof(convert(Dates.DateTime, jcal)) == Dates.DateTime @assert typeof(convert(Dates.DateTime, jsd)) == Dates.DateTime nulldate = @jimport(java.util.Date)(C_NULL) -Dates.year(convert(Dates.DateTime, nulldate)) == 1970 +@assert Dates.year(convert(Dates.DateTime, nulldate)) == 1970 nullcal = @jimport(java.util.GregorianCalendar)(C_NULL) +@assert Dates.year(convert(Dates.DateTime, nullcal)) == 1970 Dates.year(convert(Dates.DateTime, nullcal)) == 1970 #Test for Map conversion @@ -101,6 +102,18 @@ t=Test(()) inner = TestInner((Test,), t) @assert jcall(inner, "innerString", JString, ()) == "from inner" +#Static Field Access +@assert jfield(@jimport(java.lang.Math), "E", jdouble) == 2.718281828459045 +@assert jfield(@jimport(java.lang.Math), "PI", jdouble) == 3.141592653589793 +@assert jfield(@jimport(java.text.NumberFormat), "INTEGER_FIELD", jint) == 0 +Locale = @jimport java.util.Locale +lc = jfield(@jimport(java.util.Locale), "CANADA", @jimport(java.util.Locale)) +#Instance field access +#Disabled for now. Need to verify stability +#@assert jfield(@jimport(java.util.logging.Logger), "GLOBAL_LOGGER_NAME", JString ) == "global" +#@assert jcall(lc, "getCountry", JString, ()) == "CA" +#@assert jfield(t, "integerField", jint) == 100 +#@assert jfield(t, "stringField", JString) == "A STRING" # Test Memory allocation and de-allocatios # the following loop fails with an OutOfMemoryException in the absence of de-allocation From 917e1ae758c22f67e13f92fb059e08f03e81787f Mon Sep 17 00:00:00 2001 From: ScottPJones Date: Thu, 31 Dec 2015 12:05:15 -0500 Subject: [PATCH 07/21] Fix uses of isexecutable/isreadable (deprecated in v0.5) --- src/jvm.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jvm.jl b/src/jvm.jl index 3fe90a7..ca9f39e 100644 --- a/src/jvm.jl +++ b/src/jvm.jl @@ -26,7 +26,7 @@ function findjvm() if haskey(ENV,"JAVA_HOME") push!(javahomes,ENV["JAVA_HOME"]) end - if isexecutable("/usr/libexec/java_home") + if isfile("/usr/libexec/java_home") push!(javahomes,chomp(readall(`/usr/libexec/java_home`))) end @@ -47,7 +47,7 @@ function findjvm() try for n in libpaths libpath = joinpath(n,libname*ext); - if isreadable(libpath) + if isfile(libpath) global libjvm = Libdl.dlopen(libpath) println("Loaded $libpath") return From e23713637b93dbfd5addb297e19bbecfb100b37b Mon Sep 17 00:00:00 2001 From: Pradeep Mudlapur Date: Fri, 12 Feb 2016 16:11:57 +0530 Subject: [PATCH 08/21] Added basic inline documentation for exported functions --- src/core.jl | 25 +++++++++++++++++ src/reflect.jl | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/src/core.jl b/src/core.jl index dbaacbc..f7c5569 100644 --- a/src/core.jl +++ b/src/core.jl @@ -48,7 +48,32 @@ function deleteref(x::JavaObject) end +""" +``` +isnull(obj::JavaObject) +``` +Checks if the passed JavaObject is null or not + +### Args +* obj: The object of type JavaObject + +### Returns +true if the passed object is null else false +""" isnull(obj::JavaObject) = obj.ptr == C_NULL + +""" +``` +isnull(obj::JavaMetaClass) +``` +Checks if the passed JavaMetaClass is null or not + +### Args +* obj: The object of type JavaMetaClass + +### Returns +true if the passed object is null else false +""" isnull(obj::JavaMetaClass) = obj.ptr == C_NULL typealias JClass JavaObject{symbol("java.lang.Class")} diff --git a/src/reflect.jl b/src/reflect.jl index 7ced8c8..652dde3 100644 --- a/src/reflect.jl +++ b/src/reflect.jl @@ -29,29 +29,102 @@ function conventional_name(name::AbstractString) end end +""" +``` +getname(cls::JClass) +``` +Returns the fully qualified name of the java class + +### Args +* cls: The JClass object + +### Returns +The fully qualified name of the java class +""" function getname(cls::JClass) rawname = jcall(cls, "getName", JString, ()) conventional_name(rawname) end +""" +``` +getname(method::JMethod) +``` +Returns the fully qualified name of the java method + +### Args +* cls: The JClass method + +### Returns +The fully qualified name of the method +""" function getname(method::JMethod) jcall(method, "getName", JString, ()) end +""" +``` +listmethods(obj::JavaObject) +``` +Lists the methods that are available on the java object passed + +### Args +* obj: The java object + +### Returns +List of methods +""" function listmethods(obj::JavaObject) cls = getclass(obj) jcall(cls, "getMethods", Vector{JMethod}, ()) end +""" +``` +listmethods(obj::JavaObject, name::AbstractString) +``` +Lists the methods that are available on the java object passed. The methods are filtered based on the name passed + +### Args +* obj: The java object +* name: The filter (e.g. method name) + +### Returns +List of methods available on the java object and matching the name passed +""" function listmethods(obj::JavaObject, name::AbstractString) allmethods = listmethods(obj) filter(m -> getname(m) == name, allmethods) end +""" +``` +getreturntype(method::JMethod) +``` +Returns the return type of the java method + +### Args +* method: The java method object + +### Returns +Returns the type of the return object as a JClass +""" function getreturntype(method::JMethod) jcall(method, "getReturnType", JClass, ()) end +""" +``` +getparametertypes(method::JMethod) +``` +Returns the parameter types of the java method + +### Args +* method: The java method object + +### Returns +Vector the parametertypes +""" function getparametertypes(method::JMethod) jcall(method, "getParameterTypes", Vector{JClass}, ()) end From d4df111f5a79eb7f493c3fe6e6a3ceae534fdf98 Mon Sep 17 00:00:00 2001 From: Adam Brewster Date: Tue, 29 Dec 2015 16:16:58 -0500 Subject: [PATCH 09/21] avoid double free bug --- src/convert.jl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/convert.jl b/src/convert.jl index 10a7887..7040e47 100644 --- a/src/convert.jl +++ b/src/convert.jl @@ -4,12 +4,16 @@ convert{T<:AbstractString}(::Type{JObject}, str::T) = convert(JObject, JString(s #Cast java object from S to T . Needed for polymorphic calls function convert{T,S}(::Type{JavaObject{T}}, obj::JavaObject{S}) if isConvertible(T, S) #Safe static cast - return JavaObject{T}(obj.ptr) + ptr = ccall(jnifunc.NewLocalRef, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}), penv, obj.ptr) + if ptr === C_NULL geterror() end + return JavaObject{T}(ptr) end if isnull(obj) ; error("Cannot convert NULL"); end realClass = ccall(jnifunc.GetObjectClass, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void} ), penv, obj.ptr) if isConvertible(T, realClass) #dynamic cast - return JavaObject{T}(obj.ptr) + ptr = ccall(jnifunc.NewLocalRef, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}), penv, obj.ptr) + if ptr === C_NULL geterror() end + return JavaObject{T}(ptr) end error("Cannot cast java object from $S to $T") end From 3da7e2290c8dbd22a15de29174cf0c8a1347dbae Mon Sep 17 00:00:00 2001 From: dfdx Date: Tue, 4 Aug 2015 02:04:01 +0300 Subject: [PATCH 10/21] convert() for array types --- .gitignore | 2 +- src/convert.jl | 35 +++++++++++++++++++++++++++++++++++ test/Test$TestInner.class | Bin 392 -> 392 bytes test/Test.class | Bin 1625 -> 1896 bytes test/Test.java | 8 ++++++++ test/runtests.jl | 4 ++++ 6 files changed, 48 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index a635799..8e309e8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ *~ .juliahistory -.DS_Store +.DS_Store \ No newline at end of file diff --git a/src/convert.jl b/src/convert.jl index 7040e47..9f4e4b7 100644 --- a/src/convert.jl +++ b/src/convert.jl @@ -173,3 +173,38 @@ function bytestring(jstr::JString) #jstr must be a jstring obtained via a JNI c ccall(jnifunc.ReleaseStringUTFChars, Void, (Ptr{JNIEnv}, Ptr{Void}, Ptr{UInt8}), penv, jstr.ptr, buf) return s end + + +for (x, y, z) in [ (:jboolean, :(jnifunc.GetBooleanArrayElements), :(jnifunc.ReleaseBooleanArrayElements)), + (:jchar, :(jnifunc.GetCharArrayElements), :(jnifunc.ReleaseCharArrayElements)), + (:jbyte, :(jnifunc.GetByteArrayElements), :(jnifunc.ReleaseByteArrayElements)), + (:jshort, :(jnifunc.GetShortArrayElements), :(jnifunc.ReleaseShortArrayElements)), + (:jint, :(jnifunc.GetIntArrayElements), :(jnifunc.ReleaseIntArrayElements)), + (:jlong, :(jnifunc.GetLongArrayElements), :(jnifunc.ReleaseLongArrayElements)), + (:jfloat, :(jnifunc.GetFloatArrayElements), :(jnifunc.ReleaseFloatArrayElements)), + (:jdouble, :(jnifunc.GetDoubleArrayElements), :(jnifunc.ReleaseDoubleArrayElements)) ] + m=quote + function convert(::Type{Array{$(x),1}}, obj::JObject) + sz = ccall(jnifunc.GetArrayLength, jint, (Ptr{JNIEnv}, Ptr{Void}), penv, obj.ptr) + arr = ccall($(y), Ptr{$(x)}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{jboolean} ), penv, obj.ptr, C_NULL ) + jl_arr::Array = pointer_to_array(arr, (@compat Int(sz)), false) + jl_arr = deepcopy(jl_arr) + ccall($(z), Void, (Ptr{JNIEnv},Ptr{Void}, Ptr{$(x)}, jint), penv, obj.ptr, arr, 0) + return jl_arr + end + end + eval(m) +end + + +function convert{T}(::Type{Array{T, 1}}, obj::JObject) + sz = ccall(jnifunc.GetArrayLength, jint, + (Ptr{JNIEnv}, Ptr{Void}), penv, obj.ptr) + ret = Array(T, sz) + for i=1:sz + ptr = ccall(jnifunc.GetObjectArrayElement, Ptr{Void}, + (Ptr{JNIEnv}, Ptr{Void}, jint), penv, obj.ptr, i-1) + ret[i] = convert(T, JObject(ptr)) + end + return ret +end diff --git a/test/Test$TestInner.class b/test/Test$TestInner.class index 6a1b0e8d0fd6c1a9fba710cc2b75d19c995c782b..d2aff0417999c075fdbefd97d9d24672334424e8 100644 GIT binary patch delta 19 acmeBR?qJ^F!pP_}*_Ba)(PeTTqZ9x#=LE3; delta 19 acmeBR?qJ^F!pLYf*_Ba)(PnZUqZ9x#X9S@D diff --git a/test/Test.class b/test/Test.class index d2e230ad90c6d426968e4ac23c32318682071006..28feee36483338aece203a696db63f55221174d3 100644 GIT binary patch literal 1896 zcmb7Ei&EQG5Iq+gWD6w*1)Sitgc3?^hlI9C+BBggyc`UKq_K&U(3h}PBPt}1BzMX` z^*s}ZNvHjQepILDUc{TpOvf|3(%wC1_wF9~pMT%{4d5nPIxb@-jT~lEn3H}!jRlla zc&K9$WoeeAS(au+nn%*CYIvN&lN7$t@f4L5sv6dGn3$2~nNFgbG|#1Zk-|&q*EM{p z;VTVa3#6-d7?nNG4g?J4=Ugic?U1jI7uiiaC^@#<5D;a7-Y^OruNg*%+TPxDFqn@s+L7ZrrL1697gpW72>^f@>?B}XM>_wTXFZ@`yTan{? zp@we+&K*EkoRF}K`!H2PamoWC(-o)bSy4OSn690jHFdiGX(E%`mg5Oz^XsS2$+ z-wx__$x$1q@-8>z3JqMvn1L%8;SgpERD4OrOV2Fu>a5_2a;0=wS0 zJEEa(paI*!cW6qpDUBn|mNe|WYkgLrd(n1XpRKJ`OLsJUZ@|Si!!of=hX$@;g1svu)q{bL@G&Xn1qAvIRk**B^YUa&npoOnD#!6B*SxUZYEgA| zW5KKY4XXKIPsgY#J7HwA(S+Y-jlsQnlHdtHfQZtvt!)l`ul?g;UalpRq>9d7gQm`1 zZYr5CtFMIGmLCfRtz1dEBlp^ua;j-ZvpbReIKN_G5 zLav)nLav#njiCiDuS)bCrM#SV<( zZzrHv2^}N!CT_*hoT|xXio@I<70Wa4Ha_7b6kH_+{Iwc*hRLM*~P`@=A~T>)efbXWp^O9n^>Kw Z46itd2SndjtPe0uuaos1F6v!~{{S~vYij@i delta 809 zcmZuv+fEZv6kVscnU04J7J5^uZ9xmQSg(ksf*=S5q)Mwp@mgtPLYiWb_{zJ9iJ^&a zeu9a-V55m2;2)Uy0Y3QP7Z}%>R?CC)u=bf*Yp;Dd^TYQ|?tcCK=?j31s2B(%>qQ6? zI&vyr^I{THI<6a-#*Bg+3T73|DY&U%Uc-Wc9%OaoRb14uWH5VK!7T+VItnV@)^JC| zs)nL~w^VzvlW#QkUnNEJr+8P4Aue$O0|NSVtXNvjugptCaZ*D`;x6t9nE6I*vGTH# zj&0XAs@a$ZOJWUWiFMpp@Ib*s1&9C=p=mCuAdwL6W>x3zcP{?Kct@GV|xRC)0q7-l~ zZ9!tUo1GvzNb(%cE0W&F7}ettABgQr9{XF8x(oc#9JVfJuMG%)Mo;-8d`l_6d4OIk zxWE%aGt3;k>UKnp=@|6e;n f-T>&}X1>9ElMVrlGke^2y^7JB5kVGi^M9O`2y diff --git a/test/Test.java b/test/Test.java index c10ff54..9c6b6ab 100644 --- a/test/Test.java +++ b/test/Test.java @@ -1,3 +1,4 @@ +import java.io.UnsupportedEncodingException; import java.util.ArrayList; public class Test { @@ -39,6 +40,13 @@ public static java.util.HashMap testNull() { return null; } + public static Object testArrayAsObject() throws UnsupportedEncodingException { + byte[][] res = new byte[2][]; + res[0] = "Hello".getBytes("UTF8"); + res[1] = "World".getBytes("UTF8"); + return res; + } + public static ArrayList testArrayList() { ArrayList res=new ArrayList(); diff --git a/test/runtests.jl b/test/runtests.jl index 386c67b..5e729b9 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -134,6 +134,10 @@ m = listmethods(JString("test"), "indexOf")[1] @test getname(getreturntype(m)) == "int" @test [getname(typ) for typ in getparametertypes(m)] == ["java.lang.String", "int"] +# Test array conversions +jobj = jcall(T, "testArrayAsObject", JObject, ()) +arr = convert(Array{Array{UInt8, 1}, 1}, jobj) +@test ["Hello", "World"] == map(bytestring, arr) # At the end, unload the JVM before exiting JavaCall.destroy() From d40a7a79c2047f66ea0caa879ae2df50853fe72f Mon Sep 17 00:00:00 2001 From: Avik Sengupta Date: Sun, 24 Apr 2016 00:09:47 +0100 Subject: [PATCH 11/21] test for double free bug #20 #28 --- test/runtests.jl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/runtests.jl b/test/runtests.jl index 5e729b9..2d1c929 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -134,10 +134,20 @@ m = listmethods(JString("test"), "indexOf")[1] @test getname(getreturntype(m)) == "int" @test [getname(typ) for typ in getparametertypes(m)] == ["java.lang.String", "int"] +#Test for double free bug, #20 +#Fix in #28. The following lines will segfault without the fix +JHashtable = @jimport java.util.Hashtable +JProperties = @jimport java.util.Properties +ta_20=Any[] +for i=1:1000; push!(ta_20, convert(JHashtable, JProperties((),))); end +gc(); gc() +for i=1:1000; print(jcall(ta_20[i], "size", jint, ())); end + # Test array conversions jobj = jcall(T, "testArrayAsObject", JObject, ()) arr = convert(Array{Array{UInt8, 1}, 1}, jobj) @test ["Hello", "World"] == map(bytestring, arr) + # At the end, unload the JVM before exiting JavaCall.destroy() From ddbb5d547c5c94509fbe3c99b45793566d515cb3 Mon Sep 17 00:00:00 2001 From: Avik Sengupta Date: Sun, 24 Apr 2016 16:34:33 +0100 Subject: [PATCH 12/21] clean up double free tests --- test/runtests.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 2d1c929..700f8ee 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -139,9 +139,9 @@ m = listmethods(JString("test"), "indexOf")[1] JHashtable = @jimport java.util.Hashtable JProperties = @jimport java.util.Properties ta_20=Any[] -for i=1:1000; push!(ta_20, convert(JHashtable, JProperties((),))); end +for i=1:100; push!(ta_20, convert(JHashtable, JProperties((),))); end gc(); gc() -for i=1:1000; print(jcall(ta_20[i], "size", jint, ())); end +for i=1:100; @test jcall(ta_20[i], "size", jint, ()) == 0; end # Test array conversions jobj = jcall(T, "testArrayAsObject", JObject, ()) From c47c0d2325e6aaafe1c2abc74508daf3b2241e96 Mon Sep 17 00:00:00 2001 From: Avik Sengupta Date: Sun, 24 Apr 2016 17:12:48 +0100 Subject: [PATCH 13/21] enable jfield tests --- test/runtests.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 700f8ee..a6cfc4a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -110,10 +110,10 @@ Locale = @jimport java.util.Locale lc = jfield(@jimport(java.util.Locale), "CANADA", @jimport(java.util.Locale)) #Instance field access #Disabled for now. Need to verify stability -#@assert jfield(@jimport(java.util.logging.Logger), "GLOBAL_LOGGER_NAME", JString ) == "global" -#@assert jcall(lc, "getCountry", JString, ()) == "CA" -#@assert jfield(t, "integerField", jint) == 100 -#@assert jfield(t, "stringField", JString) == "A STRING" +@assert jfield(@jimport(java.util.logging.Logger), "GLOBAL_LOGGER_NAME", JString ) == "global" +@assert jcall(lc, "getCountry", JString, ()) == "CA" +@assert jfield(t, "integerField", jint) == 100 +@assert jfield(t, "stringField", JString) == "A STRING" # Test Memory allocation and de-allocatios # the following loop fails with an OutOfMemoryException in the absence of de-allocation From 32fbf97e7db1830bfb2728d03eb6c441ddeccf85 Mon Sep 17 00:00:00 2001 From: Avik Sengupta Date: Sun, 24 Apr 2016 17:13:05 +0100 Subject: [PATCH 14/21] Add faq entry for OSX segfault --- doc/faq.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/doc/faq.md b/doc/faq.md index 364b08f..50424af 100644 --- a/doc/faq.md +++ b/doc/faq.md @@ -6,9 +6,22 @@ layout: default ### ERROR: jnifunc not defined -You are attempting to call Java methods without initialising the JVM. Call `JavaCall.init(...)` first. +You are attempting to call Java methods without initialising the JVM. Call `JavaCall.init(...)` first. -### Cannot find libjvm in: +### Cannot find libjvm in: -The JVM dynamic library cannot be found. It is called `libjvm.so`, `libjvm.dylib` or `jvm.dll` depending on your system. Check that you have `JAVA_HOME` environment variable defined. If you do, verify the search logic in the code, and please file a pull request with an amemded version that can find your library. As a workaround, you can set the `JAVA_LIB` environment variable to point to the location of the library file. \ No newline at end of file +The JVM dynamic library cannot be found. It is called `libjvm.so`, `libjvm.dylib` or `jvm.dll` depending on your system. Check that you have `JAVA_HOME` environment variable defined. If you do, verify the search logic in the code, and please file a pull request with an amemded version that can find your library. As a workaround, you can set the `JAVA_LIB` environment variable to point to the location of the library file. + +### Segault on OSX + +Upon initialising JavaCall on OSX, you get an immediate segfault message, while execution carries on normally. +``` +signal (11): Segmentation fault: 11 +unknown function (ip: 0x31960c2b4) +``` +This message is usually benign. It is due to the way the JVM uses signals for its regular operations. Julia on OSX installs a signal handler, which generates the above message. However, since the signal is eventually caught and handled by the JVM, execution carries on normally. If the message troubles you for any reason, please start julia with the `--handle-signals=no` option. In this case, Julia's signal handler will be disabled, and you will no longer see the above message. However, this may cause issues with handling `^C` in Julia programs. + +_References:_ +http://stackoverflow.com/questions/27241575/why-does-java-app-crash-in-gdb-but-runs-normally-in-real-life +http://www.oracle.com/technetwork/java/javase/signals-139944.html#gbzbl From b0dd9a5106fdb0b8f2909077cfd4aed23f307a57 Mon Sep 17 00:00:00 2001 From: Abhijith Date: Fri, 17 Jun 2016 16:09:19 +0530 Subject: [PATCH 15/21] fix depwarns --- REQUIRE | 2 +- src/JavaCall.jl | 1 + src/core.jl | 8 ++++---- src/jvm.jl | 16 ++++++++-------- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/REQUIRE b/REQUIRE index a79cd4b..dd0e1ae 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1,4 +1,4 @@ julia 0.3 Memoize Compat -Dates \ No newline at end of file +Dates diff --git a/src/JavaCall.jl b/src/JavaCall.jl index 4123028..0907080 100644 --- a/src/JavaCall.jl +++ b/src/JavaCall.jl @@ -8,6 +8,7 @@ export JavaObject, JavaMetaClass, # using Debug using Memoize using Compat +import Compat.String import Base.bytestring, Base.convert diff --git a/src/core.jl b/src/core.jl index f7c5569..02e4c3a 100644 --- a/src/core.jl +++ b/src/core.jl @@ -76,10 +76,10 @@ true if the passed object is null else false """ isnull(obj::JavaMetaClass) = obj.ptr == C_NULL -typealias JClass JavaObject{symbol("java.lang.Class")} -typealias JObject JavaObject{symbol("java.lang.Object")} -typealias JMethod JavaObject{symbol("java.lang.reflect.Method")} -typealias JString JavaObject{symbol("java.lang.String")} +typealias JClass JavaObject{Symbol("java.lang.Class")} +typealias JObject JavaObject{Symbol("java.lang.Object")} +typealias JMethod JavaObject{Symbol("java.lang.reflect.Method")} +typealias JString JavaObject{Symbol("java.lang.String")} function JString(str::AbstractString) jstring = ccall(jnifunc.NewStringUTF, Ptr{Void}, (Ptr{JNIEnv}, Ptr{UInt8}), penv, utf8(str)) diff --git a/src/jvm.jl b/src/jvm.jl index ca9f39e..d4d9cac 100644 --- a/src/jvm.jl +++ b/src/jvm.jl @@ -17,8 +17,8 @@ const JNI_EEXIST = convert(Cint, -5) #/* VM already created * const JNI_EINVAL = convert(Cint, -6) #/* invalid arguments */ -@unix_only global const libname = "libjvm" -@windows_only global const libname = "jvm" +@static is_unix() ? (global const libname = "libjvm") : nothing +@static is_windows() ? (global const libname = "jvm") : nothing function findjvm() javahomes = Any[] libpaths = Any[] @@ -83,12 +83,12 @@ immutable JavaVMInitArgs end -@unix_only const sep = ":" -@windows_only const sep = ";" -cp=Array(ByteString, 0) -opts=Array(ByteString, 0) -addClassPath(s::ByteString) = isloaded()?warn("JVM already initialised. This call has no effect"): push!(cp, s) -addOpts(s::ByteString) = isloaded()?warn("JVM already initialised. This call has no effect"): push!(opts, s) +@static is_unix() ? (const sep = ":") : nothing +@static is_windows() ? (const sep = ";") : nothing +cp=Array(String, 0) +opts=Array(String, 0) +addClassPath(s::String) = isloaded()?warn("JVM already initialised. This call has no effect"): push!(cp, s) +addOpts(s::String) = isloaded()?warn("JVM already initialised. This call has no effect"): push!(opts, s) init() = init(vcat(opts, reduce((x,y)->string(x,sep,y),"-Djava.class.path=$(cp[1])",cp[2:end]) )) From e81d644c6702c9ce5292f058efcd21a0a5dfca26 Mon Sep 17 00:00:00 2001 From: Abhijith Date: Tue, 21 Jun 2016 17:18:38 +0530 Subject: [PATCH 16/21] pin Compat --- REQUIRE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/REQUIRE b/REQUIRE index dd0e1ae..6269995 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1,4 +1,4 @@ julia 0.3 Memoize -Compat +Compat 0.7.20 Dates From 6bb2306635ca2fc633a053f216c3a52971004a5f Mon Sep 17 00:00:00 2001 From: Avik Sengupta Date: Wed, 29 Jun 2016 22:06:15 +0100 Subject: [PATCH 17/21] remove memoize dependency --- REQUIRE | 1 - src/core.jl | 32 +++++++++++++++++++++----------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/REQUIRE b/REQUIRE index 6269995..dfe2548 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1,4 +1,3 @@ julia 0.3 -Memoize Compat 0.7.20 Dates diff --git a/src/core.jl b/src/core.jl index 02e4c3a..732a34b 100644 --- a/src/core.jl +++ b/src/core.jl @@ -5,7 +5,7 @@ typealias jint Cint # typedef long jlong; typealias jlong Clonglong typealias jbyte Cchar - + # jni.h typealias jboolean Cuchar @@ -20,17 +20,17 @@ immutable JavaMetaClass{T} ptr::Ptr{Void} end -#The metaclass, sort of equivalent to a the +#The metaclass, sort of equivalent to a the JavaMetaClass(T, ptr) = JavaMetaClass{T}(ptr) type JavaObject{T} ptr::Ptr{Void} - + function JavaObject(ptr) j=new(ptr) finalizer(j, deleteref) return j - end + end JavaObject(argtypes::Tuple, args...) = jnew(T, argtypes, args...) @@ -85,7 +85,7 @@ function JString(str::AbstractString) jstring = ccall(jnifunc.NewStringUTF, Ptr{Void}, (Ptr{JNIEnv}, Ptr{UInt8}), penv, utf8(str)) if jstring == C_NULL geterror() - else + else return JString(jstring) end end @@ -128,15 +128,15 @@ function jcall{T}(typ::Type{JavaObject{T}}, method::AbstractString, rettype::Typ try gc_enable(false) sig = method_signature(rettype, argtypes...) - + jmethodId = ccall(jnifunc.GetStaticMethodID, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{UInt8}, Ptr{UInt8}), penv, metaclass(T), utf8(method), sig) if jmethodId==C_NULL; geterror(true); end - + _jcall(metaclass(T), jmethodId, C_NULL, rettype, argtypes, args...) finally gc_enable(true) end - + end # Call instance methods @@ -173,7 +173,7 @@ for (x, y, z) in [ (:jboolean, :(jnifunc.GetBooleanField), :(jnifunc.GetStaticBo (:jfloat, :(jnifunc.GetFloatField), :(jnifunc.GetStaticFloatField)), (:jdouble, :(jnifunc.GetDoubleField), :(jnifunc.GetStaticDoubleField)) ] - m = quote + m = quote function _jfield(obj, jfieldID::Ptr{Void}, fieldType::Type{$(x)}) callmethod = ifelse( typeof(obj)<:JavaObject, $y , $z ) result = ccall(callmethod, $x, (Ptr{JNIEnv}, Ptr{Void}, Ptr{Void}), penv, obj.ptr, jfieldID) @@ -237,13 +237,23 @@ function _jcall(obj, jmethodId::Ptr{Void}, callmethod::Ptr{Void}, rettype::Type return convert_result(rettype, result) end -@memoize function metaclass(class::Symbol) + +global const _jmc_cache = Dict{Symbol, JavaMetaClass}() + +function _metaclass(class::Symbol) jclass=javaclassname(class) jclassptr = ccall(jnifunc.FindClass, Ptr{Void}, (Ptr{JNIEnv}, Ptr{UInt8}), penv, jclass) if jclassptr == C_NULL; error("Class Not Found $jclass"); end return JavaMetaClass(class, jclassptr) end +function metaclass(class::Symbol) + if !haskey(_jmc_cache, class) + _jmc_cache[class] = _metaclass(class) + end + return _jmc_cache[class] +end + metaclass{T}(::Type{JavaObject{T}}) = metaclass(T) metaclass{T}(::JavaObject{T}) = metaclass(T) @@ -251,7 +261,7 @@ javaclassname(class::Symbol) = utf8(replace(string(class), '.', '/')) function geterror(allow=false) isexception = ccall(jnifunc.ExceptionCheck, jboolean, (Ptr{JNIEnv},), penv ) - + if isexception == JNI_TRUE jthrow = ccall(jnifunc.ExceptionOccurred, Ptr{Void}, (Ptr{JNIEnv},), penv) if jthrow==C_NULL ; error("Java Exception thrown, but no details could be retrieved from the JVM"); end From 414ab6d481af16db92ae28bb8a8c655a7a0f9ed1 Mon Sep 17 00:00:00 2001 From: Avik Sengupta Date: Sun, 3 Jul 2016 22:56:05 +0100 Subject: [PATCH 18/21] Remove 0.3 support. Fix 0.5 deprecations --- .travis.yml | 1 - REQUIRE | 5 ++--- appveyor.yml | 4 ---- src/JavaCall.jl | 26 ++++++++++---------------- src/convert.jl | 36 +++++++++++++++++++++++------------- src/core.jl | 18 +++++++++--------- src/jvm.jl | 37 +++++++++++++++++++++++-------------- test/runtests.jl | 12 ++++++------ 8 files changed, 73 insertions(+), 66 deletions(-) diff --git a/.travis.yml b/.travis.yml index 94487fd..72af786 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ language: julia os: - linux julia: - - 0.3 - 0.4 - nightly notifications: diff --git a/REQUIRE b/REQUIRE index dfe2548..2e03691 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1,3 +1,2 @@ -julia 0.3 -Compat 0.7.20 -Dates +julia 0.4 +Compat 0.8.4 diff --git a/appveyor.yml b/appveyor.yml index eeb8fb1..eaa4416 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,9 +1,5 @@ environment: matrix: - - JULIAVERSION: "julialang/bin/winnt/x86/0.3/julia-0.3-latest-win32.exe" - JAVA_HOME: C:\Program Files (x86)\Java\jdk1.7.0\ - - JULIAVERSION: "julialang/bin/winnt/x64/0.3/julia-0.3-latest-win64.exe" - JAVA_HOME: C:\Program Files\Java\jdk1.7.0\ - JULIAVERSION: "julialang/bin/winnt/x86/0.4/julia-0.4-latest-win32.exe" JAVA_HOME: C:\Program Files (x86)\Java\jdk1.7.0\ - JULIAVERSION: "julialang/bin/winnt/x64/0.4/julia-0.4-latest-win64.exe" diff --git a/src/JavaCall.jl b/src/JavaCall.jl index 0907080..4cb349b 100644 --- a/src/JavaCall.jl +++ b/src/JavaCall.jl @@ -6,28 +6,22 @@ export JavaObject, JavaMetaClass, getname, listmethods, getreturntype, getparametertypes # using Debug -using Memoize +using Base.Dates using Compat import Compat.String -import Base.bytestring, Base.convert +import Base.convert, Base.isnull, Base.unsafe_convert -if VERSION < v"0.4.0-dev+656" - import Compat.isnull -else - import Base.isnull -end - -if VERSION < v"0.4-" - using Dates -else - using Base.Dates -end +# if VERSION < v"0.5.0-dev+4612" +# const unsafe_string = Base.bytestring +# else +# const unsafe_string = Base.unsafe_string +# end -if VERSION < v"0.4-" - const unsafe_convert = Base.convert +if VERSION < v"0.5.0-dev+4612" + import Compat.unsafe_string else - const unsafe_convert = Base.unsafe_convert + import Base.unsafe_string end diff --git a/src/convert.jl b/src/convert.jl index 9f4e4b7..e4cfd67 100644 --- a/src/convert.jl +++ b/src/convert.jl @@ -2,23 +2,23 @@ convert{T<:AbstractString}(::Type{JString}, str::T) = JString(str) convert{T<:AbstractString}(::Type{JObject}, str::T) = convert(JObject, JString(str)) #Cast java object from S to T . Needed for polymorphic calls -function convert{T,S}(::Type{JavaObject{T}}, obj::JavaObject{S}) +function convert{T,S}(::Type{JavaObject{T}}, obj::JavaObject{S}) if isConvertible(T, S) #Safe static cast ptr = ccall(jnifunc.NewLocalRef, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}), penv, obj.ptr) if ptr === C_NULL geterror() end return JavaObject{T}(ptr) - end + end if isnull(obj) ; error("Cannot convert NULL"); end realClass = ccall(jnifunc.GetObjectClass, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void} ), penv, obj.ptr) if isConvertible(T, realClass) #dynamic cast ptr = ccall(jnifunc.NewLocalRef, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}), penv, obj.ptr) if ptr === C_NULL geterror() end return JavaObject{T}(ptr) - end + end error("Cannot cast java object from $S to $T") end -#Is java type convertible from S to T. +#Is java type convertible from S to T. isConvertible(T, S) = (ccall(jnifunc.IsAssignableFrom, jboolean, (Ptr{JNIEnv}, Ptr{Void}, Ptr{Void}), penv, metaclass(S), metaclass(T) ) == JNI_TRUE) isConvertible(T, S::Ptr{Void} ) = (ccall(jnifunc.IsAssignableFrom, jboolean, (Ptr{JNIEnv}, Ptr{Void}, Ptr{Void}), penv, S, metaclass(T) ) == JNI_TRUE) @@ -34,7 +34,6 @@ function real_jtype(rettype) return jnitype end - function convert_args(argtypes::Tuple, args...) convertedArgs = Array(Int64, length(args)) savedArgs = Array(Any, length(args)) @@ -91,7 +90,7 @@ function convert_arg{T<:JavaObject}(argtype::Type{Array{T,1}}, arg) return carg, arrayptr end -convert_result{T<:JString}(rettype::Type{T}, result) = bytestring(JString(result)) +convert_result{T<:JString}(rettype::Type{T}, result) = unsafe_string(JString(result)) convert_result{T<:JavaObject}(rettype::Type{T}, result) = T(result) convert_result(rettype, result) = result @@ -107,7 +106,7 @@ for (x, y, z) in [ (:jboolean, :(jnifunc.GetBooleanArrayElements), :(jnifunc.Rel function convert_result(rettype::Type{Array{$(x),1}}, result) sz = ccall(jnifunc.GetArrayLength, jint, (Ptr{JNIEnv}, Ptr{Void}), penv, result) arr = ccall($(y), Ptr{$(x)}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{jboolean} ), penv, result, C_NULL ) - jl_arr::Array = pointer_to_array(arr, (@compat Int(sz)), false) + jl_arr::Array = unsafe_wrap(Array, arr, (@compat Int(sz)), false) jl_arr = deepcopy(jl_arr) ccall($(z), Void, (Ptr{JNIEnv},Ptr{Void}, Ptr{$(x)}, jint), penv, result, arr, 0) return jl_arr @@ -118,9 +117,9 @@ end function convert_result{T}(rettype::Type{Array{JavaObject{T},1}}, result) sz = ccall(jnifunc.GetArrayLength, jint, (Ptr{JNIEnv}, Ptr{Void}), penv, result) - + ret = Array(JavaObject{T}, sz) - + for i=1:sz a=ccall(jnifunc.GetObjectArrayElement, Ptr{Void}, (Ptr{JNIEnv},Ptr{Void}, jint), penv, result, i-1) ret[i] = JavaObject{T}(a) @@ -165,15 +164,26 @@ convert{X,Y}(::Type{@jimport(java.util.Map)}, K::Type{JavaObject{X}}, V::Type{Ja # Convert a reference to a java.lang.String into a Julia string. Copies the underlying byte buffer -function bytestring(jstr::JString) #jstr must be a jstring obtained via a JNI call +function unsafe_string(jstr::JString) #jstr must be a jstring obtained via a JNI call if isnull(jstr); return ""; end #Return empty string to keep type stability. But this is questionable pIsCopy = Array(jboolean, 1) buf::Ptr{UInt8} = ccall(jnifunc.GetStringUTFChars, Ptr{UInt8}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{jboolean}), penv, jstr.ptr, pIsCopy) - s=bytestring(buf) + s=unsafe_string(buf) ccall(jnifunc.ReleaseStringUTFChars, Void, (Ptr{JNIEnv}, Ptr{Void}, Ptr{UInt8}), penv, jstr.ptr, buf) return s end +#This is necessary to properly deprecate bytestring in 0.5, while ensuring +# callers don't need to change for 0.4. +function Base.bytestring(jstr::JString) #jstr must be a jstring obtained via a JNI call + if VERSION >= v"0.5.0-dev+4612" + Base.depwarn("bytestring(jstr::JString) is deprecated. Use unsafe_string(jstr) instead", :bytestring ) + end + return JavaCall.unsafe_string(jstr) +end + + + for (x, y, z) in [ (:jboolean, :(jnifunc.GetBooleanArrayElements), :(jnifunc.ReleaseBooleanArrayElements)), (:jchar, :(jnifunc.GetCharArrayElements), :(jnifunc.ReleaseCharArrayElements)), @@ -185,9 +195,9 @@ for (x, y, z) in [ (:jboolean, :(jnifunc.GetBooleanArrayElements), :(jnifunc.Rel (:jdouble, :(jnifunc.GetDoubleArrayElements), :(jnifunc.ReleaseDoubleArrayElements)) ] m=quote function convert(::Type{Array{$(x),1}}, obj::JObject) - sz = ccall(jnifunc.GetArrayLength, jint, (Ptr{JNIEnv}, Ptr{Void}), penv, obj.ptr) + sz = ccall(jnifunc.GetArrayLength, jint, (Ptr{JNIEnv}, Ptr{Void}), penv, obj.ptr) arr = ccall($(y), Ptr{$(x)}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{jboolean} ), penv, obj.ptr, C_NULL ) - jl_arr::Array = pointer_to_array(arr, (@compat Int(sz)), false) + jl_arr::Array = unsafe_wrap(Array, arr, (@compat Int(sz)), false) jl_arr = deepcopy(jl_arr) ccall($(z), Void, (Ptr{JNIEnv},Ptr{Void}, Ptr{$(x)}, jint), penv, obj.ptr, arr, 0) return jl_arr diff --git a/src/core.jl b/src/core.jl index 732a34b..3d25faa 100644 --- a/src/core.jl +++ b/src/core.jl @@ -82,7 +82,7 @@ typealias JMethod JavaObject{Symbol("java.lang.reflect.Method")} typealias JString JavaObject{Symbol("java.lang.String")} function JString(str::AbstractString) - jstring = ccall(jnifunc.NewStringUTF, Ptr{Void}, (Ptr{JNIEnv}, Ptr{UInt8}), penv, utf8(str)) + jstring = ccall(jnifunc.NewStringUTF, Ptr{Void}, (Ptr{JNIEnv}, Ptr{UInt8}), penv, String(str)) if jstring == C_NULL geterror() else @@ -110,13 +110,13 @@ macro jimport(class) end juliaclass = replace(juliaclass, " ", "") #handle $ for innerclass quote - JavaObject{(Base.symbol($juliaclass))} + JavaObject{(Base.Symbol($juliaclass))} end end function jnew(T::Symbol, argtypes::Tuple, args...) sig = method_signature(Void, argtypes...) - jmethodId = ccall(jnifunc.GetMethodID, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{UInt8}, Ptr{UInt8}), penv, metaclass(T), utf8(""), sig) + jmethodId = ccall(jnifunc.GetMethodID, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{UInt8}, Ptr{UInt8}), penv, metaclass(T), String(""), sig) if (jmethodId == C_NULL) error("No constructor for $T with signature $sig") end @@ -129,7 +129,7 @@ function jcall{T}(typ::Type{JavaObject{T}}, method::AbstractString, rettype::Typ gc_enable(false) sig = method_signature(rettype, argtypes...) - jmethodId = ccall(jnifunc.GetStaticMethodID, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{UInt8}, Ptr{UInt8}), penv, metaclass(T), utf8(method), sig) + jmethodId = ccall(jnifunc.GetStaticMethodID, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{UInt8}, Ptr{UInt8}), penv, metaclass(T), String(method), sig) if jmethodId==C_NULL; geterror(true); end _jcall(metaclass(T), jmethodId, C_NULL, rettype, argtypes, args...) @@ -144,7 +144,7 @@ function jcall(obj::JavaObject, method::AbstractString, rettype::Type, argtypes: try gc_enable(false) sig = method_signature(rettype, argtypes...) - jmethodId = ccall(jnifunc.GetMethodID, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{UInt8}, Ptr{UInt8}), penv, metaclass(obj), utf8(method), sig) + jmethodId = ccall(jnifunc.GetMethodID, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{UInt8}, Ptr{UInt8}), penv, metaclass(obj), String(method), sig) if jmethodId==C_NULL; geterror(true); end _jcall(obj, jmethodId, C_NULL, rettype, argtypes, args...) finally @@ -153,13 +153,13 @@ function jcall(obj::JavaObject, method::AbstractString, rettype::Type, argtypes: end function jfield{T}(typ::Type{JavaObject{T}}, field::AbstractString, fieldType::Type) - jfieldID = ccall(jnifunc.GetStaticFieldID, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{UInt8}, Ptr{UInt8}), penv, metaclass(T), utf8(field), signature(fieldType)) + jfieldID = ccall(jnifunc.GetStaticFieldID, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{UInt8}, Ptr{UInt8}), penv, metaclass(T), String(field), signature(fieldType)) if jfieldID==C_NULL; geterror(true); end _jfield(metaclass(T), jfieldID, fieldType) end function jfield(obj::JavaObject, field::AbstractString, fieldType::Type) - jfieldID = ccall(jnifunc.GetFieldID, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{UInt8}, Ptr{UInt8}), penv, metaclass(obj), utf8(field), signature(fieldType)) + jfieldID = ccall(jnifunc.GetFieldID, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{UInt8}, Ptr{UInt8}), penv, metaclass(obj), String(field), signature(fieldType)) if jfieldID==C_NULL; geterror(true); end _jfield(obj, jfieldID, fieldType) end @@ -257,7 +257,7 @@ end metaclass{T}(::Type{JavaObject{T}}) = metaclass(T) metaclass{T}(::JavaObject{T}) = metaclass(T) -javaclassname(class::Symbol) = utf8(replace(string(class), '.', '/')) +javaclassname(class::Symbol) = replace(string(class), '.', '/') function geterror(allow=false) isexception = ccall(jnifunc.ExceptionCheck, jboolean, (Ptr{JNIEnv},), penv ) @@ -273,7 +273,7 @@ function geterror(allow=false) if jmethodId==C_NULL; error("Java Exception thrown, but no details could be retrieved from the JVM"); end res = ccall(jnifunc.CallObjectMethodA, Ptr{Void}, (Ptr{JNIEnv}, Ptr{Void}, Ptr{Void}, Ptr{Void}), penv, jthrow, jmethodId,C_NULL) if res==C_NULL; error("Java Exception thrown, but no details could be retrieved from the JVM"); end - msg = bytestring(JString(res)) + msg = unsafe_string(JString(res)) ccall(jnifunc.DeleteLocalRef, Void, (Ptr{JNIEnv}, Ptr{Void}), penv, jthrow) error(string("Error calling Java: ",msg)) else diff --git a/src/jvm.jl b/src/jvm.jl index d4d9cac..9e4f75c 100644 --- a/src/jvm.jl +++ b/src/jvm.jl @@ -17,17 +17,17 @@ const JNI_EEXIST = convert(Cint, -5) #/* VM already created * const JNI_EINVAL = convert(Cint, -6) #/* invalid arguments */ -@static is_unix() ? (global const libname = "libjvm") : nothing -@static is_windows() ? (global const libname = "jvm") : nothing +@static is_unix() ? (global const libname = "libjvm") : (global const libname = "jvm") + function findjvm() javahomes = Any[] libpaths = Any[] - + if haskey(ENV,"JAVA_HOME") push!(javahomes,ENV["JAVA_HOME"]) end if isfile("/usr/libexec/java_home") - push!(javahomes,chomp(readall(`/usr/libexec/java_home`))) + push!(javahomes,chomp(readstring(`/usr/libexec/java_home`))) end if isdir("/usr/lib/jvm/default-java/") @@ -36,15 +36,24 @@ function findjvm() push!(libpaths,pwd()) for n in javahomes - @windows_only push!(libpaths, joinpath(n, "jre", "bin", "server")) - @windows_only push!(libpaths, joinpath(n, "bin", "client")) - @linux_only if WORD_SIZE==64; push!(libpaths, joinpath(n, "jre", "lib", "amd64", "server")); end - @linux_only if WORD_SIZE==32; push!(libpaths, joinpath(n, "jre", "lib", "i386", "server")); end + @static if is_windows() + push!(libpaths, joinpath(n, "jre", "bin", "server")) + push!(libpaths, joinpath(n, "bin", "client")) + end + @static if is_linux() + if WORD_SIZE==64 + push!(libpaths, joinpath(n, "jre", "lib", "amd64", "server")) + elseif WORD_SIZE==32 + push!(libpaths, joinpath(n, "jre", "lib", "i386", "server")) + end + end push!(libpaths, joinpath(n, "jre", "lib", "server")) end - - ext = "."*@windows? "dll":@osx? "dylib":"so" - try + + ext = @static is_windows()?"dll":(@static is_apple()?"dylib":"so") + ext = "."*ext + + try for n in libpaths libpath = joinpath(n,libname*ext); if isfile(libpath) @@ -56,7 +65,7 @@ function findjvm() end errorMsg = - [ + [ "Cannot find java library $libname$ext\n", "Search Path:" ]; @@ -70,7 +79,7 @@ end -immutable JavaVMOption +immutable JavaVMOption optionString::Ptr{UInt8} extraInfo::Ptr{Void} end @@ -107,7 +116,7 @@ function init{T<:AbstractString}(opts::Array{T, 1}) ppjvm=Array(Ptr{JavaVM},1) ppenv=Array(Ptr{JNIEnv},1) vm_args = JavaVMInitArgs(JNI_VERSION_1_6, convert(Cint, length(opts)), convert(Ptr{JavaVMOption}, pointer(opt)), JNI_TRUE) - + res = ccall(create, Cint, (Ptr{Ptr{JavaVM}}, Ptr{Ptr{JNIEnv}}, Ptr{JavaVMInitArgs}), ppjvm, ppenv, &vm_args) if res < 0; error("Unable to initialise Java VM: $(res)"); end global penv = ppenv[1] diff --git a/test/runtests.jl b/test/runtests.jl index a6cfc4a..9253f8f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -6,13 +6,13 @@ using Compat versioninfo(); # JavaCall.init(["-Djava.class.path=$(joinpath(Pkg.dir(), "JavaCall", "test"))"]) -JavaCall.init(["-verbose:jni", "-verbose:gc","-Djava.class.path=$(joinpath(Pkg.dir(), "JavaCall", "test"))"]) +JavaCall.init(["-verbose:gc","-Djava.class.path=$(joinpath(Pkg.dir(), "JavaCall", "test"))"]) a=JString("how are you") @test a.ptr != C_NULL @test 11==ccall(JavaCall.jnifunc.GetStringUTFLength, jint, (Ptr{JavaCall.JNIEnv}, Ptr{Void}), JavaCall.penv, a.ptr) b=ccall(JavaCall.jnifunc.GetStringUTFChars, Ptr{UInt8}, (Ptr{JavaCall.JNIEnv}, Ptr{Void}, Ptr{Void}), JavaCall.penv, a.ptr, C_NULL) -@test bytestring(b) == "how are you" +@test unsafe_string(b) == "how are you" # Test parameter passing T = @jimport Test @@ -68,9 +68,9 @@ a=jcall(j_u_arrays, "copyOf", Array{jint, 1}, (Array{jint, 1}, jint), [1,2,3], 3 a=jcall(j_u_arrays, "copyOf", Array{JObject, 1}, (Array{JObject, 1}, jint), ["a","b","c"], 3) @test 3==length(a) -@test "a"==bytestring(convert(JString, a[1])) -@test "b"==bytestring(convert(JString, a[2])) -@test "c"==bytestring(convert(JString, a[3])) +@test "a"==unsafe_string(convert(JString, a[1])) +@test "b"==unsafe_string(convert(JString, a[2])) +@test "c"==unsafe_string(convert(JString, a[3])) #Test for Dates @@ -146,7 +146,7 @@ for i=1:100; @test jcall(ta_20[i], "size", jint, ()) == 0; end # Test array conversions jobj = jcall(T, "testArrayAsObject", JObject, ()) arr = convert(Array{Array{UInt8, 1}, 1}, jobj) -@test ["Hello", "World"] == map(bytestring, arr) +@test ["Hello", "World"] == map(Compat.String, arr) # At the end, unload the JVM before exiting From 84e4469cd794f3011e8d86acfd21fe17b57df208 Mon Sep 17 00:00:00 2001 From: Avik Sengupta Date: Sun, 3 Jul 2016 23:02:08 +0100 Subject: [PATCH 19/21] Add 0.5 badge to Readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c52f362..8dd00e2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # JavaCall -[![Build Status](https://travis-ci.org/aviks/JavaCall.jl.png)](https://travis-ci.org/aviks/JavaCall.jl) [![Build status](https://ci.appveyor.com/api/projects/status/xdkfd0t8r3oqeio9?svg=true)](https://ci.appveyor.com/project/aviks/javacall-jl) [![JavaCall](http://pkg.julialang.org/badges/JavaCall_0.3.svg)](http://pkg.julialang.org/?pkg=JavaCall&ver=release) [![JavaCall](http://pkg.julialang.org/badges/JavaCall_0.4.svg)](http://pkg.julialang.org/?pkg=JavaCall&ver=nightly) +[![Build Status](https://travis-ci.org/aviks/JavaCall.jl.png)](https://travis-ci.org/aviks/JavaCall.jl) [![Build status](https://ci.appveyor.com/api/projects/status/xdkfd0t8r3oqeio9?svg=true)](https://ci.appveyor.com/project/aviks/javacall-jl) [![JavaCall](http://pkg.julialang.org/badges/JavaCall_0.3.svg)](http://pkg.julialang.org/?pkg=JavaCall) [![JavaCall](http://pkg.julialang.org/badges/JavaCall_0.4.svg)](http://pkg.julialang.org/?pkg=JavaCall) [![JavaCall](http://pkg.julialang.org/badges/JavaCall_0.5.svg)](http://pkg.julialang.org/?pkg=JavaCall) + Call Java programs from Julia. From 13e88b03d2188b1e383df728d58bb77061f41372 Mon Sep 17 00:00:00 2001 From: AndyGreenwell Date: Fri, 15 Apr 2016 19:49:08 -0400 Subject: [PATCH 20/21] Look-up value for JavaHome through Windows registry to load jvm.dll --- src/JavaCall.jl | 4 +--- src/jvm.jl | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/JavaCall.jl b/src/JavaCall.jl index 4cb349b..5f7ca40 100644 --- a/src/JavaCall.jl +++ b/src/JavaCall.jl @@ -5,10 +5,8 @@ export JavaObject, JavaMetaClass, @jimport, jcall, jfield, isnull, getname, listmethods, getreturntype, getparametertypes -# using Debug -using Base.Dates using Compat -import Compat.String +using WinReg import Base.convert, Base.isnull, Base.unsafe_convert diff --git a/src/jvm.jl b/src/jvm.jl index 9e4f75c..cb279c4 100644 --- a/src/jvm.jl +++ b/src/jvm.jl @@ -16,16 +16,26 @@ const JNI_ENOMEM = convert(Cint, -4) #/* not enough memory */ const JNI_EEXIST = convert(Cint, -5) #/* VM already created */ const JNI_EINVAL = convert(Cint, -6) #/* invalid arguments */ +function javahome_winreg() + keypath = "SOFTWARE\\JavaSoft\\Java Development Kit" + value = querykey(WinReg.HKEY_LOCAL_MACHINE, keypath, "CurrentVersion") + keypath *= "\\"*value + return querykey(WinReg.HKEY_LOCAL_MACHINE, keypath, "JavaHome") +end @static is_unix() ? (global const libname = "libjvm") : (global const libname = "jvm") function findjvm() javahomes = Any[] libpaths = Any[] - + if haskey(ENV,"JAVA_HOME") push!(javahomes,ENV["JAVA_HOME"]) + else + @static is_windows() ? ENV["JAVA_HOME"] = javahome_winreg() : nothing + @static is_windows() ? push!(javahomes, ENV["JAVA_HOME"]) : nothing end + if isfile("/usr/libexec/java_home") push!(javahomes,chomp(readstring(`/usr/libexec/java_home`))) end @@ -56,7 +66,7 @@ function findjvm() try for n in libpaths libpath = joinpath(n,libname*ext); - if isfile(libpath) + if isfile(libpath) global libjvm = Libdl.dlopen(libpath) println("Loaded $libpath") return From e6114c2810ff6640a489b291e4099842f49e434c Mon Sep 17 00:00:00 2001 From: AndyGreenwell Date: Mon, 4 Jul 2016 14:31:41 -0400 Subject: [PATCH 21/21] Fix up merge --- src/JavaCall.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/JavaCall.jl b/src/JavaCall.jl index 5f7ca40..21f5dfc 100644 --- a/src/JavaCall.jl +++ b/src/JavaCall.jl @@ -7,6 +7,7 @@ export JavaObject, JavaMetaClass, using Compat using WinReg +import Compat.string import Base.convert, Base.isnull, Base.unsafe_convert