io.neba.core.util.Annotations Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of io.neba.neba-core Show documentation
Show all versions of io.neba.neba-core Show documentation
Contains the entire NEBA core implementation, i.e. the framework that interprets the
NEBA API annotations and provides implementations for the service and lifecycle callback
interfaces provided in the NEBA API. This package must not export anything as
its implementation details are entirely private.
/**
* Copyright 2013 the original author or authors.
*
* 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 io.neba.core.util;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.util.*;
import static io.neba.core.util.ReadOnlyIterator.readOnly;
import static java.util.Arrays.asList;
import static java.util.Collections.addAll;
/**
* Supports meta-annotations by looking up annotations in the transitive
* hull (annotations and their annotations, called meta-annotations) of a given
* {@link java.lang.reflect.AnnotatedElement}.
*
* @author Olaf Otto
*/
public class Annotations implements Iterable {
private final AnnotatedElement annotatedElement;
private Map, Annotation> annotations = null;
/**
* @param annotatedElement must not be null
* @return never null.
*/
public static Annotations annotations(AnnotatedElement annotatedElement) {
if (annotatedElement == null) {
throw new IllegalArgumentException("Method argument annotatedElement must not be null.");
}
return new Annotations(annotatedElement);
}
/**
* @param annotatedElement must not be null
.
*/
public Annotations(AnnotatedElement annotatedElement) {
if (annotatedElement == null) {
throw new IllegalArgumentException("Constructor parameter annotatedElement must not be null.");
}
this.annotatedElement = annotatedElement;
}
/**
* @param type must not be null
.
* @return whether the given element or any of its meta-annotations is annotated with the given annotation type.
*/
public boolean contains(Class extends Annotation> type) {
if (type == null) {
throw new IllegalArgumentException("Method argument type must not be null.");
}
return getAnnotationMap().get(type) != null;
}
/**
* @param name must not be null
.
* @return whether the given type name matches one of the present annotations
*/
public boolean containsName(String name) {
if (name == null) {
throw new IllegalArgumentException("Method argument name must not be null.");
}
for (Class extends Annotation> annotationType : getAnnotationMap().keySet()) {
if (annotationType.getName().equals(name)) {
return true;
}
}
return false;
}
/**
* @param type must not be null
.
* @return the annotation if present on the given element or any meta-annotation thereof, or null
.
*/
@SuppressWarnings("unchecked")
public T get(Class type) {
if (type == null) {
throw new IllegalArgumentException("Method argument type must not be null.");
}
return (T) getAnnotationMap().get(type);
}
/**
* @return all annotations and meta-annotations present on the element. Never null
but rather an empty map.
*/
private Map, Annotation> getAnnotationMap() {
if (this.annotations == null) {
// We do not care about calculating the same thing twice in case of concurrent access.
HashMap, Annotation> annotations = new HashMap<>();
Queue queue = new LinkedList<>(asList(this.annotatedElement.getAnnotations()));
while (!queue.isEmpty()) {
Annotation annotation = queue.remove();
// Prevent lookup loops (@A annotated with @B annotated with @A ...)
if (!annotations.containsKey(annotation.annotationType())) {
annotations.put(annotation.annotationType(), annotation);
addAll(queue, annotation.annotationType().getAnnotations());
}
}
this.annotations = annotations;
}
return this.annotations;
}
@Override
public Iterator iterator() {
return readOnly(getAnnotationMap().values().iterator());
}
public Map, Annotation> getAnnotations() {
return new HashMap<>(getAnnotationMap());
}
}