How to Set C++ variables with Java Methods? - java

Making a C++ program and want to receive values from a Java Api using Java method calls.
I have tried using Java Virtual Machines in C++ but it did not work so far. (New to C++ and Java)
How can I set C++ variables with the outputs from Java Methods?
--
Pseudo code of Desired Outcome:
//This example getnumber() Java Method returns back the number you give it
//C++ variables get the results from the Java getnumber() function
double Number1 = getnumber(7.00);
double Number2 = getnumber(9.00);
Code so far:
#include "C:\\Program Files\\Java\\jdk-19\\include\\win32\\jni_md.h"
#include "C:\\Program Files\\Java\\jdk-19\\include\\jni.h"
JavaVM* vm;
jsize vmCount;
if (JNI_GetCreatedJavaVMs(&vm, 1, &vmCount) != JNI_OK || vmCount == 0) {
fprintf(stderr, "Could not get active VM\n");
return NULL;
}
JNIEnv* env;
jint result = vm->GetEnv((void**)&env, JNI_VERSION_1_6);
if (result == JNI_EDETACHED) {
result = vm->AttachCurrentThread((void**)&env, NULL);
}
if (result != JNI_OK) {
fprintf(stderr, "Failed to get JNIEnv\n");
return NULL;
}
jclass cls = env->FindClass("JMyService");
jmethodID ctor = env->GetMethodID(cls, "<init>", "()V");
jobject service = env->NewObject(cls, ctor);
jmethodID loadMethod = env->GetMethodID(cls, "loadContactInformation", "(I)Ljava/lang/String;");
jobject serviceResult = env->CallObjectMethod(service, loadMethod, userId);
return serviceResult;

Related

Calling Java functions from C language

I am tying to call java functions from c code.
I used the JNI as discussed in the example at http://www.ishaanguliani.com/content/calling-java-functions-c-linux-ubuntu-jni
I used the same code and followed the same steps but I am getting unable to find the class print.
I debugged but I didnt find what I did wrong.
Sharing my code here
unions#universe:~/uni_tmp/jni/vvn$ cat MyC.c
#include <stdio.h>
#include <jni.h>
#include "MyJava.h"
#include <string.h>
JNIEnv* create_vm(JavaVM ** jvm) {
JNIEnv *env;
JavaVMInitArgs vm_args;
JavaVMOption options;
options.optionString = "-Djava.class.path=./"; //Path to the java source code
vm_args.version = JNI_VERSION_1_6; //JDK version. This indicates version 1.6
vm_args.nOptions = 1;
vm_args.options = &options;
vm_args.ignoreUnrecognized = 0;
int ret = JNI_CreateJavaVM(jvm, (void**)&env, &vm_args);
if(ret < 0)
printf("\nUnable to Launch JVM\n");
return env;
}
int main(void)
{
JNIEnv *env;
JavaVM *jvm;
jmethodID mainMethod = NULL;
jmethodID smfnMethod = NULL;
jclass clsJava=NULL;
jstring StringArg=NULL;
env = create_vm(&jvm);
if (env == NULL)
{
printf("\n Unable to create environment");
return 1;
}
clsJava = (*env)->FindClass(env,"MyJava");
if (clsJava != NULL)
{
printf("\n Able to find the requested class\n");
} else {
printf("\n Unable to find the requested class\n");
return 0;
}
mainMethod = (*env)->GetStaticMethodID(env, clsJava, "main", " ([Ljava/lang/String;)V");
smfnMethod = (*env)->GetStaticMethodID(env, clsJava,"sampleStaticFunc", "(Ljava/lang/String;)V");
if (mainMethod != NULL)
{
printf("\n Calling the Java Main method");
(*env)->CallStaticVoidMethod(env, clsJava, mainMethod, NULL);
}
StringArg = (*env)->NewStringUTF(env, "Argument from C");
if (smfnMethod != NULL)
{
printf("\n Calling the Static Function method");
(*env)->CallStaticVoidMethod(env, clsJava, smfnMethod, StringArg);
}
printf("\n End C main \n");
return 0;
}
Java code
cat unions#universe:~/uni_tmp/jni/vvn$ cat MyJava.java
public class MyJava
{
public MyJava()
{
System.out.println("\n Inside the constrcutor of Java Function \n ");
}
private void sampleFunc(String str)
{
System.out.println("\n Inside sampleFunc value of string = " + str);
}
public static void sampleStaticFunc(String str)
{
System.out.println("\n Inside static sampleFunc value of string = " + str);
}
public static void main(String[] args)
{
MyJava obj = new MyJava();
obj.sampleFunc("Ishaan is my name");
System.out.println("\n Calling Java from C function \n");
}
}
After that Ran these commands
unions#universe:~/uni_tmp/jni/vvn$ javac MyJava.java
unions#universe:~/uni_tmp/jni/vvn$ javah -jni MyJava
When I compiled and Ran I got this output
export LD_LIBRARY_PATH=/usr/lib/jvm/java-6-openjdk-amd64/jre/lib/amd64/server
unions#universe:~/uni_tmp/jni/vvn$ gcc -I /usr/lib/jvm/java-6-openjdk-amd64/include -I /usr/lib/jvm/java-6-openjdk-amd64/include/linux -L /usr/bin/java -L /usr/lib/jvm/java-6-openjdk-amd64/jre/lib/amd64/server MyC.c -ljvm ; ./a.out
Unable to find the requested class
Where I did wrong?
I changed the options.optionString to like this too
options.optionString = "-Djava.class.path=/home/vpraveen/uni_tmp/jni/vvn";
Even though There is no change in the output.
Any suggestions?
I solved this by making my class into my own package.
When we did not define any package it is taking as default package.
So I created my own package something like this
package com.aqu.vvn
I know its a work around but doing this worked for me.
I will let u know the exact way when I figured out.

Running c++ application using JNI functions in debug build causes segmentation fault

I've got a c++ application that uses jni to get access to java functions.
As long as I build my application in release everything is fine and works. But when I build the application in debug, the application crashes as soon as it calls the jni code.
I'm using QTCreator under Ubuntu 14.04 x64 with gcc 4.8.2 and java 1.7.0_75
Example Methode:
void JNICommunicator::queryJNI_deleteIndividual(std::string path, std::string individualName){
if(jvmStatus != JNI_ERR){
jclass cls = env->FindClass("de/myclasspacked/MyClass"); //when getting to this point, the application crashes
if(env->ExceptionOccurred()){
env->ExceptionDescribe();
}
if(cls != 0){
jmethodID constructor = env->GetMethodID(cls, "<init>", "()V");
jobject object = env->NewObject(cls, constructor);
jmethodID mAC = env->GetMethodID(cls, "deleteIndividual", "(Ljava/lang/String;Ljava/lang/String;)V");
if(mAC != 0){
jstring path = env->NewStringUTF(owlPath.c_str());
jstring individualNameTemp = env->NewStringUTF(individualName.c_str());
jobject jAdd = env->CallObjectMethod(object, mAC, path, individualNameTemp);
if(env->ExceptionOccurred()){
env->ExceptionDescribe();
}
}
}
}
}
any ideas why it crashes or how I can get the application working under debug? Its hard do develop an application without the ability to use debug functions.
Thanks
Best Regards
I get my env from here. This is how I initiate my JVM:
void initJVM(){
std::string dPath = "-Djava.class.path=/svn/owl/OWLApiExample/bin";
char *cstr = new char[dPath .length()+1];
strcpy(cstr, dPath .c_str());
options[0].optionString = cstr;
options[1].optionString = "-Djava.library.path=/svn/owl/OWLApiExample/lib";
options[2].optionString = "-verbose:jni";
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = 0;
JNI_GetDefaultJavaVMInitArgs(&vm_args);
jvmStatus = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
if(jvmStatus != JNI_ERR){
//log
}else{
jsize nVMs;
jvmStatus = JNI_GetCreatedJavaVMs(NULL, 0, &nVMs); // 1. just get the required array length
jvmStatus = JNI_GetCreatedJavaVMs(&jvm, nVMs, &nVMs); // 2. get the data
jvmStatus = jvm->GetEnv((void **)&env, JNI_VERSION_1_6);
if (jvmStatus == JNI_EDETACHED){
if (jvm->AttachCurrentThread((void **) &env, NULL) != 0) {
//log
}else{
}else if (jvmStatus == JNI_EVERSION) {
//log
}
}
}

cocos2dx: Multithreading with pthread and JNI calls crashs with “native thread exited without detaching”

in my cross-platform cocos2dx game I want to async load some images from web and save them to the local storage. For the Android part I use JNI calls to download and save the image to storage with native java code. It works perfect. But when I try to do this in a seperated pthread to prevent my game from freezing I get the error: "native thread exited without detaching" after "ThreadFunction(void *arg)" is finished.
here is my c++ code:
//c++ code
void MyClass::loadImages(){
pthread_t thread;
SimpleStructure* args = new SimpleStructure();
args->s_url = url;
args->s_savename = savename;
pthread_create(&thread, NULL, &ThreadFunction, args);
}
void* ThreadFunction(void * arg) {
SimpleStructure * args = (SimpleStructure * ) arg;
std::string localImagePath;
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
localImagePath = getImageFilePathJNI(args->s_url.c_str(),
args->s_savename.c_str());
#endif
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
localImagePath = URLSpriteHelper::getUrlSprite(args->s_url,
args->s_savename);
#endif
pthread_mutex_lock(&mutex);
loadedImages.push_back(localImagePath);
pthread_mutex_unlock(&mutex);
return NULL;
}
here is my JNI code:
extern "C"
{
std::string getImageFilePathJNI(const char* urlStr, const char* saveName)
{
std::string ret;
JniMethodInfo t;
if (JniHelper::getStaticMethodInfo(t,
"org/cocos2dx/cpp/AppActivity",
"saveImageFromURLtoInternalStorage",
"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;")) {
jstring StringArg1 = t.env->NewStringUTF(urlStr);
jstring StringArg2 = t.env->NewStringUTF(saveName);
jstring retFromJava = (jstring)t.env->CallStaticObjectMethod(t.classID, t.methodID, StringArg1, StringArg2);
const char* str = t.env->GetStringUTFChars(retFromJava, 0);
ret = str;
t.env->ReleaseStringUTFChars(retFromJava, str);
t.env->DeleteLocalRef(StringArg1);
t.env->DeleteLocalRef(StringArg2);
t.env->DeleteLocalRef(t.classID);
}
return ret;
}
}
Any ideas what I'm doing wrong?
Thank you very much!
Question answered in the cocos2dx forum.
http://discuss.cocos2d-x.org/t/multithreading-with-pthread-and-jni-calls-crashs-with-native-thread-exited-without-detaching/15625

What is in android.util.Log#println_native()?

Here is the android.util.Log source code.
At the very bottom (line 340), what is in the method:
public static native int println_native(int bufID,
int priority, String tag, String msg);
i guess println_native() is more or less like its println(), just with an int bufID different.
But even i got the codes of println_native(), i still lack com.android.internal.os.RuntimeInit (line 19, the import) to simulate android.util.Log in old Android version.
Just did some digging in the android source code. This function maps to
static jint android_util_Log_println_native(JNIEnv* env, jobject clazz,
jint bufID, jint priority, jstring tagObj, jstring msgObj)
{
const char* tag = NULL;
const char* msg = NULL;
if (msgObj == NULL) {
jniThrowNullPointerException(env, "println needs a message");
return -1;
}
if (bufID < 0 || bufID >= LOG_ID_MAX) {
jniThrowNullPointerException(env, "bad bufID");
return -1;
}
if (tagObj != NULL)
tag = env->GetStringUTFChars(tagObj, NULL);
msg = env->GetStringUTFChars(msgObj, NULL);
int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);
if (tag != NULL)
env->ReleaseStringUTFChars(tagObj, tag);
env->ReleaseStringUTFChars(msgObj, msg);
return res;
}
Basically this then passes the arguments to the driver in the system which goes and writes to the Log buffer. Log buffer is pointed by /dev/log in the Linux kernel.
Once you have downloaded the sdk, you can use find to dig files.
Java code is linked to cpp code through jni.
In your case, you can use this command to find the related files:
find framework -type f -name "*.cpp" -exec grep "println_native" {} \; -ls
then you'll see that your java function is linked to this file : framework/base/core/jni/android_util_Log.cpp

Undefined Reference Trying to invoke Java from C++

I am trying to create a Java virtual machine from C++ and invoke the main method passing a String argument to the main method of the Java program. I am following this example found on Sun's website: http://java.sun.com/docs/books/jni/html/invoke.html#11202
Here is the simple Java Program:
public class TestJNIInvoke
{
public static void main(String[] args)
{
System.out.println(args[0]);
}
}
Here is the C++ program I am using to (try to) invoke the JVM:
#include <jni.h>
#include <cstdlib>
using namespace std;
int main()
{
JNIEnv *env;
JavaVM *jvm;
jint res;
jclass cls;
jmethodID mid;
jstring jstr;
jclass stringClass;
jobjectArray args;
JavaVMInitArgs vm_args;
JavaVMOption* options = new JavaVMOption[1]; //LINE 18 ERROR
options[0].optionString =
(char*)&"-Djava.class.path=C:\\Program Files\\Java\\jdk1.7.0\\bin";
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
/* load and initialize a Java VM, return a JNI interface
* pointer in env */
res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args); //LINE 26 ERROR
if (res < 0)
{
fprintf(stderr, "Can't create Java VM\n");
exit(1);
}
cls = env->FindClass("TestJNIInvoke");
if (cls == NULL)
{
goto destroy;
}
mid = env->GetStaticMethodID(cls, "main",
"([Ljava/lang/String;)V");
if (mid == NULL)
{
goto destroy;
}
jstr = env->NewStringUTF(" from CPP!");
if (jstr == NULL)
{
goto destroy;
}
stringClass = env->FindClass("java/lang/String");
args = env->NewObjectArray(1, stringClass, jstr);
if (args == NULL)
{
goto destroy;
}
env->CallStaticVoidMethod(cls, mid, args);
destroy:
if (env->ExceptionOccurred())
{
env->ExceptionDescribe();
}
jvm->DestroyJavaVM();
}
Anyway If I just compile the file with:
gcc -I"c:\Program Files\Java\jdk1.7.0\include"
-I"c:\Program Files\Java\jdk1.7.0\include\win32" -c TestJNIInvoke.cpp
It compiles fine, but when I try to compile and link:
gcc -I"c:\Program Files\Java\jdk1.7.0\include"
-I"c:\Program Files\Java\jdk1.7.0\include\win32" -g TestJNIInvoke.cpp
I get two weird errors that I don't understand:
TestJNIInvoke.cpp:18: undefined reference to `operator new[](unsigned int)'
TestJNIInvoke.cpp:26: undefined reference to `_imp__JNI_CreateJavaVM#12'
collect2: ld returned 1 exit status
I marked the lines in the above code where the error is occuring, has anyone encountered this problem before?
Any ideas/links would be great
Thanks
First, don't use gcc. By default, it assumes the code it's handling is written in C. When you want it to compile or link C++ code, you should run g++. This will bring in the C++ standard headers and libraries.
Second, you need to include the java libraries. Section 7.2.1 in the page you linked discusses this.
Your command line should look more like this:
g++ -I"C:\Program Files\Java\jdk1.7.0\include" -L"C:\Program Files\Java\jdk1.7.0\lib" -lthread -ljava TestJNIInvoke.cpp
Note that you might have to add additional include (-I) or linker (-L) directories.

Categories