我正在用C ++编写应用程序。我想从这个应用程序启动JVM并调用Java方法。我使用Cygwin在Windows 10上运行。
根据Java Invocation API页面,我相信我正在调用JVM;但是,当我打印系统属性“java.class.path”时,它显示为空。
如果我将类文件复制到$PWD/main/MyClass.class
一切正常,但如果我将此类文件打包到$PWD/main.jar
并尝试以相同的方式引用,那么我得到:
java.lang.NoClassDefFoundError: main/MyClass
Caused by: java.lang.ClassNotFoundException: main.MyClass
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
以下程序的输出是:
Value of 'java/lang/System.getProperty(java.class.path)' is ''.
Value of 'java/lang/System.getProperty(user.dir)' is 'C:\Users\admin\java_from_cpp_stack\bin'.
Failed to find class 'main/MyClass'.
这是C ++代码:
#include <jni.h>
#include <iostream>
bool
printSysemProperty(JNIEnv* env, std::string property)
{
std::string className = "java/lang/System";
jclass cls = env->FindClass(className.c_str());
if (cls == 0) {
std::cout << "Failed to find class '" << className.c_str() << "'.\n";
return false;
}
std::string methodName = "getProperty";
jmethodID mid = env->GetStaticMethodID(cls, methodName.c_str(), "(Ljava/lang/String;)Ljava/lang/String;");
if (mid == 0) {
std::cout << "Failed to find method '" << className.c_str() << "." << methodName.c_str() << "'.\n";
return false;
}
jstring cp = env->NewStringUTF(property.c_str());
jstring val = (jstring)env->CallStaticObjectMethod(cls, mid, (jstring)cp);
const char* valCStr = env->GetStringUTFChars(val, JNI_FALSE);
std::cout << "Value of '" << className.c_str() << "." << methodName.c_str() << "(" << property.c_str() << ")' is '" << (char*)valCStr << "'.\n";
return true;
}
int
main(int argc, char **argv)
{
// Create JVM
JavaVM* vm;
JNIEnv* env;
JavaVMInitArgs vm_args;
JavaVMOption* options = new JavaVMOption[1];
//options[0].optionString = (char*)"-Djava.class.path=.";
//options[0].optionString = (char*)"-Djava.class.path=C:\\Users\\admin\\java_from_cpp_stack\\bin\\main.jar";
//options[0].optionString = (char*)"-Djava.class.path=/cygdrive/c/Users/admin/java_from_cpp_stack/bin/main.jar";
options[0].optionString = (char*)"-Djava.class.path=main.jar";
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
int ret = JNI_CreateJavaVM(&vm, (void**)&env, &vm_args);
delete options;
if (ret != 0)
std::cerr << "Failed to create JVM.\n";
// Print System Properties
bool rc = true;
rc &= printSysemProperty( env, "java.class.path");
rc &= printSysemProperty( env, "user.dir");
if (!rc) {
std::cout << "Printing system properties failed.\n";
return rc;
}
// Call Static Method from JAR
std::string className = "main/MyClass";
jclass cls = env->FindClass(className.c_str());
if (cls == 0) {
std::cout << "Failed to find class '" << className.c_str() << "'.\n";
return -3;
}
jmethodID mid = env->GetStaticMethodID(cls, "hello", "()V");
if (mid == 0) {
std::cout << "Failed to find method '" << className.c_str() << ".hello'.\n";
return -4;
}
std::cout << "Calling '" << className.c_str() << ".main'.\n";
env->CallStaticVoidMethod(cls, mid);
// Clean up
vm->DestroyJavaVM();
std::cout << "Complete.\n";
return 0;
}
这是Java代码:
package main;
public class MyClass {
public MyClass() {
}
public static void hello() {
System.out.println("From Java: Hello World!");
}
}
这是我用来编译的BASH脚本:
#!/bin/bash
set -e
set -x
rm -rf ./build
mkdir ./build
rm -rf ./bin/
mkdir ./bin/
g++ \
-o ./bin/myprog \
./src/cpp/myprog.c \
-D__int64=int64_t \
-L/cygdrive/c/Program\ Files/Java/jdk1.8.0_131/jre/bin/server/ \
-ljvm \
-I/cygdrive/c/Program\ Files/Java/jdk1.8.0_131/include \
-I/cygdrive/c/Program\ Files/Java/jdk1.8.0_131/include/win32
/cygdrive/c/Program\ Files/Java/jdk1.8.0_131/bin/javac \
-Xlint:all \
-Werror \
-g \
-verbose \
-cp ./build \
-sourcepath ./src/java \
-d ./build \
./src/java/main/MyClass.java
/cygdrive/c/Program\ Files/Java/jdk1.8.0_131/bin/jar \
cvf ./bin/main.jar \
-C ./build \
main/MyClass.class
#mkdir ./bin/main
#cp ./build/main/MyClass.class ./bin/main
cd ./bin
PATH=/cygdrive/c/Program\ Files/Java/jdk1.8.0_131/jre/bin/server/:/cygdrive/c/Program\ Files/Java/jdk1.8.0_131/bin/:$PATH ./myprog
答案 0 :(得分:0)
事实证明解决方案发布在这里: JNI JVM Invocation Classpath
在x86-64上,Oracle Windows JDK标头定义jint为long。这是 使用Microsoft编译器的32位(编写Oracle JDK) 但64位与Cygwin gcc。由于
$.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } });
包含一些字段 在这种类型中,它的二进制布局会因这种差异而改变。
另见: Error when compiling in cygwin
我的修复是:
从JavaVMInitArgs
命令行
-D__int64=int64_t
添加标题文件g++
然后jni_local.h
被识别。
JavaVMInitArgs
文件内容为:
src/cpp/jni_local.h
#include "stdint.h"
#define __int64 int64_t
#define long int32_t
#include "jni_md.h"
#undef long
#include_next "jni.h"
被缩减为:
src/cpp/myprog.c
#include "jni_local.h"
#include <iostream>
int
main(int argc, char **argv)
{
// Create JVM
JavaVM* vm;
JNIEnv* env;
JavaVMInitArgs vm_args;
JavaVMOption* options = new JavaVMOption[1];
options[0].optionString = (char*)"-Djava.class.path=myPackage.jar";
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
int ret = JNI_CreateJavaVM(&vm, (void**)&env, &vm_args);
delete options;
if (ret != 0) {
std::cerr << "Failed to create JVM.\n";
return ret;
}
// Call Static Method from JAR
std::string className = "myPackage/MyClass";
jclass cls = env->FindClass(className.c_str());
if (cls == 0) {
std::cerr << "Failed to find class '" << className.c_str() << "'.\n";
return -3;
}
jmethodID mid = env->GetStaticMethodID(cls, "hello", "()V");
if (mid == 0) {
std::cerr << "Failed to find method '" << className.c_str() << ".hello'.\n";
return -4;
}
std::cerr << "Calling 'myPackage." << className.c_str() << ".hello()'\n";
env->CallStaticVoidMethod(cls, mid);
// Clean up
vm->DestroyJavaVM();
std::cerr << "Complete.\n";
return 0;
}
未被更改。
src/java/myPackage/MyClass.java
文件已更新为:
run.sh