Solved

JNI Interface - Passing Object Arrays

Posted on 1998-07-05
8
514 Views
Last Modified: 2013-11-23
I am utilizing native code (C++) that I must pass an array of user defined objects (not String -which I have seen examples of) to.  The native code also modifies this array of objects.  Is this possible and, if so, how do I do this?  Please send code examples.
0
Comment
Question by:kayak
  • 4
  • 4
8 Comments
 
LVL 5

Accepted Solution

by:
msmolyak earned 100 total points
ID: 1224669
For the following java class:

class HelloWorld
{
      Object[] objectArray;

      public native void displayHelloWorld(Object[] array);

      static
      {
              System.loadLibrary("hello");
        }
      public static void main(String[] args)
      {
            Object[] newArray = new Object[2];
            newArray[0] = new String("String");
            newArray[1] = new Integer(42);
            new HelloWorld().displayHelloWorld(newArray);
      }
}

I generated a header file using "javah -kni HelloWorld" and got as a result:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */

#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     HelloWorld
 * Method:    displayHelloWorld
 * Signature: ([Ljava/lang/Object;)V
 */
JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld
  (JNIEnv *, jobject, jobjectArray);

#ifdef __cplusplus
}
#endif
#endif

Thus your function definition has a parameter of type jobjectArray.

JNI has a set of functions (Array Operations) which allow you to find the array length, get each array element and assign to each element of the array. You can find them at http://java.sun.com/products/jdk/1.1/docs/guide/jni/spec/functions.doc.html#17314.

Let me know if you need more help.
0
 

Author Comment

by:kayak
ID: 1224670
msmolyak,

I have tried passing the user defined object array in this way to the C++ Native code.  On the C++ side, I have tried the GetObjectArrayElement call to get the element and I have casted this to a pointer of the object type that I want.  However, when I use this object and issue a simple native accessor method I do not get the same values as I do on the Java side.  I have also tried creating the array of objects in the JNI C++ code using the NewObjectArray function, but I have had no luck doing this also.  If you could send me a complete example with the C++ code also, I would greatly appreciate it.

Basically, the test has a C++ object that contains several integers as members and some simple accessor functions.  In some cases an array of these objects are passed as an argument to the C++ member functions.  I have created the array of objects on the Java side either directly or by calling JNI method that uses the NewObjectArray function.  On the individual members of the array (individual objects) I have used the simple accessor methods to set and examine some values.  On the Java side this seems to work.  However, if I pass the entire array of object to the JNI C++ code and try to examine or set the contents of some of the individual objects, I don't get the same values (they are all 0) as what I had set in the objects on the Java side.  

Sorry for the long-winded explaination, but Please Help Me.
0
 
LVL 5

Expert Comment

by:msmolyak
ID: 1224671
Could you instead send me some sample of your code (desirably compilable) which you are having problems with?
0
 

Author Comment

by:kayak
ID: 1224672
msmolyak,

The code (stripped down) follows.  The first two are header files for the C++ files.  CPos.h has the interface spec for a small class CPosition.  CPosition.cpp has the code for this class.  Just for similarity sake with the actual code, I made this a library called Position.lib (static lib).  The CPosition.h header file is the JNI created header.  CPositionJNI.cpp has the JNI interface code that also contains a method called arrayPass which tries to access the passed in array from Java.  The CPosition.java code contains a main to utilize the various methods.

After the Position.lib has been created (use MSDevStudio), use the following compile the cpp JNI code:
cl -LD Position.lib CPositionJNI.cpp -FeCPositionJNI.dll


//////////////////////
CPos.h
//////////////////////
class CPosition
{

   public:
      CPosition();
      ~CPosition();
      void SetX(int x);
      void SetY(int y);
      int GetX();
      int GetY();      

      //fixed coordinate (in pixels on the image)
      int    Nfeatures;
      int    xf[5],yf[5];
      int    X,Y,S,W,H,XC,YC;
      float  theta;
};



//////////////////////////////
CPosition.cpp
//////////////////////////////
class CPosition
{

   public:
      CPosition();
      ~CPosition();
      void SetX(int x);
      void SetY(int y);
      int GetX();
      int GetY();      

      //fixed coordinate (in pixels on the image)
      int    Nfeatures;
      int    xf[5],yf[5];
      int    X,Y,S,W,H,XC,YC;
      float  theta;
};


     CPosition::CPosition()
     {
     }    

     CPosition::~CPosition()
     {
     }

     void CPosition::SetX(int x)
     {
       X=x;
     }

     void CPosition::SetY(int y)
     {
       Y=y;
     }

     int CPosition::GetX()
     {
        return(X);
     }

     int CPosition::GetY()
     {
        return(Y);
     }



/////////////////////////////////
CPosition.h
////////////////////////////////////
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class CPosition */

#ifndef _Included_CPosition
#define _Included_CPosition
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     CPosition
 * Method:    initialize0
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_CPosition_initialize0
  (JNIEnv *, jobject);

/*
 * Class:     CPosition
 * Method:    finalize0
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_CPosition_finalize0
  (JNIEnv *, jobject);

/*
 * Class:     CPosition
 * Method:    newPositionArray0
 * Signature: (I)[LCPosition;
 */
JNIEXPORT jobjectArray JNICALL Java_CPosition_newPositionArray0
  (JNIEnv *, jclass, jint);

/*
 * Class:     CPosition
 * Method:    arrayPass0
 * Signature: ([LCPosition;)V
 */
JNIEXPORT void JNICALL Java_CPosition_arrayPass0
  (JNIEnv *, jobject, jobjectArray);

/*
 * Class:     CPosition
 * Method:    getX0
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_CPosition_getX0
  (JNIEnv *, jobject);

/*
 * Class:     CPosition
 * Method:    getY0
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_CPosition_getY0
  (JNIEnv *, jobject);

/*
 * Class:     CPosition
 * Method:    setX0
 * Signature: (I)V
 */
JNIEXPORT void JNICALL Java_CPosition_setX0
  (JNIEnv *, jobject, jint);

/*
 * Class:     CPosition
 * Method:    setY0
 * Signature: (I)V
 */
JNIEXPORT void JNICALL Java_CPosition_setY0
  (JNIEnv *, jobject, jint);

#ifdef __cplusplus
}
#endif
#endif



/////////////////////////////////////
CPositionJNI.cpp
////////////////////////////////////
  #include "COMDEF.h"
  #include "CPosition.h"
  #include "CPos.h"

  void DllMain()
  {
  }

  /*********************************************************************
  * Retrieves the pointer to the C++ peer object from the Java object.
  *********************************************************************/
  jlong
  getCID (
    JNIEnv*  env,
    jobject  anObj )
  {
    jclass  clazz = env->GetObjectClass ( anObj );
    jfieldID  fid = env->GetFieldID ( clazz, "peerPtr", "J" );
    return env->GetLongField ( anObj, fid );
  }

  /*********************************************************************
  * Sets the pointer to the C++ peer object in the Java object.
  *********************************************************************/
  void
  setCID (
    JNIEnv*  env,
    jobject  anObj,
    jlong    val )

  {
    jclass  clazz = env->GetObjectClass ( anObj );
    jfieldID  fid = env->GetFieldID ( clazz, "peerPtr", "J" );
    env->SetLongField ( anObj, fid, val );
  }

  //////////////////////////////////////////////////////////////////////
  // Initialization and finalization methods
  //////////////////////////////////////////////////////////////////////

  /*********************************************************************
  * Called when a Java object is first constructed.
  * Sets the pointer to the C++ peer object in the Java object.
  *********************************************************************/
  JNIEXPORT void JNICALL
  Java_CPosition_initialize0
  (JNIEnv    *env,
   jobject   thisObject)
  {
    setCID ( env, thisObject, ( jlong ) new CPosition ( ) );
  }

  /*********************************************************************
  * Called implicitly by the Java garbage collector to free the memory
  * allocated to the C++ peer object during the initialization routine.
  *********************************************************************/
  JNIEXPORT void JNICALL Java_CPosition_finalize0
  (JNIEnv    *env,
   jobject   thisObject)
  {
    CPosition*  cPosition = ( CPosition* ) getCID ( env, thisObject );
    cPosition->~CPosition ( );
  }

  //////////////////////////////////////////////////////////////////////
  // Computational methods
  //////////////////////////////////////////////////////////////////////
  JNIEXPORT jobjectArray JNICALL Java_CPosition_newPositionArray0
  (JNIEnv     *env,
   jclass     thisObject,
   jint       sz)
  {
    jclass   clazz;
    clazz = env->FindClass("CPosition");
    jobjectArray newArr;
    newArr = env->NewObjectArray(sz, clazz, NULL);

    return newArr;
  }

  //////////////////////////////////////////////////////////////////////
  // Mutator and accessor methods
  //////////////////////////////////////////////////////////////////////
  JNIEXPORT void JNICALL Java_CPosition_arrayPass0
  (JNIEnv          *env,
   jobject         thisObject,
   jobjectArray    position)
  {
    jobject       tempPosition;
    jobject       *tempPointer;
    CPosition     *tempCPointer;
    CPosition     tempCPosition;

    // Copy each Java array element into the C++ array
    jint positionSize = env->GetArrayLength(position);

    printf("C++ Array size is: %d\n", positionSize);
    fflush(stdout);

    for (int i=0; i<positionSize; i++)
    {
      tempPosition = env->GetObjectArrayElement(position, i);
      tempCPointer = (CPosition *)&tempPosition; // Could be moved
                                                 // out of the loop

      printf("C++ Pos0X is %d, Pos0Y is %d\n", tempCPointer->GetX(),
        tempCPointer->GetY());
      fflush(stdout);
     }

  }

  JNIEXPORT jint JNICALL Java_CPosition_getX0
  (JNIEnv      *env,
   jobject     thisObject)
  {
    CPosition*  cPosition = ( CPosition* ) getCID ( env, thisObject );
    return cPosition->GetX();
  }

  JNIEXPORT jint JNICALL Java_CPosition_getY0
  (JNIEnv      *env,
   jobject     thisObject)
  {
    CPosition*  cPosition = ( CPosition* ) getCID ( env, thisObject );
    return cPosition->GetY();
  }

  JNIEXPORT void JNICALL Java_CPosition_setX0
  (JNIEnv      *env,
   jobject     thisObject,
   jint        x)
  {
    CPosition*  cPosition = ( CPosition* ) getCID ( env, thisObject );
    cPosition->SetX(x);
  }

  JNIEXPORT void JNICALL Java_CPosition_setY0
  (JNIEnv      *env,
   jobject     thisObject,
   jint        y)
  {
    CPosition*  cPosition = ( CPosition* ) getCID ( env, thisObject );
    cPosition->SetY(y);
  }

//////////////////////////////////
CPosition.java
//////////////////////////////////
public class CPosition
  //////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////
  {

    /** Note that the pointer to the C++ peer object is transient. */
    /** This is just in case the object is ever made Serializable. */
    private transient long  peerPtr = 0;

    //////////////////////////////////////////////////////////////////////
    // Static initializer method.
    //////////////////////////////////////////////////////////////////////

    static
    //////////////////////////////////////////////////////////////////////
    {
       Runtime.runFinalizersOnExit ( true );

       // What if this is already loaded by another class?
       // Will it throw an exception?
       System.loadLibrary ( "CPositionJNI" );
    }

     /* ********************************************************************
     * Test method.
     ******************************************************************** */
     public static void  main ( String [ ]  args )
     //////////////////////////////////////////////////////////////////////
     {

       System.out.println("Creating master object");
       System.out.flush();

       CPosition master = new CPosition();

       System.out.println("Creating position object");
       System.out.flush();
       
//       CPosition[] position = newPositionArray0(10);
       CPosition position[] = new CPosition[10];

       // allocate space for each array element
       for (int i=0; i<position.length; i++)
       {
          position[i] = new CPosition();
       }

       System.out.println("Initializing values.");
       System.out.flush();

       position[0].SetX(4);
       position[0].SetY(5);
       position[1].SetX(6);
       position[1].SetY(7);
       position[2].SetX(8);
       position[2].SetY(9);
       position[3].SetX(10);
       position[3].SetY(11);
       position[4].SetX(12);
       position[4].SetY(13);

       System.out.println("Done Initializing.");
       System.out.flush();

       System.out.println(
"Pos0 = " + position[0].GetX() + ", " + position[0].GetY() + "\n" +
"Pos1 = " + position[1].GetX() + ", " + position[1].GetY() + "\n" +
"Pos2 = " + position[2].GetX() + ", " + position[2].GetY() + "\n" +
"Pos3 = " + position[3].GetX() + ", " + position[3].GetY() + "\n" +
"Pos4 = " + position[4].GetX() + ", " + position[4].GetY() + "\n");

       master.ArrayPass( position );

     }

     //////////////////////////////////////////////////////////////////////
     // Constructor methods
     //////////////////////////////////////////////////////////////////////

     /*********************************************************************
     * Initializes the C++ peer and saves the pointer.
     * The instance initializer is automatically called whenever a new
     * object is constructed.
     *********************************************************************/
     //////////////////////////////////////////////////////////////////////
     {
       initialize0 ( );
     }

     /*********************************************************************
     * This constructor simply calls the superclass constructor.
     * It is included as a reminder that this is the default behavior
     * if this is not explicitly implemented as shown below.
     *********************************************************************/
     public  CPosition ( )
     //////////////////////////////////////////////////////////////////////
     {
       super ( );
     }

     /*********************************************************************
     * Frees the memory for the C++ peer object.  Called by the Java
     * garbage collector automatically; do not explicitly call this method.
     *********************************************************************/
     public void  finalize ( ) throws Throwable
     //////////////////////////////////////////////////////////////////////
     {
       finalize0 ( );
       // Always call the superclass finalizer as the last step.
       super.finalize ( );
     }

    public int GetX( )
    ///////////////////////////////////////////////////////////////////////
    {
      return getX0( );
    }

    public int GetY( )
    {
      return getY0( );
    }
      
    public void SetX(
        int x)
    {
      setX0 (x);
    }
   
    public void SetY(
        int y)
    {
      setY0(y);
    }

    public void ArrayPass(
        CPosition[] position)
    {
      arrayPass0( position);
    }

    //////////////////////////////////////////////////////////////////////
    // Private native methods
    //////////////////////////////////////////////////////////////////////

    private native void  initialize0 ( );
    private native void  finalize0 ( );
    private native static CPosition[] newPositionArray0(int sz);

    private native void arrayPass0( CPosition[] position);

    private native int getX0();
    private native int getY0();
    private native void setX0(int x);
    private native void setY0(int y);

}


0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
LVL 5

Expert Comment

by:msmolyak
ID: 1224673
Before I look at the C++ code could you tell me what this piece of java code does:

 /*********************************************************************
            * Initializes the C++ peer and saves the pointer.
            * The instance initializer is automatically called whenever a new
            * object is constructed.
            *********************************************************************/
            //////////////////////////////////////////////////////////////////////
            {
              initialize0 ( );
            }
0
 

Author Comment

by:kayak
ID: 1224674
msmolyak,

That piece of code is executed whenever a CPosition object is created in the Java code.  This code then "calls" the C++ code routine with the same name which saves a pointer to the object.

Thanks,

Russ
0
 

Author Comment

by:kayak
ID: 1224675
msmolyak,

I actually figured it out on my own.  Thanks so much for your efforts in helping solve this problem.  The following is the line I added in ArrayPass method in the C++ side.

    for (int i=0; i<positionSize; i++)
    {
      tempPosition = env->GetObjectArrayElement(position, i);
//Removed: tempCPointer = (CPosition *)&tempPosition;

ADDED: tempCPointer = ( CPosition* ) getCID ( env, tempPosition );


0
 
LVL 5

Expert Comment

by:msmolyak
ID: 1224676
Glad you found it. Sorry I was not of more help.
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

For customizing the look of your lightweight component and making it look opaque like it was made of plastic.  This tip assumes your component to be of rectangular shape and completely opaque.   (CODE)
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
Video by: Michael
Viewers learn about how to reduce the potential repetitiveness of coding in main by developing methods to perform specific tasks for their program. Additionally, objects are introduced for the purpose of learning how to call methods in Java. Define …
This tutorial covers a practical example of lazy loading technique and early loading technique in a Singleton Design Pattern.

912 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

24 Experts available now in Live!

Get 1:1 Help Now