java.lang.reflect.proxy إرجاع وكيل آخر من نتائج الاحتجاج في classcastexception على المهمة

StackOverflow https://stackoverflow.com/questions/2642700

سؤال

لذلك أنا ألعب مع Geotools وأعتقد أنني سأقوم بتكليف أحد فصول الوصول إلى البيانات الخاصة بهم وتتبع كيف تم استخدامه في الكود.

لقد قمت بترميز وكيل ديناميكي ولفت ملامحه (واجهة) فيه وذهبت بسعادة. ثم أردت أن أنظر إلى بعض الكائنات المتعدية التي يتم إرجاعها بواسطة الميزات أيضًا ، لأن الشيء الرئيسي الذي تقوم به الميزات هو إرجاع meatureCollection (الميزات تشبه بيانات بيانات SQL وميسورات إلى بيان SQL).

في برنامج InvocationHandler الخاص بي ، انتقلت للتو إلى المكالمة إلى الكائن الأساسي ، وطباعة الفئة/الطريقة/args المستهدفة والنتيجة كما ذهبت ، ولكن للمكالمات التي أعادت fatureCollection (واجهة أخرى) ، لفت هذا الكائن في الوكيل الخاص بي ( نفس الفئة ولكن مثيل جديد ، لا ينبغي أن يهم ذلك؟) وأعيدها. بام! استثناء Classcast:

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

}

هل من الممكن إرجاع وكلاء الواجهات ديناميكيًا من عند واجهة وكيفية أم أفعل شيئًا خاطئًا؟ في صحتك!

هل كانت مفيدة؟

المحلول

class.getInterfaces () إرجاع فقط الواجهات التي تنفذها الفئة مباشرة. أنت بحاجة إلى إغلاق متعدية لإيقاف جميع الواجهات.

تحديث

مثال:

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

قد تحتاج أيضًا إلى "إلغاء" الوكلاء الذين يتم تمريره كحجيلات.

نصائح أخرى

لقد نجح حل @Maurice-Perry بشكل رائع بالنسبة لي وقد صوتت لصالحه ، لكنني أردت أيضًا الإشارة إلى أن هناك تطبيقات مكتبة للطريقة المطلوبة.

انتهى بي الأمر بتنفيذ هذا الحل مع طريقة مكتبة 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()]);
}

إنه يعمل بشكل رائع لتلك الحجة الثانية السحرية في newProxyInstance:

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

هناك أيضًا نهج الجوافة باستخدام:

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

ولكن بعد ذلك عليك معرفة كيف يتحول Set<TypeToken> ل Class<?>[]. ربما تافهة ، إذا كنت برتقالي الجوافا ، لكن أباتشي جاهزة للاستخدام.

وقد لوحظ كلاهما في هذا الموضوع ذي الصلة ، احصل على كل واجهات (مشتقة) من الفصل.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top