是否可以制作一个调用jdbc的Java JNI? [英] Is it possible to make a Java JNI which calls jdbc?

查看:144
本文介绍了是否可以制作一个调用jdbc的Java JNI?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我可以使用jni来实现我所需要的完成,那么我对jni很陌生,很困惑。我想做一个java api什么将使用jdbc更新数据库,但这个特定的api将从C ++程序调用。所以我想我可能应该编写通过jdbc访问数据库的jni代码(甚至是可能的),创建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: p>

  #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();

内联JavaVM * GetJVM()const {return jvm;}
内联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:

  #includeJVM.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(创建JVM实例失败);
}

delete [] options;
}

void Jvm :: InitClassLoader()
{
if(!this-> systemClassLoader)
{
jclass classloader = env-> findClass的( Ljava /郎/类加载器;);
if(!classloader)
{
throw std :: runtime_error(无法找到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.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.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 /出/生产/ EOS / Bot.jar);

jclass jMain = VM.GetENV() - > FindClass(eos / Main);

if(jMain!= nullptr)
{
jmethodID mainMethod = env-> GetStaticMethodID(jMain,main,([Ljava / lang / String; );
jclass StringClass = env-> FindClass(java / lang / String);
jobjectArray Args = env-> NewObjectArray(0,StringClass,0);
env-> CallStaticVoidMethod(jMain,MainMethod,Args);
}
}

现在这只是演示如何运行一个jar主要方法。但是,您可以从jar访问ANY类,并调用它,但需要许多参数。它不需要一个主要的。



现在有更多的工作要做,但我不会演讲你。问题是是否可能,答案是YES ..它是。只要你创建一个JVM的实例。之后,这是通过Java中的Package / Class而不是Package.Class来访问课程,然后调用你想要的任何方法。


I am new to jni and very confused if I can use jni to achieve what I need done. I want to make a java api what will use jdbc to update database, but this particular api will be called from C++ program.

So I think I probably should write jni code which access the database via jdbc (is that even possible?), create C++ code and generate dll so other C++ programs can just call the dll to update database. Is this all possible? If so, how do I really call jdbc in jni? If this dll is finally made, can Fortran call it as well?

My other thought is maybe I should make a regular java program to update the database, then use say ikvm to wrap the java class into C++ dll?

The thing is I have to use access database using Java. Our C++ programs will not access database at all, and it would be better if this java api can be accessed via system call.

Or is there any better way to do it?

I hope I explained it well. I am not all familiar with what I am assigned here and cannot find much relevant reference.

Thank you so much!!

UPDATED: The problem is not all computers have C++ postgresql driver installed but they do have Java postgresql driver installed. We don't want to force everyone to install the C++ db driver and no major changes in those C++ program will be made. So it will make sense to come up something in Java to access database. The java system service (preferred, like dll?) /API basically is called to record start time and end time of a C++ program. C++ program will make a "function" call (with pass-in parameter and returned value) to this system service/Java API to record start/end time.

解决方案

I'm not going to lecture you on the right or wrong way to approach what you are trying to do. However, if you are trying to invoke Java code (JDBC.jar) then the following is for you.. Otherwise feel free to downvote.

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

You can then create an instance of it that loads your 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);
    }
}

Now this just shows how to run a jar with a Main Method. However, you can access ANY class from the jar and invoke it with however many parameters needed. It doesn't need a main.

Now it IS a lot MORE work to do this, but I won't lecture you. The question was whether or not is was possible and the answer is YES.. it is. So long as you create an instance of the "JVM". After that, it's a matter of accessing the class via the "Package/Class" NOT "Package.Class" as done in Java.. then invoking whatever methods you want.

这篇关于是否可以制作一个调用jdbc的Java JNI?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆