java.lang.reflect.Proxyのは、割り当てにClassCastExceptionが発生して呼び出した結果から別のプロキシを返します
-
27-09-2019 - |
質問
私はgeotoolsで遊んでいると私は、私はそれが彼らのコードで使用されていたどのように自分のデータアクセスクラスとトレースのプロキシ1をしようと思いました。
だから、Iは、動的プロキシを符号化し、その中に、それは喜んで行ったオフFeatureSource(インターフェース)を包みました。それから私はFeatureSourceが行う主なものはれるFeatureCollectionを返しているので、同様featureSourceによって返されたオブジェクトの推移のいくつかを見てみたかった(FeatureSourceは、SQL文のSQLデータソースとれるFeatureCollectionに似ている)。
私のInvocationHandlerに私はちょうど私が行ったように、目標クラス/メソッド/引数と結果をプリントアウトし、基礎となるオブジェクトに至るまでの呼び出しを通過したが、れる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()を直接クラスによって実装されるインターフェースのみを返します。あなたはすべてのインターフェイスをoptainする推移閉包を必要とします。
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」に引数として渡されたプロキシが必要な場合があります。
他のヒント
@モーリス・ペリーのソリューションは、私のために素晴らしい仕事をし、私はそれに投票していますが、私はまた、必要なメソッドのライブラリの実装があることを指摘したいんでした。
私は、Apache Commonsのライブラリー法<のhref = "このソリューションを実装することになったhttps://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/ClassUtils.html# getAllInterfaces(のjava.lang.Class)」REL = "nofollowを"> 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()]);
}
それは<のhref = "https://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html#newProxyInstance(java.langにその魔法の第二引数のための素晴らしい作品.ClassLoader、%20java.lang.Class []、%20java.lang.reflect.InvocationHandler)」REL = "nofollowを"> newProxyInstance
の
Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h)
グァバのアプローチは、使用してもあります
final Set<TypeToken> tt = TypeToken.of(cls).getTypes().interfaces();
しかし、その後、あなたはSet<TypeToken>
にHOWTOコンバートClass<?>[]
を把握する必要があります。些細な、おそらく、あなたはグアババフだが、Apacheのを使用する準備ができている場合。
これらの両方は、この関連スレッドで認められた、 GET全て(派生)クラスでのインターフェイス。