Exemplo n.º 1
0
  /**
   * Choose one of the available methods to invoke if we can match the message body to the body
   * parameter
   *
   * @param pojo the bean to invoke a method on
   * @param exchange the message exchange
   * @param name an optional name of the method that must match, use <tt>null</tt> to indicate all
   *     methods
   * @return the method to invoke or null if no definitive method could be matched
   * @throws AmbiguousMethodCallException is thrown if cannot choose method due to ambiguity
   */
  protected MethodInfo chooseMethod(Object pojo, Exchange exchange, String name)
      throws AmbiguousMethodCallException {
    // @Handler should be select first
    // then any single method that has a custom @annotation
    // or any single method that has a match parameter type that matches the Exchange payload
    // and last then try to select the best among the rest

    // must use defensive copy, to avoid altering the shared lists
    // and we want to remove unwanted operations from these local lists
    final List<MethodInfo> localOperationsWithBody = new ArrayList<MethodInfo>(operationsWithBody);
    final List<MethodInfo> localOperationsWithNoBody =
        new ArrayList<MethodInfo>(operationsWithNoBody);
    final List<MethodInfo> localOperationsWithCustomAnnotation =
        new ArrayList<MethodInfo>(operationsWithCustomAnnotation);
    final List<MethodInfo> localOperationsWithHandlerAnnotation =
        new ArrayList<MethodInfo>(operationsWithHandlerAnnotation);

    // remove all abstract methods
    removeAllAbstractMethods(localOperationsWithBody);
    removeAllAbstractMethods(localOperationsWithNoBody);
    removeAllAbstractMethods(localOperationsWithCustomAnnotation);
    removeAllAbstractMethods(localOperationsWithHandlerAnnotation);

    if (name != null) {
      // filter all lists to only include methods with this name
      removeNonMatchingMethods(localOperationsWithHandlerAnnotation, name);
      removeNonMatchingMethods(localOperationsWithCustomAnnotation, name);
      removeNonMatchingMethods(localOperationsWithBody, name);
      removeNonMatchingMethods(localOperationsWithNoBody, name);
    } else {
      // remove all getter/setter as we do not want to consider these methods
      removeAllSetterOrGetterMethods(localOperationsWithHandlerAnnotation);
      removeAllSetterOrGetterMethods(localOperationsWithCustomAnnotation);
      removeAllSetterOrGetterMethods(localOperationsWithBody);
      removeAllSetterOrGetterMethods(localOperationsWithNoBody);
    }

    if (localOperationsWithHandlerAnnotation.size() > 1) {
      // if we have more than 1 @Handler then its ambiguous
      throw new AmbiguousMethodCallException(exchange, localOperationsWithHandlerAnnotation);
    }

    if (localOperationsWithHandlerAnnotation.size() == 1) {
      // methods with handler should be preferred
      return localOperationsWithHandlerAnnotation.get(0);
    } else if (localOperationsWithCustomAnnotation.size() == 1) {
      // if there is one method with an annotation then use that one
      return localOperationsWithCustomAnnotation.get(0);
    }

    // named method and with no parameters
    boolean noParameters = name != null && name.endsWith("()");
    if (noParameters && localOperationsWithNoBody.size() == 1) {
      // if there was a method name configured and it has no parameters, then use the method with no
      // body (eg no parameters)
      return localOperationsWithNoBody.get(0);
    } else if (!noParameters
        && localOperationsWithBody.size() == 1
        && localOperationsWithCustomAnnotation.isEmpty()) {
      // if there is one method with body then use that one
      return localOperationsWithBody.get(0);
    }

    Collection<MethodInfo> possibleOperations = new ArrayList<MethodInfo>();
    possibleOperations.addAll(localOperationsWithBody);
    possibleOperations.addAll(localOperationsWithCustomAnnotation);

    if (!possibleOperations.isEmpty()) {

      MethodInfo answer = null;

      if (name != null) {
        // do we have hardcoded parameters values provided from the method name then use that for
        // matching
        String parameters = ObjectHelper.between(name, "(", ")");
        if (parameters != null) {
          // special as we have hardcoded parameters, so we need to choose method that matches those
          // parameters the best
          LOG.trace("Choosing best matching method matching parameters: {}", parameters);
          answer = chooseMethodWithMatchingParameters(exchange, parameters, possibleOperations);
        }
      }
      if (answer == null) {
        // multiple possible operations so find the best suited if possible
        answer =
            chooseMethodWithMatchingBody(
                exchange, possibleOperations, localOperationsWithCustomAnnotation);
      }
      if (answer == null && possibleOperations.size() > 1) {
        answer = getSingleCovariantMethod(possibleOperations);
      }

      if (answer == null) {
        throw new AmbiguousMethodCallException(exchange, possibleOperations);
      } else {
        return answer;
      }
    }

    // not possible to determine
    return null;
  }