PostgreSQLへのJDBCアクセスがあるコードをGraalVMでネイティブイメージ化するとき、org.postgresql.core.v3.ConnectionFactoryImpl
の対応が必要だったのでメモ
たとえばこんな感じでPostgreSQLにアクセスします。
public class Main { public static void main(String[] args) throws SQLException { try (Connection conn = DriverManager.getConnection( "jdbc:postgresql://localhost:5432/mystat", "mystat", "pass"); Statement stmt = conn.createStatement(); ResultSet result = stmt.executeQuery("select * from users")) { while (result.next()) { System.out.printf("name:%s handle:%s %n", result.getString("user_name"), result.getString("user_handle")); } } } }
JDBCドライバは42.2.5を使ってます。
<dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>42.2.5</version> </dependency>
これをネイティブコンパイルすると、なんかエラーが出ました。
$ native-image -jar AccessPostgres-1.0-SNAPSHOT-jar-with-dependencies.jar Build on Server(pid: 153, port: 56330)* [AccessPostgres-1.0-SNAPSHOT-jar-with-dependencies:153] classlist: 2,296.43 ms [AccessPostgres-1.0-SNAPSHOT-jar-with-dependencies:153] (cap): 3,746.53 ms [AccessPostgres-1.0-SNAPSHOT-jar-with-dependencies:153] setup: 5,098.37 ms [AccessPostgres-1.0-SNAPSHOT-jar-with-dependencies:153] analysis: 5,581.32 ms error: unsupported features in 4 methods Detailed message: Error: com.oracle.graal.pointsto.constraints.UnresolvedElementException: Discovered unresolved type during parsing: com.sun.jna.Platform. To diagnose the issue you can use the --allow-incomplete-classpath option. The missing type is then reported at run time when it is accessed the first time. Trace: at parsing org.postgresql.sspi.SSPIClient.isSSPISupported(SSPIClient.java:90) Call path from entry point to org.postgresql.sspi.SSPIClient.isSSPISupported(): at org.postgresql.sspi.SSPIClient.isSSPISupported(SSPIClient.java:90)
ぐぐってみると、なんかスタブが必要そう。
native-image fails to compile PostgreSQL JDBC client. · Issue #727 · oracle/graal
このようなクラスで対応できるみたいです。
コンパイルするにはSubstrateVMのライブラリが必要です。
<dependency> <groupId>com.oracle.substratevm</groupId> <artifactId>svm</artifactId> <version>1.0.0-rc11</version> <scope>provided</scope> </dependency>
いけました!
$ native-image -jar AccessPostgres-1.0-SNAPSHOT-jar-with-dependencies.jar Build on Server(pid: 939, port: 58056)* [AccessPostgres-1.0-SNAPSHOT-jar-with-dependencies:939] classlist: 2,031.76 ms [AccessPostgres-1.0-SNAPSHOT-jar-with-dependencies:939] (cap): 2,046.18 ms [AccessPostgres-1.0-SNAPSHOT-jar-with-dependencies:939] setup: 3,208.73 ms [AccessPostgres-1.0-SNAPSHOT-jar-with-dependencies:939] (typeflow): 5,918.46 ms [AccessPostgres-1.0-SNAPSHOT-jar-with-dependencies:939] (objects): 4,188.45 ms [AccessPostgres-1.0-SNAPSHOT-jar-with-dependencies:939] (features): 367.38 ms [AccessPostgres-1.0-SNAPSHOT-jar-with-dependencies:939] analysis: 10,700.59 ms [AccessPostgres-1.0-SNAPSHOT-jar-with-dependencies:939] universe: 441.69 ms [AccessPostgres-1.0-SNAPSHOT-jar-with-dependencies:939] (parse): 690.96 ms [AccessPostgres-1.0-SNAPSHOT-jar-with-dependencies:939] (inline): 1,360.90 ms [AccessPostgres-1.0-SNAPSHOT-jar-with-dependencies:939] (compile): 5,880.47 ms [AccessPostgres-1.0-SNAPSHOT-jar-with-dependencies:939] compile: 8,622.91 ms [AccessPostgres-1.0-SNAPSHOT-jar-with-dependencies:939] image: 932.34 ms [AccessPostgres-1.0-SNAPSHOT-jar-with-dependencies:939] write: 365.44 ms [AccessPostgres-1.0-SNAPSHOT-jar-with-dependencies:939] [total]: 26,385.43 ms
ただ、なんかもう一度native-imageするとエラーがでます。サーバーを使わないようにしたほうがよさそう。
ネイティブコンパイルすると、やたら速いのですごく違和感がありますね。
$ time java -jar AccessPostgres-1.0-SNAPSHOT-jar-with-dependencies.jar name:John Smith handle:john real 0m0.699s user 0m0.609s sys 0m0.500s $ time ./AccessPostgres-1.0-SNAPSHOT-jar-with-dependencies name:John Smith handle:john real 0m0.033s user 0m0.000s sys 0m0.016s