マッピング仕様
この章では、Java オブジェクトと、Java オブジェクトを表す Ensemble プロキシ・クラスとの間のマッピングについて説明します。
public とマークされたクラス、メソッド、およびフィールドのみインポートできます。
この章では、以下の種類のマッピングについて説明します。
パッケージ名とクラス名
パッケージ名とクラス名は、インポート時に保持されます。ただし、Ensemble プロキシ・クラス名では、元の Java クラス名に含まれるアンダースコア (_) はそれぞれ u の文字に置き換えられ、ドル記号 ($) はそれぞれ d の文字に置き換えられます。u と d は、共に大文字と小文字を区別します (小文字)。
プリミティブ
プリミティブ型とプリミティブ・ラッパは、以下に示すように Java から Ensemble にマッピングされます。
Java | Ensemble |
---|---|
boolean | %Library.BooleanOpens in a new tab |
byte | %Library.IntegerOpens in a new tab |
char | %Library.StringOpens in a new tab |
double | %Library.NumericOpens in a new tab |
float | %Library.FloatOpens in a new tab |
int | %Library.IntegerOpens in a new tab |
long | %Library.IntegerOpens in a new tab |
short | %Library.SmallIntOpens in a new tab |
java.lang.Boolean | %Library.BooleanOpens in a new tab |
java.lang.Double | %Library.NumericOpens in a new tab |
java.lang.Float | %Library.FloatOpens in a new tab |
java.lang.Integer | %Library.IntegerOpens in a new tab |
java.lang.Long | %Library.IntegerOpens in a new tab |
java.lang.Short | %Library.SmallIntOpens in a new tab |
java.lang.String | %Library.StringOpens in a new tab |
パフォーマンス上の理由から、プリミティブ Java 型ラッパは、デフォルトでは、対応する Ensemble データ型にマッピングされます。型がプリミティブ・ラッパである引数を渡す場合は、常にデータ型を使用することをお勧めします。例えば、以下の Java メソッドを呼び出すことができます。
public Long getOrderNumber(Integer id, Float rate)
Ensemble では次のとおりです。
Set id=5
Set rate=10.0
// order is a local Ensemble variable
Set order=test.getOrderNumber(id,rate)
ただし、そのままプリミティブ・ラッパ型をインポートし、Ensemble コードからそれを使用することもできます。次はその例です。
Set id=##class(java.lang.Integer).%New(gateway,5)
Set rate=##class(java.lang.Float).%New(gateway,10.0)
// order is of java.lang.Long type
Set order=test.getOrderNumber(id,rate)
日付と時刻
日付および時刻型は、Java から Ensemble へ以下のようにマッピングされます。
Java | Ensemble |
---|---|
java.sql.Date | %Library.DateOpens in a new tab |
java.sql.Time | %Library.TimeOpens in a new tab |
java.sql.Timestamp | %Library.TimeStampOpens in a new tab |
プロパティ
Java クラスをインポートした結果は、ObjectScript 抽象クラスです。対応するゲッター・メソッドおよびセッター・メソッド (存在すれば、これらはそのままインポートされます) が存在しない Java プロパティごとに、対応する ObjectScript のゲッター・メソッドおよびセッター・メソッドが Java ゲートウェイ・エンジンで生成されます。セッターは setXXX、ゲッターは getXXX として生成されます。ここで、XXX はプロパティ名です。例えば、Name という名前の Java 文字列プロパティをインポートすると、ゲッター・メソッド getName() およびセッター・メソッド setName(%Library.String) が生成されます。ゲートウェイでは、すべての静的メンバのクラス・メソッド Get および Set も生成されます。
メソッド
Java ゲートウェイのインポート操作を実行すると、それによって得られる Ensemble プロキシ・クラスにあるすべてのメソッドには、それに対応する Java と同じ名前が与えられます。ただし、"メソッド名" の節で説明する制限があります。また、それらのメソッドは、それぞれ Java と同じ数の引数を持ちます。すべての Ensemble プロキシ引数メソッドのタイプは %Library.ObjectHandleOpens in a new tab となり、このタイプは Java ゲートウェイ・エンジンで実行時に解決されます。
例えば、以下の Java メソッド test() を考えます。
public boolean checkAddress(Person person, Address address)
これは以下のようにインポートされます。
Method checkAddress(p0 As %Library.ObjectHandle,
p1 As %Library.ObjectHandle) As %Library.ObjectHandle
オーバーロードされたメソッド
Caché Basic および ObjectScript ではオーバーロードがサポートされていませんが、オーバーロードされている Java メソッドを Ensemble プロキシ・クラスにマッピングすることはできます。これは、最大のメソッド・カーディナリティおよびデフォルトの引数の組み合わせを通じてサポートされます。例えば、2 つ、4 つ、および 5 つの引数を取るバージョンにオーバーロードされている Java メソッドをインポートする場合、Ensemble 側で対応できるメソッドは 1 つのみなので、そのメソッドは 5 つの引数 (すべて %ObjectHandleOpens in a new tab 型) を取ります。これにより、Ensemble 側で 2 つ、4 つ、または 5 つの引数を使用して、このメソッドを呼び出すことができます。Java ゲートウェイ・エンジンは、対応する適切なバージョンの Java メソッドにディスパッチします。
このスキームは適切に機能しますが、同様の型の引数を同じ数だけ持つオーバーロードされたメソッドの使用は避けてください。例えば、Java ゲートウェイは、以下のメソッドを問題なく解決します。
test(int i, String s, float f)
test(Person p)
test(Person p, String s, float f)
test(int i)
ただし、以下は避けてください。
test(int i)
test(float f)
test(boolean b)
test(Object o)
Java ゲートウェイを使用してより適切な結果が得られるようにするため、オーバーロードされた Java メソッドの使用は、どうしても必要な場合のみとしてください。
メソッド名
Ensemble ではメソッド名について、31 文字の長さ制限があります。Java メソッド名の長さが 31 文字を超えないようにしてください。名前の長さが 31 文字を超える場合、Ensemble プロキシ・メソッド名は Java メソッド名の先頭 31 文字のみとなります。例えば、以下の Java のメソッドがある場合を考えます。
thisJavaMethodHasAVeryVeryLongName(int i) // 34 characters long
thisJavaMethodHasAVeryVeryLongNameLength(int i) // 40 characters long
Ensemble は以下の名前でメソッド を 1 つだけインポートします。
thisJavaMethodHasAVeryVeryLongN // 31 characters long
Java リフレクション・エンジンでは、最初に検出された 1 つがインポートされます。どちらのメソッドがインポートされたのか調べるには、Ensemble プロキシ・クラス・コードを確認します。できれば、インポート操作の前にログ機能を有効にしておいてください。Java ゲートウェイのログ・ファイルには、名前が切り詰められたメソッドや何らかの理由でインポートされなかったメソッドのすべてに関する警告が記録されます。
元のメソッド名のアンダースコア (_) はそれぞれ u の文字に置き換えられ、ドル記号 ($) はそれぞれ d の文字に置き換えられます。u と d は、共に大文字と小文字を区別します (小文字)。Ensemble 側に既存の別のメソッド名との重複が予期せず生じた場合、これらの規則に従って、そのメソッドはインポートされません。
最後に、Ensemble クラス・コードは大文字と小文字を区別しません。したがって、大文字と小文字の組み合わせが異なる同じ名前の Java メソッドが 2 つある場合、そのメソッドのいずれか一方のみがインポートされ、該当の警告がログ・ファイルに書き込まれます。
静的メソッド
Java 静的メソッドは、Ensemble プロキシ・クラス内でクラス・メソッドとして投影されます。ObjectScript からこれらを呼び出すには、以下の構文を使用します。
// calls static Java method staticMethodName(par1,par2,...)
Do ##class(className).staticMethodName(gateway,par1,par2,)
コンストラクタ
Java のコンストラクタを呼び出すには、%New() を呼び出します。%New() のシグニチャは、対応する Java コンストラクタのシグニチャと同じです。ただし、Java ゲートウェイのインスタンスが引数として追加されています。%New() は、まず最初に、プロキシ・インスタンスを指定されたゲートウェイ・インスタンスに関連付けます。次に、対応する Java コンストラクタを呼び出します。以下に例を示します。
// calls Student(int id, String name) Java constructor
Set Student=##class(javagateway.Student).%New(Gateway,29,"John Doe")
定数
Java ゲートウェイは、Java 静的最終変数 (定数) を最終パラメータとして投影およびインポートします。名前は、インポート時に保持されます。ただし、アンダースコア (_) はそれぞれ u の文字に置き換えられ、ドル記号 ($) はそれぞれ d の文字に置き換えられます。u と d は、共に大文字と小文字を区別します (小文字)。
例えば、以下の静的最終変数を考えます。
public static final int JAVA_CONSTANT = 1;
これは、以下のように ObjectScript にマッピングされます。
Parameter JAVAuCONSTANT As INTEGER = 1;
ObjectScript から、以下のようにパラメータにアクセスします。
##class(MyJavaClass).%GetParameter("JAVAuCONSTANT"))
Java クラス
以下では、特定の種類の Java クラスで Ensemble Java ゲートウェイを使用する特定のケースについて説明します。
Java オブジェクト・スーパークラス (java.lang.Object)
Java ゲートウェイの以前のバージョンでは、java.lang.Object を使用できませんでした。このリリースでは、java.lang.Object をそのままマッピングします。java.lang.Object を使用する場合は、以下を考慮してください。
-
プリミティブ・ラッパ・クラスは、Java では java.lang.Object のサブクラスですが、Ensemble では Ensemble データ型にマッピングされるので java.lang.Object のサブクラスではありません。詳細は、"Java の配列" を参照してください。
-
Java では java.lang.Object を使用することによって高い柔軟性が得られますが、多くの場合、多数の (再) キャストが必要になります。ObjectScript のキャストおよび再キャストに対するサポートは限られています。java.lang.Object を使用してサブクラスを指定する場合は、ObjectScript でキャスト操作を使用してサブクラスのメソッドを実行してください。以下は、EJB ゲートウェイの例です。
Set jndiContext=##class(javax.naming.InitialContext).%New(gateway) Set jndiName="PersonEJB_Sample_EJBPerson" Set refPerson=jndiContext.lookup(jndiName) Set personHomeClass=##class(java.lang.Class).forName(gateway, Sample.EJBPersonHome) Set homePerson=##class(javax.rmi.PortableRemoteObject).narrow(gateway, refPerson,personHomeClass) // here homePerson is java.lang.Object, and in Java, we would simply // recast it to EJBPersonHome by saying: // homePerson = (EJBPersonHome) homePerson // In ObjectScript, you will need to 'recast' the method call: Set remotePerson=##class(Sample.EJBPersonHome)homePerson.findById(1)
オブジェクト per se を再キャストできないことを理解していれば、java.lang.Object の使用は有効です。ただし、Ensemble プロキシ・クラスは抽象クラスなので、メソッド呼び出しの再キャストは、ほとんどの場合差し支えありません。
Java の配列
プリミティブ型、ラッパ、日付および時刻型、およびクラス型の配列は、%Library.ListOfDataTypesOpens in a new tab としてマッピングされます。オブジェクト型の配列は、%Library.ListOfObjectsOpens in a new tab としてマッピングされます。1 レベルの添え字のみサポートされます。
Java のバイト配列 (byte[]) は、%Library.GlobalBinaryStreamOpens in a new tab として投影されます。同様に、Java の文字配列 (char[]) は、%Library.GlobalCharacterStreamOpens in a new tab として投影されます。これにより、バイト配列と文字配列をより効率的に扱うことができます。
Java ゲートウェイにおける「値渡しのみ」セマンティクスの一般ルールに対する唯一の例外として、バイトおよびストリーム配列は、値渡しまたは参照渡しのいずれかで渡すことができます。参照渡しにすることで、Java 側でバイトまたは文字ストリームを変更すると、Ensemble 側でもその変更を認識できます。読み取りメソッド java.io.InputStream が良い例です。
int read(byte ba[], int maxLen
このメソッドは、maxLen バイトまで ba バイト配列に読み取ります。例えば、Java では以下のようになります。
byte[] ba = new byte[maxLen];
int bytesRead = inputStream.read(ba,maxLen);
ObjectScript における相当コードは、以下のとおりです。
Set readStream=##class(%GlobalBinaryStream).%New()
// reserve a number of bytes since we are passing the stream by reference
For i=1:1:50 Do readStream.Write("0")
Set bytesRead=test.read(.readStream,50)
以下の例では、文字ストリームが値渡しされるので、対応する Java char[] を変更しても Ensemble 側には反映されません。
Set charStream=##class(%GlobalCharacterStream).%New()
Do charStream.Write("Global character stream")
Do test.setCharArray(charStream)
Java Collections フレームワーク
以前のバージョンの Java ゲートウェイでは、java.util.List (およびそのサブクラス)、java.util.Map (およびそのサブクラス)、および java.util.Class をインポートするときに、特別な扱いが用意されていました。Java ゲートウェイは、最初の 2 つを %Library.ListOfDataTypesOpens in a new tab または %Library.ListOfObjectsOpens in a new tab としてインポートし、java.util.Class を %Library.StringOpens in a new tab としてインポートしていました。
今回のリリースでは、上記のクラスがすべて "そのまま" インポートされるようになりました。Java Collections フレームワーク全体を Ensemble で "そのまま" 使用できます。また、java.lang.Class メソッドも利用できます。ObjectScript を使用した HashMap の例を以下に示します。
Set grades=##class(java.util.HashMap).%New(gateway)
Set x=grades.put("Biology",3.8)
Set x=grades.put("Spanish",2.75)
Do student.mySetGrades(grades)
Set grades=student.myGetGrades()
Set it=grades.keySet().iterator()
While (it.hasNext()) {
Set key=it.next()
Set value=grades.get(key)
Write " ",key," ",value,!
}
以下の例では、Class.forName と java.utilArrayList を使用しています。
Set arrayListCls=##class(java.lang.Class).forName(gateway,"java.util.ArrayList")
Set sports=arrayListCls.newInstance()
Do sports.add("Basketball")
Do sports.add("Swimming")
Set list=student.myGetFavoriteSports()
For i=0:1:list.size()-1 {
Write " "_list.get(i),!
}
再キャスト
ObjectScript の再キャストに対するサポートには、メソッド呼び出しの時点でのみ再キャストが可能であるという制限があります。ただし、すべての Ensemble プロキシは抽象クラスなので、これで十分です。再キャスト方法の例については、"Java オブジェクト・スーパークラス" を参照してください。
Java 標準出力のリダイレクト
Java ゲートウェイは、対応する Java コード内の標準 Java 出力を、呼び出し元の Ensemble セッションに自動的にリダイレクトします。Java メソッド呼び出しでの System.out に対する呼び出しをすべて収集し、これらを Ensemble に送信して、Java からコードを実行したときの表示と同じ形式で表示します。この動作を無効にして、Java コードで指定した標準の出力デバイス (多くの場合はコンソール) に出力するには、Ensemble 対応ネームスペースで以下のグローバル参照を設定します。
Set ^%SYS("Gateway","Remote","DisableOutputRedirect") = 1
制限事項
Java ゲートウェイ・エンジンは、生成できないメンバがある場合、インポートを中断するのではなく、生成できないすべてのメンバを通知せずにスキップします。ユーザがログ機能を有効にした状態でインポート手順を繰り返すと、スキップされたすべてのメンバ (およびスキップの理由) がログ・ファイルの WARNING セクションに記録されます。
Java ゲートウェイ・エンジンは、パッケージとメソッドの名前、パラメータ型などを必ず保持しようとします。したがって、Ensemble プロキシ・メソッドを呼び出すことは、対応する Java のメソッドを呼び出すこととほとんど同じです。このため、Java コードを記述するときは、Caché Basic および ObjectScript の制限事項に注意してください。ほとんどの場合、まったく問題はありません。ただし、以下のような場合に、Caché Basic または ObjectScript の制限事項に直面することがあります。
-
Java メソッド名の長さが 30 文字を超える。
-
引数が 100 個以上ある。
-
32K より長い文字列オブジェクトを渡そうとしている。
-
メソッド名を選択するときに、Java では大文字と小文字を区別するという事実を利用している。
-
インスタンス・メソッドを上書きする静的メソッドをインポートしようとしている。
最新の Caché Basic および ObjectScript のドキュメントで制限事項を参照してください。以下のドキュメントを参照してください。