是否有可能制作一个调用jdbc的Java JNI
Is it possible to make a Java JNI which calls jdbc?
我是jni的新手,非常困惑,如果我可以使用jni来实现我需要做的事情。我想做一个java api将使用jdbc来更新数据库,但这个特定的api将从c++程序调用。
所以我想我可能应该写jni代码通过jdbc访问数据库(这是可能的吗?),创建c++代码并生成dll,以便其他c++程序可以调用dll来更新数据库。这一切都有可能吗?如果是这样,我如何在jni中真正调用jdbc ?如果最终生成了这个dll, Fortran也可以调用它吗?
我的另一个想法是,也许我应该做一个常规的java程序来更新数据库,然后使用说ikvm包装java类到c++ dll?
事情是我必须使用Java访问数据库。我们的c++程序根本不会访问数据库,如果这个java api可以通过系统调用访问就更好了。
或者有没有更好的方法?
我希望我解释得很清楚。我对分配给我的任务不太熟悉,找不到很多相关的参考资料。非常感谢!!
更新:问题是并不是所有的计算机都安装了c++ postgresql驱动程序,但它们确实安装了Java postgresql驱动程序。我们不希望强迫每个人都安装c++数据库驱动程序,也不希望对这些c++程序进行重大更改。所以用Java来访问数据库是有意义的。java系统服务(首选,如dll?)/API基本上是用来记录c++程序的开始时间和结束时间的。c++程序将对该系统服务/Java API进行"函数"调用(带传入参数和返回值)以记录开始/结束时间。
我并不是要告诉你如何去做你想做的事情是正确的还是错误的。但是,如果您正在尝试调用Java代码(JDBC.jar),那么下面是为您准备的。否则,请随意投票。
JVM.hpp:
#ifndef JVM_HPP_INCLUDED
#define JVM_HPP_INCLUDED
#include "../java/jni.h"
#include <windows.h>
#include <iostream>
#include <stdexcept>
#include <algorithm>
class Jvm
{
private:
JavaVM* jvm;
JNIEnv* env;
JavaVMInitArgs jvm_args;
jclass systemClassLoader;
public:
Jvm(std::string ClassPath = ".");
~Jvm();
inline JavaVM* GetJVM() const {return jvm;}
inline JNIEnv* GetENV() const {return env;}
inline jclass GetSystemClassLoader() const {return systemClassLoader;}
void DestroyJVM();
void PrintStackTrace();
jclass DefineClass(const char* FullClassName, const void* ClassBuffer, std::uint32_t BufferLength);
jclass DefineClass(const char* FullClassName, jobject ClassLoader, const void* ClassBuffer, std::uint32_t BufferLength);
void RegisterNativeMethod(const char* MethodName, const char* MethodSignature, void* func_ptr);
void RegisterNativeMethod(jobject ClassLoader, const char* MethodName, const char* MethodSignature, void* func_ptr);
void RegisterNativeMethods(JNINativeMethod* Methods, std::uint32_t MethodCount);
void RegisterNativeMethods(jobject ClassLoader, JNINativeMethod* Methods, std::uint32_t MethodCount);
protected:
void InitClassLoader();
};
#endif // JVM_HPP_INCLUDED
JVM.cpp:
#include "JVM.hpp"
Jvm::~Jvm()
{
env->DeleteGlobalRef(this->systemClassLoader);
jvm->DestroyJavaVM();
}
Jvm::Jvm(std::string ClassPath) : jvm(NULL), env(NULL), jvm_args(), systemClassLoader(NULL)
{
JavaVMOption* options = new JavaVMOption[2];
jvm_args.version = JNI_VERSION_1_6;
JNI_GetDefaultJavaVMInitArgs(&jvm_args);
options[0].optionString = const_cast<char*>("-Djava.compiler=NONE");
options[1].optionString = const_cast<char*>(("-Djava.class.path=" + ClassPath).c_str());
jvm_args.nOptions = 2;
jvm_args.options = options;
jvm_args.ignoreUnrecognized = false;
if (JNI_CreateJavaVM(&jvm, reinterpret_cast<void**>(&env), &jvm_args))
{
delete[] options;
throw std::runtime_error("Failed To Create JVM Instance.");
}
delete[] options;
}
void Jvm::InitClassLoader()
{
if (!this->systemClassLoader)
{
jclass classloader = env->FindClass("Ljava/lang/ClassLoader;");
if (!classloader)
{
throw std::runtime_error("Failed To find ClassLoader.");
}
jmethodID SystemLoaderMethod = env->GetStaticMethodID(classloader, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
jobject loader = env->CallStaticObjectMethod(classloader, SystemLoaderMethod);
this->systemClassLoader = reinterpret_cast<jclass>(env->NewGlobalRef(loader));
}
}
void Jvm::PrintStackTrace()
{
if (env->ExceptionOccurred())
{
env->ExceptionDescribe();
env->ExceptionClear();
}
}
jclass Jvm::DefineClass(const char* FullClassName, const void* ClassBuffer, std::uint32_t BufferLength)
{
this->InitClassLoader();
return this->DefineClass(FullClassName, this->systemClassLoader, ClassBuffer, BufferLength);
}
jclass Jvm::DefineClass(const char* FullClassName, jobject ClassLoader, const void* ClassBuffer, std::uint32_t BufferLength)
{
return ClassLoader ? env->DefineClass(FullClassName, ClassLoader, static_cast<const jbyte*>(ClassBuffer), BufferLength) : NULL;
}
void Jvm::RegisterNativeMethod(const char* MethodName, const char* MethodSignature, void* func_ptr)
{
JNINativeMethod method;
method.name = const_cast<char*>(MethodName);
method.signature = const_cast<char*>(MethodSignature);
method.fnPtr = func_ptr;
this->RegisterNativeMethods(&method, 1);
}
void Jvm::RegisterNativeMethod(jobject ClassLoader, const char* MethodName, const char* MethodSignature, void* func_ptr)
{
JNINativeMethod method;
method.name = const_cast<char*>(MethodName);
method.signature = const_cast<char*>(MethodSignature);
method.fnPtr = func_ptr;
this->RegisterNativeMethods(ClassLoader, &method, 1);
}
void Jvm::RegisterNativeMethods(JNINativeMethod* Methods, std::uint32_t MethodCount)
{
this->InitClassLoader();
this->RegisterNativeMethods(this->systemClassLoader, Methods, MethodCount);
}
void Jvm::RegisterNativeMethods(jobject ClassLoader, JNINativeMethod* Methods, std::uint32_t MethodCount)
{
if (ClassLoader)
{
env->RegisterNatives(static_cast<jclass>(ClassLoader), Methods, MethodCount);
}
}
你可以创建一个实例来加载你的jar。
int main()
{
Jvm VM("C:/Users/Brandon/IdeaProjects/Eos/out/production/Eos/Bot.jar");
jclass jMain = VM.GetENV()->FindClass("eos/Main");
if (jMain != nullptr)
{
jmethodID mainMethod = env->GetStaticMethodID(jMain, "main", "([Ljava/lang/String;)V");
jclass StringClass = env->FindClass("java/lang/String");
jobjectArray Args = env->NewObjectArray(0, StringClass, 0);
env->CallStaticVoidMethod(jMain, MainMethod, Args);
}
}
现在,这只是展示了如何使用Main方法运行jar。但是,您可以访问jar中的任何类,并使用所需的任意多个参数调用它。它不需要main。
现在做这个要做很多工作,但我不会教训你。问题是这是否可能,答案是肯定的。它是。只要创建一个"JVM"实例即可。在那之后,这是一个通过"Package/class"访问类的问题,而不是像Java中那样"Package. class"。然后调用你想要的任何方法
- 构造函数正在调用一个使用当前类类型的函数
- C++ 如何根据作为输入传递的参数调用一个构造函数或另一个构造函数?
- 使用另一个函数调用一个函数(都在类中)时出现问题.没有错误代码C++
- 为什么我可以调用一个从const方法更改成员的方法
- 如何在另一个.cpp文件中调用一个.cpp文件中的函数
- 调用一个小函数两次(例如在if条件和主体中)比将结果存储在局部变量中更可取
- 使用线程从另一个成员函数调用一个Member函数
- 如何在另一个类中调用一个类的构造函数?
- 每 1 秒(准确地)调用一个函数
- 是否有一种方法可以调用一个函数,而不会创建变量,而不会创建变量
- 是否可以从另一个类对象调用一个类函数而不继承第一个类
- llvm 调用一个以 char * 作为参数的外部函数
- 它不是编译.我正在调用一个通过引用调用的函数,但有一个错误,无法将双*转换为双倍
- 如何在另一个函数中调用一个函数进行循环,同时通过函数传递数组
- 创建并调用一个空功能
- 是否有希望在std::变体上高效地调用一个公共基类方法
- Rcpp:从全局环境调用一个R函数,并在C++代码中使用它
- 每个线程或每个调用一个 ZeroMQ 套接字
- 虚幻c++使用LineTrace从Actor调用一个void
- 如何从另一个类调用一个类中的函数?(C++)