Frage

Also habe ich mit GeoTools bin zu spielen und ich dachte, ich würde Proxy eine ihrer Datenzugriffsklassen und Spur, wie es in ihrem Code verwendet wird.

I codiert einen dynamischen Proxy und wickelte eine FeatureSource (Schnittstelle) in ihm und von ihm weg glücklich ging. Dann habe ich auf einige der transitiven durch die featureSource auch, Objekte zurückgegeben aussehen wollte, da die Hauptsache ein FeatureSource tut, ist eine FeatureCollection zurückkehren (FeatureSource ist analog zu einer SQL-Datasource und featurecollection zu einer SQL-Anweisung).

in meinem InvocationHandler ich gerade den übergebenen Anruf bis zur Aufgabe zugrunde, Ausdrucken der Zielklasse / Verfahren / args und Ergebnis, wie ich ging, aber für Anrufe, die eine FeatureCollection (eine andere Schnittstelle) zurückgeführt, wickelte ich das Objekt in meinem Proxy (die gleiche Klasse, sondern eine neue Instanz, sollte nicht sollte eine Rolle?) und gab ihm. BAM! Classcast Ausnahme:

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

die Telefonvorwahl:

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

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

}

Ist es möglich, Proxies von Schnittstellen dynamisch zurückkehren von eine Proxy-Schnittstelle oder bin ich etwas falsch? Prost!

War es hilfreich?

Lösung

Class.getInterfaces () gibt nur die eine direkte Schnittstelle von der Klasse implementiert. Sie benötigen einen transitiven Abschluss alle die Schnittstellen optain.

UPDATE

Beispiel:

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

Sie können auch müssen „unwrapp“ die Proxys, die als Argumente übergeben werden.

Andere Tipps

@ maurice-Perrys Lösung funktionierte für mich großartig und ich habe dafür gestimmt, aber ich wollte auch darauf hinweisen, dass es Bibliothek Implementierungen der benötigten Methode.

ich am Ende der Implementierung diese Lösung mit der Apache Commons Bibliothek Methode 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()]);
}

Es funktioniert gut für das magische zweite Argument in newProxyInstance :

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

Es gibt auch einen Guava Ansatz:

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

Aber dann muss man Howto convert Set<TypeToken> zu Class<?>[] herauszufinden. Trivial vielleicht, wenn Sie ein Guava buff, aber Apache ist einsatzbereit.

Beide wurden in diesem verwandten Thread erwähnt, get all (abgeleitet) Schnittstellen einer Klasse .

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top