2011-09-24 207 views
28

似乎大多数与JNI(Java本地接口)相关的文档或帮助程序库都与从Java调用本地代码有关。这似乎是它的主要用途,即使它有更多的功能。寻找一种方便的方式从C++调用Java

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

所以我最好喜欢编写可以调用Java类的C++代码,就像C++/CLI可以调用CLR类一样容易。喜欢的东西:

​​

这样,我就不会去manually do the work of getting the method ID by passing the name and the weird signature strings,并会从调用方法所造成的未检查的API编程错误保护。实际上它看起来很像是等效的Java。

注:我还在谈论使用JNI!作为一项基础技术,它非常适合我的需求。它“在进行中”并且高效。我不想在单独的进程中运行Java并对其进行RPC调用。 JNI本身很好。我只是想要一个愉快的界面。

必须有一个代码生成工具才能使等价的C++类,名称空间,方法等完全匹配我指定的一组Java类所公开的内容。生成的C++类将会:

  • 有成员函数接受它们的参数的类似包装版本,然后执行必要的JNI voodoo来进行调用。
  • 以相同的方式包装返回值,以便以自然方式链接调用。
  • 维护方法ID的每类静态缓存,以避免每次都查找它们。
  • 完全是线程安全的,便携式的,开源的。
  • 在每次方法调用后自动检查异常并生成std C++异常。
  • 当我以通常的JNI方式编写本机方法时也适用,但我需要调用其他Java代码。
  • 该数组应该在原始类型和类之间完全一致地工作。
  • 毫无疑问,当它们需要在局部参考框架之外生存时,需要像全局一样来包装引用 - 再次,对于所有数组/对象引用应该都是相同的。

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

注:我发现this existing question,但在这种情况下,OP远没有完美的苛求,因为我是...

更新:关于SWIG评论使我this previous question,这似乎表明它主要是相反的方向,所以不会做我想要的。

重要

  • 这是关于能够编写C++代码,操纵Java类和对象,而不是倒过来(见标题!)
  • 我已经知道JNI存在( )但是对JNI API的手写代码不必要的冗长,重复,容易出错,不会在编译时进行类型检查等。如果您想要缓存方法ID和类对象,那么它更加冗长。我想自动生成C++包装类,为我处理所有这些。

更新:我开始了我自己的解决方案的工作:

https://github.com/danielearwicker/cppjvm

如果已经存在,请让我知道!

NB。如果你正在考虑在你自己的项目中使用它,请随时留意,但请记住,现在代码已经过了几个小时了,到目前为止我只写了三个非常艰难的测试。

+1

虽然我只用它用于C和Python ...一个很长的时间以前,还有[SWIG](http://www.swig.org/Doc1.3/Java.html)。 – 2011-09-24 08:52:24

+0

查看更新:SWIG显然不会这样做。 –

+0

你想在哪个编译器/解释器执行你的程序,C还是Java?如果是Java,那么使用JNI是不可能的。 – Naved

回答

16

是的,现有的工具可以做到这一点 - 为Java类生成C++包装。这使得C++中的Java API更加透明和令人愉快,同时降低了成本和风险。我使用最多的是JunC++ion。它成熟,强大而稳定。主要作者非常好,并且非常敏感。不幸的是,这是一个商业产品,而且价格昂贵。

Jace是一款免费的开源工具,带有BSD许可证。我上次和杰斯一起打球已经有好几年了。看起来还有一些积极的发展。 (我还记得十多年前原作者的USENET文章,基本上提出了同样的问题)

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

+0

谢谢。我从Jace的消息来源看到,它将每一个参考变成全球!这不是一个好主意。 JNI故意让这个选项:全局变量比本地变量更重,实际程序中绝大多数变量都是本地变量。当JVM负责处理时,不需要在析构函数中“释放”本地语言。你只需要一个RAII类来封装'PushLocalFrame' /'PopLocalFrame'。 JunC++离子采取什么方法? –

+2

顺便说一下,我的Google搜索条件是'C++ Java JNI Wrapper',我现在看到JunC++ ion在结果的第22页!还没有发现Jace ... –

+0

JunC++离子将在第1页,如果搜索是基于质量。我现在无法访问JunC++。我猜想在某些情况下全局引用是必要的,而其他的则足够了,但这只是一种猜测。我会看看我能否让作者回应。 –

1

文章Java Tip 17: Integrating Java with C++描述了如何详细说明。

+2

不错的猜测,但那篇文章是从1996年开始的(它提到没有办法保存全局引用!很久以前,它已经被添加到了1.2中)。另外,本文仅介绍如何手动编写JNI调用代码,这是我想避免使用代码生成工具所做的事情。 –

+0

+1,好东西。 – Naved

2

从C++重新调用Java。

你可以做你想做的事情,但你必须让Java控制。我的意思是,你创建的Java线程调用本地代码,并从那里阻止,有种等待你的本地代码给它做的事情。您可以创建尽可能多的Java线程来完成足够的工作/吞吐量。因此你的C++应用程序启动时,它会创建一个JVM/JavaVM(按照记录的方式,在qtjambi代码库中存在的示例请参见下文),然后执行通常的JNI初始化和System.loadLibrary(),并提供JAR与“本地”链接。然后初始化一堆线程并调用一些JNI代码(您创建的),在那里它们可以阻塞,等待您的C++代码给他们做一些工作。

然后,您的C++代码(大概来自另一个线程)设置并将所需的所有信息传递给其中一个被阻塞和正在等待的Java线程worker,然后给它命令运行, Java代码做工作并返回结果。

...

它可以设置和创建和C++代码包含的JavaVM实例。这可以强制喂你自己的CLASSPATH/JAR来设置你需要封装在C++程序中的包含环境。那

大纲,因为我敢肯定你已经找到了在http://download.oracle.com/javase/1.5.0/docs/guide/jni/spec/invocation.html

...

有一种在QtJambi项目C++ => Java的JNI发生器(即我的工作和帮助维护)。这是Qt工具包的特色,但实质上它将一堆C++头文件转换为C++ .cpp/ .h文件和* .java文件的集合,以提供对象的链接和外壳遏制,以便竞争内存分配方案一起发挥得很好。也许有什么需要从这个。

这无疑是cencept证明你所问的发电机恰好包含在qtjambi项目(但可以由独立的一些工作),这是LGPL许可(开源)。 Qt工具包不是一个小的API,但它可以生成100个类来覆盖大部分的API(> 85%和几乎100%的Core/GUI部分)。

HTH

+0

有关线程的部分答案对我来说没有意义。我已经可以做比使用纯JNI更简单的事情了。我只是初始化JVM,请求它加载一个类,调用它的构造函数,调用它的方法。这里的所有都是它的。 –

+0

QtJambi库是一个项目,允许Java代码使用Qt库,即Java调用C++。它是否读取现有的Java类并生成相应的C++包装类,以便可以从C++轻松调用Java类? –

+1

线程问题是关于如何设置一个进程,以便C++可以在任何时候安全地调用Java。 Qt库的一部分是复杂的,它是一个C++库,也需要回调到Java。您可以注册以C++运行的callback/eventHandlers /线程,但偶尔会在Java中调用事物。 Java拥有纯Java和C/C++的API。但是C/C++没有用于在Java中执行操作的API。当Java已经有一个C++ API(即JNI)时,做一个Java事物的C++包装是没有意义的。 –

0

也许有点过大锤子这种指甲的,但是,这不是什么CORBA是为建?

+3

来自该链接:“C++映射非常困难;映射要求程序员学习早于C++标准模板库的复杂和令人困惑的数据类型”听起来很棒! :) –

1

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

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

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

  2. 作为迷你服务器,接受来自C/C++ 程序的TCP/IP套接字请求,并且 也通过此套接字返回结果。 这需要编写网络和序列化函数 ,但将C/C++和Java进程分开,并且您可以清楚地发现任何问题,因为它们在C++端或Java端。

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

+0

谢谢。到目前为止,我已经有了在Windows和Linux上工作的JNI,没有任何问题 - 它看起来基本相同。 CORBA是离开我需要的。将进程外的所有调用编组看起来像是使用SOA(或CORBA)获得的东西的手写版本,所有这些调用都会带来额外的额外开销和更多的复杂性。 –

+0

同时,如果只是每个方法调用的咒语(通过方法名称和签名,缓存ID,确定'Call [Static] MethodT'的正确风味,检查异常),JNI将是完美的轻量级解决方案。完全自动化。这就是我想要的。 –

+0

另一个商业产品:http://www.javain.com/javain/oojni.jsp?cat=oojni&sub=whatIs –

1

如何使用​​或Protocol Buffers来简化Java到C++的调用?

+0

我应该更新我的问题,以排除使用RPC到进程外服务器。 –

0

回答我的问题:

http://java4cpp.kapott.org/

不会出现一个活跃的项目。作者建议不要使用JDK 1.5或更高版本。

它似乎有一个严重的问题:它绕过裸指针的包装对象:

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

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

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

7

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

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

我们还发现,您确实想给人们一个基于GUI的代码生成器来创建集成规范。一旦他们指定了它,就可以使用CLI版本将其整合到夜间构建中。

祝您的项目顺利。正确的工作很多。我们花了好几年的时间,并且我们仍然定期更好。

+0

谢谢。回复:明智的默认选择,我完全同意 - 这是有关设计IMO的最重要的事情。对于我现在的项目来说,选择使用本地语言将是非常重要的,共享数据将是非常少数的,所以我要为'java :: lang :: String'和'global '分别作为本地语言和全局语法的语法。 –

3

我有几乎相同的问题,结果我自己做,也许这有助于某人。

https://github.com/mo22/jnipp

它具有占用资源很小(< 30KB),管理参考,并支持生成Java类接口。 也就是说LocalRef> stringArray;然后使用stringArray [1] - > getBytes()或其他。

相关问题