private Expression createParameterUnmarshalExpressionForAnnotation( Class<?> clazz, Method method, Class<?> parameterType, Annotation annotation) { if (annotation instanceof AttachmentObjects) { return ExpressionBuilder.attachmentObjectsExpression(); } else if (annotation instanceof Attachments) { return ExpressionBuilder.attachmentsExpression(); } else if (annotation instanceof Property) { Property propertyAnnotation = (Property) annotation; return ExpressionBuilder.exchangePropertyExpression(propertyAnnotation.value()); } else if (annotation instanceof ExchangeProperty) { ExchangeProperty propertyAnnotation = (ExchangeProperty) annotation; return ExpressionBuilder.exchangePropertyExpression(propertyAnnotation.value()); } else if (annotation instanceof Properties) { return ExpressionBuilder.propertiesExpression(); } else if (annotation instanceof Header) { Header headerAnnotation = (Header) annotation; return ExpressionBuilder.headerExpression(headerAnnotation.value()); } else if (annotation instanceof Headers) { return ExpressionBuilder.headersExpression(); } else if (annotation instanceof OutHeaders) { return ExpressionBuilder.outHeadersExpression(); } else if (annotation instanceof ExchangeException) { return ExpressionBuilder.exchangeExceptionExpression( CastUtils.cast(parameterType, Exception.class)); } else { LanguageAnnotation languageAnnotation = annotation.annotationType().getAnnotation(LanguageAnnotation.class); if (languageAnnotation != null) { Class<?> type = languageAnnotation.factory(); Object object = camelContext.getInjector().newInstance(type); if (object instanceof AnnotationExpressionFactory) { AnnotationExpressionFactory expressionFactory = (AnnotationExpressionFactory) object; return expressionFactory.createExpression( camelContext, annotation, languageAnnotation, parameterType); } else { LOG.warn( "Ignoring bad annotation: " + languageAnnotation + "on method: " + method + " which declares a factory: " + type.getName() + " which does not implement " + AnnotationExpressionFactory.class.getName()); } } } return null; }
public static Expression header(String headerName) { return ExpressionBuilder.headerExpression(headerName); }
public SetHeaderDefinition(String headerName, String value) { super(ExpressionBuilder.constantExpression(value)); setHeaderName(headerName); }
private MethodInfo chooseBestPossibleMethodInfo( Exchange exchange, Collection<MethodInfo> operationList, Object body, List<MethodInfo> possibles, List<MethodInfo> possiblesWithException, List<MethodInfo> possibleWithCustomAnnotation) throws AmbiguousMethodCallException { Exception exception = ExpressionBuilder.exchangeExceptionExpression().evaluate(exchange, Exception.class); if (exception != null && possiblesWithException.size() == 1) { LOG.trace( "Exchange has exception set so we prefer method that also has exception as parameter"); // prefer the method that accepts exception in case we have an exception also return possiblesWithException.get(0); } else if (possibles.size() == 1) { return possibles.get(0); } else if (possibles.isEmpty()) { LOG.trace("No possible methods so now trying to convert body to parameter types"); // let's try converting Object newBody = null; MethodInfo matched = null; int matchCounter = 0; for (MethodInfo methodInfo : operationList) { if (methodInfo.getBodyParameterType() != null) { if (methodInfo.getBodyParameterType().isInstance(body)) { return methodInfo; } // we should only try to convert, as we are looking for best match Object value = exchange .getContext() .getTypeConverter() .tryConvertTo(methodInfo.getBodyParameterType(), exchange, body); if (value != null) { if (LOG.isTraceEnabled()) { LOG.trace( "Converted body from: {} to: {}", body.getClass().getCanonicalName(), methodInfo.getBodyParameterType().getCanonicalName()); } matchCounter++; newBody = value; matched = methodInfo; } } } if (matchCounter > 1) { throw new AmbiguousMethodCallException(exchange, Arrays.asList(matched, matched)); } if (matched != null) { LOG.trace("Setting converted body: {}", body); Message in = exchange.getIn(); in.setBody(newBody); return matched; } } else { // if we only have a single method with custom annotations, let's use that one if (possibleWithCustomAnnotation.size() == 1) { MethodInfo answer = possibleWithCustomAnnotation.get(0); LOG.trace("There are only one method with annotations so we choose it: {}", answer); return answer; } // try to choose among multiple methods with annotations MethodInfo chosen = chooseMethodWithCustomAnnotations(exchange, possibles); if (chosen != null) { return chosen; } // just make sure the methods aren't all actually the same chosen = getSingleCovariantMethod(possibles); if (chosen != null) { return chosen; } throw new AmbiguousMethodCallException(exchange, possibles); } // cannot find a good method to use return null; }
protected MethodInfo createMethodInfo(Class<?> clazz, Method method) { Class<?>[] parameterTypes = method.getParameterTypes(); List<Annotation>[] parametersAnnotations = collectParameterAnnotations(clazz, method); List<ParameterInfo> parameters = new ArrayList<ParameterInfo>(); List<ParameterInfo> bodyParameters = new ArrayList<ParameterInfo>(); boolean hasCustomAnnotation = false; boolean hasHandlerAnnotation = ObjectHelper.hasAnnotation(method.getAnnotations(), Handler.class); int size = parameterTypes.length; if (LOG.isTraceEnabled()) { LOG.trace( "Creating MethodInfo for class: {} method: {} having {} parameters", new Object[] {clazz, method, size}); } for (int i = 0; i < size; i++) { Class<?> parameterType = parameterTypes[i]; Annotation[] parameterAnnotations = parametersAnnotations[i].toArray(new Annotation[parametersAnnotations[i].size()]); Expression expression = createParameterUnmarshalExpression(clazz, method, parameterType, parameterAnnotations); hasCustomAnnotation |= expression != null; ParameterInfo parameterInfo = new ParameterInfo(i, parameterType, parameterAnnotations, expression); LOG.trace("Parameter #{}: {}", i, parameterInfo); parameters.add(parameterInfo); if (expression == null) { boolean bodyAnnotation = ObjectHelper.hasAnnotation(parameterAnnotations, Body.class); LOG.trace("Parameter #{} has @Body annotation", i); hasCustomAnnotation |= bodyAnnotation; if (bodyParameters.isEmpty()) { // okay we have not yet set the body parameter and we have found // the candidate now to use as body parameter if (Exchange.class.isAssignableFrom(parameterType)) { // use exchange expression = ExpressionBuilder.exchangeExpression(); } else { // assume it's the body and it must be mandatory convertible to the parameter type // but we allow null bodies in case the message really contains a null body expression = ExpressionBuilder.mandatoryBodyExpression(parameterType, true); } LOG.trace("Parameter #{} is the body parameter using expression {}", i, expression); parameterInfo.setExpression(expression); bodyParameters.add(parameterInfo); } else { // will ignore the expression for parameter evaluation } } LOG.trace("Parameter #{} has parameter info: ", i, parameterInfo); } // now let's add the method to the repository return new MethodInfo( camelContext, clazz, method, parameters, bodyParameters, hasCustomAnnotation, hasHandlerAnnotation); }
private MethodInvocation createInvocation(Object pojo, Exchange exchange, Method explicitMethod) throws AmbiguousMethodCallException, MethodNotFoundException { MethodInfo methodInfo = null; // find the explicit method to invoke if (explicitMethod != null) { for (List<MethodInfo> infos : operations.values()) { for (MethodInfo info : infos) { if (explicitMethod.equals(info.getMethod())) { return info.createMethodInvocation(pojo, exchange); } } } throw new MethodNotFoundException(exchange, pojo, explicitMethod.getName()); } String methodName = exchange.getIn().getHeader(Exchange.BEAN_METHOD_NAME, String.class); if (methodName != null) { // do not use qualifier for name String name = methodName; if (methodName.contains("(")) { name = ObjectHelper.before(methodName, "("); // the must be a ending parenthesis if (!methodName.endsWith(")")) { throw new IllegalArgumentException( "Method should end with parenthesis, was " + methodName); } } boolean emptyParameters = methodName.endsWith("()"); // special for getClass, as we want the user to be able to invoke this method // for example to log the class type or the likes if ("class".equals(name) || "getClass".equals(name)) { try { Method method = pojo.getClass().getMethod("getClass"); methodInfo = new MethodInfo( exchange.getContext(), pojo.getClass(), method, Collections.<ParameterInfo>emptyList(), Collections.<ParameterInfo>emptyList(), false, false); } catch (NoSuchMethodException e) { throw new MethodNotFoundException(exchange, pojo, "getClass"); } // special for length on an array type } else if ("length".equals(name) && pojo.getClass().isArray()) { try { // need to use arrayLength method from ObjectHelper as Camel's bean OGNL support is method // invocation based // and not for accessing fields. And hence we need to create a MethodInfo instance with a // method to call // and therefore use arrayLength from ObjectHelper to return the array length field. Method method = ObjectHelper.class.getMethod("arrayLength", Object[].class); ParameterInfo pi = new ParameterInfo( 0, Object[].class, null, ExpressionBuilder.mandatoryBodyExpression(Object[].class, true)); List<ParameterInfo> lpi = new ArrayList<ParameterInfo>(1); lpi.add(pi); methodInfo = new MethodInfo( exchange.getContext(), pojo.getClass(), method, lpi, lpi, false, false); // Need to update the message body to be pojo for the invocation exchange.getIn().setBody(pojo); } catch (NoSuchMethodException e) { throw new MethodNotFoundException(exchange, pojo, "getClass"); } } else { List<MethodInfo> methods = getOperations(name); if (methods != null && methods.size() == 1) { // only one method then choose it methodInfo = methods.get(0); // validate that if we want an explicit no-arg method, then that's what we get if (emptyParameters && methodInfo.hasParameters()) { throw new MethodNotFoundException(exchange, pojo, methodName, "(with no parameters)"); } } else if (methods != null) { // there are more methods with that name so we cannot decide which to use // but first let's try to choose a method and see if that complies with the name // must use the method name which may have qualifiers methodInfo = chooseMethod(pojo, exchange, methodName); // validate that if we want an explicit no-arg method, then that's what we get if (emptyParameters) { if (methodInfo == null || methodInfo.hasParameters()) { // we could not find a no-arg method with that name throw new MethodNotFoundException(exchange, pojo, methodName, "(with no parameters)"); } } if (methodInfo == null || (name != null && !name.equals(methodInfo.getMethod().getName()))) { throw new AmbiguousMethodCallException(exchange, methods); } } else { // a specific method was given to invoke but not found throw new MethodNotFoundException(exchange, pojo, methodName); } } } if (methodInfo == null) { // no name or type methodInfo = chooseMethod(pojo, exchange, null); } if (methodInfo == null) { methodInfo = defaultMethod; } if (methodInfo != null) { LOG.trace("Chosen method to invoke: {} on bean: {}", methodInfo, pojo); return methodInfo.createMethodInvocation(pojo, exchange); } LOG.debug("Cannot find suitable method to invoke on bean: {}", pojo); return null; }