2017-12-07 28 views
1

Java SEコンソールアプリケーションのJNDIを設定しようとしています。新しいInitialContext()の無限再帰

私は、次のコードを持っている:

public class FooMain { 

    public static void main (String args[]) throws NamingException { 
     Context context = new InitialContext(); 
     context.bind("foo", "bar"); 
    } 
} 

&hellipを。私が使用して私のFooMainクラスを呼び出すと

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); 
      }  
     }; 
    } 
} 

java -Djava.naming.factory.initial=MyContextFactory -cp ... FooMain 

を私は無限再帰と最終的なStackOverflowの例外を取得:

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) 
... 

私が作ることができ、コンテキストファクトリは、以下のように定義されますコードは "environment" Hashtableを作成し、そこにMyContextFactoryクラスの名前を置いて( "java.naming.factory.initial"キーの下に)、次にを作成します

Context context = new InitialContext(environment); 

しかし、私の質問は:どのように私はこの作品が引数なしのコンストラクタを使用して「-Djava.naming.factory使用してファクトリクラスの名前を供給することができますHashtableの環境を受け取るコンストラクタを使用してJVMの起動時に ".initial"?

+1

これは興味深い質問です。 'InitialContext'は実際にはコンストラクタでカスタムファクトリを探してそれを使うことを知っている' Context'のラッパーです。 JVMを起動する前にファクトリを置き換えると、デフォルトのファクトリは決して使用されないので、再帰が発生します。これを修正する方法はわかりませんが、InitialContextのコードを読み込み、デフォルトが実行されないときの動作をオーバーライドすることになると思われます。 –

+1

提案されている調査方法:匿名の内部クラスを使用できない場合があります。これは、InitialContextの遅延初期化コンストラクタを使用する必要があると思われるためです。 –

+0

はい、そうでした。 –

答えて

0

ジムギャリソンの提案のおかげで、ここに答えがあります。 問題の要点は、MyContextクラスのコンストラクタでsuper(true);というコールです。

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); 
    } 
} 

起動コマンドラインから:

$ java -Djava.naming.factory.initial=MyContextFactory -cp [actual classpath] FooMain 
42 
関連する問題