I am trying to setup JNDI for a Java SE console application.
I have the following code:
public class FooMain {
public static void main (String args[]) throws NamingException {
Context context = new InitialContext();
context.bind("foo", "bar");
}
}
… and the context factory is defined as:
public class MyContextFactory implements InitialContextFactory {
private static Hashtable store = new Hashtable();
@Override
public Context getInitialContext(Hashtable environment) throws NamingException {
return new InitialContext() {
@Override
public void bind(String name, Object obj) {
store.put(name, obj);
}
@Override
public Object lookup(String name) {
return store.get(name);
}
};
}
}
When I invoke my FooMain
class using:
java -Djava.naming.factory.initial=MyContextFactory -cp ... FooMain
I get infinite recursion and an eventual StackOverflow Exception:
Exception in thread "main" java.lang.StackOverflowError
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.naming.internal.VersionHelper12.getContextClassLoader(VersionHelper12.java:185)
at com.sun.naming.internal.ResourceManager.getApplicationResources(ResourceManager.java:549)
at com.sun.naming.internal.ResourceManager.getInitialEnvironment(ResourceManager.java:244)
at javax.naming.InitialContext.init(InitialContext.java:240)
at javax.naming.InitialContext.<init>(InitialContext.java:192)
at MyContextFactory$1.<init>(MyContextFactory.java:20)
at MyContextFactory.getInitialContext(MyContextFactory.java:20)
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:684)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:313)
at javax.naming.InitialContext.init(InitialContext.java:244)
at javax.naming.InitialContext.<init>(InitialContext.java:192)
at MyContextFactory$1.<init>(MyContextFactory.java:20)
at MyContextFactory.getInitialContext(MyContextFactory.java:20)
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:684)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:313)
at javax.naming.InitialContext.init(InitialContext.java:244)
at javax.naming.InitialContext.<init>(InitialContext.java:192)
at MyContextFactory$1.<init>(MyContextFactory.java:20)
at MyContextFactory.getInitialContext(MyContextFactory.java:20)
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:684)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:313)
at javax.naming.InitialContext.init(InitialContext.java:244)
at javax.naming.InitialContext.<init>(InitialContext.java:192)
...
I can make the code work by creating an "environment" Hashtable, placing the name of the MyContextFactory
class there (under the "java.naming.factory.initial" key) and then creating the InitialContext using the constructor that accepts a Hashtable environment:
Context context = new InitialContext(environment);
But my question is: how can I make this work using the no-args constructor and supplying the name of the factory class using "-Djava.naming.factory.initial" at the invocation of the JVM ?
Thanks to the suggestion by Jim Garrison, here's the answer.
The crux of the matter is the call super(true);
in the constructor of the MyContext
class.
class MyContext extends InitialContext {
private Hashtable store;
public MyContext(Hashtable store) throws NamingException {
super(true);
this.store = store;
}
@Override
public void bind(String name, Object obj) {
store.put(name, obj);
}
@Override
public Object lookup(String name) {
return store.get(name);
}
}
public class FooMain {
private static final int ANSWER = 42;
private static final String JNDI_NAME = "/config/theAnswerToEverything";
public static void main (String args[]) throws NamingException {
Context context = new InitialContext();
putInContext( JNDI_NAME, ANSWER);
int answer = retrieveFromContext(JNDI_NAME);
Assert.assertEquals(ANSWER, answer);
System.out.printf("%d\n", answer);
}
private static void putInContext(final String key, final Object value) throws NamingException {
Context context = new InitialContext();
context.bind(key, value);
}
private static int retrieveFromContext(final String key) throws NamingException {
Context context = new InitialContext();
return (int) context.lookup(key);
}
}
public class MyContextFactory implements InitialContextFactory {
private static Hashtable store = new Hashtable();
/*
Do not confuse [store] with [environment]. They serve different
purposes.
*/
@Override
public Context getInitialContext(Hashtable environment) throws NamingException {
return new MyContext(store);
}
}
Invoke from the command line:
$ java -Djava.naming.factory.initial=MyContextFactory -cp [actual classpath] FooMain
42