JNIより簡単にJavaとC/C++をつなぐ「JNA」とは
富士ソフト株式会社
高見 誠
2009/12/14
■ 【6】入れ子構造体型のマッピング
引数としてStructureの配列を渡す方法とStructureの配列を受け取る方法をすでに、理解していただけたと思います。これらを利用すれば、さらに入れ子構造体型のマッピングできます。
ここも、やはりサンプルソースコードを通じ、説明します。いままでの社員情報に、給与基本情報と家族構成情報を追加します。給与基本情報は、構造体SALARYで表現します。家族構成情報は、FAMILYMEMBERで表現します。リスト8とリスト9は、そのサンプルソースコードです。
● C/C++側
リスト8 入れ子構造体型のマッピングC/C++側のサンプルソースコード
1 /**
2 * 給与基本情報構造体
3 */
4 typedef struct {
5 int type; /*給与レベルタイプ*/
6 int salary; /*基本月給*/
7 } SALARY;
8 /**
9 * 家族構成情報構造体
10 */
11 typedef struct {
12 char* name; /*氏名*/
13 int sex; /*性別*/
14 char* relationship; /*続柄*/
15 char* address /*住所*/
16 } FAMILYMEMBER;
17 /**
18 * 社員情報構造体
19 */
20 typedef struct {
21 char* id; /*社員番号*/
22 char* name; /*氏名*/
23 int age; /*年齢*/
24 char* sectionId /*部署番号*/
25 SALARY* salary /*給与基本情報*/
26 int memberSize /*家族人数*/
27 FAMILYMEMBER* members /*家族構成情報*/
28 } EMPLOYEE;
1〜7行目では、給与基本情報構造体の宣言です。8〜16行目では、家族構成情報構造体の宣言です。17〜28行目では、リスト2の社員情報構造体の拡張で、25行目では、給与基本情報で、25行目では、家族構成情報で、25行目のmemberSizeは、配列membersのサイズです。
● Java側
リスト9 入れ子構造体型のマッピングJava側のサンプルソースコード
1 public interface StructureSample extends Library {
2 /**
3 * 給与基本情報構造体にマッピングクラス
4 */
5 public static class _Salary extends Structure {
6 int type; /*給与レベルタイプ*/
7 int salary; /*基本月給*/
8 }
9 /**
10 * 家族構成情報構造体にマッピングクラス
11 */
12 public static class _FamilyMember extends Structure {
13 String name; /*氏名*/
14 int sex; /*性別*/
15 String relationship; /*続柄*/
16 String address /*住所*/
17 }
18 /**
19 * 社員情報構造体にマッピングクラス
20 */
21 public static class _Employee extends Structure {
22 String id; /*社員番号*/
23 String name; /*氏名*/
24 int age; /*年齢*/
25 String sectionId; /*部署番号*/
26 _Salary salary; /*給与基本情報*/
27 int memberSize; /*家族人数*/
28 Pointer members; /*家族構成情報*/
29 }
26行目は、給与基本情報であり、配列ではないので、そのままでマッピングできます。28行目は、家族構成情報あり、配列としますので、Pointerでマッピングします。Structure配列を受け取る方法で示した方法で、実データを受け取ります。
以上、よく利用されるデータ型のJavaとC/C++の間にやりとり方法をサンプルソースコード通じて説明しました。また、サンプルソースコードに示した方法は、目的を達成する唯一の方法ありません。JNAの機能多様性を利用して、ほかの方法を試してください。
JNAアプリケーションのアーキテクチャ
ここまで、JNAの利用で、C/C++コードを書かず、直接にネイティブライブラリにアクセスできると強調してきました。プリミティブデータ型のような簡単なデータしか利用しない場合は、その通りです。
JNAを利用する際、JNIと同じで、Cのネイティブライブラリしか直接にアクセスできません。C++のライブラリや、ロジックとのセッションも必要な場合には、ターゲットのネイティブライブラリを、Cのアダプタネイティブライブラリでラップしてアクセスします。
■ Cのアダプタネイティブライブラリ
このCアダプタネイティブライブラリを作成することで、既存ロジックの複雑なデータ型でも一時に基本型に変換してから、JNAを利用可能です。
そこで、一般のセッション管理がある既存のロジックライブラリをアクセスすることが可能な、JavaからC/C++のネイティブライブラリをアクセスする、汎用的なアーキテクチャを検討してみたいと思います。そのアーキテクチャは図4で示しています。
図4 JNAアプリケーションのアーキテクチャ |
図4の各ブロックを見てみましょう。
■Java側のレイヤ
JNA Facadeはロジックライブラリのファサードクラスです。JNA Facade を通して、呼び出し側は、Javaクラスを利用するような感覚で、ネイティブライブラリのロジック機能を利用できます。JNA Facadeの内部では、データ変換ブロックを利用して、Webプレゼンテーション層で利用するデータ型とCのデータ型との変換を行います。
データ変換ブロックは、Webプレゼンテーション層で利用するデータ型と、Cのデータ型にマッピングするJNA用データ型と、変換を行うクラスあるいはクラス群です。主にAPIの引数と戻り値のマッピングします。
ネイティブインターフェイスは、ネイティブライブラリのマッピングします。ネイティブインターフェイスの中に、利用するすべてのデータ型やネイティブAPIを宣言します。
以上はJava側のレイヤで、Webアプリケーションの構築する場合は、これらはプレゼンテーションサービス層で、実装できます。
■ C/C++側のレイヤ
JnaAdaptorはCのネイティブライブラリに当たります。JavaのJnaFacadeと既存のロジックライブラリの間には、ロジックのセッション管理が必要な場合はセッション管理をここで実装します。それに、JNAがサポートしない特殊なデータ型も、例えばVARIANT、STLなど、JNAがサポートするデータ型へ変換します。
JnaAdaptorの存在で、既存のロジックライブラリは、任意のC/C++ライブラリであってもアクセス可能になります。JnaAdaptorを通して、一般のライブラリだけではなく、COM/DCOMインスタンスをも生成することができるため、ライブラリの種類制限はありません。
このアーキテクチャを採用することで、追加される新規ロジックと既存ロジックが分離できて、処理が階層化されて、新規APIを追加しやすいし、幅広い既存ロジックライブラリに対応可能です。全体的にシステムの拡張性と保守性を高めます。
JNIよりも保守性を高めるJNA
JNAの概要と利用方法を紹介しました。JNAはC/C++のネイティブコードを取り込みたいJavaベースのプロジェクトに対して、1つの良い選択肢だと思います。JNIと比べて、プラットフォーム依存せず、簡単かつ直接ネイティブライブラリにアクセス方法を提供してくれますので、利用ハードルが低くて、システム開発の生産性の向上を期待できます。結果的に、システムの保守性も高めることにつながります。
筆者は、プロジェクトの開発過程中に、そのメリッドをよく感じさせられました。
日本では、JNAの利用例がまだ少ないようですが、海外では、多数の大規模プロジェクトに採用されています。最近では、JNIを使用していたプロジェクトがJNAに移植するのもあるそうで、ネイティブライブラリをアクセスするなら、JNAは第1選択肢になっているようです。
最近人気のプラットフォームAndroid上のアプリケーション開発でも、JNA利用者の間でJNAサポートが話題になっています。将来は利用可能になることを期待したいし、またはAndroidの特殊性に特化するJNA類似の技術が出てくると思われます。読者のみなさんも、ぜひ試してみてはいかがでしょうか。
■ 参考資料
■ @IT関連記事
Androidアプリで高速描画チューニングをするコツ インタビュー特集:Google直伝!(1) Googleのさまざまなサービスを使いこなすコツをグーグル担当者に聞くインタビュー。初回は日本で端末販売がせまるAndroidについて 「リッチクライアント & 帳票」フ ォーラム 2009/4/21 |
ネイティブコードとの連携によるAndroidの機能拡張 Androidがもたらす組み込み開発の新たな可能性(2) 組み込み機器に「Android」を適用する場合、ネイティブコードとの連携は欠かせない。「Android NDK」について解説 |
生産性向上への道 Eclipseで行うC/C++開発 オープンソースのビジュアル開発環境“Eclipse”を用いた、C/C++アプリケーションのクロス開発方法について解説 |
アンマネージ・コードの型情報と連携する 連載:深入り.NETプログラミング(最終回) .NETコードからネイティブ・コードを呼び出す際の定型作業を効率化するには? それに関連して注釈と型情報の取得に触れる 「Insider.NET」フォーラム
2009/7/21 |
1-2-3-4 |
INDEX 特集「組み込みにも役立つJavaとネイティブコードの橋渡し」 | ||
Page1 | ||
C/Sでは、サーバサイドはC/C++がまだまだ主役 JNIを使いやすくした「JNA」とは |
||
Page2 | ||
JNAを利用するための基本的な流れ JavaとC/C++のマッピング方法、6パターン 【1】ライブラリのマッピング 【2】APIのマッピング 【3】プリミティブデータ型のマーシャリング |
||
Page3 | ||
【4】構造体型のマッピング 【5】配列型のマッピング |
||
Page4 | ||
【6】入れ子構造体型のマッピング JNAアプリケーションのアーキテクチャ JNIよりも保守性を高めるJNA |
Java Solution全記事一覧 |
- 実運用の障害対応時間比較に見る、ログ管理基盤の効果 (2017/5/9)
ログ基盤の構築方法や利用方法、実際の案件で使ったときの事例などを紹介する連載。今回は、実案件を事例とし、ログ管理基盤の有用性を、障害対応時間比較も交えて紹介 - Chatwork、LINE、Netflixが進めるリアクティブシステムとは何か (2017/4/27)
「リアクティブ」に関連する幾つかの用語について解説し、リアクティブシステムを実現するためのライブラリを紹介します - Fluentd+Elasticsearch+Kibanaで作るログ基盤の概要と構築方法 (2017/4/6)
ログ基盤を実現するFluentd+Elasticsearch+Kibanaについて、構築方法や利用方法、実際の案件で使ったときの事例などを紹介する連載。初回は、ログ基盤の構築、利用方法について - プログラミングとビルド、Androidアプリ開発、Javaの基礎知識 (2017/4/3)
初心者が、Java言語を使ったAndroidのスマホアプリ開発を通じてプログラミングとは何かを学ぶ連載。初回は、プログラミングとビルド、Androidアプリ開発、Javaに関する基礎知識を解説する。
|
|