Reputation: 63
I have a requirement where I need to pass some values from C++ to JAVA using JNI. As per the requirement, input to c++ code is a line with list of points and I have to read x and y coordinates of each and every point and return to java code.I have declared a list as std::list> listofpoints; and reading x and y coordinates as
for(size_t j = 0; j < track->geometry.points.size(); ++j)
{
PointZ &p = track->geometry.points[j] listofpoints.push_back(std::pair<double, double>(p.vertex.position.x,p.vertex.position.y));
This geometry.points is to read each and point gets x and y coordinates. Now I am returning this listofpoints to JNI method. Here I have to write code so that it reads x and y coordinates and send it to JAVA method. I am finding a way to iterate list and get values but , i am finding it difficult to return from JNI to JAVA as JNI returns only jobjectarray. How can i convert this list to array in JNI and send to JAVA method. I am very much new to JNI and JAVA as well.
Upvotes: 1
Views: 2361
Reputation: 33865
You can convert the std::list<std::pair<double, double>>
to a Java List<Pair<Double, Double>>
.
Here is an example:
The Java method:
public static native List<Pair<Double, Double>> getList();
The C++ part:
std::list<std::pair<double, double>> myList{ // example input
{1, 2},
{3, 4}
};
JNIEXPORT jobject JNICALL Java_Main_getList(JNIEnv *env, jclass cls) {
// First, get all the methods we need:
jclass arrayListClass = env->FindClass("java/util/ArrayList");
jmethodID arrayListConstructor = env->GetMethodID(arrayListClass, "<init>", "()V");
jmethodID addMethod = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
jclass pairClass = env->FindClass("javafx/util/Pair");
jmethodID pairConstructor = env->GetMethodID(pairClass, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;)V");
// This is needed to go from double to Double (boxed)
jclass doubleClass = env->FindClass("java/lang/Double");
jmethodID doubleValueOf = env->GetStaticMethodID(doubleClass, "valueOf", "(D)Ljava/lang/Double;");
// The list we're going to return:
jobject list = env->NewObject(arrayListClass, arrayListConstructor);
for(auto& coord : myList) {
// Convert each C++ double to a java.lang.Double:
jobject x = env->CallStaticObjectMethod(doubleClass, doubleValueOf, coord.first);
jobject y = env->CallStaticObjectMethod(doubleClass, doubleValueOf, coord.second);
// Create a new pair object
jobject pair = env->NewObject(pairClass, pairConstructor, x, y);
// Add it to the list
env->CallBooleanMethod(list, addMethod, pair);
}
return list;
}
That said, it is probably easier to use a std::vector
on the C++ side. Flatten the components of the std::pair
into a double[]
, and pass that back to java:
public static native double[] getList();
C++:
std::vector<std::pair<double, double>> myList{ // Now an std::vector
{1, 2},
{3, 4}
};
JNIEXPORT jdoubleArray JNICALL Java_Main_getList(JNIEnv *env, jclass cls) {
size_t length = myList.size() * 2;
double input[length];
// Flatten pairs
for(int i = 0, j = 0; i < length; i += 2, j++) {
input[i] = myList[j].first;
input[i + 1] = myList[j].second;
}
// Copy into Java double[]
jdoubleArray array = env->NewDoubleArray(length);
env->SetDoubleArrayRegion(array, 0, length, ((jdouble*) &input));
return array;
}
Then on the Java side, you would do some further translations. For instance:
public List<Pair<Double, Double>> getTranslated() {
List<Pair<Double, Double>> ret = new ArrayList<>();
double[] list = getList(); // Calling our native method
for(int i = 0; i < list.length; i += 2) {
ret.add(new Pair<>(list[i], list[i + 1]));
}
return ret;
}
Upvotes: 6