フォーラム » つれづれ 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)に差し替えて実施 - 高橋 徹 さんが5年以上前に追加
他のライブラリへの実行時の依存がないオリジナルの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
ここから試行錯誤しつつも進まず