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

时间:2011-09-24 08:06:16

标签: java java-native-interface swig invocation

似乎大多数与JNI(Java Native Interface)相关的文档或帮助程序库都涉及从Java调用本机代码。这似乎是它的主要用途,即使它能够更多。

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

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

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;

这样,我就不必manually do the work of getting the method ID by passing the name and the weird signature strings,并且可以防止由未经检查的API调用方法引起的编程错误。实际上它看起来很像等效的Java。

NB。我仍然在谈论使用JNI!作为一项基础技术,它完全符合我的需求。它“在进行中”并且高效。我不想在一个单独的进程中运行Java并对它进行RPC调用。 JNI本身很好。我只想要一个愉快的界面。

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

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

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

注意:我发现this existing question但在这种情况下,OP并不像我一样对完美的要求......

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

重要

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

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

https://github.com/danielearwicker/cppjvm

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

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

10 个答案:

答案 0 :(得分:16)

是的,现有的工具正是这样做的 - 为Java类生成C ++包装器。这使得在C ++中使用Java API更加透明和愉快,而且成本和风险更低。

我最常用的是JunC++ion。它成熟,强大而稳定。主要作者非常好,反应灵敏。不幸的是,它是一种商业产品,价格昂贵。

Jace是一款免费的开源工具,具有BSD许可证。自从我上次与杰斯一起比赛已经好几年了。看起来还有一些积极的发展。 (我还记得十多年前原作者的USENET帖子,问你问的问题基本相同。)

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

答案 1 :(得分:7)

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

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

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

祝你的项目好运。要做到这一点,还有很多工作要做。我们花了几年的时间,我们仍在定期做得更好。

答案 2 :(得分:4)

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

https://github.com/mo22/jnipp

它具有较小的运行时占用空间(<30kb),管理引用,并支持生成Java类接口。 即&localRef所GT;字符串数组;然后使用stringArray [1] - &gt; getBytes()或其他东西。

答案 3 :(得分:2)

从C ++调用Java。

你可以做你想做的事,但你必须让Java得到控制。我的意思是你创建调用Native代码的Java线程,然后从那里阻止它们,等待你的本机代码给它做一些事情。您可以根据需要创建尽可能多的Java线程,以获得足够的工作/吞吐量。

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

你的C ++代码(大概是来自另一个线程)然后设置并传递一个被阻塞和等待的Java Thread工作者所需的所有信息,然后它被赋予运行的顺序,然后它可能会回到pure-Java代码做工作并返回结果。

...

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

我相信你已经在http://download.oracle.com/javase/1.5.0/docs/guide/jni/spec/invocation.html

找到了这个概要

...

有一种C ++ =&gt; QtJambi项目中的Java JNI生成器(我工作并帮助维护)。这对于Qt工具包来说是非常有用的,但实际上它将一堆C ++头文件转换为C ++ .cpp / .h文件和* .java文件的集合,以提供对象的链接和shell包含这样竞争的内存分配方案可以很好地协同工作。也许从中可以采取一些措施。

这肯定是一个证据,你要求生成器恰好包含在qtjambi项目中(但可以与某些工作无关),这是LGPL许可(开源)。 Qt工具包不是一个小API,它可以生成100个类来覆盖高%的API(> 85%和几乎100%的Core / GUI部分)。

HTH

答案 4 :(得分:1)

文章Java Tip 17: Integrating Java with C++详细介绍了如何执行此操作。

答案 5 :(得分: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 ++发出HTTP请求 程序(其他servlet容器也可以工作)。 这还需要编写网络和序列化功能。 这更像是SOA。

答案 6 :(得分:1)

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

答案 7 :(得分:0)

这个钉子的锤子可能有点太大了,但是CORBA是不是建造的?

答案 8 :(得分:0)

由于CORBA似乎不是你想要的,下面是描述如何从C / C ++启动JVM并调用JAVA方法的链接。

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

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

答案 9 :(得分: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!

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