/** * Does the given method info override an existing method registered before (from a subclass) * * @param methodInfo the method to test * @return the already registered method to use, null if not overriding any */ private MethodInfo overridesExistingMethod(MethodInfo methodInfo) { for (MethodInfo info : methodMap.values()) { Method source = info.getMethod(); Method target = methodInfo.getMethod(); boolean override = ObjectHelper.isOverridingMethod(source, target); if (override) { // same name, same parameters, then its overrides an existing class return info; } } return null; }
/** * Validates whether the given method is a valid candidate for Camel Bean Binding. * * @param clazz the class * @param method the method * @return true if valid, false to skip the method */ protected boolean isValidMethod(Class<?> clazz, Method method) { // must not be in the excluded list for (Method excluded : EXCLUDED_METHODS) { if (ObjectHelper.isOverridingMethod(excluded, method)) { // the method is overriding an excluded method so its not valid return false; } } // must be a public method if (!Modifier.isPublic(method.getModifiers())) { return false; } // return type must not be an Exchange and it should not be a bridge method if ((method.getReturnType() != null && Exchange.class.isAssignableFrom(method.getReturnType())) || method.isBridge()) { return false; } return true; }
/** * Returns the {@link MethodInfo} for the given method if it exists or null if there is no * metadata available for the given method */ public MethodInfo getMethodInfo(Method method) { MethodInfo answer = methodMap.get(method); if (answer == null) { // maybe the method overrides, and the method map keeps info of the source override we can use for (Method source : methodMap.keySet()) { if (ObjectHelper.isOverridingMethod(source, method, false)) { answer = methodMap.get(source); break; } } } if (answer == null) { // maybe the method is defined on a base class? if (type != Object.class) { Class<?> superclass = type.getSuperclass(); if (superclass != null && superclass != Object.class) { BeanInfo superBeanInfo = new BeanInfo(camelContext, superclass, strategy); return superBeanInfo.getMethodInfo(method); } } } return answer; }
/** * Introspects the given class * * @param clazz the class */ private void introspect(Class<?> clazz) { // get the target clazz as it could potentially have been enhanced by CGLIB etc. clazz = getTargetClass(clazz); ObjectHelper.notNull(clazz, "clazz", this); LOG.trace("Introspecting class: {}", clazz); // does the class have any public constructors? publicConstructors = clazz.getConstructors().length > 0; // favor declared methods, and then filter out duplicate interface methods List<Method> methods; if (Modifier.isPublic(clazz.getModifiers())) { LOG.trace("Preferring class methods as class: {} is public accessible", clazz); methods = new ArrayList<Method>(Arrays.asList(clazz.getDeclaredMethods())); } else { LOG.trace("Preferring interface methods as class: {} is not public accessible", clazz); methods = getInterfaceMethods(clazz); // and then we must add its declared methods as well List<Method> extraMethods = Arrays.asList(clazz.getDeclaredMethods()); methods.addAll(extraMethods); } Set<Method> overrides = new HashSet<Method>(); Set<Method> bridges = new HashSet<Method>(); // do not remove duplicates form class from the Java itself as they have some "duplicates" we // need boolean javaClass = clazz.getName().startsWith("java.") || clazz.getName().startsWith("javax."); if (!javaClass) { // it may have duplicate methods already, even from declared or from interfaces + declared for (Method source : methods) { for (Method target : methods) { // skip ourselves if (ObjectHelper.isOverridingMethod(source, target, true)) { continue; } // skip duplicates which may be assign compatible (favor keep first added method when // duplicate) if (ObjectHelper.isOverridingMethod(source, target, false)) { overrides.add(target); } } } methods.removeAll(overrides); overrides.clear(); } // if we are a public class, then add non duplicate interface classes also if (Modifier.isPublic(clazz.getModifiers())) { // add additional interface methods List<Method> extraMethods = getInterfaceMethods(clazz); for (Method target : extraMethods) { for (Method source : methods) { if (ObjectHelper.isOverridingMethod(source, target, false)) { overrides.add(target); } } } // remove all the overrides methods extraMethods.removeAll(overrides); methods.addAll(extraMethods); } // now introspect the methods and filter non valid methods for (Method method : methods) { boolean valid = isValidMethod(clazz, method); LOG.trace("Method: {} is valid: {}", method, valid); if (valid) { introspect(clazz, method); } } Class<?> superclass = clazz.getSuperclass(); if (superclass != null && !superclass.equals(Object.class)) { introspect(superclass); } }