2
votes

I need to pass a callback to java code within an custom object. This my custom class which i wanna write from C++ code.

public class Result {   
    private String utterance[][];
    private float confidence[][];

    public String[][] getUtterance() {
        return utterance;
    }   
    public float[][] getConfidence() {
        return confidence;
    }   
    public void setUtterance(String utterance[][]) {
        this.utterance = utterance;
    }   
    public void setConfidence(float confidence[][]) {
        this.confidence = confidence;
    }   
}

The class Recognizer has communication with JNI. So, the callback comes to her.

public class Recognizer {   

    private Result result;

    Recognizer(){
        System.load(LibNameLoader.libRoot(jarLibPath);
    }
    ...
    private void newResultCallback(Result result){//C++ send this object to java
        this.result = result;
    }
}

Now this is my C++ code which comes with my C++ object at the same i want in java. Remember it's a callback, i can't change the signature.

void Recognized(RecoResult *result){
    //class package
    jclass cls = env->FindClass("Lbr/ufpa/laps/jlapsapi/recognizer/Result;");

    jobject theObject; //i don't how to manipulate this one and set it arrays

    int row = result->sentenceNumber; //Vertical array lenght
    int column = result->wordsNumber; //Horizontal array lenght
    string *ptrUtterance = result->getUtterancePtr(); //simple acess ptrUtterance[i][j]
    float *ptrConfidence = result->getConfidencePtr(); //  "     "  ptrconfidence[i][j]
    jstring utteranceArray[row][column];
    jfloat floatArray[row][column];

    env->CallVoidMethod(obj_, midU, theObject);
    //obj_ is global and has the reference to java Recognizer  class
    //midU is the reference to java method called
    //theObject is the object that java will receive
}

I just need help to set the array fields inside theObject. Or i could send the jstring and the jfloat array using this method env->CallVoidMethod(obj_, midU1, jstringArray); and env->CallVoidMethod(obj_, midU2, jfloatArray);

thanks for help!

Edited!

Recognizer is like this, i'm trying first with a unidimensional array ... jclass testecls; jmethodID testemtdid; jobject testeobj; jstring testestr; jobjectArray testearray; int i;

cout << "Rec cls"<< endl;
testecls = env->FindClass("Ljava/lang/String;");
if(testecls==NULL)
    cout << "Rec cls = NULL"<< endl;

cout << "Rec mtdid"<< endl;
testemtdid = env->GetMethodID(testecls,"<init>","(Ljava/lang/String;)V");
if(testemtdid==NULL)
    cout << "Rec mtdid = NULL"<< endl;

cout << "Rec obj"<< endl;
testeobj = env->NewObject(testecls, NULL);
if(testeobj==NULL)
    cout << "Rec obj = NULL"<< endl;

cout << "Rec str"<< endl;
testestr = env->NewStringUTF(result->getUtterance().c_str());
if(testestr==NULL)
    cout << "Rec str = NULL"<< endl;

cout << "Rec array"<< endl;
testearray = env->NewObjectArray(result->wordsNumber, testecls, testeobj);
if(testearray==NULL)
    cout << "Rec array = NULL"<< endl;


for(i=0;i<result->wordsNumber;i++){
    cout << "Rec setarray"<< endl;
    env->SetObjectArrayElement(testearray, i, testestr);
}

    cout << "Rec before call"<< endl;
env->CallVoidMethod(obj_, midUArray, testearray);
cout << "Rec after call"<< endl;

the output is, it crashes when i try to instatiate the object of String Type.

Rec cls
Rec mtdid
Rec obj
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0xb6dbf389, pid=15337, tid=1769995120
#
# JRE version: 6.0_24-b07
# Java VM: Java HotSpot(TM) Server VM (19.1-b02 mixed mode linux-x86 )
# Problematic frame:
# V  [libjvm.so+0x3e0389]
#
# An error report file with more information is saved as:
# /home/10080000701/workspace/jlapsapi/hs_err_pid15337.log
#
# If you would like to submit a bug report, please visit:
#   http://java.sun.com/webapps/bugreport/crash.jsp
#

What do you suggest?

1
Are you getting a compile-time or run-time error? If so, please post it.John Dibling
i edited, i'm using the last code to testHugo Santos

1 Answers

0
votes

You need to call the constructor of Result and then manipulate the fields of that.

To call create a new instance of Result the constructor must be called like this:

jclass resultClass = env->FindClass("Lbr/ufpa/laps/jlapsapi/recognizer/Result");
jmethodID cid = env->GetMethodID(resultClass, "<init>", "()V");
jobject theObject = env->NewObject(resultClass, cid);

To create a new array of arrays of Strings (String[][]) do this:

jclass strArrArrCls = env->FindClass("[[Ljava/lang/String;");
jclass strArrCls = env->FindClass("[Ljava/lang/String;");
jobjectArray strArrArr = env->NewObjectArray(row, strArrArrCls, NULL);
for(i = 0; i < row; i++) {
    jobjectArray strArr = env->NewObjectArray(column);
    jfloat tmp[3];
    for(j = 0; j < colummn; j++) {
        jstring tmp = env->NewStringUTF(ptrUtterance[row][column].c_str());
        env->SetObjectArrayElement(strArr, j, tmp);
    }
    env->SetObjectArrayElement(strArrArr, i, strArr);
    env->DeleteLocalRef(strArr);
}

You then are able to pass strArrArr to setUtterance(String[][]).