Link to home
Start Free TrialLog in
Avatar of jsm11482
jsm11482

asked on

Copying jobjectarray to CString[] with JNI

ASKER CERTIFIED SOLUTION
Avatar of itsmeandnobodyelse
itsmeandnobodyelse
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of jsm11482
jsm11482

ASKER

For the first one, i do not want to add each char to the jobjectArray, i want each string, CString[] arr = new CString[] {"this", "is", "a", "string", "array"};  Can you post good code to accomplish this?

I am trying out your other code changes and will get back to you!

Thanks!
<This _should_ really be continued in only 1 thread; jsm11482, which thread do you wish to continue this in? C++ or Java?>
>>>> For the first one, i do not want to add each char to the jobjectArray,

//CString array to jobjectArray

jobjectArray JNIUtil::CopyArray(JNIEnv* env, CString in[], int siz)
{
     jobjectArray out = env->NewObjectArray(siz, env->FindClass("java/lang/String"), NULL);

     for (int i = 0; i < siz; i++)
          env->SetObjectArrayElement(out, i, env->NewStringUTF(in[i]));

     return out;
}

'CString in[]' is equivalent to CString* but you easier can see that it is an array of CStrings. The size of the array can't be detected from the argument as it turned to a pointer (size is always 4) when passed as an argument. So, you would need an additional argument as it would be with any C array. As an alternative you might use std::vector<CString> or CStringArray that were container classes with a size() or GetSize() function.

jobjectArray JNIUtil::CopyArray(JNIEnv* env, CStringArray in)
{
     jobjectArray out = env->NewObjectArray(in->GetSize(), env->FindClass("java/lang/String"), NULL);

     for (int i = 0; i < in.GetSize(); i++)
          env->SetObjectArrayElement(out, i, env->NewStringUTF(in[i]));

     return out;
}

Regards, Alex


>>>> This _should_ really be continued in only 1 thread

As it is C++ code that is required I would suggest to let the solution here in C++ TA.

The Java thread may be closed as well as the maximum points for one question is not exceeded.



correction:

jobjectArray JNIUtil::CopyArray(JNIEnv* env, const CStringArray& in)
{
     jobjectArray out = env->NewObjectArray(in.GetSize(), env->FindClass("java/lang/String"), NULL);

     for (int i = 0; i < in.GetSize(); i++)
          env->SetObjectArrayElement(out, i, env->NewStringUTF(in[i]));

     return out;
}

please continue this thread in the C++ area
ok so if i send a double array of {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} i am getting back an array of (| delimited):
0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|4.9E-324|-999.0|-999.0|-999.0|-999.0|-999.0|-999.0|0.0|0.05|1.0|0.0|1.0|0.0|0.0|0.0|0.0|1.016208805E-315|0.045|0.0|0.0|1.4967570022479021E-249|2.7585945288E-313|0.0|0.0|1.4784031306360101E-249|1.06099789573E-313|1.2288611814499066E-249|1.9199678765E-313|4.4E-323|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|2.0|1.016208805E-315|0.03|0.04|0.0|1.537211390420101E-249|2.223731269E-314|1.5372071280969523E-249|2.121995796E-314

trace:
calc.setPctSharesVestArray(new double[]  {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});
-> to C++ DLL convert jobjectArray to double array

calc.setPctSharesVestArray()
-> to C++ DLL convert double array to jobjectArray

returns the long array above (after making the suggested code changes)
>>>> calc.setPctSharesVestArray(new double[]  {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});

The code above isn't valid C++ code.

Please, post the original call that failed (plus array creation) and the code of the function that does the conversion( should be JNIUtil::CopyArray).

Regards, Alex
The line: calc.setPctSharesVestArray(new double[]  {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});

is run in java via JNI, the array is passed to the following C++ function:

JNIEXPORT void JNICALL Java_com_towers_ltip_LTIPCalc_setPctSharesVestArray (JNIEnv *env, jobject obj, jint ptr, jdoubleArray value)
{
      CLTIPCalc* calc = (CLTIPCalc*)ptr;
      JNIUtil* util = new JNIUtil();

      util->CopyArray(env, value, calc->m_adPctSharesVest);
}

i just want to copy the passed-in jdoubleArray to the member variable m_adPctSharesVest.

Sorry for the confusion.
>>>> Sorry for the confusion

No problem, but I need both the class/struct definition of CLTIPCalc and the code of JNIUtil::CopyArray.

You always should be aware that C++ needs allocation if handling with plain C arrays rather than with container classes.

Regards, Alex

Definition of variable in CLTIPCalc:
    double m_adPctSharesVest[11];

JNIUtil::CopyArray definitions:

//jdoubleArray to double[]
void JNIUtil::CopyArray(JNIEnv* env, jdoubleArray inObj, double* out)
{
      jdouble* in = env->GetDoubleArrayElements(inObj, FALSE);
      int size = env->GetArrayLength(inObj);

      if (size > 0)
      {
            out = new double[size];

            for (int i = 0; i < size; i++)
                  out[i] = in[i];
      }
      else
            out = NULL;
}


and then....
//double[] to jdoubleArray
jdoubleArray JNIUtil::CopyArray(JNIEnv*env, double* in, int size)
{
      jdoubleArray out = env->NewDoubleArray(size);

      env->SetDoubleArrayRegion(out, 0, size, in);

      return out;
}
>>>> void JNIUtil::CopyArray(JNIEnv* env, jdoubleArray inObj, double* out)

That is wrong cause we need to return 'out' pointer but were changing it locally only.

Either change to

    void JNIUtil::CopyArray(JNIEnv* env, jdoubleArray inObj, double*& out)

Then out pointer was returned. Or - maybe better -

double* JNIUtil::CopyArray(JNIEnv* env, jdoubleArray inObj)
{
    jdouble* in = env->GetDoubleArrayElements(inObj, FALSE);
     int size = env->GetArrayLength(inObj);

     double out* = NULL;
     if (size > 0)
     {
          out = new double[size];

          for (int i = 0; i < size; i++)
               out[i] = in[i];
     }

     return out;
}

Regards, Alex
 
correction:

I saw that you already have an allocation for the double array. So, you could change the code to

jdoubleArray to double[]
void JNIUtil::CopyArray(JNIEnv* env, jdoubleArray inObj, double* out)
{
     jdouble* in = env->GetDoubleArrayElements(inObj, FALSE);
     int size = env->GetArrayLength(inObj);

     if (size > 0 && size <= 11)
     {
          for (int i = 0; i < size; i++)
               out[i] = in[i];
     }
}

Returning a pointer is senseful only if you would change the array in the struct CLTIPCalc to a pointer initialized by NULL. Then, you would call like

   calc->m_adPctSharesVest = util->CopyArray(env, value );

Regards, Alex


>>>> Definition of variable in CLTIPCalc:
>>>>    double m_adPctSharesVest[11];

Did you initialize the array somehow? You could do it in a constructor:


   CLTIPCalc::CLTIPCalc()
   {
     memset(m_adPctSharesVest, 0, sizeof(m_adPctSharesVest));
     // init other members or use an initialiser list

  }

Or - maybe simpler - initialize the struct when creating an instance:

   CLTIPCalc any = { 0 };  // make all zero

Note, that can't be done if there are class members.

Regards, Alex
it is initialized as a static array in the header file: double m_adPctSharesVest[11];
Seems OK, I ended up using a solution not posted here. Thank you.
>>>> Seems OK, I ended up using a solution not posted here. Thank you.

I made at least 6 comments with valid C++ code responding to various additional questions made by jsm11482.

If the questioner doesn't honour that, I don't want points, but a refund isn't appropriate, especially as there is no open question left - as far as I can see.

Regards, Alex