Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / February 2006

Tip: Looking for answers? Try searching our database.

accessing objects in JNI

Thread view: 
stixwix - 02 Feb 2006 16:23 GMT
Most of the examples I've seen for JNI seem to allow access to 'top
level' instance variables like this:

public class HelloNative{

   private String str;
   private native void setObjLong();

   public static void main(String[] args) {
       HelloNative test = new HelloNative();
       test.setObjLong();
       System.out.println("The java s is: "+ test.str);
   }
}

The string is created in the c code:
JNIEXPORT void JNICALL
Java_HelloNative_setObjLong (JNIEnv* env, jobject obj) {

   /* get the class object */
   jclass cls = (*env)->GetObjectClass(env, obj);
   /* get the field id */
   jfieldID fid = (*env)->GetFieldID(env, cls, "str",
"Ljava/lang/String;");
   /* make new string */
   jstring myStr = (*env)->NewStringUTF(env,"1234");
   /* set the value */
   (*env)->SetObjectField(env, obj, fid, myStr);
   return 0;
}

This all works fine, the question is how do you get to user-defined
object's instanace variables?
So if I change the java bit thus:
public class HelloNative {

   private MyClass myObj = new MyClass();
   private native void setObjLong();

   class MyClass{
       private long address;
       // getters and setters omitted
   }

   public static void main(String[] args) {
       HelloNative test = new HelloNative();
       test.setObjLong();
       System.out.println("The java long is: "+
test.myObj.getAddress());
   }
}

How can I set the address field of myObj?

If I try:
  jfieldID fid = (*env)->GetFieldID(env, cls, "myObj",
"Ljava/lang/Object;");

I get:
java.lang.NoSuchFieldError: HelloNative.myObj

...and anyway this would only get me to the object and not to the
address instance which I wish to set.

Thanks,
Andy
Gordon Beaton - 02 Feb 2006 16:46 GMT
> the question is how do you get to user-defined
> object's instanace variables?
[quoted text clipped - 26 lines]
> I get:
> java.lang.NoSuchFieldError: HelloNative.myObj

Your call to GetFieldId() says "look in HelloNative for a field called
myObj whose type is java.lang.Object". But myObj in HelloNative is
clearly of type HelloNative$MyClass (because MyClass is an inner class
to HelloNative), not java.lang.Object.

"javap -s HelloNative" will show you the correct signatures to use for
all of the fields and methods in that class.

> ...and anyway this would only get me to the object and not to the
> address instance which I wish to set.

To create an instance of the inner class, look up that class, then
look up one of its constructors (realizing that there is a hidden
first argument, an object of the enclosing class) and use that to
invoke NewObject().

/gordon

Signature

[  do not email me copies of your followups  ]
g o r d o n + n e w s @  b a l d e r 1 3 . s e

stixwix - 02 Feb 2006 18:32 GMT
> To create an instance of the inner class, look up that class, then
> look up one of its constructors (realizing that there is a hidden
> first argument, an object of the enclosing class) and use that to
> invoke NewObject().

Thanks for that.  I now get a little further.  With regard to the clip
above, do i need to do this if I am passing an (instantiated) object
into the c code from the java code?

To get to the address field (String) in the MyClass, I was thinking the
following should work but it crashes nastily. (Note: I have now changed
this field in MyClass from long to String).

   /* get the class object */
   jclass cls = (*env)->GetObjectClass(env, obj);

   /* get the myObj instance from HelloNative  */
   jfieldID fid = (*env)->GetFieldID(env, cls, "myObj",
"LHelloNative$MyClass;");

  /* get the address field from MyClass */
   jfieldID fidStr = (*env)->GetFieldID(env, fid, "address",
"Ljava/lang/String;");

It crashes when I introduce the last line.
There is a compiler warning:
"passing arg 2 of pointer to function from incompatible pointer type"

but I've no idea what I can pass to that function instead.

Thanks,
Andy
Gordon Beaton - 03 Feb 2006 08:18 GMT
> With regard to the clip above, do i need to do this if I am passing
> an (instantiated) object into the c code from the java code?

Yes, it's perfectly reasonable to use the enclosing object ("this")
when you create instances of its inner class.

>    /* get the address field from MyClass */
>     jfieldID fidStr = (*env)->GetFieldID(env, fid, "address",
> "Ljava/lang/String;");
>
>  It crashes when I introduce the last line.

You're attempting to find the fieldID by looking it up in another
fieldID, but you should be looking in a class instead.

Start with the class HelloNative$MyClass, and from there you can look
up its fields:

 jclass my_cls = (*env)->FindClass(env,"HelloNative$MyClass");
 jfieldID addr_fid = (*env)->GetFieldID(env,my_cls,"address",
                                        "Ljava/lang/String;");

Now to actually get or change the *value* associated with this field,
you need an *object* of that type (i.e. one that holds the field you
just looked up), and you choose one of the Get/Set<type>Field()
functions based on the type of the field itself (i.e. one of the
primitive types, or Object for all others).

/gordon

Signature

[  do not email me copies of your followups  ]
g o r d o n + n e w s @  b a l d e r 1 3 . s e

stixwix - 06 Feb 2006 10:57 GMT
> Start with the class HelloNative$MyClass, and from there you can look
> up its fields:
[quoted text clipped - 8 lines]
> functions based on the type of the field itself (i.e. one of the
> primitive types, or Object for all others).

When I try the above with the following additional code - jstr is
NULL.:
   jstring jstr = (*env)->GetObjectField(env, obj, addr_fid);
   const char *str  = (*env)->GetStringUTFChars(env, jstr, NULL);

All the examples I see use GetObjectClass instead of FindClass.  I
can't find/understand any docs relating to FindClass, but it doesn't
imply object instance scope.
Gordon Beaton - 06 Feb 2006 11:38 GMT
> When I try the above with the following additional code - jstr is
> NULL.:
>     jstring jstr = (*env)->GetObjectField(env, obj, addr_fid);
>     const char *str  = (*env)->GetStringUTFChars(env, jstr, NULL);

It's hard to tell from these code fragments, but is "obj" really an
instance of the class containing the field you are looking up?

I.e. you looked up up a field ID in HelloNative$MyClass, so "obj" must
be a HelloNative$MyClass object (or it won't have that field).

/gordon

Signature

[  do not email me copies of your followups  ]
g o r d o n + n e w s @  b a l d e r 1 3 . s e



Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.