001 /* $Id: MethodHandler.java 992091 2010-09-02 19:58:12Z simonetripodi $
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one or more
004 * contributor license agreements. See the NOTICE file distributed with
005 * this work for additional information regarding copyright ownership.
006 * The ASF licenses this file to You under the Apache License, Version 2.0
007 * (the "License"); you may not use this file except in compliance with
008 * the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 package org.apache.commons.digester.annotations.handlers;
019
020 import java.lang.annotation.Annotation;
021 import java.lang.reflect.Method;
022 import java.lang.reflect.Modifier;
023
024 import org.apache.commons.digester.Rule;
025 import org.apache.commons.digester.annotations.AnnotationRuleProvider;
026 import org.apache.commons.digester.annotations.CreationRule;
027 import org.apache.commons.digester.annotations.DigesterLoaderHandler;
028 import org.apache.commons.digester.annotations.DigesterLoadingException;
029 import org.apache.commons.digester.annotations.DigesterRule;
030 import org.apache.commons.digester.annotations.DigesterRuleList;
031 import org.apache.commons.digester.annotations.FromAnnotationsRuleSet;
032 import org.apache.commons.digester.annotations.utils.AnnotationUtils;
033
034 /**
035 * Handler that takes care to create the
036 * {@link org.apache.commons.digester.annotations.providers.SetNextRuleProvider}
037 * and
038 * {@link org.apache.commons.digester.annotations.providers.SetRootRuleProvider}.
039 *
040 * @since 2.1
041 */
042 public final class MethodHandler implements DigesterLoaderHandler<Annotation, Method> {
043
044 /**
045 * The default args size the method has to have in order to be analyzed.
046 */
047 private static final int SUPPORTED_ARGS = 1;
048
049 /**
050 * {@inheritDoc}
051 */
052 public void handle(Annotation annotation, Method element, FromAnnotationsRuleSet ruleSet) {
053 if (SUPPORTED_ARGS != element.getParameterTypes().length) {
054 DigesterRule rule = annotation.annotationType().getAnnotation(DigesterRule.class);
055
056 throw new DigesterLoadingException("Methods annotated with digester annotation rule @"
057 + rule.reflectsRule().getName()
058 + " must have just one argument");
059 }
060
061 Object explicitTypesObject = AnnotationUtils.getAnnotationValue(annotation);
062 if (explicitTypesObject == null
063 || !explicitTypesObject.getClass().isArray()
064 || Class.class != explicitTypesObject.getClass().getComponentType()) {
065 throw new DigesterLoadingException("Impossible to apply this handler, @"
066 + annotation.getClass().getName()
067 + ".value() has to be of type 'Class<?>[]'");
068 }
069
070 Class<?>[] explicitTypes = (Class<?>[]) explicitTypesObject;
071 Class<?> paramType = element.getParameterTypes()[0];
072
073 if (explicitTypes.length > 0) {
074 for (Class<?> explicitType : explicitTypes) {
075 if (!paramType.isAssignableFrom(explicitType)) {
076 throw new DigesterLoadingException("Impossible to handle annotation "
077 + annotation
078 + " on method "
079 + element.toGenericString()
080 + ", "
081 + explicitType.getName()
082 + " has to be a "
083 + paramType.getName());
084 }
085
086 this.doHandle(annotation, element, explicitType, ruleSet);
087 }
088 } else {
089 this.doHandle(annotation, element, paramType, ruleSet);
090 }
091 }
092
093 private void doHandle(Annotation methodAnnotation, Method method, Class<?> type, FromAnnotationsRuleSet ruleSet) {
094 if (type.isInterface()
095 && Modifier.isAbstract(type.getModifiers())) {
096 throw new DigesterLoadingException("Impossible to proceed analyzing "
097 + methodAnnotation
098 + ", specified type '"
099 + type.getName()
100 + "' is an interface/abstract");
101 }
102
103 for (Annotation annotation : type.getAnnotations()) {
104 this.doHandle(methodAnnotation, annotation, method, type, ruleSet);
105 }
106 }
107
108 @SuppressWarnings("unchecked")
109 private <A extends Annotation, R extends Rule> void doHandle(A methodAnnotation,
110 Annotation annotation,
111 Method method,
112 Class<?> type,
113 FromAnnotationsRuleSet ruleSet) {
114 if (annotation.annotationType().isAnnotationPresent(DigesterRule.class)
115 && annotation.annotationType().isAnnotationPresent(CreationRule.class)) {
116 ruleSet.addRules(type);
117
118 DigesterRule digesterRule = methodAnnotation.annotationType().getAnnotation(DigesterRule.class);
119 Class<? extends AnnotationRuleProvider<A, Method, R>> providerType =
120 (Class<? extends AnnotationRuleProvider<A, Method, R>>) digesterRule.providedBy();
121 ruleSet.addRuleProvider(AnnotationUtils.getAnnotationPattern(annotation),
122 providerType,
123 methodAnnotation,
124 method);
125 } else if (annotation.annotationType().isAnnotationPresent(DigesterRuleList.class)) {
126 // check if it is one of the *.List annotation
127 Annotation[] annotations = AnnotationUtils.getAnnotationsArrayValue(annotation);
128 if (annotations != null) {
129 // if it is an annotations array, process them
130 for (Annotation ptr : annotations) {
131 this.doHandle(methodAnnotation, ptr, method, type, ruleSet);
132 }
133 }
134 }
135 }
136
137 }