ネイティブ呼び出しが気になった件

これは Java Advent Calendar 202320日目の記事です。

Testcontainers でDockerにアクセスできることからUNIXドメインソケットの利用にネイティブ呼び出しが使われているのでは?と気になって調べてみました。

UNIXドメインソケットとは何かですが、Unixのプロセス間通信にはpipeやfifoの他にUNIXドメインソケットがあります。pipeやfifoは一方通行ですが、UNIXドメインソケットは双方向で通信できます。現在ではUNIXドメインソケットはUnixライクなLinuxだけでなくWindowsでも利用できるようになっています。

Dockerは通常UNIXドメインソケットを使ってdockerコマンド等のクライアントとバックエンドが通信します。Testcontainersの場合はdockerコマンドを介さず直接UNIXドメインソケットを使ってDockerのバックエンドと通信を行います。JavaUNIXドメインソケットを使う場合ネイティブ呼び出しが使用されるJava Native Library等を利用してきました。

Java 16以降は JEP 380: Unix-Domain Socket Channels が取り入れられたことでUNIXドメインソケットへのアクセスにネイティブ呼び出しを利用する必要はなくなっています。実際調べてみるとTestcontainersが利用しているdocker-javaで、JEP 380 を使う UnixSocket.java が追加されていました。Java 16以降を使っていればネイティブ呼び出しにはならないと確認できました。

ネイティブ呼び出しの問題

ではネイティブ呼び出しは何が問題なのか。ネイティブ呼び出しのあるライブラリを利用するコードはそのネイティブコードが対応していないプラットフォームであってもコンパイルはエラーになりません。そして実行時にエラーになります。これはマルチプラットフォームで動作するアプリケーションを開発できるというJavaの利点を損なってしまうことにつながります。

またネイティブコードはライブラリのjar内にパッケージングされていることが多くネイティブ呼び出しの有無はわかりにくいです。さらに、どのOS等をサポートしているかもわかりにくいです。ネイティブコードはサポートする複数のOS用に個別にコンパイルされています。例えば次のリストはTestcontainersの依存ライブラリ Java Native Library のjarに同梱されたネイティブライブラリです。

com/sun/jna/win32-x86/jnidispatch.dll
com/sun/jna/aix-ppc/libjnidispatch.a
com/sun/jna/aix-ppc64/libjnidispatch.a
com/sun/jna/darwin-x86-64/libjnidispatch.jnilib
com/sun/jna/darwin-aarch64/libjnidispatch.jnilib
com/sun/jna/linux-x86/libjnidispatch.so
com/sun/jna/linux-x86-64/libjnidispatch.so
com/sun/jna/linux-arm/libjnidispatch.so
com/sun/jna/linux-armel/libjnidispatch.so
com/sun/jna/linux-aarch64/libjnidispatch.so
com/sun/jna/linux-ppc/libjnidispatch.so
com/sun/jna/linux-ppc64le/libjnidispatch.so
com/sun/jna/linux-mips64el/libjnidispatch.so
com/sun/jna/linux-loongarch64/libjnidispatch.so
com/sun/jna/linux-s390x/libjnidispatch.so
com/sun/jna/linux-riscv64/libjnidispatch.so
com/sun/jna/sunos-x86/libjnidispatch.so
com/sun/jna/sunos-x86-64/libjnidispatch.so
com/sun/jna/sunos-sparc/libjnidispatch.so
com/sun/jna/sunos-sparcv9/libjnidispatch.so
com/sun/jna/freebsd-x86/libjnidispatch.so
com/sun/jna/freebsd-x86-64/libjnidispatch.so
com/sun/jna/openbsd-x86/libjnidispatch.so
com/sun/jna/openbsd-x86-64/libjnidispatch.so
com/sun/jna/win32-x86-64/jnidispatch.dll
com/sun/jna/win32-aarch64/jnidispatch.dll

おそらく上記のようなリストからどのプラットフォームをサポートしているかを判断する必要がありそうです。

おわりに

普段何気なく利用しているライブラリの中にもネイティブ呼び出しを含んだものが時々あります。今回気になったTestcontainersの場合は、Java 16以降を使っていれば心配ありませんでした。あまり神経質にならない程度に、たまに依存関係にネイティブ呼び出しがないか注意を払い、進化を続けるJavaを楽しんでいきたいと考えています。