001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.camel.component.bean;
018
019 import java.lang.annotation.Annotation;
020 import java.lang.reflect.Method;
021 import java.lang.reflect.Modifier;
022 import java.lang.reflect.Proxy;
023 import java.util.ArrayList;
024 import java.util.Arrays;
025 import java.util.Collection;
026 import java.util.Iterator;
027 import java.util.List;
028 import java.util.Map;
029 import java.util.concurrent.ConcurrentHashMap;
030
031 import org.apache.camel.Body;
032 import org.apache.camel.CamelContext;
033 import org.apache.camel.Exchange;
034 import org.apache.camel.ExchangeException;
035 import org.apache.camel.Expression;
036 import org.apache.camel.Handler;
037 import org.apache.camel.Header;
038 import org.apache.camel.Headers;
039 import org.apache.camel.Message;
040 import org.apache.camel.OutHeaders;
041 import org.apache.camel.Properties;
042 import org.apache.camel.Property;
043 import org.apache.camel.builder.ExpressionBuilder;
044 import org.apache.camel.language.LanguageAnnotation;
045 import org.apache.camel.spi.Registry;
046 import org.apache.camel.util.CastUtils;
047 import org.apache.camel.util.IntrospectionSupport;
048 import org.apache.camel.util.ObjectHelper;
049 import org.apache.commons.logging.Log;
050 import org.apache.commons.logging.LogFactory;
051
052 import static org.apache.camel.util.ExchangeHelper.convertToType;
053
054 /**
055 * Represents the metadata about a bean type created via a combination of
056 * introspection and annotations together with some useful sensible defaults
057 *
058 * @version $Revision: 904498 $
059 */
060 public class BeanInfo {
061 private static final transient Log LOG = LogFactory.getLog(BeanInfo.class);
062 private static final String CGLIB_CLASS_SEPARATOR = "$$";
063 private static final List<Method> EXCLUDED_METHODS = new ArrayList<Method>();
064 private final CamelContext camelContext;
065 private final Class<?> type;
066 private final ParameterMappingStrategy strategy;
067 private final Map<String, List<MethodInfo>> operations = new ConcurrentHashMap<String, List<MethodInfo>>();
068 private final List<MethodInfo> operationsWithBody = new ArrayList<MethodInfo>();
069 private final List<MethodInfo> operationsWithCustomAnnotation = new ArrayList<MethodInfo>();
070 private final List<MethodInfo> operationsWithHandlerAnnotation = new ArrayList<MethodInfo>();
071 private final Map<Method, MethodInfo> methodMap = new ConcurrentHashMap<Method, MethodInfo>();
072 private MethodInfo defaultMethod;
073 private BeanInfo superBeanInfo;
074
075 public BeanInfo(CamelContext camelContext, Class<?> type) {
076 this(camelContext, type, createParameterMappingStrategy(camelContext));
077 }
078
079 public BeanInfo(CamelContext camelContext, Class<?> type, ParameterMappingStrategy strategy) {
080 this.camelContext = camelContext;
081 this.type = type;
082 this.strategy = strategy;
083
084 // configure the default excludes methods
085 synchronized (EXCLUDED_METHODS) {
086 if (EXCLUDED_METHODS.size() == 0) {
087 // exclude all java.lang.Object methods as we dont want to invoke them
088 EXCLUDED_METHODS.addAll(Arrays.asList(Object.class.getMethods()));
089 // exclude all java.lang.reflect.Proxy methods as we dont want to invoke them
090 EXCLUDED_METHODS.addAll(Arrays.asList(Proxy.class.getMethods()));
091 }
092 }
093
094 introspect(getType());
095 // if there are only 1 method with 1 operation then select it as a default/fallback method
096 if (operations.size() == 1) {
097 List<MethodInfo> methods = operations.values().iterator().next();
098 if (methods.size() == 1) {
099 defaultMethod = methods.get(0);
100 }
101 }
102 }
103
104 public Class<?> getType() {
105 return type;
106 }
107
108 public CamelContext getCamelContext() {
109 return camelContext;
110 }
111
112 public static ParameterMappingStrategy createParameterMappingStrategy(CamelContext camelContext) {
113 // lookup in registry first if there is a user define strategy
114 Registry registry = camelContext.getRegistry();
115 ParameterMappingStrategy answer = registry.lookup(BeanConstants.BEAN_PARAMETER_MAPPING_STRATEGY, ParameterMappingStrategy.class);
116 if (answer == null) {
117 // no then use the default one
118 answer = new DefaultParameterMappingStrategy();
119 }
120
121 return answer;
122 }
123
124 public MethodInvocation createInvocation(Method method, Object pojo, Exchange exchange) {
125 MethodInfo methodInfo = introspect(type, method);
126 if (methodInfo != null) {
127 return methodInfo.createMethodInvocation(pojo, exchange);
128 }
129 return null;
130 }
131
132 public MethodInvocation createInvocation(Object pojo, Exchange exchange) throws AmbiguousMethodCallException, MethodNotFoundException {
133 MethodInfo methodInfo = null;
134
135 String name = exchange.getIn().getHeader(Exchange.BEAN_METHOD_NAME, String.class);
136 if (name != null) {
137 if (operations.containsKey(name)) {
138 List<MethodInfo> methods = operations.get(name);
139 if (methods != null && methods.size() == 1) {
140 // only one method then choose it
141 methodInfo = methods.get(0);
142 } else {
143 // there are more methods with that name so we cannot decide which to use
144
145 // but first lets try to choose a method and see if that comply with the name
146 methodInfo = chooseMethod(pojo, exchange, name);
147 if (methodInfo == null || !name.equals(methodInfo.getMethod().getName())) {
148 throw new AmbiguousMethodCallException(exchange, methods);
149 }
150 }
151 } else {
152 // a specific method was given to invoke but not found
153 throw new MethodNotFoundException(exchange, pojo, name);
154 }
155 }
156 if (methodInfo == null) {
157 methodInfo = chooseMethod(pojo, exchange, name);
158 }
159 if (methodInfo == null) {
160 methodInfo = defaultMethod;
161 }
162 if (methodInfo != null) {
163 if (LOG.isTraceEnabled()) {
164 LOG.trace("Chosen method to invoke: " + methodInfo + " on bean: " + pojo);
165 }
166 return methodInfo.createMethodInvocation(pojo, exchange);
167 }
168
169 if (LOG.isDebugEnabled()) {
170 LOG.debug("Cannot find suitable method to invoke on bean: " + pojo);
171 }
172 return null;
173 }
174
175 /**
176 * Introspects the given class
177 *
178 * @param clazz the class
179 */
180 protected void introspect(Class<?> clazz) {
181 // get the target clazz as it could potentially have been enhanced by CGLIB etc.
182 clazz = getTargetClass(clazz);
183
184 if (LOG.isTraceEnabled()) {
185 LOG.trace("Introspecting class: " + clazz);
186 }
187
188 Method[] methods = clazz.getDeclaredMethods();
189 for (Method method : methods) {
190 boolean valid = isValidMethod(clazz, method);
191 if (LOG.isTraceEnabled()) {
192 LOG.trace("Method: " + method + " is valid: " + valid);
193 }
194 if (valid) {
195 introspect(clazz, method);
196 }
197 }
198
199 Class<?> superclass = clazz.getSuperclass();
200 if (superclass != null && !superclass.equals(Object.class)) {
201 introspect(superclass);
202 }
203 }
204
205 /**
206 * Introspects the given method
207 *
208 * @param clazz the class
209 * @param method the method
210 * @return the method info, is newer <tt>null</tt>
211 */
212 protected MethodInfo introspect(Class<?> clazz, Method method) {
213 if (LOG.isTraceEnabled()) {
214 LOG.trace("Introspecting class: " + clazz + ", method: " + method);
215 }
216 String opName = method.getName();
217
218 MethodInfo methodInfo = createMethodInfo(clazz, method);
219
220 // methods already registered should be preferred to use instead of super classes of existing methods
221 // we want to us the method from the sub class over super classes, so if we have already registered
222 // the method then use it (we are traversing upwards: sub (child) -> super (farther) )
223 MethodInfo existingMethodInfo = overridesExistingMethod(methodInfo);
224 if (existingMethodInfo != null) {
225 if (LOG.isTraceEnabled()) {
226 LOG.trace("This method is already overridden in a subclass, so the method from the sub class is preferred: " + existingMethodInfo);
227 }
228
229 return existingMethodInfo;
230 }
231
232 if (LOG.isTraceEnabled()) {
233 LOG.trace("Adding operation: " + opName + " for method: " + methodInfo);
234 }
235
236 if (operations.containsKey(opName)) {
237 // we have an overloaded method so add the method info to the same key
238 List<MethodInfo> existing = operations.get(opName);
239 existing.add(methodInfo);
240 } else {
241 // its a new method we have not seen before so wrap it in a list and add it
242 List<MethodInfo> methods = new ArrayList<MethodInfo>();
243 methods.add(methodInfo);
244 operations.put(opName, methods);
245 }
246
247 if (methodInfo.hasCustomAnnotation()) {
248 operationsWithCustomAnnotation.add(methodInfo);
249 } else if (methodInfo.hasBodyParameter()) {
250 operationsWithBody.add(methodInfo);
251 }
252
253 if (methodInfo.hasHandlerAnnotation()) {
254 operationsWithHandlerAnnotation.add(methodInfo);
255 }
256
257 // must add to method map last otherwise we break stuff
258 methodMap.put(method, methodInfo);
259
260 return methodInfo;
261 }
262
263
264 /**
265 * Returns the {@link MethodInfo} for the given method if it exists or null
266 * if there is no metadata available for the given method
267 */
268 public MethodInfo getMethodInfo(Method method) {
269 MethodInfo answer = methodMap.get(method);
270 if (answer == null) {
271 // maybe the method is defined on a base class?
272 if (superBeanInfo == null && type != Object.class) {
273 Class<?> superclass = type.getSuperclass();
274 if (superclass != null && superclass != Object.class) {
275 superBeanInfo = new BeanInfo(camelContext, superclass, strategy);
276 return superBeanInfo.getMethodInfo(method);
277 }
278 }
279 }
280 return answer;
281 }
282
283 @SuppressWarnings("unchecked")
284 protected MethodInfo createMethodInfo(Class clazz, Method method) {
285 Class[] parameterTypes = method.getParameterTypes();
286 Annotation[][] parametersAnnotations = method.getParameterAnnotations();
287
288 List<ParameterInfo> parameters = new ArrayList<ParameterInfo>();
289 List<ParameterInfo> bodyParameters = new ArrayList<ParameterInfo>();
290
291 boolean hasCustomAnnotation = false;
292 boolean hasHandlerAnnotation = ObjectHelper.hasAnnotation(method.getAnnotations(), Handler.class);
293
294 int size = parameterTypes.length;
295 if (LOG.isTraceEnabled()) {
296 LOG.trace("Creating MethodInfo for class: " + clazz + " method: " + method + " having " + size + " parameters");
297 }
298
299 for (int i = 0; i < size; i++) {
300 Class parameterType = parameterTypes[i];
301 Annotation[] parameterAnnotations = parametersAnnotations[i];
302 Expression expression = createParameterUnmarshalExpression(clazz, method, parameterType, parameterAnnotations);
303 hasCustomAnnotation |= expression != null;
304
305 ParameterInfo parameterInfo = new ParameterInfo(i, parameterType, parameterAnnotations, expression);
306 if (LOG.isTraceEnabled()) {
307 LOG.trace("Parameter #" + i + ": " + parameterInfo);
308 }
309 parameters.add(parameterInfo);
310 if (expression == null) {
311 boolean bodyAnnotation = ObjectHelper.hasAnnotation(parameterAnnotations, Body.class);
312 if (LOG.isTraceEnabled() && bodyAnnotation) {
313 LOG.trace("Parameter #" + i + " has @Body annotation");
314 }
315 hasCustomAnnotation |= bodyAnnotation;
316 if (bodyParameters.isEmpty()) {
317 // okay we have not yet set the body parameter and we have found
318 // the candidate now to use as body parameter
319 if (Exchange.class.isAssignableFrom(parameterType)) {
320 // use exchange
321 expression = ExpressionBuilder.exchangeExpression();
322 } else {
323 // lets assume its the body and it must be mandatory convertable to the parameter type
324 // but we allow null bodies in case the message really contains a null body
325 expression = ExpressionBuilder.mandatoryBodyExpression(parameterType, true);
326 }
327 if (LOG.isTraceEnabled()) {
328 LOG.trace("Parameter #" + i + " is the body parameter using expression " + expression);
329 }
330 parameterInfo.setExpression(expression);
331 bodyParameters.add(parameterInfo);
332 } else {
333 // will ignore the expression for parameter evaluation
334 }
335 }
336 if (LOG.isTraceEnabled()) {
337 LOG.trace("Parameter #" + i + " has parameter info: " + parameterInfo);
338 }
339 }
340
341 // now lets add the method to the repository
342 return new MethodInfo(camelContext, clazz, method, parameters, bodyParameters, hasCustomAnnotation, hasHandlerAnnotation);
343 }
344
345 /**
346 * Lets try choose one of the available methods to invoke if we can match
347 * the message body to the body parameter
348 *
349 * @param pojo the bean to invoke a method on
350 * @param exchange the message exchange
351 * @param name an optional name of the method that must match, use <tt>null</tt> to indicate all methods
352 * @return the method to invoke or null if no definitive method could be matched
353 * @throws AmbiguousMethodCallException is thrown if cannot chose method due to ambiguous
354 */
355 protected MethodInfo chooseMethod(Object pojo, Exchange exchange, String name) throws AmbiguousMethodCallException {
356 // @Handler should be select first
357 // then any single method that has a custom @annotation
358 // or any single method that has a match parameter type that matches the Exchange payload
359 // and last then try to select the best among the rest
360
361 if (name != null) {
362 // filter all lists to only include methods with this name
363 removeNonMatchingMethods(operationsWithHandlerAnnotation, name);
364 removeNonMatchingMethods(operationsWithCustomAnnotation, name);
365 removeNonMatchingMethods(operationsWithBody, name);
366 } else {
367 // remove all getter/setter as we do not want to consider these methods
368 removeAllSetterOrGetterMethods(operationsWithHandlerAnnotation);
369 removeAllSetterOrGetterMethods(operationsWithCustomAnnotation);
370 removeAllSetterOrGetterMethods(operationsWithBody);
371 }
372
373 if (operationsWithHandlerAnnotation.size() > 1) {
374 // if we have more than 1 @Handler then its ambiguous
375 throw new AmbiguousMethodCallException(exchange, operationsWithHandlerAnnotation);
376 }
377
378 if (operationsWithHandlerAnnotation.size() == 1) {
379 // methods with handler should be preferred
380 return operationsWithHandlerAnnotation.get(0);
381 } else if (operationsWithCustomAnnotation.size() == 1) {
382 // if there is one method with an annotation then use that one
383 return operationsWithCustomAnnotation.get(0);
384 } else if (operationsWithBody.size() == 1) {
385 // if there is one method with body then use that one
386 return operationsWithBody.get(0);
387 }
388
389 Collection<MethodInfo> possibleOperations = new ArrayList<MethodInfo>();
390 possibleOperations.addAll(operationsWithBody);
391 possibleOperations.addAll(operationsWithCustomAnnotation);
392
393 if (!possibleOperations.isEmpty()) {
394 // multiple possible operations so find the best suited if possible
395 MethodInfo answer = chooseMethodWithMatchingBody(exchange, possibleOperations);
396 if (answer == null) {
397 throw new AmbiguousMethodCallException(exchange, possibleOperations);
398 } else {
399 return answer;
400 }
401 }
402
403 // not possible to determine
404 return null;
405 }
406
407 @SuppressWarnings("unchecked")
408 private MethodInfo chooseMethodWithMatchingBody(Exchange exchange, Collection<MethodInfo> operationList)
409 throws AmbiguousMethodCallException {
410 // lets see if we can find a method who's body param type matches the message body
411 Message in = exchange.getIn();
412 Object body = in.getBody();
413 if (body != null) {
414 Class bodyType = body.getClass();
415 if (LOG.isTraceEnabled()) {
416 LOG.trace("Matching for method with a single parameter that matches type: " + bodyType.getCanonicalName());
417 }
418
419 List<MethodInfo> possibles = new ArrayList<MethodInfo>();
420 List<MethodInfo> possiblesWithException = new ArrayList<MethodInfo>();
421 for (MethodInfo methodInfo : operationList) {
422 // test for MEP pattern matching
423 boolean out = exchange.getPattern().isOutCapable();
424 if (out && methodInfo.isReturnTypeVoid()) {
425 // skip this method as the MEP is Out so the method must return something
426 continue;
427 }
428
429 // try to match the arguments
430 if (methodInfo.bodyParameterMatches(bodyType)) {
431 if (LOG.isTraceEnabled()) {
432 LOG.trace("Found a possible method: " + methodInfo);
433 }
434 if (methodInfo.hasExceptionParameter()) {
435 // methods with accepts exceptions
436 possiblesWithException.add(methodInfo);
437 } else {
438 // regular methods with no exceptions
439 possibles.add(methodInfo);
440 }
441 }
442 }
443
444 // find best suited method to use
445 return chooseBestPossibleMethodInfo(exchange, operationList, body, possibles, possiblesWithException);
446 }
447
448 // no match so return null
449 return null;
450 }
451
452 @SuppressWarnings("unchecked")
453 private MethodInfo chooseBestPossibleMethodInfo(Exchange exchange, Collection<MethodInfo> operationList, Object body,
454 List<MethodInfo> possibles, List<MethodInfo> possiblesWithException)
455 throws AmbiguousMethodCallException {
456
457 Exception exception = ExpressionBuilder.exchangeExceptionExpression().evaluate(exchange, Exception.class);
458 if (exception != null && possiblesWithException.size() == 1) {
459 if (LOG.isTraceEnabled()) {
460 LOG.trace("Exchange has exception set so we prefer method that also has exception as parameter");
461 }
462 // prefer the method that accepts exception in case we have an exception also
463 return possiblesWithException.get(0);
464 } else if (possibles.size() == 1) {
465 return possibles.get(0);
466 } else if (possibles.isEmpty()) {
467 if (LOG.isTraceEnabled()) {
468 LOG.trace("No possible methods so now trying to convert body to parameter types");
469 }
470
471 // lets try converting
472 Object newBody = null;
473 MethodInfo matched = null;
474 for (MethodInfo methodInfo : operationList) {
475 Object value = convertToType(exchange, methodInfo.getBodyParameterType(), body);
476 if (value != null) {
477 if (LOG.isTraceEnabled()) {
478 LOG.trace("Converted body from: " + body.getClass().getCanonicalName()
479 + "to: " + methodInfo.getBodyParameterType().getCanonicalName());
480 }
481 if (newBody != null) {
482 // we already have found one new body that could be converted so now we have 2 methods
483 // and then its ambiguous
484 throw new AmbiguousMethodCallException(exchange, Arrays.asList(matched, methodInfo));
485 } else {
486 newBody = value;
487 matched = methodInfo;
488 }
489 }
490 }
491 if (matched != null) {
492 if (LOG.isTraceEnabled()) {
493 LOG.trace("Setting converted body: " + body);
494 }
495 Message in = exchange.getIn();
496 in.setBody(newBody);
497 return matched;
498 }
499 } else {
500 // if we only have a single method with custom annotations, lets use that one
501 if (operationsWithCustomAnnotation.size() == 1) {
502 MethodInfo answer = operationsWithCustomAnnotation.get(0);
503 if (LOG.isTraceEnabled()) {
504 LOG.trace("There are only one method with annotations so we choose it: " + answer);
505 }
506 return answer;
507 }
508 // phew try to choose among multiple methods with annotations
509 return chooseMethodWithCustomAnnotations(exchange, possibles);
510 }
511
512 // cannot find a good method to use
513 return null;
514 }
515
516 /**
517 * Validates whether the given method is a valid candidate for Camel Bean Binding.
518 *
519 * @param clazz the class
520 * @param method the method
521 * @return true if valid, false to skip the method
522 */
523 protected boolean isValidMethod(Class<?> clazz, Method method) {
524 // must not be in the excluded list
525 for (Method excluded : EXCLUDED_METHODS) {
526 if (ObjectHelper.isOverridingMethod(excluded, method)) {
527 // the method is overriding an excluded method so its not valid
528 return false;
529 }
530 }
531
532 // must be a public method
533 if (!Modifier.isPublic(method.getModifiers())) {
534 return false;
535 }
536
537 // return type must not be an Exchange and it should not be a bridge method
538 if ((method.getReturnType() != null && Exchange.class.isAssignableFrom(method.getReturnType())) || method.isBridge()) {
539 return false;
540 }
541
542 return true;
543 }
544
545 /**
546 * Does the given method info override an existing method registered before (from a subclass)
547 *
548 * @param methodInfo the method to test
549 * @return the already registered method to use, null if not overriding any
550 */
551 private MethodInfo overridesExistingMethod(MethodInfo methodInfo) {
552 for (MethodInfo info : methodMap.values()) {
553 Method source = info.getMethod();
554 Method target = methodInfo.getMethod();
555
556 boolean override = ObjectHelper.isOverridingMethod(source, target);
557 if (override) {
558 // same name, same parameters, then its overrides an existing class
559 return info;
560 }
561 }
562
563 return null;
564 }
565
566 private MethodInfo chooseMethodWithCustomAnnotations(Exchange exchange, Collection<MethodInfo> possibles)
567 throws AmbiguousMethodCallException {
568 // if we have only one method with custom annotations lets choose that
569 MethodInfo chosen = null;
570 for (MethodInfo possible : possibles) {
571 if (possible.hasCustomAnnotation()) {
572 if (chosen != null) {
573 chosen = null;
574 break;
575 } else {
576 chosen = possible;
577 }
578 }
579 }
580 if (chosen != null) {
581 return chosen;
582 }
583 throw new AmbiguousMethodCallException(exchange, possibles);
584 }
585
586 /**
587 * Creates an expression for the given parameter type if the parameter can
588 * be mapped automatically or null if the parameter cannot be mapped due to
589 * insufficient annotations or not fitting with the default type
590 * conventions.
591 */
592 private Expression createParameterUnmarshalExpression(Class<?> clazz, Method method,
593 Class<?> parameterType, Annotation[] parameterAnnotation) {
594
595 // look for a parameter annotation that converts into an expression
596 for (Annotation annotation : parameterAnnotation) {
597 Expression answer = createParameterUnmarshalExpressionForAnnotation(clazz, method, parameterType, annotation);
598 if (answer != null) {
599 return answer;
600 }
601 }
602 // no annotations then try the default parameter mappings
603 return strategy.getDefaultParameterTypeExpression(parameterType);
604 }
605
606 private Expression createParameterUnmarshalExpressionForAnnotation(Class<?> clazz, Method method,
607 Class<?> parameterType, Annotation annotation) {
608
609 if (annotation instanceof Property) {
610 Property propertyAnnotation = (Property)annotation;
611 return ExpressionBuilder.propertyExpression(propertyAnnotation.value());
612 } else if (annotation instanceof Properties) {
613 return ExpressionBuilder.propertiesExpression();
614 } else if (annotation instanceof Header) {
615 Header headerAnnotation = (Header)annotation;
616 return ExpressionBuilder.headerExpression(headerAnnotation.value());
617 } else if (annotation instanceof Headers) {
618 return ExpressionBuilder.headersExpression();
619 } else if (annotation instanceof OutHeaders) {
620 return ExpressionBuilder.outHeadersExpression();
621 } else if (annotation instanceof ExchangeException) {
622 return ExpressionBuilder.exchangeExceptionExpression(CastUtils.cast(parameterType, Exception.class));
623 } else {
624 LanguageAnnotation languageAnnotation = annotation.annotationType().getAnnotation(LanguageAnnotation.class);
625 if (languageAnnotation != null) {
626 Class<?> type = languageAnnotation.factory();
627 Object object = camelContext.getInjector().newInstance(type);
628 if (object instanceof AnnotationExpressionFactory) {
629 AnnotationExpressionFactory expressionFactory = (AnnotationExpressionFactory) object;
630 return expressionFactory.createExpression(camelContext, annotation, languageAnnotation, parameterType);
631 } else {
632 LOG.warn("Ignoring bad annotation: " + languageAnnotation + "on method: " + method
633 + " which declares a factory: " + type.getName()
634 + " which does not implement " + AnnotationExpressionFactory.class.getName());
635 }
636 }
637 }
638
639 return null;
640 }
641
642 private static void removeAllSetterOrGetterMethods(List<MethodInfo> methods) {
643 Iterator<MethodInfo> it = methods.iterator();
644 while (it.hasNext()) {
645 MethodInfo info = it.next();
646 if (IntrospectionSupport.isGetter(info.getMethod())) {
647 // skip getters
648 it.remove();
649 } else if (IntrospectionSupport.isSetter(info.getMethod())) {
650 // skip setters
651 it.remove();
652 }
653 }
654 }
655
656 private static void removeNonMatchingMethods(List<MethodInfo> methods, String name) {
657 Iterator<MethodInfo> it = methods.iterator();
658 while (it.hasNext()) {
659 MethodInfo info = it.next();
660 if (!name.equals(info.getMethod().getName())) {
661 // name does not match so remove it
662 it.remove();
663 }
664 }
665 }
666
667 private static Class<?> getTargetClass(Class<?> clazz) {
668 if (clazz.getName().indexOf(CGLIB_CLASS_SEPARATOR) != -1) {
669 return clazz.getSuperclass();
670 }
671 return clazz;
672 }
673
674 }