## This file is part of the rJava package - low-level R/Java interface
## (C)2006 Simon Urbanek <[email protected]>
## For license terms see DESCRIPTION and/or LICENSE
## $Id$
# create a new object
<- (, , =, silent=!, class.loader=) {
<- ("\\.", "/", ()) # allow non-JNI specifiation
# TODO: should this do "S" > "java/lang/String", ... like .jcall
if () (silent=)
o<-(RcreateObject, , , silent=silent, class.loader=class.loader)
if () (silent=silent)
if ((o)) {
if (!silent) {
("Failed to create object of class `",,"'")
} {
o <- .jzeroRef
("jobjRef", jobj=o, jclass=)
# create a new object reference manually (avoid! for backward compat only!)
# the problem with this is that you need a valid `jobj' which
# is implementation-dependent so it is undefined outside rJava internals
# it is now used by JRI.createRJavaRef, though
.jmkref <- (jobj, jclass="java/lang/Object") {
("jobjRef", jobj=jobj, jclass=('\\.','/',(jclass)))
# evaluates an array reference. If rawJNIRefSignature is set, then obj is not assumed to be
# jarrayRef, but rather direct JNI reference with the corresponding signature
<- (obj, rawJNIRefSignature=, silent=, simplify=) {
jobj<-obj
sig<-rawJNIRefSignature
if ((rawJNIRefSignature)) {
(!(obj,"jarrayRef"
)) {
if (!(obj,"jobjRef"))
("object is not a Java object reference (jobjRef/jarrayRef).")
cl <- ("\\.","/",.jclass(obj))
if ((cl) || !isJavaArraySignature(cl) )
("object is not a Java array.")
sig <- cl
} sig <- obj@jsig
jobj<-obj@jobj
} if ((obj, "jobjRef")) jobj<-obj@jobj
if (sig=="[I")
((RgetIntArrayCont, jobj))
if (sig=="[J")
((RgetLongArrayCont, jobj))
if (sig=="[Z")
((RgetBoolArrayCont, jobj))
if (sig=="[B")
((RgetByteArrayCont, jobj))
if (sig=="[D")
((RgetDoubleArrayCont, jobj))
if (sig=="[S")
((RgetShortArrayCont, jobj))
if (sig=="[C")
((RgetCharArrayCont, jobj))
if (sig=="[F")
((RgetFloatArrayCont, jobj))
if (sig=="[Ljava/lang/String;")
((RgetStringArrayCont, jobj))
if (sig=="[Ljava/lang/Double;" && simplify) {
obj@jclass <- sig; (("RJavaArrayTools", "[D", "unboxDoubles", obj)) }
if (sig=="[Ljava/lang/Integer;" && simplify) {
obj@jclass <- sig; (("RJavaArrayTools", "[I", "unboxIntegers", obj)) }
if (sig=="[Ljava/lang/Boolean;" && simplify) {
obj@jclass <- sig; ((("RJavaArrayTools", "[I", "unboxBooleans", obj))) }
if ((sig,1,2)=="[L")
(((RgetObjectArrayCont, jobj),
(x) ("jobjRef", jobj=x, jclass=(sig, 3, (sig)-1)) ))
if ((sig,1,2)=="[[") {
if (simplify) { # try to figure out if this is a rectangular array in which case we can do better
o <- newArray(simplify=, jobj=jobj, =sig)
# if o is not a reference then we were able to simplify it
if (!(o, "jobjRef")) (o)
# otherwise simplify has no effect
(((RgetObjectArrayCont, jobj),
(x) newArray(jobj=x, =(sig, 2, 999), simplify=simplify)))
# if we don't know how to evaluate this, issue a warning and return the jarrayRef
if (!silent)
(("I don't know how to evaluate an array with signature",sig,". Returning a reference."))
newArray(jobj = jobj, = sig, simplify = )
<- (obj, returnSig="V", method, , evalArray=,
evalString=, =, interface="RcallMethod",
simplify=, use.true.class = ) {
if () ()
iaddr <- .env[interface]]
interface <- if ((iaddr)) (interface, "rJava", , )$address iaddr
r<-
# S is a shortcut for Ljava/lang/String;
if (returnSig=="S")
returnSig<-"Ljava/lang/String;"
if (returnSig=="[S")
returnSig<-"[Ljava/lang/String;"
# original S (short) is now mapped to T so we need to re-map it (we don't really support short, though)
if (returnSig=="T") returnSig <- "S"
if (returnSig=="[T") returnSig <- "[S"
if ((obj,"jobjRef") || (obj,"jarrayRef") || (obj,"jrectRef") )
r<-(interface, obj@jobj, returnSig, method, )
r<-(interface, (obj), returnSig, method, )
if (returnSig=="V") (())
( use.true.class && !( r ) ){
( ! ( isPrimitiveTypeName(returnSig) || isArraySignature(returnSig) ) ){
# avoid calling .jcall since we work on external pointers directly here
clazz <- (interface, r , "Ljava/lang/Class;", "getClass")
clazzname <- (interface, clazz, "Ljava/lang/String;", "getName")
clazzname <- (RgetStringValue, clazzname)
returnSig <- tojniSignature( clazzname )
if (isJavaArraySignature(returnSig)) {
# eval or return a reference
r <- if (evalArray) (r, rawJNIRefSignature=returnSig, simplify=simplify) newArray(jobj = r, = returnSig, simplify = )
} if ( (returnSig,1,1)=="L") {
if (
(r)){
( ) ( silent = )
(r)
if (returnSig=="Ljava/lang/String;" && evalString){
( ) ( silent = )
((RgetStringValue, r))
r <- ("jobjRef", jobj=r, jclass=(returnSig,2,(returnSig)-1))
if () ()
if (.conv.in$.) .convert.in(r) r
.jstrVal <- (obj) {
# .jstrVal(.jstrVal(...)) = .jstrVal(...)
if ((obj))
(obj)
r<-
if (!(obj,"jobjRef"))
("can get value of Java objects only")
if (!(obj@jclass) && obj@jclass=="lang/java/String")
r<-(RgetStringValue, obj@jobj)
r<-(RtoString, obj@jobj)
#' casts java object into new.class
#' @param obj a java object reference
#' @param new.class the new class (in JNI or Java)
#' @param check logical. If TRUE the cast if checked
#' @param convert.array logical. If TRUE and the new class represents an array, then a jarrayRef object is made
<- (obj, new.class="java/lang/Object", = , convert.array = ) {
if (!(obj,"jobjRef"))
("cannot cast anything but Java objects")
( && !( obj, new.class) ){
( ( "cannot cast object to '%s'", new.class ) )
new.class <- ("\\.","/", (new.class)) # allow non-JNI specifiation
( convert.array && !( obj, "jarrayRef" ) && isJavaArray( obj ) ){
r <- ( obj, = new.class)
} {
r <- obj
r@jclass <- new.class
# makes sure that a given object is jarrayRef
<- (obj, =, ="", quiet=) {
if (!(obj, "jobjRef"))
((obj))
if (()) {
# TODO: factor out these two calls into a separate function
cl <- (obj, "Ljava/lang/Class;", "getClass")
cn <- (cl, "Ljava/lang/String;", "getName")
if ( !isJavaArraySignature(cn) ) {
if (quiet)
(obj)
("cannot cast to array, object signature is unknown and class name is not an array")
<- cn
} {
( !isJavaArraySignature() ){
( quiet ) {
( obj )
} {
( "cannot cast to array, signature is not an array signature" )
<- ('\\.', '/', )
if ((obj, "jarrayRef")) {
obj@jsig <-
(obj)
newArray(obj, simplify=)
# creates a new "null" object of the specified class
# although it sounds weird, the class is important when passed as
# a parameter (you can even cast the result)
<- (="java/lang/Object") {
("jobjRef", jobj=.jzeroRef, jclass=())
<- (silent=) ((RJavaCheckExceptions, silent))
.jproperty <- (key) {
if ((key)>1)
(key, .jproperty)
("java/lang/System", "S", "getProperty", (key)[1])
#' gets the dim of an array, or its length if it is just a vector
getDim <- (x){
<- (x)
( ( ) ) <- (x)
<- (x, contents.class = , dispatch = ) {
# this already is an array, so don't bother
( isJavaArray( x ) ) ( newArray( x, simplify = ) )
# this is a two stage process, first we need to convert into
# a flat array using the jni code
# TODO: but this needs to move to the internal jni world to avoid
# too many copies
# common mistake is to not specify a list but just a single Java object
# but, well, people just keep doing it so we may as well support it
<- if ((x,"jobjRef")) {
x <- (x)
} getDim(x)
# the jni call
<- (RcreateArray, x, contents.class)
if (!dispatch) ( )
( ( x ) ){
# if the input of RcreateArray was a list, we need some more care
# because we cannot be sure the array is rectangular so we have to
# check it
newArray( , simplify = )
} {
# then we transform this to a rectangular array of the proper dimensions
( ( ) == 1L ) {
# single dimension array
( "jrectRef", jobj = @jobj, jsig = @jsig,
jclass = @jclass, dimension = )
} {
builder <- ( "RectangularArrayBuilder", (
), )
clazz <- ( builder, "Ljava/lang/String;", "getArrayClassName" )
# we cannot use .jcall here since it will try to simplify the array
# or go back to java to calculate its dimensions, ...
r <- ( RcallMethod, builder@jobj,
"Ljava/lang/Object;", "getArray" )
( "jrectRef", jobj = r, dimension = ,
jclass = clazz, jsig = tojni( clazz ) )
# works on EXTPTR or jobjRef or NULL. NULL is always silently converted to .jzeroRef
.jidenticalRef <- (a,b) {
if ((a,"jobjRef")) a<-a@jobj
if ((b,"jobjRef")) b<-b@jobj
if ((a)) a <- .jzeroRef
if ((b)) b <- .jzeroRef
if (!(a,"externalptr") || !(b,"externalptr")) ("Invalid argument to .jidenticalRef, must be a pointer or jobjRef")
(RidenticalRef,a,b)
# returns TRUE only for NULL or jobjRef with jobj=0x0
<- (x) {
((x) || ((x,"jobjRef") && .jidenticalRef(x@jobj,.jzeroRef)))
# should we move this to C?
.jclassRef <- (x, silent=) {
if ((x)) {
if (silent) () ("null reference has no class")
if (!(x, "jobjRef")) {
if (silent) () ("invalid object")
cl <-
(cl <- (x, "Ljava/lang/Class;", "getClass", =))
(silent=)
if ((cl) && !silent) ("cannot get class object")
# return class object for a given class name; silent determines whether
# an error should be thrown on failure (FALSE) or just null reference (TRUE)
.jfindClass <- (cl, silent=, class.loader=.rJava.class.loader) {
if ((cl, "jclassName")) (cl@jobj)
if (!(cl) || (cl)!=1)
("invalid class name")
cl<-("/",".",cl)
a <-
if (!(class.loader))
(a <- ("java/lang/Class","Ljava/lang/Class;","forName",cl,,(class.loader, "java.lang.ClassLoader"), =))
(a <- ("java/lang/Class","Ljava/lang/Class;","forName",cl,=
))
# this is really .jcheck but we don't want it to appear on the call stack
(RJavaCheckExceptions, silent)
if (!silent && (a)) ("class not found")
# Java-side inheritance check; NULL inherits from any class, because
# it can be cast to any class type; cl can be a class name or a jobjRef to a class object
.jinherits <- (o, cl, class.loader=.rJava.class.loader) {
if ((o)) ()
if (!(o, "jobjRef")) ("invalid object")
if ((cl)) cl <- .jfindClass(cl, class.loader=class.loader) if ((cl, "jclassName")) cl <- cl@jobj
if (!(cl, "jobjRef")) ("invalid class object")
ocl <- .jclassRef(o)
(RisAssignableFrom, ocl@jobj, cl@jobj)
# compares two things which may be Java objects. invokes Object.equals if applicable and thus even different pointers can be equal. if one parameter is not Java object, but scalar string/int/number/boolean then a corresponding Java object is created for comparison
# strict comparison returns FALSE if Java-reference is compared with non-reference. otherwise conversion into Java scalar object is attempted
<- (a, b, strict=) {
if ((a)) a <- ("jobjRef")
if ((b)) b <- ("jobjRef")
if ((a,"jobjRef")) o <- a
if ((b,"jobjRef")) { o <- b; b <- a }
((a,b))
if (!(b,"jobjRef")) {
if (strict) ()
if ((b)!=1) { ("comparison of non-scalar values is always FALSE"); () }
if ((b)) b <- ("java/lang/String",b)
if ((b)) b <- ("java/lang/Integer",b)
if ((b)) b <- ("java/lang/Double",b)
if ((b)) b <- ("java/lang/Boolean", b)
{ ("comparison of non-trivial values to Java objects is always FALSE"); () }
if ((a))
(b)
(o, "Z", "equals", (b, "java/lang/Object"))
<- (o, sig=, , true.class=(sig), convert=) {
if ((sig)) {
if (sig=='S') sig<-"Ljava/lang/String;"
if (sig=='T') sig<-"S"
if (sig=='[S') sig<-"[Ljava/lang/String;"
if (sig=='[T') sig<-"[S"
r <- (RgetField, o, sig, (), (true.class))
if ((r, "jobjRef")) {
if (isJavaArraySignature(r@jclass)) {
r <- if (convert) (r, rawJNIRefSignature=r@jclass, simplify=) newArray(r, simplify=)
if (convert && (r, "jobjRef")) {
if (r@jclass == "java/lang/String")
((RgetStringValue, r@jobj))
if (.conv.in$.) (.convert.in(r))
".jfield<-" <- (o, , value)
(RsetField, o, , value)