/* * ============================================================================ * GNU Lesser General Public License * ============================================================================ * * Beanlet - JSE Application Container. * Copyright (C) 2006 Leon van Zantvoort * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * * Leon van Zantvoort * 243 Acalanes Drive #11 * Sunnyvale, CA 94086 * USA * * zantvoort@users.sourceforge.net * http://beanlet.org */ package org.beanlet.annotation; import java.lang.annotation.Annotation; import java.lang.annotation.Inherited; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; /** * * @author Leon van Zantvoort */ class AnnotationDeclarationImpl<T extends Annotation> implements AnnotationDeclaration<T> { private final Class<T> annotationType; private final List<ElementAnnotation<Element, T>> list; private final ConcurrentMap<Class, List<ElementAnnotation<Element, T>>> classSpecificList; private final Map<Class<? extends Element>, ElementAnnotationHolder<Element, T>> elementAnnotationMap; private final ConcurrentMap<Class, ConcurrentMap<Class<? extends Element>, ElementAnnotationHolder<Element, T>>> classSpecificElementAnnotationMap; private final Map<Element, ElementAnnotation<Element, T>> annotations; public AnnotationDeclarationImpl(Class<T> annotationType) { this.annotationType = annotationType; this.list = Collections.emptyList(); this.classSpecificList = new ConcurrentHashMap<Class, List<ElementAnnotation<Element, T>>>(); this.elementAnnotationMap = Collections.emptyMap(); this.classSpecificElementAnnotationMap = new ConcurrentHashMap<Class, ConcurrentMap<Class<? extends Element>, ElementAnnotationHolder<Element, T>>>(); this.annotations = Collections.emptyMap(); } public AnnotationDeclarationImpl(Class<T> annotationType, List<ElementAnnotation<Element, T>> elementAnnotationList) { this.annotationType = annotationType; // Defensive copy. this.list = new ArrayList<ElementAnnotation<Element, T>>(elementAnnotationList); this.classSpecificList = new ConcurrentHashMap<Class, List<ElementAnnotation<Element, T>>>(); this.elementAnnotationMap = new HashMap<Class<? extends Element>, ElementAnnotationHolder<Element, T>>(); this.classSpecificElementAnnotationMap = new ConcurrentHashMap<Class, ConcurrentMap<Class<? extends Element>, ElementAnnotationHolder<Element, T>>>(); this.annotations = new HashMap<Element, ElementAnnotation<Element, T>>(); for (ElementAnnotation<Element, T> ea : elementAnnotationList) { ElementAnnotationHolder<Element, T> holder = elementAnnotationMap.get(ea.getElement().getClass()); if (holder == null) { holder = new ElementAnnotationHolder<Element, T>(); elementAnnotationMap.put(ea.getElement().getClass(), holder); } holder.elementAnnotations.add(ea); annotations.put(ea.getElement(), ea); } } public List<ElementAnnotation<Element, T>> getElements() { return Collections.unmodifiableList(list); } public List<ElementAnnotation<Element, T>> getElements(Class<?> cls) { List<ElementAnnotation<Element, T>> list = classSpecificList.get(cls); if (list == null) { list = new ArrayList<ElementAnnotation<Element, T>>(); for (ElementAnnotation<Element, T> ea : getElements()) { Element e = ea.getElement(); if (e.isElementOf(cls) && !e.isOverridden(cls)) { list.add(ea); } } classSpecificList.putIfAbsent(cls, list); } return Collections.unmodifiableList(list); } public <E extends Element> List<ElementAnnotation<E, T>> getTypedElements(Class<E> elementClass) { @SuppressWarnings("unchecked") ElementAnnotationHolder<E, T> holder = (ElementAnnotationHolder<E, T>) elementAnnotationMap.get(elementClass); final List<ElementAnnotation<E, T>> list; if (holder == null) { list = Collections.emptyList(); } else { list = Collections.unmodifiableList(holder.elementAnnotations); } return list; } public <E extends Element> List<ElementAnnotation<E, T>> getTypedElements(Class<E> elementClass, Class<?> cls) { ConcurrentMap<Class<? extends Element>, ElementAnnotationHolder<Element, T>> map = classSpecificElementAnnotationMap.get(cls); if (map == null) { map = new ConcurrentHashMap<Class<? extends Element>, ElementAnnotationHolder<Element, T>>(); classSpecificElementAnnotationMap.putIfAbsent(cls, map); } @SuppressWarnings("unchecked") ElementAnnotationHolder<Element, T> holder = map.get(elementClass); if (holder == null) { holder = new ElementAnnotationHolder<Element, T>(); for (ElementAnnotation<E, T> ea : getTypedElements(elementClass)) { @SuppressWarnings("unchecked") ElementAnnotation<Element, T> tmp = (ElementAnnotation<Element, T>) ea; Element e = tmp.getElement(); if (e.isElementOf(cls) && !e.isOverridden(cls)) { holder.elementAnnotations.add(tmp); } } map.put(elementClass, holder); } @SuppressWarnings("unchecked") ElementAnnotationHolder<E, T> h = (ElementAnnotationHolder<E, T>) holder; return Collections.unmodifiableList(h.elementAnnotations); } public boolean isAnnotationPresent(Element element) { return getAnnotation(element) != null; } protected <E extends Element> ElementAnnotation<E, T> getElementAnnotation(E element) { @SuppressWarnings("unchecked") ElementAnnotation<E, T> ea = (ElementAnnotation<E, T>) annotations.get(element); return ea; } public T getAnnotation(Element element) { if (element instanceof TypeElement && annotationType.isAnnotationPresent(Inherited.class)) { Class<?> cls = ((TypeElement) element).getType(); do { T annotation = getDeclaredAnnotation(TypeElement.instance(cls)); if (annotation != null) { return annotation; } } while ((cls = cls.getSuperclass()) != null); return null; } else { return getDeclaredAnnotation(element); } } public T getDeclaredAnnotation(Element element) { ElementAnnotation<Element, T> ea = getElementAnnotation(element); return ea == null ? null : ea.getAnnotation(); } public Class<T> annotationType() { return annotationType; } public String toString() { return "AnnotationDeclaration" + list; } private class ElementAnnotationHolder<E extends Element, V extends Annotation> { private final List<ElementAnnotation<E, V>> elementAnnotations = new ArrayList<ElementAnnotation<E, V>>(); } }