📄 eventhandler.java
字号:
try { actionMethod = targetClass.getMethod(action, null); } catch(NoSuchMethodException nsme) { // Note: If we want to be really strict the specification says that a no-argument method should // accept an EventObject (or subclass I guess). However since the official implementation is broken // anyways, it's more flexible without the EventObject restriction and we are compatible on everything // else this can stay this way. if(arguments != null && arguments.length >= 1/* && arguments[0] instanceof EventObject*/) { Class[] targetArgTypes = new Class[] { initClass(arguments[0].getClass()) }; while(targetArgTypes[0] != null) { try { // If no property exists we expect the first element of the arguments to be // an EventObject which is then applied to the target method. actionMethod = targetClass.getMethod(action, targetArgTypes); return actionMethod.invoke(target, new Object[] { arguments[0] }); } catch(NoSuchMethodException nsme2) { } targetArgTypes[0] = nextClass(targetArgTypes[0]); } } } // If we do not have a Method instance at this point this means that all our tries // failed. The JDK throws an ArrayIndexOutOfBoundsException in this case. if(actionMethod == null) throw new ArrayIndexOutOfBoundsException(0); // Invoke target.action(property) return actionMethod.invoke(target, null); } catch(InvocationTargetException ite) { throw new RuntimeException(ite.getCause()); } catch(IllegalAccessException iae) { // Cannot happen because we always use getMethod() which returns public // methods only. Otherwise there is something seriously broken in // GNU Classpath. throw (InternalError) new InternalError("Non-public method was invoked.").initCause(iae); } } /** * <p>Returns the primitive type for every wrapper class or the * class itself if it is no wrapper class.</p> * * <p>This is needed because to be able to find both kinds of methods: * One that takes a wrapper class as the first argument and one that * accepts a primitive instead.</p> */ private Class initClass(Class klass) { if(klass == Boolean.class) { return Boolean.TYPE; } else if(klass == Byte.class) { return Byte.TYPE; } else if(klass == Short.class) { return Short.TYPE; } else if(klass == Integer.class) { return Integer.TYPE; } else if(klass == Long.class) { return Long.TYPE; } else if(klass == Float.class) { return Float.TYPE; } else if(klass == Double.class) { return Double.TYPE; } else { return klass; } } /** * * * @param klass * @return */ private Class nextClass(Class klass) { if(klass == Boolean.TYPE) { return Boolean.class; } else if(klass == Byte.TYPE) { return Byte.class; } else if(klass == Short.TYPE) { return Short.class; } else if(klass == Integer.TYPE) { return Integer.class; } else if(klass == Long.TYPE) { return Long.class; } else if(klass == Float.TYPE) { return Float.class; } else if(klass == Double.TYPE) { return Double.class; } else { return klass.getSuperclass(); } } /** * <p>Constructs an implementation of <code>listenerInterface</code> * to dispatch events.</p> * * <p>You can use such an implementation to simply call a public * no-argument method of an arbitrary target object or to forward * the first argument of the listener method to the target method.</p> * * <p>Call this method like:</p> * <code> * button.addActionListener((ActionListener) * EventHandler.create(ActionListener.class, target, "dispose")); * </code> * * <p>to achieve the following behavior:</p> * <code> * button.addActionListener(new ActionListener() { * public void actionPerformed(ActionEvent ae) { * target.dispose(); * } * }); * </code> * * <p>That means if you need a listener implementation that simply calls a * a no-argument method on a given instance for <strong>each</strong> * method of the listener interface.</p> * * <p>Note: The <code>action</code> is interpreted as a method name. If your target object * has no no-argument method of the given name the EventHandler tries to find * a method with the same name but which can accept the first argument of the * listener method. Usually this will be an event object but any other object * will be forwarded, too. Keep in mind that using a property name instead of a * real method here is wrong and will throw an <code>ArrayIndexOutOfBoundsException</code> * whenever one of the listener methods is called.<p/> * * <p>The <code>EventHandler</code> will automatically convert primitives * to their wrapper class and vice versa. Furthermore it will call * a target method if it accepts a superclass of the type of the * first argument of the listener method.</p> * * <p>In case that the method of the target object throws an exception * it will be wrapped in a <code>RuntimeException</code> and thrown out * of the listener method.</p> * * <p>In case that the method of the target object cannot be found an * <code>ArrayIndexOutOfBoundsException</code> will be thrown when the * listener method is invoked.</p> * * <p>A call to this method is equivalent to: * <code>create(listenerInterface, target, action, null, null)</code></p> * * @param listenerInterface Listener interface to implement. * @param target Object to invoke action on. * @param action Target property or method to invoke. * @return A constructed proxy object. */ public static Object create(Class listenerInterface, Object target, String action) { return create(listenerInterface, target, action, null, null); } /** * <p>Constructs an implementation of <code>listenerInterface</code> * to dispatch events.</p> * * <p>Use this method if you want to create an implementation that retrieves * a property value from the <b>first</b> argument of the listener method * and applies it to the target's property or method. This first argument * of the listener is usually an event object but any other object is * valid, too.</p> * * <p>You can set the value of <code>eventPropertyName</code> to "prop" * to denote the retrieval of a property named "prop" from the event * object. In case that no such property exists the <code>EventHandler</code> * will try to find a method with that name.</p> * * <p>If you set <code>eventPropertyName</code> to a value like this "a.b.c" * <code>EventHandler</code> will recursively evaluate the properties "a", "b" * and "c". Again if no property can be found the <code>EventHandler</code> * tries a method name instead. This allows mixing the names, too: "a.toString" * will retrieve the property "a" from the event object and will then call * the method "toString" on it.</p> * * <p>An exception thrown in any of these methods will provoke a * <code>RuntimeException</code> to be thrown which contains an * <code>InvocationTargetException</code> containing the triggering exception.</p> * * <p>If you set <code>eventPropertyName</code> to a non-null value the * <code>action</code> parameter will be interpreted as a property name * or a method name of the target object.</p> * * <p>Any object retrieved from the event object and applied to the * target will converted from primitives to their wrapper class or * vice versa or applied to a method that accepts a superclass * of the object.</p> * * <p>Examples:</p> * <p>The following code:</p><code> * button.addActionListener( * new ActionListener() { * public void actionPerformed(ActionEvent ae) { * Object o = ae.getSource().getClass().getName(); * textField.setText((String) o); * } * }); * </code> * * <p>Can be expressed using the <code>EventHandler</code> like this:</p> * <p> * <code>button.addActionListener((ActionListener) * EventHandler.create(ActionListener.class, textField, "text", "source.class.name"); * <code> * </p> * * <p>As said above you can specify the target as a method, too:</p> * <p> * <code>button.addActionListener((ActionListener) * EventHandler.create(ActionListener.class, textField, "setText", "source.class.name"); * <code> * </p> * * <p>Furthermore you can use method names in the property:</p> * <p> * <code>button.addActionListener((ActionListener) * EventHandler.create(ActionListener.class, textField, "setText", "getSource.getClass.getName"); * <code> * </p> * * <p>Finally you can mix names:</p> * <p> * <code>button.addActionListener((ActionListener) * EventHandler.create(ActionListener.class, textField, "setText", "source.getClass.name"); * <code> * </p> * * <p>A call to this method is equivalent to: * <code>create(listenerInterface, target, action, null, null)</code> * </p> * * @param listenerInterface Listener interface to implement. * @param target Object to invoke action on. * @param action Target property or method to invoke. * @param eventPropertyName Name of property to extract from event. * @return A constructed proxy object. */ public static Object create(Class listenerInterface, Object target, String action, String eventPropertyName) { return create(listenerInterface, target, action, eventPropertyName, null); } /** * <p>Constructs an implementation of <code>listenerInterface</code> * to dispatch events.</p> * * <p>Besides the functionality described for {@link create(Class, Object, String)} * and {@link create(Class, Object, String, String)} this method allows you * to filter the listener method that should have an effect. Look at these * method's documentation for more information about the <code>EventHandler</code>'s * usage.</p> * * <p>If you want to call <code>dispose</code> on a <code>JFrame</code> instance * when the <code>WindowListener.windowClosing()</code> method was invoked use * the following code:</p> * <p> * <code> * EventHandler.create(WindowListener.class, jframeInstance, "dispose", null, "windowClosing"); * </code> * </p> * * <p>A <code>NullPointerException</code> is thrown if the <code>listenerInterface</code> * or <code>target</code> argument are <code>null</code>. * * @param listenerInterface Listener interface to implement. * @param target Object to invoke action on. * @param action Target method name to invoke. * @param eventPropertyName Name of property to extract from event. * @param listenerMethodName Listener method to implement. * @return A constructed proxy object. */ public static Object create(Class listenerInterface, Object target, String action, String eventPropertyName, String listenerMethodName) { // Create EventHandler instance EventHandler eh = new EventHandler(target, action, eventPropertyName, listenerMethodName); // Create proxy object passing in the event handler Object proxy = Proxy.newProxyInstance(listenerInterface.getClassLoader(), new Class[] {listenerInterface}, eh); return proxy; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -