Но при всём при этом, мало кому из нас приходилось насиловать код так, как недавно пришлось мне. Собственно, нужно было решить простую задачу: у org.eclipse.swt.widgets.Tree забрать org.eclipse.jface.viewers.TreeViewer. Понятно, что Tree и в помине не знает ни про какой viewer (собственно, его может и не быть в общем случае). Более того, TreeViewer, оборачивая дерево, практически не оставил следов. Однако, решение всё-таки нашлось и выглядит оно так:
public static TreeViewer getTreeViewer(Tree tree) {
return getViewer(TreeViewer.class, tree, SWT.Expand);
}
private static <T> T getViewer(Class<T> clazz, Control control, int event) {
Listener[] listeners = control.getListeners(event);
for (Listener listener : listeners) {
Object lookFor = listener;
if (listener instanceof TypedListener) {
lookFor = ((TypedListener) listener).getEventListener();
}
try {
Field this$0 = lookFor.getClass().getDeclaredField("this$0");
this$0.setAccessible(true);
Object viewer = this$0.get(lookFor);
if (clazz.isInstance(viewer)) {
return clazz.cast(viewer);
}
} catch (Exception e) {
// ignore exceptions
}
}
return null;
}
Происходит здесь вот что: viewer неосторожно добавил listener к tree. Этот слушатель мало того, что может дополнительно оборачиваться TypedListener, так ещё и является анонимным внутренним классом TreeViewer. Поэтому в примере мы проходим по всем слушателям нужного события, опционально избавляем его от Typed-обёртки, а затем спрашиваем не лежит ли он в нужном TreeViewer. При этом, если мы наткнулись на неправильный listener, то скорее всего кинется исключение, которое благоразумно игнорируется.
А как вам приходилось использовать reflection?
