ClassLoader#setPackageAssertionStatusがウゴゲ。

こんなクラスを用意しるます。

public class Hoge {
  public void fuga(String s) {
    assert s != null : "s must not be null";
    System.out.println(s);
  }
}

ポイントは、全く同じクラスを、二つのパッケージに配置する事。

  • aaa.bbb.ccc
    • SystemClassLoaderでロードする。
  • zzz.zzz
    • 俺様URLClassLoaderでロードする。

の二つ。


つまり、こんな感じのコード。

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

import aa.bb.cc.Hoge;

public class Main {
  public static void main(String[] args) throws Exception {
    Hoge h = new Hoge();
    h.fuga("s");
    h.fuga(null);

    URLClassLoader cl = new URLClassLoader(new URL[] { new File("classes")
        .toURI().toURL() });
    cl.setPackageAssertionStatus("zzz", true);
    Class<?> clazz = cl.loadClass("zzz.zzz.Hoge");
    Object o = clazz.newInstance();
    Method m = o.getClass().getMethod("fuga", String.class);
    m.invoke(o, "aaa");
    m.invoke(o, new Object[] { null });
  }
}

これを、-ea でassert構文を有効化せずJVMを起動しる。

s
null
aaa
Exception in thread "main" java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at Main.main(Main.java:26)
Caused by: java.lang.AssertionError: s must not be null
	at zzz.zzz.Hoge.fuga(Hoge.java:6)
	... 5 more

おおう!ファンタスティック!
JVMの-eaオプションは、まぁ、何というかビックリする位扱い辛い*1ので、
オレオレClassLoaderを提供する皆様におかれましては、
その実行を制御する為の設定ファイル内において、
assertモードをハンドリング出来る様にしてはうかがか?


例えば、こんな感じ?

<config assert="enable">
<component assert="enable" class="aaa.bbb.ccc.Hoge" />
</config>

アプリケーションコードのアサートと、
フレームワークのアサートのスイッチを、
JVMの起動オプションじゃ無しに、
設定ファイル的な何かでスイッチ出来たりすると、何か幸せかもぞ。


ちなむと、java.lang.ClassLoader には、こんな感じでメソッドが並んでいる。

  • clearAssertionStatus()
  • setClassAssertionStatus(String className, boolean enabled)
  • setDefaultAssertionStatus(boolean enabled)
  • setPackageAssertionStatus(String packageName, boolean enabled)

尚、このassertionStatusは、Classのロードじスタティックイニシャライザで、
Class#desiredAssertionStatus() を呼出してstaticメンバに抱えてしまうので、
一度ロードされたクラスの状態を変更する事は出来ませぬ。