/** * Find method with given name and unknown parameter types. Traverses all declared methods from given class and * returns the one with specified name; if none found throws {@link NoSuchMethodException}. If there are overloaded * methods returns one of them but there is no guarantee which one. Returned method has accessibility enabled. * <p> * Implementation note: this method is inherently costly since at worst case needs to traverse all class methods. It * is recommended to be used with external method cache. * * @param clazz Java class to return method from, * @param methodName method name. * @return class reflective method. * @throws NoSuchMethodException if there is no method with requested name. */ public static Method findMethod(Class<?> clazz, String methodName) throws NoSuchMethodException { for(Method method : clazz.getDeclaredMethods()) { if(method.getName().equals(methodName)) { method.setAccessible(true); return method; } } Class<?> superclass = clazz.getSuperclass(); if(superclass != null) { if(superclass.getPackage().equals(clazz.getPackage())) { return findMethod(superclass, methodName); } } throw new NoSuchMethodException(String.format("%s#%s", clazz.getName(), methodName)); }
/** * Invoke setter method on given object instance. Setter name has format as accepted by * {@link Strings#getMethodAccessor(String, String)} and value string is converted to method parameter type using * {@link Converter} facility. For this reason set parameter type should have a converter registered. * <p> * This method has no means to determine method using {@link Class#getMethod(String, Class...)} because parameter * value is always string and setter parameter type is unknown. For this reason this method uses * {@link #findMethod(Class, String)}. Note that find method searches for named method on object super hierarchy too. * * @param object object instance, * @param name setter name, method name only without <code>set</code> prefix, dashed case accepted, * @param value value to set, string value that is converted to setter method parameter type. * @throws NoSuchMethodException if setter not found. * @throws Exception if invocation fail for whatever reason including method logic. */ public static void invokeSetter(Object object, String name, String value) throws NoSuchMethodException, Exception { String setterName = Strings.getMethodAccessor("set", name); Class<?> clazz = object.getClass(); Method method = findMethod(clazz, setterName); Class<?>[] parameterTypes = method.getParameterTypes(); if(parameterTypes.length != 1) { throw new NoSuchMethodException(String.format("%s#%s", clazz.getName(), setterName)); } invoke(object, method, ConverterRegistry.getConverter().asObject((String)value, parameterTypes[0])); }
/** * Variant for {@link #invokeSetter(Object, String, String)} but no exception if setter not found. * * @param object object instance, * @param name setter name, * @param value value to set. * @throws Exception if invocation fail for whatever reason including method logic. */ public static void invokeOptionalSetter(Object object, String name, String value) throws Exception { String setterName = Strings.getMethodAccessor("set", name); Class<?> clazz = object.getClass(); Method method = null; try { method = findMethod(clazz, setterName); } catch(NoSuchMethodException e) { log.debug("Setter |%s| not found in class |%s| or its super hierarchy.", setterName, clazz); return; } Class<?>[] parameterTypes = method.getParameterTypes(); if(parameterTypes.length != 1) { log.debug("Setter |%s#%s(%s)| with invalid parameters number.", method.getDeclaringClass(), method.getName(), Strings.join(parameterTypes, ',')); return; } invoke(object, method, ConverterRegistry.getConverter().asObject((String)value, parameterTypes[0])); }