ClassLoader
親子関係のない異なる によってロードされた 2 つのクラスがデータを共有する必要がある場合、通常の Java 言語構造は機能しません。Class
オブジェクトまたはインスタンスを手に入れることができれば、異なるローダーによってロードされたばかりの同じクラスであっても、リフレクションを介してそれらにアクセスする必要があります。
さらに、ヒープ変数を介してデータを渡すと、両方ClassLoader
が独自の「名前空間」を確立するため機能しません。したがって、2 つの異なるオブジェクトを作成する 2 つの異なるローダーによってロードされたクラスには、変数Class
の異なるコピーも含まれます。static
独自のクラスから独立したストレージが必要です。
ありがたいことに、そのストレージはタグレットのコンテキストに存在します。このregister
メソッドは、Map
以前に登録されたすべてのタグレットを含む を受け取ります。instanceof
しかし、「友達」のタグレットを見つけるために、または比較ではなくリフレクションを使用する必要があるという事実に加えて、Class
別の障害があります。JavaDoc の実装では、タグレットを別のオブジェクト内にラップすることです。
すべてをまとめると、タグレットの基本クラスに検索と共有のロジックを実装し、タグレットのregister
メソッドにそれを呼び出させることができます。
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Properties;
public abstract class Base
{
static Properties CONFIG=new Properties();
static void initProperties(Map<?, ?> fromTagManager) {
String className=Base.class.getName();
for(Object o: fromTagManager.values()) {
o=extractTagLet(o);
if(o==null) continue;
for(Class<?> cl=o.getClass(); cl!=null; cl=cl.getSuperclass())
if(cl.getName().equals(className) && initFromPrevious(cl)) return;
}
// not found, first initialization
try {
CONFIG.load(Base.class.getResourceAsStream("config.properties"));
} catch(IOException ex) {
throw new ExceptionInInitializerError(ex);
}
}
private static Object extractTagLet(Object o) {
if(!o.getClass().getSimpleName().equals("LegacyTaglet"))
return o;
try {
Field f=o.getClass().getDeclaredField("legacyTaglet");
f.setAccessible(true);
return f.get(o);
} catch(NoSuchFieldException | IllegalAccessException ex) {
ex.printStackTrace();
}
return null;
}
private static boolean initFromPrevious(Class<?> cl) {
// this is the same class but loaded via a different ClassLoader
try {
Field f=cl.getDeclaredField("CONFIG");
f.setAccessible(true);
CONFIG=(Properties)f.get(null);
return true;
} catch(NoSuchFieldException | IllegalAccessException ex) {
return false;
}
}
}
次に、タグレットは次のように実装されます。
import java.util.Map;
import com.sun.javadoc.Tag;
import com.sun.tools.doclets.Taglet;
public class ExampleTaglet extends Base implements Taglet {
@SuppressWarnings("unchecked")
public static void register(@SuppressWarnings("rawtypes") Map map) {
initProperties(map);
final ExampleTaglet taglet = new ExampleTaglet();
final String name = taglet.getName();
map.remove(name);// must ensure new Taglet is the last one (LinkedHashMap)
map.put(name, taglet);
}
// implement the Taglet interface below…