ProxyFactoryに見るスタティックな処理のオーバライド

ここで何度かネタにしてきたJavassistのProxyFactoryだが、同クラスを使ったことがあるプログラマはClassLoaderProviderインタフェースのスタティックなフィールドが公開されていることに気がついただろうか。

  • 公開されているProxyFactory.classLoaderProvider
public static ClassLoaderProvider classLoaderProvider
    = new ClassLoaderProvider() {
          public ClassLoader get(ProxyFactory pf) {
              return pf.getClassLoader0();
          }
      };

ソースコードを追いかけるとすぐに解ることだが、ProxyFactoryは内部で生成したクラスをロードするために使うクラスローダの取得処理を、このclassLoaderProviderに格納されたインタフェースに委譲しているのである。

このように処理を委譲するスタティック且つ書き換え可能なインタフェース型のフィールドを外部に公開することにより、(デフォルトの実装を記述しつつ)必要な時に外部からスタティックな初期処理を挿げ替えることができるようになる。

  • 外部でProxyFactory.classLoaderProviderをカレントスレッドのクラスローダを返すように書き換える例
ProxyFactory.classLoaderProvider = 
    new ProxyFactory.ClassLoaderProvider() {
        @Override
        public ClassLoader get(ProxyFactory pf) {
            return Thread.currentThread().getContextClassLoader();
        }};
final ProxyFactory factory = new ProxyFactory();

クラスのスタティックな処理を書換えるのは通常の継承メカニズムは使えないため、例えばクラスのイニシャライザでシステムプロパティを読み込み、その値で初期処理を変える等の手を使ったりするが、このように外部のコードから処理を書き換える簡単な方法が簡単に実現されているのには良い意味でショックを覚えた。

変数、それもクラスの重要な処理が委譲されているスタティックフィールドが公開されており、その気になれば内容を破壊することができるのは、final主義や隠蔽主義な技術者からは非難の対象になるかもしれないが、このようなフィールドは明示的に変更するということはその部分を敢えて書換えたいという意思があってのことなのだし、プロが注意して使うことを前提にしていれば何の問題も無いと思うのだ。