フォーラム » つれづれ Java編 »
高徹Java SEでJNDI(スタンドアロン)
JDBC APIを使ってデータベースアクセスするアプリケーションを作っている(スペクトラム表示)。
データベース接続に、DataSourceを使うとよいが、スタンドアロンのJava SEベースのアプリでは自力でJNDIサーバーを用意するのが難儀。
しかし、ファイルに置いた設定を読み込む簡易なJNDIライブラリがあった。
SimpleJNDI
pomを見ると依存ライブラリは、DHCP機能を使う場合にのみcommons-dhcpとcommons-poolが必要。
2008年9月のVer.0.11.4.1を最後に更新がない。
フォークして更新をしている版があった。
https://github.com/h-thurow/Simple-JNDI
2019-02-22にVer.0.18.1をリリースしている。
> jar --describe-module --file simple-jndi-0.18.1.jar モジュール・ディスクリプタが見つかりません。自動モジュールが導出されました。 simple.jndi@0.18.1 automatic requires java.base mandated contains org.osjava contains org.osjava.datasource contains org.osjava.sj contains org.osjava.sj.jndi contains org.osjava.sj.loader contains org.osjava.sj.loader.convert
フォーク版のpom.xmlを見ると、次のライブラリへの依存(実行時)が定義されていた。
commons-logging, slf4j-api, org.jetbrains, commons-lang
サンプルプログラム¶
簡単なサンプルプログラムを作ってみる。次のディレクトリ構成とファイルを用意。
work
+-- config
| +-- database.properties
+-- mods
+-- lib
| +-- simple-jndi-0.18.1.jar
+-- src
+-- com.torutk.jdbcex
+-- module-info.java
+-- com
+-- torutk
+-- jdbcex
+-- Main.java
+-- jndi.properties
- module-info.java
module com.torutk.jdbcex { requires java.naming; requires simple.jndi; } - Main.java
package com.torutk.jdbcex; import javax.naming.InitialContext; import javax.naming.NamingException; public class Main { public static void main(String... args) { InitialContext context = null; try { context = new InitialContext(); var type = context.lookup("database.type"); System.out.println("JNDI type=" + type); } catch (NamingException ex) { System.err.println("ERROR: " + ex.getMessage()); } finally { try { if (context != null) { context.close(); } } catch (NamingException ex) { // ... } } } } - database.properties
type=javax.sql.DataSource driver=com.microsoft.sqlserver.jdbc.SQLServerDriver url=jdbc:sqlserver://localhost;databaseName=mydatabase user=myname password=mypassword
コンパイルは次
work> javac -d mods ^ --module-path lib ^ --module-source-path src ^ -m com.torutk.jdbcex
実行は次
java --module-path mods;lib ^ -m com.torutk.jdbcex/com.torutk.jdbcex.Main
実行するとエラーとなる。
ERROR: Need to specify class name in environment or system property, or in an application resource file: java.naming.factory.initial
これは、Java SEのスタンドアロン環境(Java EEコンテナがない)において、new InitialContext() ではコンテキストが生成できないため。
Simple JNDIライブラリは、jndi.propertiesのファイル名でクラス名を指定し、このファイルをクラスパスに置くとなっている。
java.naming.factory.initial=org.osjava.sj.SimpleContextFactory org.osjava.sj.root=config/
しかし、モジュールパス(mods\com.torutk.jdbcex\com\torutk\jdbcex\jndi.properties)においても認識されない。
jndi.propertiesをカレントディレクトリに移し、実行時にカレントディレクトリをクラスパスに追加したところ、
java --module-path mods;lib -cp . -m com.torutk.jdbcex/com.torutk.jdbcex.Main
Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory
at simple.jndi@0.18.1/org.osjava.sj.SimpleJndi.<clinit>(SimpleJndi.java:60)
at simple.jndi@0.18.1/org.osjava.sj.SimpleJndiContextFactory.getInitialContext(SimpleJndiContextFactory.java:69)
at java.naming/javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:730)
at java.naming/javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:305)
at java.naming/javax.naming.InitialContext.init(InitialContext.java:236)
at java.naming/javax.naming.InitialContext.<init>(InitialContext.java:184)
at com.torutk.jdbcex/com.torutk.jdbcex.Main.main(Main.java:11)
Caused by: java.lang.ClassNotFoundException: org.slf4j.LoggerFactory
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 7 more
なんと、SLF4J への依存がある。pomを調べると無条件でcommons-loggingへの依存がある。
うーむ、いったん中止。
返答 (1)
高徹 オリジナル(simple-jndi-0.11.4.1.jar)に差し替えて実施 - 高橋 徹 さんが約6年前に追加
他のライブラリへの実行時の依存がないオリジナルのsimple-jndi-0.11.4.1.jarを使用して実行する。
Caused by: java.lang.ClassNotFoundException: javax.sql.DataSource
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 22 more
あ、これはSQLのクラスが含まれるモジュールをmodule-info.javaで要求していないからだなぁ。
module-info.javaに以下を追記
module com.torutk.jdbcex {
requires java.naming;
+ requires java.sql;
requires simple.jndi;
}
やっとクラスがないといったエラーは解消。
次は、ディレクトリの参照の問題
java --module-path mods;lib -cp . -m com.torutk.jdbcex/com.torutk.jdbcex.Main ERROR: Invalid subcontext 'database' in context ''
jndi.propertiesに次を追記すると、エラーが一歩前進した。
java.naming.factory.initial=org.osjava.sj.SimpleContextFactory
org.osjava.sj.root=config/
+ org.osjava.sj.delimiter=/
java --module-path mods;lib -cp . -m com.torutk.jdbcex/com.torutk.jdbcex.Main JNDI type=null
ここから試行錯誤しつつも進まず