/* $Id: DigesterLoader.java 992084 2010-09-02 19:52:17Z simonetripodi $
 *
 * 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.
 */
package org.apache.commons.digester.annotations;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import org.apache.commons.digester.Digester;
import org.apache.commons.digester.Rule;
import org.apache.commons.digester.RuleSet;
import org.apache.commons.digester.annotations.handlers.DefaultLoaderHandler;
import org.apache.commons.digester.annotations.internal.RuleSetCache;
import org.apache.commons.digester.annotations.reflect.MethodArgument;
import org.apache.commons.digester.annotations.spi.AnnotationRuleProviderFactory;
import org.apache.commons.digester.annotations.spi.DigesterLoaderHandlerFactory;
import org.apache.commons.digester.annotations.utils.AnnotationUtils;

This class manages the creation of Digester instances analyzing target classes annotated with digester annotations.
Since:2.1
/** * This class manages the creation of Digester instances analyzing target classes * annotated with digester annotations. * * @since 2.1 */
public final class DigesterLoader {
In-memory LRU cache that stores already analyzed classes and relative RuleSet.
/** * In-memory LRU cache that stores already analyzed classes and relative * {@link RuleSet}. */
private final RuleSetCache cachedRuleSet = new RuleSetCache(); private final AnnotationRuleProviderFactory annotationRuleProviderFactory; private final DigesterLoaderHandlerFactory digesterLoaderHandlerFactory;
Creates a new DigesterLoader instance.
Params:
  • annotationRuleProviderFactory –
  • digesterLoaderHandlerFactory –
/** * Creates a new {@link DigesterLoader} instance. * * @param annotationRuleProviderFactory * @param digesterLoaderHandlerFactory */
protected DigesterLoader(AnnotationRuleProviderFactory annotationRuleProviderFactory, DigesterLoaderHandlerFactory digesterLoaderHandlerFactory) { this.annotationRuleProviderFactory = annotationRuleProviderFactory; this.digesterLoaderHandlerFactory = digesterLoaderHandlerFactory; } protected AnnotationRuleProviderFactory getAnnotationRuleProviderFactory() { return annotationRuleProviderFactory; } protected DigesterLoaderHandlerFactory getDigesterLoaderHandlerFactory() { return digesterLoaderHandlerFactory; }
Creates a new digester which rules are defined by analyzing the digester annotations in the target class.
Params:
  • target – the class has to be analyzed.
Returns:a new Digester instance.
/** * Creates a new digester which rules are defined by analyzing the digester * annotations in the target class. * * @param target the class has to be analyzed. * @return a new Digester instance. */
public Digester createDigester(final Class<?> target) { Digester digester = new Digester(); digester.setClassLoader(target.getClassLoader()); addRules(target, digester); return digester; }
Add rules to an already created Digester instance, analyzing the digester annotations in the target class.
Params:
  • target – the class has to be analyzed.
  • digester – the Digester instance reference.
/** * Add rules to an already created Digester instance, analyzing the digester * annotations in the target class. * * @param target the class has to be analyzed. * @param digester the Digester instance reference. */
public void addRules(final Class<?> target, final Digester digester) { RuleSet ruleSet = getRuleSet(target); ruleSet.addRuleInstances(digester); }
Builds a new RuleSet analyzing the digester annotations in the target class. It avoids iterate the annotations analysis for already analyzed classes, using an in-memory LRU cache.
Params:
  • target – the class has to be analyzed.
Returns:a new RuleSet.
/** * Builds a new {@link RuleSet} analyzing the digester annotations in the * target class. * * It avoids iterate the annotations analysis for already analyzed classes, * using an in-memory LRU cache. * * @param target the class has to be analyzed. * @return a new {@link RuleSet}. */
public RuleSet getRuleSet(final Class<?> target) { if (this.cachedRuleSet.containsKey(target)) { return this.cachedRuleSet.get(target); } FromAnnotationsRuleSet ruleSet = new FromAnnotationsRuleSet(this); addRulesTo(target, ruleSet); this.cachedRuleSet.put(target, ruleSet); return ruleSet; }
Analyzes the target class and adds the AnnotationRuleProviders to the existing FromAnnotationsRuleSet.
Params:
  • target – the class has to be analyzed.
  • ruleSet – the RuleSet where adding the providers.
/** * Analyzes the target class and adds the {@link AnnotationRuleProvider}s to * the existing {@link FromAnnotationsRuleSet}. * * @param target the class has to be analyzed. * @param ruleSet the RuleSet where adding the providers. */
public void addRulesTo(final Class<?> target, FromAnnotationsRuleSet ruleSet) { if (target == Object.class || target.isInterface() || ruleSet.mapsClass(target)) { return; } if (this.cachedRuleSet.containsKey(target)) { ruleSet.addRulesProviderFrom(this.cachedRuleSet.get(target)); ruleSet.addMappedClass(target); return; } // current analyzed class handle(target, ruleSet); // class fields for (Field field : target.getDeclaredFields()) { handle(field, ruleSet); } // class methods for (Method method : target.getDeclaredMethods()) { handle(method, ruleSet); // method args Annotation[][] parameterAnnotations = method.getParameterAnnotations(); Class<?>[] parameterTypes = method.getParameterTypes(); for (int i = 0; i < parameterTypes.length; i++) { handle(new MethodArgument(i, parameterTypes[i], parameterAnnotations[i]), ruleSet); } } ruleSet.addMappedClass(target); addRulesTo(target.getSuperclass(), ruleSet); }
Executes an analysis for each annotation present in the element.
Params:
  • element – the current element under analysis.
  • ruleSet – the ruleSet where add providers.
/** * Executes an analysis for each annotation present in the element. * * @param element the current element under analysis. * @param ruleSet the ruleSet where add providers. */
private void handle(AnnotatedElement element, FromAnnotationsRuleSet ruleSet) { for (Annotation annotation : element.getAnnotations()) { handle(annotation, element, ruleSet); } }
Handles the current visited element and related annotation, invoking the right handler putting the rule provider in the rule set.
Params:
  • annotation – the current visited annotation.
  • element – the current visited element.
/** * Handles the current visited element and related annotation, invoking the * right handler putting the rule provider in the rule set. * * @param annotation the current visited annotation. * @param element the current visited element. */
@SuppressWarnings("unchecked") private <A extends Annotation, E extends AnnotatedElement, R extends Rule> void handle(A annotation, E element, FromAnnotationsRuleSet ruleSet) { Class<?> annotationType = annotation.annotationType(); // check if it is one of the @*.List annotation if (annotationType.isAnnotationPresent(DigesterRuleList.class)) { Annotation[] annotations = AnnotationUtils.getAnnotationsArrayValue(annotation); if (annotations != null && annotations.length > 0) { // if it is an annotations array, process them for (Annotation ptr : annotations) { handle(ptr, element, ruleSet); } } } else if (annotationType.isAnnotationPresent(DigesterRule.class)) { DigesterRule digesterRule = annotationType.getAnnotation(DigesterRule.class); if (DefaultLoaderHandler.class == digesterRule.handledBy()) { Class<? extends AnnotationRuleProvider<A, E, R>> providerType = (Class<? extends AnnotationRuleProvider<A, E, R>>) digesterRule.providedBy(); ruleSet.addRuleProvider(AnnotationUtils.getAnnotationPattern(annotation), providerType, annotation, element); } else { Class<? extends DigesterLoaderHandler<Annotation, AnnotatedElement>> handlerType = (Class<? extends DigesterLoaderHandler<Annotation, AnnotatedElement>>) digesterRule.handledBy(); DigesterLoaderHandler<Annotation, AnnotatedElement> handler = this.digesterLoaderHandlerFactory.newInstance(handlerType); // run! handler.handle(annotation, element, ruleSet); } } } }