Skip to content

Commit 1ba3c6c

Browse files
expose (and cache) RJavaTools to the jni world
git-svn-id: svn://svn.rforge.net/rJava/trunk@490 634b503b-a89c-4e0f-88f7-82c2bf7838a2
1 parent af28bad commit 1ba3c6c

7 files changed

Lines changed: 250 additions & 49 deletions

File tree

R/jinit.R

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,10 @@
147147
pe[[x]] <- .env[[x]]
148148
lockBinding(x, pe)
149149
}
150-
}
150+
}
151+
152+
# init the cached RJavaTools class in the jni side
153+
.Call( "initRJavaTools", PACKAGE = "rJava" )
151154

152155
import( c( "java.lang", "java.util") )
153156

man/java-tools.Rd

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,12 @@ J("RJavaTools_Test")$runtests()
1010
J("RJavaArrayTools_Test")$runtests()
1111
J("ArrayWrapper_Test")$runtests()
1212
J("RectangularArrayBuilder_Test")$runtests()
13+
14+
# now testing some jni functions
15+
p <- .jnew( "java/awt/Point" )
16+
classes <- .Call( "RgetSimpleClassNames", p@jobj, TRUE, PACKAGE = "rJava" )
17+
stopifnot( all( c( "Point", "Point2D", "Object", "error", "condition" ) \%in\% classes ) )
18+
classes <- .Call( "RgetSimpleClassNames", p@jobj, FALSE, PACKAGE = "rJava" )
19+
stopifnot( all( c( "Point", "Point2D", "Object" ) \%in\% classes ) )
1320
}
1421
}

src/arrayc.c

Lines changed: 114 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -38,51 +38,15 @@ REPC SEXP RgetObjectArrayCont(SEXP e) {
3838
return ar;
3939
}
4040

41-
/** get contents of the object array in the form of int* */
41+
/** get contents of the object array in the form of STRSXP vector */
4242
REPC SEXP RgetStringArrayCont(SEXP e) {
43-
SEXP ar;
44-
jarray o;
45-
int l,i;
46-
const char *c;
47-
JNIEnv *env=getJNIEnv();
48-
49-
profStart();
43+
SEXP ar = R_NilValue ;
5044
if (e==R_NilValue) return R_NilValue;
5145
if (TYPEOF(e)==EXTPTRSXP) {
5246
jverify(e);
53-
o=(jobject)EXTPTR_PTR(e);
47+
ar = getStringArrayCont( (jarray)EXTPTR_PTR(e) ) ;
5448
} else
5549
error("invalid object parameter");
56-
_dbg(rjprintf("RgetStringArrayCont: jarray %x\n",o));
57-
if (!o) return R_NilValue;
58-
l=(int)(*env)->GetArrayLength(env, o);
59-
_dbg(rjprintf(" convert string array of length %d\n",l));
60-
if (l<0) return R_NilValue;
61-
PROTECT(ar=allocVector(STRSXP,l));
62-
i=0;
63-
while (i<l) {
64-
jobject sobj=(*env)->GetObjectArrayElement(env, o, i);
65-
_mp(MEM_PROF_OUT(" %08x LNEW object array element [%d]\n", (int) sobj, i))
66-
c=0;
67-
if (sobj) {
68-
/* we could (should?) check the type here ...
69-
if (!(*env)->IsInstanceOf(env, sobj, javaStringClass)) {
70-
printf(" not a String\n");
71-
} else
72-
*/
73-
c=(*env)->GetStringUTFChars(env, sobj, 0);
74-
}
75-
if (!c)
76-
SET_STRING_ELT(ar, i, R_NaString);
77-
else {
78-
SET_STRING_ELT(ar, i, mkCharUTF8(c));
79-
(*env)->ReleaseStringUTFChars(env, sobj, c);
80-
}
81-
if (sobj) releaseObject(env, sobj);
82-
i++;
83-
}
84-
UNPROTECT(1);
85-
_prof(profReport("RgetStringArrayCont[%d]:",o))
8650
return ar;
8751
}
8852

@@ -357,3 +321,114 @@ REPC SEXP RgetLongArrayCont(SEXP e) {
357321
_prof(profReport("RgetLongArrayCont[%d]:",o));
358322
return ar;
359323
}
324+
325+
326+
/* these below have been factored out of the ones above so that they
327+
can also be used internally in jni code */
328+
329+
/**
330+
* get contents of the String array in the form of STRSXP vector
331+
*
332+
* @param e a pointer to a String[] object
333+
*
334+
* @return a STRSXP vector mirroring the java array
335+
*/
336+
HIDE SEXP getStringArrayCont(jarray o) {
337+
SEXP ar;
338+
int l,i;
339+
const char *c;
340+
JNIEnv *env=getJNIEnv();
341+
342+
profStart();
343+
344+
_dbg(rjprintf("RgetStringArrayCont: jarray %x\n",o));
345+
if (!o) return R_NilValue;
346+
l=(int)(*env)->GetArrayLength(env, o);
347+
_dbg(rjprintf(" convert string array of length %d\n",l));
348+
if (l<0) return R_NilValue;
349+
PROTECT(ar=allocVector(STRSXP,l));
350+
i=0;
351+
while (i<l) {
352+
jobject sobj=(*env)->GetObjectArrayElement(env, o, i);
353+
_mp(MEM_PROF_OUT(" %08x LNEW object array element [%d]\n", (int) sobj, i))
354+
c=0;
355+
if (sobj) {
356+
/* we could (should?) check the type here ...
357+
if (!(*env)->IsInstanceOf(env, sobj, javaStringClass)) {
358+
printf(" not a String\n");
359+
} else
360+
*/
361+
c=(*env)->GetStringUTFChars(env, sobj, 0);
362+
}
363+
if (!c)
364+
SET_STRING_ELT(ar, i, R_NaString);
365+
else {
366+
SET_STRING_ELT(ar, i, mkCharUTF8(c));
367+
(*env)->ReleaseStringUTFChars(env, sobj, c);
368+
}
369+
if (sobj) releaseObject(env, sobj);
370+
i++;
371+
}
372+
UNPROTECT(1);
373+
_prof(profReport("RgetStringArrayCont[%d]:",o))
374+
return ar;
375+
}
376+
377+
378+
/**
379+
* Get the list of class names of a java object
380+
* This is a jni wrapper around the RJavaTools.getSimpleClassNames method
381+
*/
382+
HIDE jarray getSimpleClassNames( jobject o, jboolean addConditionClasses ){
383+
384+
JNIEnv *env=getJNIEnv();
385+
jarray a ;
386+
387+
profStart();
388+
a = (jarray) (*env)->CallStaticObjectMethod(env,
389+
rj_RJavaTools_Class, mid_rj_getSimpleClassNames,
390+
o, addConditionClasses ) ;
391+
_prof(profReport("getSimpleClassNames[%d]:",o)) ;
392+
return a ;
393+
}
394+
395+
/**
396+
* Get the list of class names of a java object, and
397+
* structure it as a STRSXP vector
398+
*/
399+
HIDE SEXP getSimpleClassNames_asSEXP( jobject o, jboolean addConditionClasses ){
400+
return getStringArrayCont( getSimpleClassNames( o, addConditionClasses ) );
401+
}
402+
403+
/**
404+
* Returns the STRSXP vector of simple class names of the object o
405+
*/
406+
REPC SEXP RgetSimpleClassNames( SEXP e, SEXP addConditionClasses ){
407+
408+
SEXP ar = R_NilValue ;
409+
if (e==R_NilValue) return R_NilValue;
410+
jobject jobj ;
411+
if (TYPEOF(e)==EXTPTRSXP) {
412+
jverify(e);
413+
jobj = (jobject)EXTPTR_PTR(e) ;
414+
} else {
415+
error("invalid object parameter");
416+
}
417+
418+
Rboolean add ;
419+
switch(TYPEOF(addConditionClasses)) {
420+
case LGLSXP:
421+
add = LOGICAL(addConditionClasses)[0];
422+
break;
423+
case INTSXP:
424+
add = INTEGER(addConditionClasses)[0];
425+
break;
426+
default:
427+
add = asLogical(addConditionClasses);
428+
}
429+
430+
ar = getSimpleClassNames_asSEXP( jobj , (jboolean)add ) ;
431+
432+
return ar;
433+
}
434+

src/init.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
JavaVM *jvm;
88

99
/* cached, global objects */
10+
1011
jclass javaStringClass;
1112
jclass javaObjectClass;
1213
jclass javaClassClass;
@@ -15,9 +16,15 @@ jclass javaFieldClass;
1516
/* cached, global method IDs */
1617
jmethodID mid_forName;
1718
jmethodID mid_getName;
19+
jmethodID mid_getSimpleName;
20+
jmethodID mid_getSuperclass;
1821
jmethodID mid_getType;
1922
jmethodID mid_getField;
2023

24+
/* internal classes and methods */
25+
jclass rj_RJavaTools_Class = (jclass)0;
26+
jmethodID mid_rj_getSimpleClassNames = (jmethodID)0 ;
27+
2128
int rJava_initialized = 0;
2229

2330

@@ -207,11 +214,20 @@ HIDE void init_rJava(void) {
207214

208215
mid_forName = (*env)->GetStaticMethodID(env, javaClassClass, "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
209216
if (!mid_forName) error("cannot obtain Class.forName method ID");
217+
210218
mid_getName = (*env)->GetMethodID(env, javaClassClass, "getName", "()Ljava/lang/String;");
211219
if (!mid_getName) error("cannot obtain Class.getName method ID");
220+
221+
mid_getSimpleName = (*env)->GetMethodID(env, javaClassClass, "getSimpleName", "()Ljava/lang/String;");
222+
if (!mid_getSimpleName) error("cannot obtain Class.getSimpleName method ID");
223+
224+
mid_getSuperclass =(*env)->GetMethodID(env, javaClassClass, "getSuperclass", "()Ljava/lang/Class;");
225+
if (!mid_getSuperclass) error("cannot obtain Class.getSuperclass method ID");
226+
212227
mid_getField = (*env)->GetMethodID(env, javaClassClass, "getField",
213228
"(Ljava/lang/String;)Ljava/lang/reflect/Field;");
214229
if (!mid_getField) error("cannot obtain Class.getField method ID");
230+
215231
mid_getType = (*env)->GetMethodID(env, javaFieldClass, "getType",
216232
"()Ljava/lang/Class;");
217233
if (!mid_getType) error("cannot obtain Field.getType method ID");
@@ -310,3 +326,29 @@ REP void doneJVM() {
310326
eenv = 0;
311327
}
312328

329+
/**
330+
* Initializes the cached values of classes and methods used internally
331+
* These classes and methods are the ones that are in rJava (RJavaTools, ...)
332+
* not java standard classes (Object, Class)
333+
*/
334+
REPC SEXP initRJavaTools(){
335+
336+
JNIEnv *env=getJNIEnv();
337+
338+
// RJavaTools class
339+
jclass c;
340+
c= findClass( env, "RJavaTools" ) ;
341+
if (!c) error("unable to find the RJavaTools class");
342+
rj_RJavaTools_Class=(*env)->NewGlobalRef(env, c);
343+
if (!rj_RJavaTools_Class) error("unable to create a global reference to the RJavaTools class");
344+
(*env)->DeleteLocalRef(env, c);
345+
346+
mid_rj_getSimpleClassNames = (*env)->GetStaticMethodID(env, rj_RJavaTools_Class,
347+
"getSimpleClassNames", "(Ljava/lang/Object;Z)[Ljava/lang/String;");
348+
if (!mid_rj_getSimpleClassNames) error("cannot obtain RJavaTools.getDimpleClassNames method ID");
349+
350+
// maybe add RJavaArrayTools, ...
351+
352+
return R_NilValue;
353+
}
354+

src/java/RJavaTools.java

Lines changed: 69 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
import java.lang.reflect.Modifier ;
66
import java.lang.reflect.Member ;
77

8-
import java.util.Vector ;
8+
import java.util.Vector ;
9+
910

1011
/**
1112
* Tools used internally by rJava.
@@ -25,7 +26,7 @@ public class RJavaTools {
2526
public static Class getClass(Class cl, String name, boolean staticRequired){
2627
Class[] clazzes = cl.getClasses();
2728
for( int i=0; i<clazzes.length; i++){
28-
if( clazzes[i].getSimpleName().equals( name ) && ( !staticRequired || isStatic(clazzes[i]) ) ){
29+
if( getSimpleName( clazzes[i].getName() ).equals( name ) && ( !staticRequired || isStatic(clazzes[i]) ) ){
2930
return clazzes[i] ;
3031
}
3132
}
@@ -289,7 +290,7 @@ public static boolean classHasMethod(Class cl, String name, boolean staticRequir
289290
public static boolean classHasClass(Class cl, String name, boolean staticRequired) {
290291
Class[] clazzes = cl.getClasses();
291292
for (int i = 0; i < clazzes.length; i++)
292-
if (name.equals(clazzes[i].getSimpleName()) && (!staticRequired || isStatic( clazzes[i] ) ) )
293+
if (name.equals( getSimpleName(clazzes[i].getName()) ) && (!staticRequired || isStatic( clazzes[i] ) ) )
293294
return true;
294295
return false;
295296
}
@@ -568,21 +569,82 @@ public static String[] getClassNames(Object o){
568569
return res ;
569570
}
570571

571-
/**
572+
/**
572573
* Returns the list of simple class names of the object
573574
*
574575
* @param o an Object
575576
*/
576-
public static String[] getSimpleClassNames(Object o){
577+
public static String[] getSimpleClassNames(Object o, boolean addConditionClasses){
577578
Vector/*<String>*/ vec = new Vector();
578-
Class cl = o.getClass();
579+
Class cl = o.getClass();
579580
while( cl != null ){
580-
vec.add( cl.getSimpleName() ) ;
581+
vec.add( getSimpleName( cl.getName() ) ) ;
581582
cl = cl.getSuperclass() ;
582583
}
584+
if( addConditionClasses ){
585+
vec.add( "error" ) ;
586+
vec.add( "condition" ) ;
587+
}
588+
583589
String[] res = new String[ vec.size() ] ;
584590
vec.toArray( res) ;
585591
return res ;
586592
}
587593

594+
/* because Class.getSimpleName is java 5 API */
595+
private static String getSimpleClassName( Object o ){
596+
return getSimpleName( o.getClass().getName() ) ;
597+
}
598+
599+
private static String getSimpleName( String s ){
600+
int lastsquare = s.lastIndexOf( '[' ) ;
601+
if( lastsquare >= 0 ){
602+
if( s.charAt( s.lastIndexOf( '[' ) + 1 ) == 'L' ){
603+
s = s.substring( s.lastIndexOf( '[' ) + 2, s.lastIndexOf( ';' ) ) ;
604+
} else {
605+
char first = s.charAt( 0 );
606+
if( first == 'I' ) {
607+
s = "int" ;
608+
} else if( first == 'D' ){
609+
s = "double" ;
610+
} else if( first == 'Z' ){
611+
s = "boolean" ;
612+
} else if( first == 'B' ){
613+
s = "byte" ;
614+
} else if( first == 'J' ){
615+
s = "long" ;
616+
} else if( first == 'F' ){
617+
s = "float" ;
618+
} else if( first == 'S' ){
619+
s = "short" ;
620+
} else if( first == 'C' ){
621+
s = "char" ;
622+
}
623+
}
624+
}
625+
626+
int lastdollar = s.lastIndexOf( '$' ) ;
627+
if( lastdollar >= 0 ){
628+
s = s.substring( lastdollar + 1);
629+
}
630+
631+
int lastdot = s.lastIndexOf( '.' ) ;
632+
if( lastdot >= 0 ){
633+
s = s.substring( lastdot + 1);
634+
}
635+
636+
if( lastsquare >= 0 ){
637+
StringBuffer buf = new StringBuffer( s );
638+
int i ;
639+
for( i=0; i<=lastsquare; i++){
640+
buf.append( "[]" );
641+
}
642+
return buf.toString();
643+
} else {
644+
return s ;
645+
}
646+
647+
}
648+
649+
588650
}

0 commit comments

Comments
 (0)