3

動的プロキシクラスを目的のオブジェクトにキャストすると、奇妙なことが起こります。実行時に、特定の条件下で、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
4

1 に答える 1

4

作成されたプロキシ クラスは、実装すると思われるインターフェイスを渡す必要があります。

return Proxy.newProxyInstance(
                sender.getClass().getClassLoader(),
                sender.getClass().getInterfaces(),
                new CommandSignsMessagingProxy(sender, receiver, silent));

呼び出し sender.getClass().getInterfaces() メソッドから CommandSender インターフェイスが返されない可能性があるため、失敗が発生するようです。なのでデバッグでちゃんと通るか試してみてください。そうでない場合は、インターフェイスを手動でメソッドに送信して、機能するかどうかを確認してください。

于 2012-09-29T12:34:44.917 に答える