package ns.foundation; import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import ns.foundation._private._NSMethod; public class NSSelector<T> implements Serializable { protected static final Class<?>[] _NoClassArray = new Class[0]; protected static final Object[] _NoObjectArray = new Object[0]; protected String _name; protected Class<?>[] _types; private transient Class<?> _cachedClass; private transient _NSMethod _cachedMethod; private transient NSMutableDictionary<String, _NSMethod> _classToMethodMapTable = new NSMutableDictionary<String, _NSMethod>(8); public static <T> T _safeInvokeSelector(NSSelector<T> selector, Object receiver, Object... parameters) { try { return selector.invoke(receiver, parameters != null ? parameters : _NoObjectArray); } catch (InvocationTargetException e) { throw NSForwardException._runtimeExceptionForThrowable(e); } catch (IllegalAccessException e) { throw new IllegalArgumentException("Either the receiver or the method is not public: " + e.getMessage()); } catch (NoSuchMethodException e) { throw new IllegalArgumentException(e.getMessage()); } } protected NSSelector() { } public NSSelector(String name) { this(name, (Class[]) null); } public String name() { return _name; } public NSSelector(String name, Class<?>... parameterTypes) { if (name == null) { throw new IllegalArgumentException("Selector name cannot be null"); } _name = name; if (parameterTypes != null) { _types = new Class[parameterTypes.length]; System.arraycopy(parameterTypes, 0, _types, 0, parameterTypes.length); } else { _types = _NoClassArray; } } @SuppressWarnings("unchecked") public T invoke(Object target, Object... parameters) throws IllegalArgumentException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { _NSMethod method = methodOnObject(target); return (T) method.invoke(target, parameters != null ? parameters : new Object[0]); } public T invoke(Object target) throws IllegalArgumentException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { return invoke(target, _NoObjectArray); } public static Object invoke(String name, Class<?> parameterTypes[], Object target, Object... parameters) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException { NSSelector<?> selector = new NSSelector<Object>(name, parameterTypes); return selector.invoke(target, parameters); } public static Object invoke(String name, Class<?> parameterType, Object target, Object argument) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException { if (parameterType == null) { throw new IllegalArgumentException("Parameter type cannot be null"); } NSSelector<?> selector = new NSSelector<Object>(name, parameterType); return selector.invoke(target, argument); } public static Object invoke(String name, Class<?> parameterType1, Class<?> parameterType2, Object target, Object argument1, Object argument2) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException { if (parameterType1 == null || parameterType2 == null) { throw new IllegalArgumentException("Neither parameter type can be null"); } NSSelector<?> selector = new NSSelector<Object>(name, parameterType1, parameterType2); return selector.invoke(target, argument1, argument2); } public Class<?>[] parameterTypes() { if (_types.length == 0) { return _types; } Class<?>[] types = new Class[_types.length]; System.arraycopy(_types, 0, types, 0, _types.length); return types; } private synchronized _NSMethod _methodOnObject(Object targetObject) { Class<?> targetClass = targetObject.getClass(); if (targetClass == _cachedClass) { return _cachedMethod; } String className = targetClass.getName(); Object value = _classToMethodMapTable.objectForKey(className); if (value == null) { try { value = _NSReflectionUtilities.methodOnObject(targetObject, _name, _types); } catch (NoSuchMethodException exception) { exception.printStackTrace(); } if (value == null) value = NSKeyValueCoding.NullValue; _classToMethodMapTable.takeValueForKey(value, className); } _NSMethod method = null; if (value != NSKeyValueCoding.NullValue) { method = (_NSMethod) value; } _cachedClass = targetClass; _cachedMethod = method; return method; } private _NSMethod methodOnObject(Object targetObject) throws NoSuchMethodException { if (targetObject == null) throw new IllegalArgumentException("Target object cannot be null"); _NSMethod method = _methodOnObject(targetObject); Class<?> targetClass = targetObject.getClass(); if (method == null) throw new NoSuchMethodException("Class " + targetClass.getName() + " does not implement method " + _NSReflectionUtilities._methodSignature(_name, _types)); return method; } public static boolean respondsToSelector(Object object, NSSelector<?> selector) { return selector._methodOnObject(object) != null; } }