動的プロキシクラスを目的のオブジェクトにキャストすると、奇妙なことが起こります。実行時に、特定の条件下で、ClassCastExceptionを受け取ります。
これをよりよく説明するために、ここに私が使用したいクラス/インターフェースの定義があります。ブラケットは、無関係な(あるべき)拡張インターフェースの周りに配置されています。
public interface CommandSender (extends Permissible)
public interface ConsoleCommandSender extends CommandSender, (Conversable)
public interface Player extends (HumanEntity, Conversable), CommandSender, (OfflinePlayer, PluginMessageRecipient)
完全なJavadocはここにあります:http://jd.bukkit.org/apidocs/org/bukkit/command/CommandSender.html
さて、これが私のプロキシクラスのコードです:
public class CommandSignsMessagingProxy implements InvocationHandler {
private Object sender;
private Object receiver;
private boolean silent;
public static Object newInstance(Object proxy) {
return newInstance(proxy, proxy, false);
}
public static Object newInstance(Object proxy, boolean silent) {
return newInstance(proxy, proxy, silent);
}
public static Object newInstance(Object sender, Object receiver) {
return newInstance(sender, receiver, false);
}
public static Object newInstance(Object sender, Object receiver, boolean silent) {
return Proxy.newProxyInstance(
sender.getClass().getClassLoader(),
sender.getClass().getInterfaces(),
new CommandSignsMessagingProxy(sender, receiver, silent));
}
private CommandSignsMessagingProxy(Object sender, Object receiver, boolean silent) {
this.sender = sender;
this.receiver = receiver;
this.silent = silent;
}
// Is called whenever a method is invoked
public Object invoke(Object p, Method m, Object[] args) throws Throwable {
Object result = null;
try {
String name = m.getName();
// If the receiver is being sent a message, only do so if the silent flag is not set
if (name == "sendMessage" || name == "sendRawMessage") {
if (!silent && receiver != null)
result = m.invoke(receiver, args);
} else {
result = m.invoke(sender, args);
}
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (Exception e) {
throw new RuntimeException("Unexpected invocation exception: " + e.getMessage());
}
return result;
}
}
そして、これがクラスの完全に機能するインスタンスです。
Player proxy = (Player)CommandSignsMessagingProxy.newInstance(player, false);
proxy.sendMessage("Hi! Silent is turned off, so you can see this!");
proxy.setOp(true);
proxy.other_stuff();
しかし、これは機能しません。
ConsoleCommandSender ccs = plugin.getServer().getConsoleSender();
CommandSender cs = (CommandSender)CommandSignsMessagingProxy.newInstance(ccs, false);
実行時に、この例では次のようになります。
java.lang.ClassCastException: $Proxy18 cannot be cast to org.bukkit.command.CommandSender