/** * 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); // if the class is not public then fallback and use interface methods if possible // this allow Camel to invoke private beans which implements interfaces List<Method> methods = Arrays.asList(clazz.getDeclaredMethods()); if (!Modifier.isPublic(clazz.getModifiers())) { LOG.trace("Preferring interface methods as class: {} is not public accessible", clazz); List<Method> interfaceMethods = getInterfaceMethods(clazz); // still keep non-accessible class methods to provide more specific Exception if method is // non-accessible interfaceMethods.addAll(methods); methods = interfaceMethods; } 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); } }
/** * 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); } }
public BeanInfo( CamelContext camelContext, Class<?> type, Method explicitMethod, ParameterMappingStrategy strategy) { this.camelContext = camelContext; this.type = type; this.strategy = strategy; this.component = camelContext.getComponent("bean", BeanComponent.class); final BeanInfoCacheKey key = new BeanInfoCacheKey(type, explicitMethod); // lookup if we have a bean info cache BeanInfo beanInfo = component.getBeanInfoFromCache(key); if (beanInfo != null) { // copy the values from the cache we need defaultMethod = beanInfo.defaultMethod; operations = beanInfo.operations; operationsWithBody = beanInfo.operationsWithBody; operationsWithNoBody = beanInfo.operationsWithNoBody; operationsWithCustomAnnotation = beanInfo.operationsWithCustomAnnotation; operationsWithHandlerAnnotation = beanInfo.operationsWithHandlerAnnotation; methodMap = beanInfo.methodMap; publicConstructors = beanInfo.publicConstructors; return; } if (explicitMethod != null) { // must be a valid method if (!isValidMethod(type, explicitMethod)) { throw new IllegalArgumentException( "The method " + explicitMethod + " is not valid (for example the method must be public)"); } introspect(getType(), explicitMethod); } else { introspect(getType()); } // if there are only 1 method with 1 operation then select it as a default/fallback method MethodInfo method = null; if (operations.size() == 1) { List<MethodInfo> methods = operations.values().iterator().next(); if (methods.size() == 1) { method = methods.get(0); } } defaultMethod = method; // mark the operations lists as unmodifiable, as they should not change during runtime // to keep this code thread safe operations = Collections.unmodifiableMap(operations); operationsWithBody = Collections.unmodifiableList(operationsWithBody); operationsWithNoBody = Collections.unmodifiableList(operationsWithNoBody); operationsWithCustomAnnotation = Collections.unmodifiableList(operationsWithCustomAnnotation); operationsWithHandlerAnnotation = Collections.unmodifiableList(operationsWithHandlerAnnotation); methodMap = Collections.unmodifiableMap(methodMap); // add new bean info to cache component.addBeanInfoToCache(key, this); }