简体   繁体   English

从调用返回另一个代理的Java.lang.reflect.Proxy在赋值时导致ClassCastException

[英]Java.lang.reflect.Proxy returning another proxy from invocation results in ClassCastException on assignment

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. 所以我正在玩geotools,我想我会代理他们的一个数据访问类,并跟踪它们在代码中的使用方式。

I coded up a dynamic proxy and wrapped a FeatureSource (interface) in it and off it went happily. 我编写了一个动态代理并在其中包含了一个FeatureSource(接口),并且很高兴。 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). 然后我想看一下featureSource返回的一些传递对象,因为FeatureSource做的主要事情是返回一个FeatureCollection(FeatureSource类似于sql DataSource和featurecollection到sql语句)。

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. 在我的invocationhandler中,我只是将调用传递给底层对象,打印出目标类/方法/ args并按原样结果,但对于返回FeatureCollection(另一个接口)的调用,我将该对象包装在我的代理中(相同的类,但一个新的实例,应该不重要吗?)并返回它。 BAM! BAM! Classcast exception: Classcast异常:

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

the calling code: 调用代码:

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

the Proxy: 代理人:

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() returns only the interfaces DIRECTLY implemented by the class. Class.getInterfaces()仅返回类实现的DIRECTLY接口。 You need a transitive closure to optain all the interfaces. 您需要一个传递闭包来获取所有接口。

UPDATE UPDATE

Example: 例:

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);
        }
    }
}

You may also need to "unwrapp" the proxies that are passed as arguments. 您可能还需要“解开”作为参数传递的代理。

@maurice-perry's solution worked great for me and I have voted for it, but I did also want to point out that there are library implementations of the needed method. @ maurice-perry的解决方案对我很有用,我已经投了赞成票,但我也想指出有所需方法的库实现。

I ended up implementing this solution with the Apache Commons library method ClassUtils.getAllInterfaces() : 我最终使用Apache Commons库方法ClassUtils.getAllInterfaces()实现了这个解决方案:

...
import org.apache.commons.lang3.ClassUtils;
...

private static Class<?>[] getAllInterfaces(Object object) {
    final List<Class<?>> interfaces =
        ClassUtils.getAllInterfaces(object.getClass());

    return interfaces.toArray(new Class<?>[interfaces.size()]);
}

It works great for that magical second argument in newProxyInstance : 它适用于newProxyInstance中神奇的第二个参数:

Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, 
                       InvocationHandler h)

There is also a Guava approach using: 还有一种番石榴方法使用:

final Set<TypeToken> tt = TypeToken.of(cls).getTypes().interfaces();

But then you have to figure out howto convert Set<TypeToken> to Class<?>[] . 但是你必须弄清楚如何将Set<TypeToken>转换为Class<?>[] Trivial perhaps, if you're a Guava buff, but Apache's is ready for use. 也许是微不足道的,如果你是番石榴buff,但是Apache已经可以使用了。

Both of these were noted in this related thread, get all (derived) interfaces of a class . 这两个都在这个相关的线程中被注意到, 获得了类的所有(派生)接口

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 替换java.lang.reflect.Proxy中的InvocationHandler - Replace InvocationHandler in java.lang.reflect.Proxy java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler - java.lang.reflect.Proxy and java.lang.reflect.InvocationHandler 为什么在正常方法调用不需要的情况下,java.lang.reflect.Proxy需要声明检查的异常? - Why does a java.lang.reflect.Proxy require declaring checked exceptions when normal method invocation does not? java.lang.reflect.Proxy:巨大的异常堆栈跟踪 - java.lang.reflect.Proxy: Huge exception stack trace 通过网络传输java.lang.reflect.Proxy - transmit a java.lang.reflect.Proxy over a network java.lang.reflect.Proxy实例是否专门用于最终化处理? - Are java.lang.reflect.Proxy instances treated specially for finalization? 在 java.lang.reflect.Proxy 上实现 equals、hashCode 和 toString - Implementing equals, hashCode, and toString on java.lang.reflect.Proxy 如何从两个单独的类加载器制作java.lang.reflect.Proxy? - How can I make a java.lang.reflect.Proxy from two separate classloaders? 在java.lang.reflect.Proxy对象上调用扩展函数时Kotlin奇怪的行为 - Kotlin strange behaviour when calling extension function on java.lang.reflect.Proxy object java.lang.reflect.Proxy的替代方法,用于创建抽象类(而不是接口)的代理 - Alternatives to java.lang.reflect.Proxy for creating proxies of abstract classes (rather than interfaces)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM