package org.apache.commons.digester3.annotations.handlers;
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;
abstract class AbstractMethodHandler<A extends Annotation> implements AnnotationHandler<A, Method>
{
private static final int SUPPORTED_ARGS = 1;
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 ) )
{
Annotation[] annotations = getAnnotationsArrayValue( annotation );
if ( annotations != null )
{
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 );
}