| package org.apache.commons.digester3.annotations.handlers; |
| |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| import static org.apache.commons.digester3.annotations.utils.AnnotationUtils.getAnnotationNamespaceURI; |
| import static org.apache.commons.digester3.annotations.utils.AnnotationUtils.getAnnotationPattern; |
| import static org.apache.commons.digester3.annotations.utils.AnnotationUtils.getAnnotationValue; |
| import static org.apache.commons.digester3.annotations.utils.AnnotationUtils.getAnnotationsArrayValue; |
| import static org.apache.commons.digester3.annotations.utils.AnnotationUtils.getFireOnBegin; |
| |
| import java.lang.annotation.Annotation; |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Modifier; |
| |
| import org.apache.commons.digester3.annotations.AnnotationHandler; |
| import org.apache.commons.digester3.annotations.DigesterRule; |
| import org.apache.commons.digester3.annotations.DigesterRuleList; |
| import org.apache.commons.digester3.annotations.FromAnnotationsRuleModule; |
| import org.apache.commons.digester3.annotations.rules.CreationRule; |
| import org.apache.commons.digester3.binder.RulesBinder; |
| |
| /** |
| * Handler that takes care to create the |
| * {@link org.apache.commons.digester3.annotations.rules.SetNext} |
| * and |
| * {@link org.apache.commons.digester3.annotations.rules.SetRoot}. |
| * |
| * @since 3.0 |
| */ |
| abstract class AbstractMethodHandler<A extends Annotation> implements AnnotationHandler<A, Method> |
| { |
| |
| /** |
| * The default args size the method has to have in order to be analyzed. |
| */ |
| private static final int SUPPORTED_ARGS = 1; |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void handle( A annotation, Method element, RulesBinder rulesBinder ) |
| { |
| if ( SUPPORTED_ARGS != element.getParameterTypes().length ) |
| { |
| DigesterRule rule = annotation.annotationType().getAnnotation( DigesterRule.class ); |
| |
| rulesBinder.addError( "Methods annotated with digester annotation rule @%s must have just one argument", |
| rule.reflectsRule().getName() ); |
| return; |
| } |
| |
| Object explicitTypesObject = getAnnotationValue( annotation ); |
| if ( explicitTypesObject == null || !explicitTypesObject.getClass().isArray() |
| || Class.class != explicitTypesObject.getClass().getComponentType() ) |
| { |
| rulesBinder.addError( "Impossible to apply this handler, @%s.value() has to be of type 'Class<?>[]'", |
| annotation.getClass().getName() ); |
| return; |
| } |
| |
| Class<?>[] explicitTypes = (Class<?>[]) explicitTypesObject; |
| Class<?> paramType = element.getParameterTypes()[0]; |
| boolean fireOnBegin = getFireOnBegin( annotation ); |
| |
| if ( explicitTypes.length > 0 ) |
| { |
| for ( Class<?> explicitType : explicitTypes ) |
| { |
| if ( !paramType.isAssignableFrom( explicitType ) ) |
| { |
| rulesBinder.addError( "Impossible to handle annotation %s on method, %s has to be a %s", |
| annotation, element.toGenericString(), explicitType.getName(), |
| paramType.getName() ); |
| return; |
| } |
| |
| doHandle( annotation, element, explicitType, fireOnBegin, rulesBinder ); |
| } |
| } |
| else |
| { |
| doHandle( annotation, element, paramType, fireOnBegin, rulesBinder ); |
| } |
| } |
| |
| private void doHandle( A methodAnnotation, Method method, Class<?> type, boolean fireOnBegin, |
| RulesBinder rulesBinder ) |
| { |
| if ( type.isInterface() && Modifier.isAbstract( type.getModifiers() ) ) |
| { |
| rulesBinder.addError( "Impossible to proceed analyzing %s, specified type '%s' is an interface/abstract", |
| methodAnnotation, type.getName() ); |
| return; |
| } |
| |
| for ( Annotation annotation : type.getAnnotations() ) |
| { |
| doHandle( methodAnnotation, annotation, method, type, fireOnBegin, rulesBinder ); |
| } |
| |
| for ( Constructor<?> constructor : type.getConstructors() ) |
| { |
| for ( Annotation annotation : constructor.getAnnotations() ) |
| { |
| doHandle( methodAnnotation, annotation, method, type, fireOnBegin, rulesBinder ); |
| } |
| } |
| } |
| |
| private void doHandle( A methodAnnotation, Annotation annotation, Method method, final Class<?> type, |
| boolean fireOnBegin, RulesBinder rulesBinder ) |
| { |
| if ( annotation.annotationType().isAnnotationPresent( DigesterRule.class ) |
| && annotation.annotationType().isAnnotationPresent( CreationRule.class ) ) |
| { |
| rulesBinder.install( new FromAnnotationsRuleModule() |
| { |
| |
| @Override |
| protected void configureRules() |
| { |
| bindRulesFrom( type ); |
| } |
| |
| } ); |
| |
| String pattern = getAnnotationPattern( annotation ); |
| String namespaceURI = getAnnotationNamespaceURI( annotation ); |
| doBind( pattern, namespaceURI, method, type, fireOnBegin, rulesBinder ); |
| } |
| else if ( annotation.annotationType().isAnnotationPresent( DigesterRuleList.class ) ) |
| { |
| // check if it is one of the *.List annotation |
| Annotation[] annotations = getAnnotationsArrayValue( annotation ); |
| if ( annotations != null ) |
| { |
| // if it is an annotations array, process them |
| for ( Annotation ptr : annotations ) |
| { |
| doHandle( methodAnnotation, ptr, method, type, fireOnBegin, rulesBinder ); |
| } |
| } |
| } |
| } |
| |
| protected abstract void doBind( String pattern, String namespaceURI, Method method, Class<?> type, |
| boolean fireOnBegin, RulesBinder rulesBinder ); |
| |
| } |