Java.lang.reflect.Proxy从调用返回另一个代理导致分配时ClassCastException [英] Java.lang.reflect.Proxy returning another proxy from invocation results in ClassCastException on assignment

查看:93
本文介绍了Java.lang.reflect.Proxy从调用返回另一个代理导致分配时ClassCastException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我在玩geotools,我想我将代理他们的数据访问类之一,并跟踪它们在代码中的使用方式。

So I'm playing with geotools and I thought I'd proxy one of their data-access classes and trace how it was being used in their code.

我编写了一个动态代理,并在其中包装了FeatureSource(接口),然后愉快地运行了。然后,我还想看一下FeatureSource返回的一些可传递对象,因为FeatureSource所做的主要工作是返回FeatureCollection(FeatureSource类似于sql DataSource,featurecollection类似于sql语句)。

I coded up a dynamic proxy and wrapped a FeatureSource (interface) in it and off it went happily. Then I wanted to look at some of the transitive objects returned by the featureSource as well, since the main thing a FeatureSource does is return a FeatureCollection (FeatureSource is analogous to a sql DataSource and featurecollection to an sql statement).

传递给了基础对象,随即打印了目标类/方法/ args和结果,但是对于返回FeatureCollection的调用(另一个接口) ,我将该对象包装在代理中(相同的类,但是有一个新的实例,应该没关系吗?)并返回它。
BAM! Classcast例外:

in my invocationhandler I just passed the call through to the underlying object, printing out the target class/method/args and result as I went, but for calls that returned a FeatureCollection (another interface), I wrapped that object in my proxy (the same class but a new instance, shouldn't matter should it?) and returned it. BAM! Classcast exception:

java.lang.ClassCastException: $Proxy5 cannot be cast to org.geotools.feature.FeatureCollection  
    at $Proxy4.getFeatures(Unknown Source)  
    at MyClass.myTestMethod(MyClass.java:295)  

调用代码:

FeatureSource<SimpleFeatureType, SimpleFeature> featureSource = ... // create the FS
featureSource = (FeatureSource<SimpleFeatureType, SimpleFeature>) FeatureSourceProxy.newInstance(featureSource, features);
featureSource.getBounds();// ok
featureSource.getSupportedHints();// ok

DefaultQuery query1 = new DefaultQuery(DefaultQuery.ALL);
FeatureCollection<SimpleFeatureType, SimpleFeature> results = featureSource.getFeatures(query1); //<- explosion here

代理:

public class FeatureSourceProxy  implements java.lang.reflect.InvocationHandler {

private Object target;
private List<SimpleFeature> features;

public static Object newInstance(Object obj, List<SimpleFeature> features) {
return java.lang.reflect.Proxy.newProxyInstance(
    obj.getClass().getClassLoader(), 
    obj.getClass().getInterfaces(), 
    new FeatureSourceProxy(obj, features)
);
}

private FeatureSourceProxy(Object obj, List<SimpleFeature> features) {
this.target = obj;
this.features = features;
}

public Object invoke(Object proxy, Method m, Object[] args)throws Throwable{
Object result = null;
try {
    if("getFeatures".equals(m.getName())){ 
        result = interceptGetFeatures(m, args);
    }
    else{
        result = m.invoke(target, args);
    }
} 
catch (Exception e) {
    throw new RuntimeException("unexpected invocation exception: " +  e.getMessage(), e);
} 
return result;
}

private Object interceptGetFeatures(Method m, Object[] args) throws Exception{
    return newInstance(m.invoke(target, args), features);
}

}

是否可以从代理接口动态返回接口 的代理,或者我做错了什么?
欢呼!

Is it possible to dynamically return proxies of interfaces from a proxied interface or am I doing something wrong? cheers!

推荐答案

Class.getInterfaces()仅返回由类直接实现的接口。您需要一个传递闭包来获取所有接口。

Class.getInterfaces() returns only the interfaces DIRECTLY implemented by the class. You need a transitive closure to optain all the interfaces.

UPDATE

示例:

private static Class<?>[] getInterfaces(Class<?> c) {
    List<Class<?>> result = new ArrayList<Class<?>>();
    if (c.isInterface()) {
        result.add(c);
    } else {
        do {
            addInterfaces(c, result);
            c = c.getSuperclass();
        } while (c != null);
    }
    for (int i = 0; i < result.size(); ++i) {
        addInterfaces(result.get(i), result);
    }
    return result.toArray(new Class<?>[result.size()]);
}

private static void addInterfaces(Class<?> c, List<Class<?>> list) {
    for (Class<?> intf: c.getInterfaces()) {
        if (!list.contains(intf)) {
            list.add(intf);
        }
    }
}

您可能还需要 unwrapp作为参数传递的代理。

You may also need to "unwrapp" the proxies that are passed as arguments.

这篇关于Java.lang.reflect.Proxy从调用返回另一个代理导致分配时ClassCastException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆