寻找一种从 C++ 调用 Java 的便捷方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7537822/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 20:23:54  来源:igfitidea点击:

Looking for a convenient way to call Java from C++

javajava-native-interfaceswiginvocation

提问by Daniel Earwicker

It seems most documentation or helper libraries relating to JNI (Java Native Interface) are concerned with calling native code from Java. This seems to be the main use of it, even though it is capable of more.

似乎大多数与 JNI(Java 本机接口)相关的文档或帮助程序库都与从 Java 调用本机代码有关。这似乎是它的主要用途,尽管它有更多功能。

I want to mostly work in the opposite direction: modify an existing (fairly large) portable C++ program by adding some Java libraries to it. For example, I want to make it call databases via JDBC, or message queue systems via JMS, or send emails, or call my own Java classes, etc. But with raw JNI this is pretty unpleasant and error-prone.

我主要希望在相反的方向上工作:通过向其中添加一些 Java 库来修改现有(相当大的)可移植 C++ 程序。例如,我想让它通过 JDBC 调用数据库,或者通过 JMS 调用消息队列系统,或者发送电子邮件,或者调用我自己的 Java 类等。但是对于原始 JNI,这非常令人不快且容易出错。

So I would ideally like to write C++ code that can call Java classes as easily as C++/CLI can call CLR classes. Something like:

因此,我希望编写可以像 C++/CLI 调用 CLR 类一样轻松地调用 Java 类的 C++ 代码。就像是:

using namespace java::util::regex; // namespaces mapped

Pattern p = Pattern.compile("[,\s]+");

array<java::lang::String> result = 
    p.split("one,two, three   four ,  five");

for (int i=0; i < result.length(); i++)
    std::cout << result[i] << std::endl;

This way, I wouldn't have to manually do the work of getting the method ID by passing the name and the weird signature strings, and would be protected from programming errors caused by the unchecked APIs for calling methods. In fact it would look a lot like the equivalent Java.

这样,我就不必通过传递名称和奇怪的签名字符串手动执行获取方法 ID 的工作,并且可以防止因调用方法的未经检查的 API 导致的编程错误。事实上,它看起来很像等效的 Java。

NB. I AM STILL TALKING ABOUT USING JNI!As an underlying technology it is perfect for my needs. It is "in process" and highly efficient. I don't want to run Java in a separate process and make RPC calls to it. JNI itself is fine. I just want a pleasant interface to it.

注意。我还在谈论使用 JNI!作为一项底层技术,它非常适合我的需求。它处于“过程中”且高效。我不想在单独的进程中运行 Java 并对其进行 RPC 调用。JNI 本身没问题。我只想要一个愉快的界面。

There would have to be a code generation tool to make equivalent C++ classes, namespaces, methods, etc. to exactly match what is exposed by a set of Java classes I specify. The generated C++ classes would:

必须有一个代码生成工具来制作等效的 C++ 类、命名空间、方法等,以完全匹配我指定的一组 Java 类公开的内容。生成的 C++ 类将:

  • Have member functions that accept similarly-wrapped versions of their parameters and then do the necessary JNI voodoo to make the call.
  • Wrap the return values in the same way so I can chain calls in a natural way.
  • Maintain a per-class static cache of method IDs to avoid looking up them every time.
  • Be totally thread-safe, portable, open source.
  • Automatically check for exceptions after every method call and produce a std C++ exception.
  • Also work for when I'm writing native methods in the usual JNI way but I need to call on to other Java code.
  • The array should work totally consistently between primitive types and classes.
  • Will no doubt need something like global to wrap references in when they need to survive outside of a local reference frame - again, should work the same for all array/object references.
  • 让成员函数接受其参数的类似包装版本,然后执行必要的 JNI voodoo 以进行调用。
  • 以相同的方式包装返回值,以便我可以以自然的方式链接调用。
  • 维护每个类的方法 ID 静态缓存,以避免每次都查找它们。
  • 完全线程安全、可移植、开源。
  • 在每次方法调用后自动检查异常并产生 std C++ 异常。
  • 也适用于我以通常的 JNI 方式编写本机方法但我需要调用其他 Java 代码的情况。
  • 数组应该在基本类型和类之间完全一致地工作。
  • 毫无疑问,当引用需要在本地参考框架之外生存时,将需要像 global 之类的东西来包装引用 - 同样,对于所有数组/对象引用都应该相同。

Does such a free, open-source, portable library/tool exist or am I dreaming?

是否存在这样一个免费、开源、可移植的库/工具,还是我在做梦?

Note: I found this existing questionbut the OP in that case wasn't nearly as demanding of perfection as I am being...

注意:我发现了这个现有的问题,但在这种情况下,OP 并不像我那样要求完美......

Update:a comment about SWIG led me to this previous question, which seems to indicate that it is mostly about the opposite direction and so wouldn't do what I want.

更新:关于 SWIG 的评论让我想到了上一个问题,这似乎表明它主要是关于相反的方向,所以不会做我想做的。

IMPORTANT

重要的

  • This is about being able to write C++ code that manipulates Java classes and objects, not the other way round (see the title!)
  • I already know that JNI exists (see the question!) But hand-written code to the JNI APIs is unnecessarily verbose, repetitious, error-prone, not type-checked at compile time, etc. If you want to cache method IDs and class objects it's even more verbose. I want to automatically generate C++ wrapper classes that take care of all that for me.
  • 这是关于能够编写操作 Java 类和对象的 C++ 代码,而不是相反(见标题!)
  • 我已经知道 JNI 存在(请参阅问题!)但是 JNI API 的手写代码是不必要的冗长、重复、容易出错、在编译时未进行类型检查等。如果您想缓存方法 ID 和类对象它更冗长。我想自动生成 C++ 包装器类,为我处理所有这些。

Update:I've started working on my own solution:

更新:我已经开始研究我自己的解决方案:

https://github.com/danielearwicker/cppjvm

https://github.com/danielearwicker/cppjvm

If this already exists, please let me know!

如果这已经存在,请告诉我!

NB. If you're considering using this in your own project, feel free, but bear in mind that right now the code is a few hours old, and I only wrote three very unstrenuous tests so far.

注意。如果您正在考虑在自己的项目中使用它,请随意,但请记住,现在代码已经有几个小时了,到目前为止我只编写了三个非常轻松的测试。

采纳答案by Andy Thomas

Yes, there are existing tools that do exactly this -- generate C++ wrappers for Java classes. This makes use of Java APIs in C++ more transparent and enjoyable, with lower cost and risk.

是的,有一些现有的工具可以做到这一点——为 Java 类生成 C++ 包装器。这使得在 C++ 中使用 Java API 更加透明和愉快,成本和风险更低。

The one that I've used the most is JunC++ion. It's mature, powerful and stable. The primary author is very nice, and very responsive. Unfortunately, it's a commercial product, and pricey.

我用得最多的一个是JunC++ion。它成熟、强大且稳定。主要作者人很好,反应也很快。不幸的是,它是一种商业产品,而且价格昂贵。

Jaceis a free, open-source tool with a BSD license. It's been years since I last played with jace. Looks like there's still some active development. (I still remember the USENET post by the original author, over a decade ago, asking basically the same question you're asking.)

Jace是具有 BSD 许可证的免费开源工具。我上次和杰斯一起玩已经有好几年了。看起来仍然有一些积极的发展。(我仍然记得原作者在十多年前发表的 USENET 帖子,问的问题基本上与您所问的问题相同。)

If you need to support callbacks from Java to C++, it's helpful to define C++ classes that implement Java interfaces. At least JunC++ion allows you to pass such C++ classes to Java methods that take callbacks. The last time I tried jace, it did not support this -- but that was seven years ago.

如果需要支持从 Java 到 C++ 的回调,定义实现 Java 接口的 C++ 类会很有帮助。至少 JunC++ion 允许您将此类 C++ 类传递给采用回调的 Java 方法。我上次尝试 jace 时,它​​不支持这一点——但那是七年前。

回答by Alexander Krapf

I'm one of the prinicpal architects for Codemesh's language integration products, including JunC++ion. We have been doing this kind of integration since 1999 and it works really well. The biggest problem is not the JNI part. JNI is tedious and hard to debug, but once you get it right, it mostly just keeps working. Every now and then, you get broken by a JVM or an OS update, and then you have to fine-tune your product, but in general it's stable.

我是 Codemesh 语言集成产品(包括 JunC++ion)的主要架构师之一。自 1999 年以来,我们一直在进行这种集成,而且效果非常好。最大的问题不是 JNI 部分。JNI 既乏味又难于调试,但是一旦你做对了,它基本上就可以继续工作。时不时地,您会被 JVM 或操作系统更新破坏,然后您必须微调您的产品,但总的来说它是稳定的。

The biggest problem is the type system mapping and the trade-offs between general usability and targeted solution. You state for example that you don't like the fact that JACE treats all object references as globals. We do the same thing (with some escape hatches) because it turns out that this is the behavior that works best for 95% of customers, even if it hurts performance. If you're going to publish an API or a product, you have to pick the defaults that make things work for most people. Picking local references as the default option would be wrong because more and more people are writing multithreaded applications, and a lot of Java APIs that people want to use from other languages are intrinsically multithreaded with asynchronous callbacks and the like.

最大的问题是类型系统映射以及通用可用性和目标解决方案之间的权衡。例如,您声明您不喜欢 JACE 将所有对象引用视为全局变量这一事实。我们做同样的事情(有一些逃生舱口),因为事实证明这是最适合 95% 客户的行为,即使它会损害性能。如果您要发布 API 或产品,则必须选择使大多数人都能使用的默认设置。选择本地引用作为默认选项是错误的,因为越来越多的人正在编写多线程应用程序,而人们想要从其他语言中使用的许多 Java API 本质上是多线程的,带有异步回调等。

We also found out that you really want to give people a GUI-based code generator to create the integration specification. Once they've specified it, you use the CLI version to integrate it into the nightly build.

我们还发现您确实希望为人们提供基于 GUI 的代码生成器来创建集成规范。一旦他们指定了它,您就可以使用 CLI 版本将其集成到每晚构建中。

Good luck with your project. It's a lot of work to get right. We spent several years on it and we're still making it better regularly.

祝你的项目好运。要做到正确需要做很多工作。我们花了几年时间,我们仍在定期改进它。

回答by Moritz

I had pretty much the same problems, ended up doing it on my own, maybe this helps someone.

我遇到了几乎相同的问题,最终自己完成了,也许这对某人有帮助。

https://github.com/mo22/jnipp

https://github.com/mo22/jnipp

It has a small runtime footprint (<30kb), manages references, and supports generating Java class interfaces. I.e. LocalRef> stringArray; and then using stringArray[1]->getBytes() or something.

它具有很小的运行时占用空间 (<30kb),管理引用,并支持生成 Java 类接口。即LocalRef> stringArray; 然后使用 stringArray[1]->getBytes() 或其他东西。

回答by Darryl Miles

Re calling Java from C++.

从 C++ 重新调用 Java。

You can do what you wish but you must let Java be in control. What I mean by this is that you create Java threads that call into Native code and from there they block, kind of waiting for your native code to give it something to do. You create as many Java threads as you need to get enough work / throuhput done.

您可以随心所欲,但必须让 Java 处于控制之中。我的意思是,您创建 Java 线程,这些线程调用本机代码并从那里阻塞,有点等待您的本机代码为其提供一些操作。您可以根据需要创建尽可能多的 Java 线程来完成足够的工作/吞吐量。

So your C++ application starts up, it creates a JVM/JavaVM (as per the documented way, example exists in qtjambi codebase see below), this in turn perform the usual JNI initialization and System.loadLibrary() and provides JARs with "native" linkage. You then initialize a bunch of threads and call some JNI code (that you created) where they can block in wait for your C++ code to give them some work to do.

所以你的 C++ 应用程序启动,它创建了一个 JVM/JavaVM(按照记录的方式,示例存在于 qtjambi 代码库中,见下文),这反过来执行通常的 JNI 初始化和 System.loadLibrary() 并提供具有“本机”的 JAR连锁。然后您初始化一堆线程并调用一些 JNI 代码(您创建的),它们可以在其中阻塞等待您的 C++ 代码为它们提供一些工作。

Your C++ code (presumabily from another thread) then sets up and passes all the information needed to one of the blocked and waiting Java Thread workers, it is then given the order to run, it may then go back into pure-Java code to do work and return with a result.

您的 C++ 代码(可能来自另一个线程)然后设置并将所需的所有信息传递给其中一个阻塞和等待的 Java 线程工作者,然后给出运行命令,然后它可能会返回到纯 Java 代码中执行工作并返回结果。

...

...

It is possible to setup and create and contain a JavaVM instance from C++ code. This can be force fed your own CLASSPATH/JARs to setup the contained environment you need encapsulated inside your C++ program.

可以从 C++ 代码设置、创建和包含 JavaVM 实例。这可以强制输入您自己的 CLASSPATH/JAR 以设置您需要封装在 C++ 程序中的包含环境。

Outline of that as I'm sure you have found already at http://download.oracle.com/javase/1.5.0/docs/guide/jni/spec/invocation.html

我相信您已经在http://download.oracle.com/javase/1.5.0/docs/guide/jni/spec/invocation.html 上找到了概要

...

...

There is a kind of C++ => Java JNI generator in the QtJambi project (that I work on and help maintain). This is quite bespoke for the Qt toolkit but essentially it translates a bunch of C++ header files into a collection of C++ .cpp/.h files and *.java file to provide linkage and shell containment of the object so that the competing memory allocation schemes play well together. Maybe there is something to be taken from this.

QtJambi 项目中有一种 C++ => Java JNI 生成器(我负责并帮助维护)。这是为 Qt 工具包量身定制的,但本质上它将一堆 C++ 头文件转换为 C++ .cpp/.h 文件和 *.java 文件的集合,以提供对象的链接和 shell 包含,以便相互竞争的内存分配方案一起玩好。也许可以从中得到一些东西。

This is certainly a proof in cencept for what you are asking the generator just happens to be contained in the qtjambi project (but could be made independant with some work) and this is LGPL licensed (open-source). The Qt toolkit is not a small API yet it can generated 100s of classes to cover high % of API (>85% and almost 100% of Core/GUI parts).

对于您所要求的生成器恰好包含在 qtjambi 项目中(但可以通过某些工作使其独立),这当然是一个概念证明,并且这是 LGPL 许可的(开源)。Qt 工具包不是一个小 API,但它可以生成 100 多个类来覆盖大部分 API(>85% 和几乎 100% 的核心/GUI 部分)。

HTH

HTH

回答by Simon C

I also had many difficulties getting JNI to work on different operating systems, coping with 32/64-bit architectures and making sure the correct shared libraries were found and loaded. I found CORBA (MICO and JacORB) difficult to use too.

让 JNI 在不同的操作系统上工作、处理 32/64 位体系结构以及确保找到并加载正确的共享库,我也遇到了很多困难。我发现 CORBA(MICO 和 JacORB)也很难使用。

I found no effective way to call from C/C++ into Java and my preferred solutions in this situation are to run my Java code as either:

我发现没有从 C/C++ 调用到 Java 的有效方法,在这种情况下我的首选解决方案是将我的 Java 代码运行为:

  1. a stand-alone program that I can easily run from C/C++ programs with java -cp myjar.jar org.foo.MyClass. I guess this is too simplistic for your situation.

  2. As a mini-server, accepting requests from C/C++ programs on a TCP/IP socket and returning results through this socket too. This requires writing networking and serializing functions but decouples the C/C++ and Java processes and you can clearly identify any problems as being in the C++ side or Java side.

  3. As a Servlet in Tomcat and make HTTP requests from my C/C++ program (other servlet containers would also work too). This also requires writing networking and serializing functions. This is more like SOA.

  1. 一个独立的程序,我可以很容易地从 C/C++ 程序运行java -cp myjar.jar org.foo.MyClass。我想这对你的情况来说太简单了。

  2. 作为迷你服务器,在 TCP/IP 套接字上接受来自 C/C++ 程序的请求,并通过该套接字返回结果。这需要编写网络和序列化函数,但将 C/C++ 和 Java 进程解耦,您可以清楚地识别任何问题是在 C++ 端还是 Java 端。

  3. 作为 Tomcat 中的 Servlet 并从我的 C/C++ 程序发出 HTTP 请求(其他 servlet 容器也可以工作)。这也需要编写网络和序列化函数。这更像是 SOA。

回答by MattRing

What about using Thriftor Protocol Buffersto facilitate your Java to C++ calls?

如何使用ThriftProtocol Buffers来促进 Java 到 C++ 的调用?

回答by Daniel Earwicker

Answering my own question:

回答我自己的问题:

http://java4cpp.kapott.org/

http://java4cpp.kapott.org/

Doesn't appear to be an active project. The author recommends it not be used with JDK 1.5 or later.

似乎不是一个活跃的项目。作者建议不要与 JDK 1.5 或更高版本一起使用。

It appears to have a serious problem: it passes around naked pointers to its wrapper objects:

它似乎有一个严重的问题:它传递指向其包装对象的裸指针:

java::lang::Integer* i = new java::lang::Integer("10");

delete i; // don't forget to do this!

It also causes a more subtle problem that in order to represent assignment compatibility (e.g. a class as a subtype of the interface it implements) the wrappers have to inherit from each other.

它还导致了一个更微妙的问题,即为了表示赋值兼容性(例如,一个类作为它实现的接口的子类型),包装器必须相互继承。

回答by Axel

Maybe a bit of a too large hammer for this nail, but isn't that what CORBAwas built for?

对于这颗钉子来说,锤子可能有点太大了,但这不是CORBA 的目的吗?

回答by Axel

Since CORBA doesn't seem to be what you want, here are links describing how to start JVM from C/C++ and calling JAVA-methods.

由于 CORBA 似乎不是您想要的,这里有描述如何从 C/C++ 启动 JVM 和调用 JAVA 方法的链接。

http://java.sun.com/docs/books/jni/html/invoke.htmland http://java.sys-con.com/node/45840

http://java.sun.com/docs/books/jni/html/invoke.htmlhttp://java.sys-con.com/node/45840

PS: When interfacing Java with C++ you should also have a look at JNAor bridj.

PS:当将 Java 与 C++ 接口时,您还应该查看JNAbridj