Slide 1

Slide 1 text

Goから Javaのライブラリを使う 滝安 純平 (juntaki) 2017-12-11 golang.tokyo #11

Slide 2

Slide 2 text

= &Me{ Name: "Jumpei Takiyasu", Company: "M3, Inc.", Github: "juntaki", Twitter: "juntaki", Web: "https://juntaki.com", }

Slide 3

Slide 3 text

エムスリーって何の会社? 医療に関するWebサービスを多数展開 ● 日本で約25万人の医師会員 ● 全世界で約400万人の医師会員

Slide 4

Slide 4 text

Goから Javaのライブラリを使う

Slide 5

Slide 5 text

背景

Slide 6

Slide 6 text

それGoでもできるよ (って言いたかっただけ)

Slide 7

Slide 7 text

どうやるのか Go C Java cgo JNI cgoと、Java Native Interface(JNI)を使います

Slide 8

Slide 8 text

Java Native Interface(JNI)とは? CやC++から、Javaを実行するためのインターフェース 詳細はエムスリー Advent Calender1日目@Qiitaで!

Slide 9

Slide 9 text

つくりました juntaki/jnigo JNIのインターフェースをGoでラップしたもの juntaki/javago Javaのライブラリからjnigoを使ったラッパーライブラリを生成 するコマンド

Slide 10

Slide 10 text

使い方 1. javagoコマンドを実行すると./javaにライブラリができる 2. “./java”をimportする $ javago --classfile java.lang.Math package main import "fmt" import "./java" func main() { val, _ := java.Mathexp(0.5) fmt.Println(val) }

Slide 11

Slide 11 text

juntaki/jnigoの仕組み

Slide 12

Slide 12 text

JNIをGoから使いやすくするライブラリ Go-C-Java間の変換 ● cgoでJNIの関数をラップする ● GoのオブジェクトとJNIの変数の相互変換 メモリ管理 ● JavaとGoのGCタイミングを合わせる ● Cのメモリ管理をする パフォーマンス対策 探索済みクラス、メソッドIDのキャッシュ

Slide 13

Slide 13 text

メモリ管理 JavaとCの変数をGoのオブジェクトでラップ runtime.Finalizerでまとめて開放 GoObject C (JNI) Java GetObject / malloc GetObject Object reference Pointer to Object ref. NewGlobalRef Go GC runtime.Finalizer DeleteGlobalRef free Java GC

Slide 14

Slide 14 text

パフォーマンス対策 参考:Java Native Interface を使用する上でのベスト・プラクティス https://www.ibm.com/developerworks/jp/java/library/j-jni/index.html // FQCNでクラスを取得 jclass clazz = (*env)->FindClass(env, "Test"); // メソッド名とシグニチャで、メソッドIDを取得 jmethodID id = (*env)->GetStaticMethodID(env, clazz, "hello", "()V"); // 取得したクラスとメソッドID、引数を渡してメソッドを呼び出す。 (*env)->CallStaticVoidMethodA(env, clazz, id, NULL); クラスとメソッドIDは キャッシュして使いまわせる

Slide 15

Slide 15 text

juntaki/javagoの仕組み

Slide 16

Slide 16 text

javapコマンドをパースしてコード生成 Javaっぽくjnigoを呼び出せるようにする $ javap -p -s java.lang.Math Compiled from "Math.java" public final class java.lang.Math { public static final double E; descriptor: D … public static float max(float, float); descriptor: (FF)F public static double max(double, double); descriptor: (DD)D (DD)D: 引数Double2つ 戻り値Doubleの意味

Slide 17

Slide 17 text

Javaっぽさ func Mathmax(args ...interface{}) (jnigo.JObject, error) { convertedArgs, err := jvm.ConvertAll(args) if err != nil { return nil, err } sigArgs := "" for _, arg := range convertedArgs { sigArgs += arg.Signature() } sigMap := map[string]string{"JJ":"(JJ)J", "FF":"(FF)F", "DD":"(DD)D", "II":"(II)I"} return jvm.CallStaticFunction( "java/lang/Math", "max", sigMap[sigArgs], convertedArgs) } メソッドオーバーロードをリフレクションで実現 コンパイル時に型チェックはできず、実行時に落ちるのが難点・・ Switch function signature by argument signatures

Slide 18

Slide 18 text

まとめ 既存のJavaコードが使いたい? →それGoでもできるよ!