Copying jobjectarray to CString[] with JNI

jsm11482Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

itsmeandnobodyelseCommented:
//CString array to jobjectArray
jobjectArray JNIUtil::CopyArray(JNIEnv* env, CString* in)
{
     jobjectArray out = env->NewObjectArray(in->GetLength(), env->FindClass("java/lang/String"), NULL);

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

     return out;
}

Do you really want to add any single character as a JNI string to the object array? If so, the function seems to be ok though I don't know whether JNIEnv::NewStringUTF takes a char as an argument (note, in[i] is a single char). If not you need to use the CString::Mid member function:

     env->SetObjectArrayElement(out, i, env->NewStringUTF(in.Mid(i, 1)));

in.Mid(i, 1) returns a substring of length 1 beginning at position i. As CString automatically converts to 'const char*' - if required - that should compile.

//CStringList to jobjectArray
jobjectArray JNIUtil::CopyArray(JNIEnv* env, CStringList* in)
{
     jobjectArray out = env->NewObjectArray(in->GetCount(), env->FindClass("java/lang/String"), NULL);
     // return out;  //  SEEMS TO BE A TYPO ???

     // for (int i = 0; i < in->GetCount(); i++)
     //     env->SetObjectArrayElement(out, i, env->NewStringUTF((CString)in->GetAt((POSITION)i)));

     int i = 0;
     for (POSITION pos = in.GetHeadPosition(); pos != NULL)
           env->SetObjectArrayElement(out, i++, env->NewStringUTF((CString)in->GetNext(pos)));
     return out;
}

Note, POSITION is *not* a counter but an iterator. GetNext returns the CString at the current position and increments the iterator pos.


//double array to jdoubleArray
jdoubleArray JNIUtil::CopyArray(JNIEnv*env, double* in, int siz)
{
     jdoubleArray out = env->NewDoubleArray(siz);

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

     return out;
}

In C/C++ an array turns to a pointer (to the first array element) when passed as an argument. Thus, the array size got lost and you need to pass the array size as an additionally argument (or use some sort of termination, e. g. by setting the last element to the minimum double value).

//jobjectArray to CString array
void JNIUtil::CopyArray(JNIEnv* env, jobjectArray in, CString* out)
{
     for (int i = 0; i < env->GetArrayLength(in); i++)
          out += env->GetStringUTFChars((jstring)env->GetObjectArrayElement(in, i), FALSE);
}

You would need to concatinate the string you got from object array (assuming GetStringUTFChars returns a const char*).

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

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

Assuming 'out' wasn't allocated yet.

Regards, Alex
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
jsm11482Author Commented:
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!
0
InteractiveMindCommented:
<This _should_ really be continued in only 1 thread; jsm11482, which thread do you wish to continue this in? C++ or Java?>
0
Cloud Class® Course: Microsoft Windows 7 Basic

This introductory course to Windows 7 environment will teach you about working with the Windows operating system. You will learn about basic functions including start menu; the desktop; managing files, folders, and libraries.

itsmeandnobodyelseCommented:
>>>> 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.



0
itsmeandnobodyelseCommented:
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;
}

0
jsm11482Author Commented:
please continue this thread in the C++ area
0
jsm11482Author Commented:
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)
0
itsmeandnobodyelseCommented:
>>>> 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
0
jsm11482Author Commented:
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.
0
itsmeandnobodyelseCommented:
>>>> 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

0
jsm11482Author Commented:
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;
}
0
itsmeandnobodyelseCommented:
>>>> 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
 
0
itsmeandnobodyelseCommented:
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


0
itsmeandnobodyelseCommented:
>>>> 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
0
jsm11482Author Commented:
it is initialized as a static array in the header file: double m_adPctSharesVest[11];
0
jsm11482Author Commented:
Seems OK, I ended up using a solution not posted here. Thank you.
0
itsmeandnobodyelseCommented:
>>>> 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
 
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.