blob: 33e0031e5b02f7d008e1e2f90b64befdff05469e [file] [log] [blame]
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 );
}