2011-09-24 79 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()或其他。

相關問題