public void testXPathNodeListTest() throws Exception { String xml = "<foo><person id=\"1\">Claus<country>SE</country></person>" + "<person id=\"2\">Jonathan<country>CA</country></person></foo>"; Document doc = context.getTypeConverter().convertTo(Document.class, xml); Object result = xpath("/foo/person").nodeSetResult().evaluate(createExchange(doc)); assertNotNull(result); String s = context.getTypeConverter().convertTo(String.class, result); assertEquals(ObjectHelper.between(xml, "<foo>", "</foo>"), s); }
/** * 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; }
private boolean matchMethod(Method method, String methodName) { if (methodName == null) { return true; } if (methodName.contains("(") && !methodName.endsWith(")")) { throw new IllegalArgumentException( "Name must have both starting and ending parenthesis, was: " + methodName); } // do not use qualifier for name matching String name = methodName; if (name.contains("(")) { name = ObjectHelper.before(name, "("); } // must match name if (name != null && !name.equals(method.getName())) { return false; } // is it a method with no parameters boolean noParameters = methodName.endsWith("()"); if (noParameters) { return method.getParameterTypes().length == 0; } // match qualifier types which is used to select among overloaded methods String types = ObjectHelper.between(methodName, "(", ")"); if (ObjectHelper.isNotEmpty(types)) { // we must qualify based on types to match method String[] parameters = StringQuoteHelper.splitSafeQuote(types, ','); Iterator<?> it = ObjectHelper.createIterator(parameters); for (int i = 0; i < method.getParameterTypes().length; i++) { if (it.hasNext()) { Class<?> parameterType = method.getParameterTypes()[i]; String qualifyType = (String) it.next(); if (ObjectHelper.isEmpty(qualifyType)) { continue; } // trim the type qualifyType = qualifyType.trim(); if ("*".equals(qualifyType)) { // * is a wildcard so we accept and match that parameter type continue; } if (BeanHelper.isValidParameterValue(qualifyType)) { // its a parameter value, so continue to next parameter // as we should only check for FQN/type parameters continue; } // if qualify type indeed is a class, then it must be assignable with the parameter type Boolean assignable = BeanHelper.isAssignableToExpectedType( getCamelContext().getClassResolver(), qualifyType, parameterType); // the method will return null if the qualifyType is not a class if (assignable != null && !assignable) { return false; } } else { // there method has more parameters than was specified in the method name qualifiers return false; } } // if the method has no more types then we can only regard it as matched // if there are no more qualifiers if (it.hasNext()) { return false; } } // the method matched return true; }