Eclipse 4.x中Command是如何映射到Handler的

1. Eclipse中的Command模式,使得具体的实现和Command定义分离,便于维护。

但是在Debug的时候,或者没有souce code的时候,我们想知道每一个commandId对应的Handler是什么,怎么办?

2. 在Eclipse
4.x中,其实当Eclipse启动完成后,它已经创建了commandId和对应Handler的Map,保存在EclipseContext中,

然后通过反射调用到对应的Handler。 见下图:

Eclipse是在上图中我框出来的地方,通过commandId在EclipseContext中查找到。

3. 如何将EclipseContext中的Handler都dump出来呢?

一句话,反射。

注意,以下代码我只在Eclipse 4.3.0上测试通过。

    //try to print all handler in eclipse 4.x
    result = ReflectionUtils.getField("e4Context", site);
    if(!isSuccess(result)) {
        return;
    }

    if(result instanceof IEclipseContext) {
        IEclipseContext context = (IEclipseContext)result;
        printHandlerForEclipseContext(context, 0);
    }




@SuppressWarnings("unchecked")
private void printHandlerForEclipseContext(IEclipseContext context, int step) {
    Assert.isNotNull(context);

    Object result = null;
    if(step != 0) {
        result = ReflectionUtils.getField("localValueComputations", context);
    } else {
        result = ReflectionUtils.getField("localValues", context);
    }
    if(!isSuccess(result)) {
        return;
    }

    if(result instanceof Map) {
        String stepString = makeStep(step);
        Map<String, Object> localValueComputations = (Map<String, Object>)result;
        for (String string : localValueComputations.keySet()) {
            Object object = localValueComputations.get(string);

            String last = object.toString();
            if(string.startsWith("legacy::handler::")) {
                if(object instanceof ArrayList) {
                    ArrayList list = (ArrayList)object;
                    //TODO may be more than one item in list
                    object = list.get(0);
                    if(object instanceof IHandlerActivation) {
                        IHandlerActivation activation = (IHandlerActivation)object;
                        last = activation.getHandler().toString();
                    }
                }
            }
            System.out.println(stepString + string + ", " + last);
        }
    }
    result = null;

    result = ReflectionUtils.invokeMethod(context, "getChildren");
    if(!isSuccess(result)) {
        return;
    }

    if(result instanceof Set) {
        Set<IEclipseContext> children = (Set<IEclipseContext>)result;
        Iterator<IEclipseContext> iterator = children.iterator();
        IEclipseContext child = null;
        int moreStep = step + 1;
        while(iterator.hasNext()) {
            child = iterator.next();
            printHandlerForEclipseContext(child, moreStep);
        }
        step ++;
    }
}

以下是我的屏幕输出的一部分,输出格式为:commandId, Handler

legacy::handler::org.eclipse.ui.edit.text.recenter,
ActionHandler(org.eclipse.ui.texteditor.RecenterAction@7efaa9e2)
legacy::handler::org.eclipse.jdt.ui.edit.text.java.search.declarations.in.hierarchy,
ActionHandler(org.eclipse.jdt.ui.actions.FindDeclarationsInHierarchyAction@14c26e4a)
legacy::handler::org.eclipse.jdt.ui.edit.text.java.search.declarations.in.project,
ActionHandler(org.eclipse.jdt.ui.actions.FindDeclarationsInProjectAction@174043f5)
legacy::handler::org.eclipse.jdt.ui.edit.text.java.surround.with.try.multicatch,
ActionHandler(org.eclipse.jdt.ui.actions.SurroundWithTryMultiCatchAction@49e3c996)
legacy::handler::org.eclipse.jdt.ui.edit.text.java.override.methods,
ActionHandler(org.eclipse.jdt.ui.actions.OverrideMethodsAction@11e18e8c)
legacy::handler:: org.eclipse.ui.edit.findPrevious , ActionHandler(
org.eclipse.ui.texteditor.FindNextAction @69d5ee81)
handler::org.eclipse.jdt.ui.edit.text.java.remove.block.comment,
org.eclipse.ui.internal.handlers.LegacyHandlerService$HandlerSelectionFunction@207462c0