private void addListener(Object bean, Element e) {
        ListenerMate lm = getListenerMate(getClass(e.getTagName()));
        final Map<Method, Method> methodMap = new HashMap<>();
        String forProp = null;
        String propName = null;
        for (Node attr : DocumentUtils.getAttributes(e)) {
            String name = attr.getNodeName();
            String value = attr.getNodeValue();
            switch (name) {
                case "for":
                    forProp = value;
                    break;
                case "propertyName":
                    propName = evaluate(value, String.class, null);
                    break;
                default:
                    Method listenerMethod = lm.methodMap.get(name);
                    methodMap.put(listenerMethod, ReflectionUtils.getDeclaredMethod(
                            controllerClass, value, listenerMethod.getParameterTypes()));
            }
        }

        Object listener = Proxy.newProxyInstance(controllerLoader,
                new Class<?>[] {lm.listenerClass}, new AbstractInvocationHandler() {
            @Override
            public Object invokeOthers(Object proxy, Method method, Object[] args) {
                Method controllerMethod = methodMap.get(method);
                if (controllerMethod != null) {
                    ReflectionUtils.invoke(controllerMethod, controller, args);
                }
                return null;
            }
        });

        Object target = bean;
        if (forProp != null) {
            String getter = "get" + Character.toUpperCase(forProp.charAt(0))
                    + forProp.substring(1);
            target = ReflectionUtils.invoke(
                    ReflectionUtils.getMethod(bean.getClass(), getter), bean);
        }

        if (propName != null && PropertyChangeListener
                .class.isAssignableFrom(lm.listenerClass)) {
            ReflectionUtils.invoke(
                    ReflectionUtils.getMethod(target.getClass(),
                            "addPropertyChangeListener",
                            String.class, PropertyChangeListener.class),
                    target, listener);
        } else {
            ReflectionUtils.invoke(
                    getBeanMate(target.getClass()).addListenerMap.get(lm.listenerClass),
                    target, listener);
        }
    }