Javaとの相互運用性

GraalVM Rランタイムでは、Javaとの組込みの相互運用性が提供されます。Javaクラス・オブジェクトは、java.type(...)を介して取得できます。Javaとの相互運用性機能を使用してRを実行するには、--jvmオプションを指定してRまたはRscriptコマンドを起動する必要があります。

R --jvm

ノート: この後の例はすべて、R REPLで実行することを目的としています。追加のJava依存性は必要ありません。

次の例では、新しいJava BufferedImageオブジェクトを作成し、Rのgridパッケージを使用してそれにランダム・データをプロットし、JavaのAWTフレームワークを使用してウィンドウにイメージを表示します。Javaとの相互運用性機能を使用するには、--jvmを指定してRスクリプトを開始する必要があります。

library(grid)
openJavaWindow <- function () {
   # create image and register graphics
   imageClass <- java.type('java.awt.image.BufferedImage')
   image <- new(imageClass, 450, 450, imageClass$TYPE_INT_RGB);
   graphics <- image$getGraphics()
   graphics$setBackground(java.type('java.awt.Color')$white);
   grDevices:::awt(image$getWidth(), image$getHeight(), graphics)

   # draw image
   grid.newpage()
   pushViewport(plotViewport(margins = c(5.1, 4.1, 4.1, 2.1)))
   grid.xaxis(); grid.yaxis()
   grid.points(x = runif(10, 0, 1), y = runif(10, 0, 1),
        size = unit(0.01, "npc"))

   # open frame with image
   imageIcon <- new("javax.swing.ImageIcon", image)
   label <- new("javax.swing.JLabel", imageIcon)
   panel <- new("javax.swing.JPanel")
   panel$add(label)
   frame <- new("javax.swing.JFrame")
   frame$setMinimumSize(new("java.awt.Dimension",
                image$getWidth(), image$getHeight()))
   frame$add(panel)
   frame$setVisible(T)
   while (frame$isVisible()) Sys.sleep(1)
}
openJavaWindow()

GraalVMのRランタイムには、GitHubで入手可能な独自のrJava互換の置換パッケージが用意されており、次を使用してインストールできます:

R -e "install.fastr.packages('rJava')"

サード・パーティのJavaライブラリにアクセスするには、それらをRのクラスパスに配置する必要があります:

> java.addToClasspath("/foo/bar.jar")
> java.addToClasspath(c("/foo/bar.jar", "/foo/bar2.jar"))

Javaクラスの取得

Java型へのアクセスを確立するには、java.type関数に完全修飾クラス名を指定します:

> calendarClass <- java.type('java.util.GregorianCalendar')

返される値は、Java型を表すポリグロット・オブジェクトです。

その後、classプロパティを介してそれぞれのJavaクラスを使用できます:

> calendarClass$class

同じことが静的クラス・メンバーにも機能します:

> calendarClass$getInstance()

要求したそれぞれのクラスがRのクラスパスに存在する必要があります。上で使用したGregorianCalendarなどのJDKクラスは即時利用可能です。

新しいJavaオブジェクトの作成

新しいJavaオブジェクトを作成するには、new関数にJava型を指定します:

> calendar <- new(calendarClass)

追加のコンストラクタ引数を渡すこともできます:

> calendar <- new(calendarClass, year=2042L, moth=3L, day=1L)

また、クラス名のみを使用することもできます:

calendar <- new("java.util.GregorianCalendar")
calendar <- new("java.util.GregorianCalendar", year=2042L, moth=3L, day=1L)

フィールドおよびメソッドへのアクセス

静的フィールドおよびメソッドとインスタンス・フィールドおよびメソッドへのアクセスは、$および[演算子によって提供されます。

Javaフィールドにアクセスするには:

> calendarClass$SUNDAY
> calendarClass["SUNDAY"]

Javaメソッドを起動するには:

> currentTime <- calendar$getTime()
> currentTime["toString"]()
> calendar$setTime(currentTime)

フィールドまたはメソッドから返された、あるいはnewを介して作成されたポリグロット・オブジェクトは、対応するR値に自動的に変換されるか、GraalVM Rランタイムにポリグロット・オブジェクトとして存続します。必要に応じて、それらをJavaに渡すことができます:

> cet <- java.type("java.util.TimeZone")$getTimeZone("CET")
> cetCalendar <- new(calendarClass, cet)

Javaプリミティブの処理

返されたJavaプリミティブ、プリミティブ・ラッパーおよびStringインスタンスは、対応するR値に自動的に変換され、次のようにマップされます:

ポリグロット・オブジェクトの検査

names関数を使用して、ポリグロットJavaオブジェクトまたはJavaクラスからインスタンス・メンバーおよび静的メンバーのリストを取得できます:

> names(calendar)
> names(calendarClass)

コード補完も機能します:

> calendar$a<TAB>

Java配列の操作

Java配列の必要性が生じるのは、それらを引数としてjavaに渡す必要がある場合です。

配列を作成するには、配列クラスを作成し、そこから配列をインスタンス化します:

> arrayClass <- java.type('int[]')
> intArray <- new(arrayClass, 3)

プリミティブ配列のコンポーネントの型名は、booleanbytechardoublefloatintlongおよびshortで、それぞれの特定のプリミティブ・ラッパーのTYPE定数と同じです(Integer.TYPE.getName()などを参照)。予想されるJava配列がプリミティブ・コンポーネント型またはStringである場合は、RベクターをJavaメソッドに渡すことができます。その後、バックグラウンドで自動的に変換が行われます。

> integerArray <- new(java.type('java.lang.Integer[]'), 3L)
> integer2DimArray <- new('java.lang.Integer[][]', c(2L, 3L))
> stringArray <- new(java.type('java.lang.String[]'), 3L)

配列要素へのアクセスは、[演算子によって提供されます:

> stringArray[1] <- 'a'
> string2DimArray[1,1] <- 'a'
> element <- stringArray[1]
> element <- string2DimArray[1,1]

RオブジェクトへのJava配列の変換

Javaプリミティブやそのラッパーとは異なり、Java配列は自動的にRベクターに変換されません。ただし、適切な場合は、R組込み関数によってネイティブのRオブジェクトと同様にそれらを処理できます:

> sapply(intArray, function(e) { e })
> length(stringArray)
> length(string2DimArray[1])

明示的なJava配列の変換

Java配列の変換を明示的に行うには、as.vector関数にJava配列を指定します:

> intVec <- as.vector(intArray)

Javaプリミティブ・コンポーネント型を持つ配列は、Rベクターに変換されます。それ以外の場合は、配列要素を含むリストが作成されます:

> characterVector <- as.character(intArray)
> logicalVector <- as.logical(intArray)
> ...

Javaの反復可能インタフェース

適切な場合、java.lang.Iterableを実装するJavaオブジェクトは、引数として関数に渡されたときにJava配列と同様に処理されます:

> javaList <- new(java.type('java.util.ArrayList'))
> javaList$add(0);
> javaList$add(1)
> length(javaList)
> as.integer(javaList)
> as.logical(javaList)

rJavaとの互換性

GraalVM Rランタイムには、Javaとの相互運用性機能に基づくrJava互換性レイヤーが付属しています。公式に文書化されたrJava関数のほとんどがサポートされています。詳細は、rJavaのCRANドキュメントを参照してください。

サポートされているrJava機能:

Java Graphicsとの相互運用性

GraalVM Rランタイムには、gridパッケージと、pngjpegbmpsvgおよびawt (X11awtに別名設定されます)グラフィック・デバイスの独自のJavaベース実装が含まれています。graphicsパッケージとその関数のほとんどは現時点ではサポートされていません。

awtデバイスはJava Graphics2Dオブジェクトに基づいており、ユーザーは、Javaとの相互運用性の例に示されているように、awt関数を使用してデバイスを開くときに独自のGraphics2Dオブジェクト・インスタンスにそれを渡すことができます。Graphics2Dオブジェクトがawtに提供されない場合は、X11のような新しいウィンドウが開きます。

GraalVM Rランタイムのsvgデバイスでは、GNU Rのsvg実装よりも軽量なSVGコードが生成されます。さらに、SVGデバイスを操作するために調整された関数svg.offおよびsvg.stringが用意されています。次のコード・サンプルにSVGデバイスを示します:

library(lattice)
svg()
mtcars$cars <- rownames(mtcars)
print(barchart(cars~mpg, data=mtcars))
svgCode <- svg.off()
cat(svgCode)

さらに学習するには、?functionName構文を参照してください。