Можно ли создать Java JNI, который вызывает jdbc?

91
10

Я новичок в jni и очень смущен, если я могу использовать jni для достижения того, что мне нужно. Я хочу сделать java api, что будет использовать jdbc для обновления базы данных, но этот конкретный api будет вызван из программы на С++.


Итак, я думаю, мне, вероятно, следует написать jni-код, который обращается к базе данных через jdbc (возможно, это возможно?), создать код на С++ и сгенерировать dll, чтобы другие С++-программы могли просто вызвать DLL для обновления базы данных. Это все возможно? Если да, то как я действительно называю jdbc в jni?
Если эта dll наконец-то сделана, может ли Fortran назвать это также?


Моя другая мысль, может быть, я должен сделать обычную java-программу для обновления базы данных, а затем использовать say ikvm для переноса класса java в dll С++?


Дело в том, что я должен использовать базу данных доступа с помощью Java. Наши программы на С++ вообще не будут обращаться к базе данных, и было бы лучше, если бы этот java-api можно было получить через системный вызов.


Или есть ли лучший способ сделать это?


Надеюсь, я объяснил это хорошо. Я не совсем знаком с тем, что мне назначено здесь, и не может найти много актуальной справки.


Большое вам спасибо!


ОБНОВЛЕНО:
Проблема заключается не в том, что на всех компьютерах установлен драйвер С++ postgresql, но у них установлен драйвер Java postgresql. Мы не хотим заставить всех устанавливать драйвер db С++, и никаких серьезных изменений в этой программе на С++ не будет. Поэтому имеет смысл придумать что-то в Java для доступа к базе данных. Системная служба java (предпочтительнее, например dll?)/API в основном вызывается для записи времени начала и окончания программы С++. Программа С++ сделает вызов "функции" (с параметром pass-in и возвращаемым значением) для этой системной службы /Java API для записи времени начала и окончания.

спросил(а) 2014-08-19T04:16:00+04:00 6 лет, 2 месяца назад
1
Решение
71

Я не буду лечить вас по правильному или неправильному пути, чтобы приблизиться к тому, что вы пытаетесь сделать. Однако, если вы пытаетесь вызвать 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);
}
}

Затем вы можете создать экземпляр, который загружает вашу банку.


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);
}
}


Теперь это просто показывает, как запустить банку с помощью основного метода. Тем не менее, вы можете получить доступ к ЛЮБОЙ класс из банки и вызвать его с каким-либо количеством необходимых параметров. Он не нуждается в основном.


Теперь для этого много БОЛЬШЕЙ работы, но я не буду читать вам лекции. Вопрос был в том, возможно или нет, и ответ ДА ​​.. это так. Пока вы создаете экземпляр "JVM". После этого, это вопрос доступа к классу через "Package/Class" NOT "Package.Class", как это сделано на Java, затем вызывая любые методы, которые вы хотите.

ответил(а) 2014-08-19T04:31:00+04:00 6 лет, 2 месяца назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема