/*
* JBoss, Home of Professional Open Source
* Copyright 2008, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed 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.jboss.weld.annotated.enhanced.jlr;
import static org.jboss.weld.util.collections.WeldCollections.immutableMapView;
import static org.jboss.weld.util.reflection.Reflections.EMPTY_ANNOTATIONS;
import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.enterprise.inject.Default;
import javax.enterprise.inject.spi.Annotated;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.inject.Qualifier;
import org.jboss.weld.annotated.enhanced.EnhancedAnnotated;
import org.jboss.weld.annotated.slim.SlimAnnotatedType;
import org.jboss.weld.logging.ReflectionLogger;
import org.jboss.weld.resources.ClassTransformer;
import org.jboss.weld.resources.ReflectionCache;
import org.jboss.weld.util.collections.Arrays2;
import org.jboss.weld.util.collections.ImmutableSet;
import org.jboss.weld.util.collections.Multimap;
import org.jboss.weld.util.collections.Multimaps;
import org.jboss.weld.util.collections.SetMultimap;
import org.jboss.weld.util.collections.WeldCollections;
import org.jboss.weld.util.reflection.Reflections;
/**
* Represents functionality common for all annotated items, mainly different
* mappings of the annotations and meta-annotations
* <p/>
* AbstractAnnotatedItem is an immutable class and therefore threadsafe
*
* @param <T>
* @param <S>
* @author Pete Muir
* @author Nicklas Karlsson
* @see org.jboss.weld.annotated.enhanced.EnhancedAnnotated
*/
public abstract class AbstractEnhancedAnnotated<T, S> implements EnhancedAnnotated<T, S> {
// The set of default binding types
private static final Set<Annotation> DEFAULT_QUALIFIERS = Collections.<Annotation>singleton(Default.Literal.INSTANCE);
/**
* Builds the annotation map (annotation type -> annotation)
*
* @param annotations The array of annotations to map
* @return The annotation map
*/
protected static Map<Class<? extends Annotation>, Annotation> buildAnnotationMap(Iterable<Annotation> annotations) {
Map<Class<? extends Annotation>, Annotation> annotationMap = new HashMap<Class<? extends Annotation>, Annotation>();
for (Annotation annotation : annotations) {
annotationMap.put(annotation.annotationType(), annotation);
}
return annotationMap;
}
protected static void addMetaAnnotations(SetMultimap<Class<? extends Annotation>, Annotation> metaAnnotationMap, Annotation annotation, Iterable<Annotation> metaAnnotations, boolean declared) {
for (Annotation metaAnnotation : metaAnnotations) {
addMetaAnnotation(metaAnnotationMap, annotation, metaAnnotation.annotationType(), declared);
}
}
private static void addMetaAnnotation(SetMultimap<Class<? extends Annotation>, Annotation> metaAnnotationMap, Annotation annotation, Class<? extends Annotation> metaAnnotationType, boolean declared) {
// Only map meta-annotations we are interested in
if (declared ? MAPPED_DECLARED_METAANNOTATIONS.contains(metaAnnotationType) : MAPPED_METAANNOTATIONS.contains(metaAnnotationType)) {
metaAnnotationMap.put(metaAnnotationType, annotation);
}
}
// The annotation map (annotation type -> annotation) of the item
private final Map<Class<? extends Annotation>, Annotation> annotationMap;
// The meta-annotation map (annotation type -> set of annotations containing
// meta-annotation) of the item
private final Multimap<Class<? extends Annotation>, Annotation> metaAnnotationMap;
private final Class<T> rawType;
private final Type[] actualTypeArguments;
private final Annotated delegate;
private final Set<Annotation> annotations;
/**
* Constructor
* <p/>
* Also builds the meta-annotation map. Throws a NullPointerException if
* trying to register a null map
*
* @param annotationMap A map of annotation to register
*/
public AbstractEnhancedAnnotated(Annotated annotated, Map<Class<? extends Annotation>, Annotation> annotationMap, Map<Class<? extends Annotation>, Annotation> declaredAnnotationMap, ClassTransformer classTransformer) {
this.delegate = annotated;
if (annotated instanceof AnnotatedType<?>) {
this.rawType = Reflections.<AnnotatedType<T>>cast(annotated).getJavaClass();
} else {
this.rawType = Reflections.getRawType(annotated.getBaseType());
}
if (annotationMap == null) {
throw ReflectionLogger.LOG.annotationMapNull();
}
this.annotationMap = immutableMapView(annotationMap);
SetMultimap<Class<? extends Annotation>, Annotation> metaAnnotationMap = SetMultimap.newSetMultimap();
processMetaAnnotations(metaAnnotationMap, annotationMap.values(), classTransformer, false);
this.metaAnnotationMap = Multimaps.unmodifiableMultimap(metaAnnotationMap);
if (declaredAnnotationMap == null) {
throw ReflectionLogger.LOG.declaredAnnotationMapNull();
}
if (delegate.getBaseType() instanceof ParameterizedType) {
this.actualTypeArguments = ((ParameterizedType) delegate.getBaseType()).getActualTypeArguments();
} else {
this.actualTypeArguments = Arrays2.EMPTY_TYPE_ARRAY;
}
this.annotations = ImmutableSet.copyOf(this.annotationMap.values());
}
protected void processMetaAnnotations(SetMultimap<Class<? extends Annotation>, Annotation> metaAnnotationMap, Collection<Annotation> annotations, ClassTransformer classTransformer, boolean declared) {
for (Annotation annotation : annotations) {
processMetaAnnotations(metaAnnotationMap, annotation, classTransformer, declared);
}
}
protected void processMetaAnnotations(SetMultimap<Class<? extends Annotation>, Annotation> metaAnnotationMap, Annotation[] annotations, ClassTransformer classTransformer, boolean declared) {
for (Annotation annotation : annotations) {
processMetaAnnotations(metaAnnotationMap, annotation, classTransformer, declared);
}
}
protected void processMetaAnnotations(SetMultimap<Class<? extends Annotation>, Annotation> metaAnnotationMap, Annotation annotation, ClassTransformer classTransformer, boolean declared) {
// WELD-1310 Include synthetic annotations
SlimAnnotatedType<?> syntheticAnnotationAnnotatedType = classTransformer.getSyntheticAnnotationAnnotatedType(annotation.annotationType());
if (syntheticAnnotationAnnotatedType != null) {
addMetaAnnotations(metaAnnotationMap, annotation, syntheticAnnotationAnnotatedType.getAnnotations(), declared);
} else {
addMetaAnnotations(metaAnnotationMap, annotation, classTransformer.getReflectionCache().getAnnotations(annotation.annotationType()), declared);
ReflectionCache.AnnotationClass<?> annotationClass = classTransformer.getReflectionCache().getAnnotationClass(annotation.annotationType());
if (annotationClass.isRepeatableAnnotationContainer()) {
processMetaAnnotations(metaAnnotationMap, annotationClass.getRepeatableAnnotations(annotation), classTransformer, declared);
}
}
addMetaAnnotations(metaAnnotationMap, annotation, classTransformer.getTypeStore().get(annotation.annotationType()), declared);
}
public Class<T> getJavaClass() {
return rawType;
}
public Type[] getActualTypeArguments() {
return Arrays.copyOf(actualTypeArguments, actualTypeArguments.length);
}
public Set<Type> getInterfaceClosure() {
Set<Type> interfaces = new HashSet<Type>();
for (Type t : getTypeClosure()) {
if (Reflections.getRawType(t).isInterface()) {
interfaces.add(t);
}
}
return WeldCollections.immutableSetView(interfaces);
}
public abstract S getDelegate();
public boolean isParameterizedType() {
return rawType.getTypeParameters().length > 0;
}
public boolean isPrimitive() {
return getJavaClass().isPrimitive();
}
public Type getBaseType() {
return delegate.getBaseType();
}
public Set<Type> getTypeClosure() {
return delegate.getTypeClosure();
}
public Set<Annotation> getAnnotations() {
return annotations;
}
public Set<Annotation> getMetaAnnotations(Class<? extends Annotation> metaAnnotationType) {
return ImmutableSet.copyOf(metaAnnotationMap.get(metaAnnotationType));
}
@Deprecated
public Set<Annotation> getQualifiers() {
Set<Annotation> qualifiers = getMetaAnnotations(Qualifier.class);
if (qualifiers.size() > 0) {
return WeldCollections.immutableSetView(qualifiers);
} else {
return DEFAULT_QUALIFIERS;
}
}
@Deprecated
public Annotation[] getBindingsAsArray() {
return getQualifiers().toArray(EMPTY_ANNOTATIONS);
}
public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
return annotationType.cast(annotationMap.get(annotationType));
}
public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
return annotationMap.containsKey(annotationType);
}
Map<Class<? extends Annotation>, Annotation> getAnnotationMap() {
return annotationMap;
}
}