Таким образом, я играю с геоинструментами, и я думал, что проксирую один из их классов доступа к данным и прослежу, как он использовался в их коде.
Я кодировал динамический прокси и перенес FeatureSource (интерфейс) в него, и от него пошел счастливо. Затем я хотел посмотреть на некоторые переходные объекты, возвращенные featureSource также, так как главное, которое делает FeatureSource, возвратить FeatureCollection (FeatureSource походит на sql DataSource и featurecollection к sql оператору).
в моем invocationhandler я просто передал вызов до основного объекта, распечатывая цель class/method/args и результат, когда я пошел, но для вызовов, которые возвратили FeatureCollection (другой интерфейс), я перенес тот объект в свой прокси (тот же класс, но новый экземпляр, не должен иметь значения, должен он?) и возвратил его. BAM! Исключение 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 () возвращает только интерфейсы, НЕПОСРЕДСТВЕННО реализованные классом. Вам нужно переходное закрытие, чтобы отключить все интерфейсы.
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);
}
}
}
Вам также может потребоваться «развернуть» прокси, переданные в качестве аргументов.