Finding java class from jar file in QT using JNI - java

I have created a simple java class and exported as jar file.
Then I tried to load the java class in C++ using JNI but i couldn't.
But if I load it directly from java file its wokring but from jar file it's not wokring.
Pdf.java
package PdfCore;
public class Pdf {
public int x,y;
public Pdf(int _x, int _y){
x = _x;
y = _y;
}
public int sum(){
return x+y;
}
}
Test.pro
TEMPLATE = app
QT += qml quick
CONFIG += c++11
SOURCES += main.cpp
RESOURCES += qml.qrc
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
# Default rules for deployment.
include(deployment.pri)
DISTFILES += \
android/AndroidManifest.xml \
android/gradle/wrapper/gradle-wrapper.jar \
android/gradlew \
android/res/values/libs.xml \
android/build.gradle \
android/gradle/wrapper/gradle-wrapper.properties \
android/gradlew.bat \
android/src/XPdf.jar
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
main.cpp
#include <jni.h>
#include <QDebug>
static JavaVM* s_javaVM = 0;
static jclass s_XPdfID = 0;
static jmethodID s_XPdfConstructorMethodID=0;
static jmethodID s_XPdfSumMethodID=0;
jobject m_XPdfObject;
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*)
{
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
qCritical()<<"Can't get the enviroument";
return -1;
}
s_javaVM = vm;
jclass clazz=env->FindClass("PdfCore/Pdf");
if (!clazz)
{
qCritical()<<"Can't find Pdf class";
return -1;
}
return JNI_VERSION_1_6;
}
jni.h file undefine following
#ifdef __cplusplus
extern "C" {
#endif
/*
* VM initialization functions.
*
* Note these are the only symbols exported for JNI by the VM.
*/
#if 0 /* In practice, these are not exported by the NDK so don't declare them */
jint JNI_GetDefaultJavaVMInitArgs(void*);
jint JNI_CreateJavaVM(JavaVM**, JNIEnv**, void*);
jint JNI_GetCreatedJavaVMs(JavaVM**, jsize, jsize*);
#endif

Related

After creation of JNI_CreateJavaVM, cout no longer works? [duplicate]

I am trying to run a java program using c++ code. I tried below code
#include<jni.h>
#include<stdio.h>
int main(int argc, char** argv) {
JavaVM* vm;
JNIEnv* env;
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_2;
vm_args.nOptions = 0;
vm_args.ignoreUnrecognized = 1;
// Construct a VM
jint results = JNI_CreateJavaVM(&vm, (void**)& env, &vm_args);
// Construct a String
jstring jstr = env->NewStringUTF("Hello World");
// First get the class that contains the method you need to call
jclass clazz = env->FindClass("java/lang/String");
// Get the method that you want to call
jmethodID to_lower = env->GetMethodID(clazz, "toLowerCase",
"()Ljava/lang/String;");
// Call the method on the object
jobject result = env->CallObjectMethod(jstr, to_lower);
// Get a C-style string
const char* str = env->GetStringUTFChars((jstring)result, NULL);
printf("%s\n", str);
// Clean up
env->ReleaseStringUTFChars(jstr, str);
// Shutdown the VM.
vm->DestroyJavaVM();
}
I used below command to compile the code
g++ LoadJVM.c -I/c/apps64/Java/jdk-11.0.1/include -I/c/apps64/Java/jdk-11.0.1/include/win32 -L/c/apps64/Java/jdk-11.0.1/lib/ -ljvm
It compiles fine, but when i run the executable like below, i am facing error
./a.exe
Error
error while loading shared libraries: jvm.dll: cannot open shared object file: No such file or directory
Any Idea why this jvm.dll is not getting loaded?
PS: I am compiling and running from Git-Bash on windows 10.
It looks like your jvm.dll can not be found.
Let's say we have 32bit MinGW installation (this is the version I have).
simple.cc
#include<jni.h>
#include<stdio.h>
int main(int argc, char** argv) {
JavaVM* vm;
JNIEnv* env;
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_2;
vm_args.nOptions = 0;
vm_args.ignoreUnrecognized = 1;
// Construct a VM
jint results = JNI_CreateJavaVM(&vm, (void**)& env, &vm_args);
printf("Hello");
// Shutdown the VM.
(*vm).DestroyJavaVM();
}
compilation and execution
> export JAVA_HOME="/c/Program\ Files\ \(x86\)/Java/jdk1.8.0_211/"
> export PATH="/c/Program Files (x86)/Java/jdk1.8.0_211/jre/bin/server/":"$PATH"
> g++ -o simple simple.cc -I"$JAVA_HOME/include/" -I"$JAVA_HOME/include/win32/" -L"$JAVA_HOME/lib" -ljvm
> ./simple
Hello
you have to make sure that jvm.dll is visible on %PATH% - $PATH inside git-bash.

Using JNI to call Java Method that Returns String Array from Cpp

I am trying to call the following java method from C++
final String[] games = GameLoader.listGames();
where GameLoader was imported with import player.GameLoader;. The GameLoader class exists within a jar file. I am trying to use JNI to load the jar file from C++ and then call the above method. The following is my C++ code which I have tried to extend from this SO post.
#include <iostream>
#include <string.h>
#include <jni.h>
#include <stdlib.h>
using namespace std;
#define PATH_SEPARATOR ';'
#define USER_CLASSPATH "Ludii-0.3.0.jar"
#define GAME_LOADER "player/GameLoader"
JNIEnv *env;
JavaVM *jvm;
jint res;
void initJVM() {
#ifdef JNI_VERSION_1_2
JavaVMInitArgs vm_args;
JavaVMOption options[1];
options[0].optionString =
"-Djava.class.path=" USER_CLASSPATH;
vm_args.version = 0x00010002;
vm_args.options = options;
vm_args.nOptions = 1;
vm_args.ignoreUnrecognized = JNI_TRUE;
/* Create the Java VM */
res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
#else
JDK1_1InitArgs vm_args;
char classpath[1024];
vm_args.version = 0x00010001;
JNI_GetDefaultJavaVMInitArgs(&vm_args);
/* Append USER_CLASSPATH to the default system class path */
sprintf(classpath, "%s%c%s",
vm_args.classpath, PATH_SEPARATOR, USER_CLASSPATH);
vm_args.classpath = classpath;
/* Create the Java VM */
res = JNI_CreateJavaVM(&jvm, &env, &vm_args);
#endif /* JNI_VERSION_1_2 */
}
void closeJVM() {
jvm->DestroyJavaVM();
}
int main() {
initJVM();
jclass gameLoader = env->FindClass(GAME_LOADER);
//final String[] games = GameLoader.listGames();
jmethodID mid = env->GetMethodID(gameLoader,"listGames","()[Ljava/lang/String;");
jobjectArray stringArray = (jobjectArray) env->CallObjectMethod(gameLoader,mid);
closeJVM();
}
I am able to successfully create the JVM and the code compiles however at runtime I get the error
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007f0e835619d7, pid=3504, tid=0x00007f0e84028740
#
# JRE version: OpenJDK Runtime Environment (8.0_222-b10) (build 1.8.0_222-8u222-b10-1ubuntu1~16.04.1-b10)
# Java VM: OpenJDK 64-Bit Server VM (25.222-b10 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# V [libjvm.so+0x6849d7]
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /home/alex/jni_examples/hs_err_pid3504.log
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
#
Aborted (core dumped)
I think that the error is related to the CallObjectMethod call but I'm not sure.
Also I am using Java 8
EDIT:
It looks like mid evaluated to 0 which means that the method was not found. I guess this is the problem however I'm not sure why it wasn't found. This was checked with
int main() {
initJVM();
jclass gameLoader = env->FindClass("player/GameLoader");
//final String[] games = GameLoader.listGames();
if(gameLoader == NULL)
{
cout << "Could not load class!" << endl;
return 1;
}
jmethodID mid = env->GetMethodID(gameLoader,"listGames","()[Ljava/lang/String;");
if(mid == NULL)
{
cout << "Could not load method!" << endl;
return 1;
}
jobjectArray stringArray = (jobjectArray) env->CallObjectMethod(gameLoader,mid);
if(stringArray == NULL)
{
cout << "Could not load object!" << endl;
return 1;
}
closeJVM();
}
ANOTHER EDIT:
So it looks like the problem was that listGames() should be found with GetStaticMethodID rather than GetMethodID and it should be called with CallStaticObjectMethod rather than CallObjectMethod. Thank you.

FindClass returns null when .class is not in a default package

I've just looked at anyone else questions but it seems that nobody has the same problem of mine. I have a Java class HelloWorldHandler.java (in org.eclipse.gemoc.testapplilauncher.handlers package in org.eclipse.gemoc.testapplilauncher project) that launches another java application. Then I have a c file launcherC.c (in the same project but different directory) that is supposed to call the execute method in the java file, through JNI. Now, all my previous JNI applications worked, this one doesn't. The only difference is that HelloWorldHandler.java is not in the default package (so the .class is not directy in /bin) and there are multiple package imports (maybe something changes with the FindClass call (?)).
I launch the c file with
gcc -fPIC -I"/usr/lib/jvm/java-8-oracle/include" -I"/usr/lib/jvm/java-8-oracle/include/linux" -L/usr/lib/jvm/java-8-oracle/lib/amd64/jli/ -L/usr/lib/va-8-oracle/jre/lib/amd64/server/ -o launcherC launcherC.c -ljli -ljvm
and
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/lib/jvm/java-8-oracle/jre/lib/amd64/server/
and there is no problem. But when I execute it, it doesn't do anything, without any Expections and errors. I checked and the FindClass returns NULL.
HelloWorldHandler.java
package org.eclipse.gemoc.testapplilauncher.handlers;
public class HelloWorldHandler {
#Execute
public static void execute() {
ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager();
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IFile ff = root.getFile(new Path("d/Test.launch"));
ILaunchConfiguration res = manager.getLaunchConfiguration(ff);
DebugUITools.launch(res, ILaunchManager.DEBUG_MODE);
}
}
launcherC.c
#include <jni.h>
#include <string.h>
int main()
{
JavaVMOption options[1];
JNIEnv *env;
JavaVM *jvm;
JavaVMInitArgs vm_args;
long status;
jclass cls;
jmethodID mid;
options[0].optionString = "-Djava.class.path=/home/ezambon/Desktop/modeling/org/eclipse/gemoc/testAppliLauncher/bin/org/eclipse/gemoc/testapplilauncher/handlers";
memset(&vm_args, 0, sizeof(vm_args));
vm_args.version = JNI_VERSION_1_2;
vm_args.nOptions = 1;
vm_args.options = options;
status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
if (status != JNI_ERR)
{
cls = (*env)->FindClass(env, "HelloWorldHandler");
if(cls != 0) {
//printf("asdfgh\n");
mid = (*env)->GetStaticMethodID(env, cls, "execute", "()V");
if(mid !=0) {
(*env)->CallStaticVoidMethod(env, cls, mid);
}
}
//printf("qwerty");
(*jvm)->DestroyJavaVM(jvm);
return 0;
}
else
return -1;
}
All the suggestions are really welcome, I'm getting crazy. Thank you :)
First problem you setup classpath wrong
Instead of
options[0].optionString = "-Djava.class.path=/home/ezambon/Desktop/modeling/org/eclipse/gemoc/testAppliLauncher/bin/org/eclipse/gemoc/testapplilauncher/handlers";
you should have
options[0].optionString = "-Djava.class.path=/home/ezambon/Desktop/modeling/org/eclipse/gemoc/testAppliLauncher";
and you should use full class name
cls = (*env)->FindClass(env, "org.eclipse.gemoc.testapplilauncher.handlers.HelloWorldHandler");
But I suppose this is not all your problems.

JNI Call java method from c program

I need to call java method from c program. i have tried below code to call the java method through Java native interface but facing issues while compilation. i m new to C and have experience in java. so, i m not able to think myself what is happening while creating JVM.
Below is the code.
CTest.c
#include <stdio.h>
#include <jni.h>
JNIEnv* create_vm() {
JavaVM* jvm;
JNIEnv* env;
JavaVMInitArgs args;
JavaVMOption options[1];
args.version = JNI_VERSION_1_6;
args.nOptions = 1;
options[0].optionString = "-Djava.class.path=D:\\Ashish_Review\\JNI\\src";
args.options = options;
args.ignoreUnrecognized = JNI_FALSE;
JNI_CreateJavaVM(&jvm, (void **)&env, &args);
return env;
}
void invoke_class(JNIEnv* env) {
jclass helloWorldClass;
jmethodID mainMethod;
jobjectArray applicationArgs;
jstring applicationArg0;
helloWorldClass = (*env)->FindClass(env, "HelloWorld");
mainMethod = (*env)->GetStaticMethodID(env, helloWorldClass, "main", "([Ljava/lang/String;)V");
applicationArgs = (*env)->NewObjectArray(env, 1, (*env)->FindClass(env, "java/lang/String"), NULL);
applicationArg0 = (*env)->NewStringUTF(env, "From-C-program");
(*env)->SetObjectArrayElement(env, applicationArgs, 0, applicationArg0);
(*env)->CallStaticVoidMethod(env, helloWorldClass, mainMethod, applicationArgs);
}
int main(int argc, char **argv) {
JNIEnv* env = create_vm();
invoke_class( env );
}
C:\Users\Desktop\tcc>tcc C:\TurboC++\Disk\TurboC3\BIN\CTest.c -I "C:\Program Files\Java\jdk1.6.0_16\include" -I "C:\Program Files\Java\jdk1.6.0_16\include\win32" -shared -o CTest.dll
tcc: undefined symbol '_JNI_CreateJavaVM#12'
please help me out.
The error message is about the linking stage, not compilation - you have included the header file, but to create the executable you have to specify the .a (library files) also.
You have to link with JVM's library (add some reference to libjvm.a to the tcc's command line).
If you don't have a precompiled jvm.lib file for TurboC++, there is another option - link with the jvm.dll file and export all the methods from JVM manually. This uses the LoadLibrary/GetProcAddress functions.
For a short sample (sorry, couldn't find the entire export source code), look at this:
/* load library */
HMODULE dll = LoadLibraryA("jvm.dll");
/* declare a function pointer and initialize it with the "pointer" to dll's code */
JNI_CreateJavaVM_func JNI_CreateJavaVM_ptr = GetProcAddress(dll, "JNI_CreateJavaVM");
Later use the JNI_CreateJavaVM_ptr instead of JNI_CreateJavaVM. Also you'll have to declare the JNI_CreateJavaVM_func type - you might just copy the signature from "jni.h"

How to run java class file from C inside a Maven project

I do have a WebApp (WAR file) in a Maven project running fine.
I want to call a Java method in a class file which is inside the maven project from a C file. The C program reads the GPIO input of my beagleboard and when it's on, it runs the Java method. I use JNI for doing that.
I can run a classic HelloWorld Java method, but when I want to run a method from my Maven project, I got a fatal error from my JVM when its trying to load the Java static method.
I added the C code in my WebApp, in /WEB-INF/myapp/classes/classfile/
Class file : App
Method : test
my C program:
JNIEnv* create_vm(JavaVM ** jvm) {
JNIEnv *env;
JavaVMInitArgs vm_args;
JavaVMOption options;
//Path to the java source code
options.optionString = "-Djava.class.path=./";
//JDK version. This indicates version 1.6
vm_args.version = JNI_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(int argc, char** argv)
{
int fd, ret, data[64];
JNIEnv *env;
JavaVM * jvm;
env = create_vm(&jvm);
if (env == NULL)
return 1;
fd = ret = open(argv[argc - 1], O_RDONLY);
printf("open returned %d\n", ret);
while (1) {
ret = read(fd, &data, sizeof(data));
printf("read returned %d\n", ret);
jclass helloWorldClass = (*env)->FindClass(env, "App");
printf("appel class\n");
jmethodID mainMethod = (*env)->GetStaticMethodID(
env, helloWorldClass, "test", "([Ljava/lang/String;)V");
printf("appel method\n");
(*env)->CallStaticVoidMethod(env, helloWorldClass, mainMethod, NULL);
sleep(2);
}
(*jvm)->DestroyJavaVM(jvm);
exit(0);
}
Java class :
package App;
public class App
{
public static void test (String[] args){
System.out.println("Hello World");
}
}
Have you investigated using Reverse JNI?
I notice that you have the following line:
options.optionString = "-Djava.class.path=./"; //Path to the java source code
The classpath needs to point to either the jar file generated by Maven, or the root directory under which your Java class files are located.
See: Setting the ClassPath,
In a standard Maven project, Maven will create your jar under target/ when you execute mvn package. So you'll likely change -Djava.class.path=./ to -cp /target/App.jar

Categories

Resources