/** * Copyright 2011-2017 Asakusa Framework Team. * * 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 com.asakusafw.operator.util; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import javax.lang.model.util.Elements; import com.asakusafw.operator.CompileEnvironment; /** * Common helper methods about annotations. */ public final class AnnotationHelper { private AnnotationHelper() { return; } /** * Returns the annotation presented in the target element. * @param environment current environment * @param annotationDecl target annotation type element * @param element target annotated element * @return target annotation (includes inherited annotations), or {@code null} if does not present * @throws IllegalArgumentException if some parameters were {@code null} */ public static AnnotationMirror findAnnotation( CompileEnvironment environment, TypeElement annotationDecl, Element element) { Objects.requireNonNull(environment, "environment must not be null"); //$NON-NLS-1$ Objects.requireNonNull(annotationDecl, "annotationDecl must not be null"); //$NON-NLS-1$ Objects.requireNonNull(element, "element must not be null"); //$NON-NLS-1$ List<? extends AnnotationMirror> annotations = environment.getProcessingEnvironment().getElementUtils().getAllAnnotationMirrors(element); for (AnnotationMirror annotation : annotations) { TypeElement type = (TypeElement) annotation.getAnnotationType().asElement(); if (type.equals(annotationDecl)) { return annotation; } } return null; } /** * Returns the name-value pairs in annotation. * @param environment current environment * @param annotation target annotation * @return element name and its value pairs * @throws IllegalArgumentException if some parameters were {@code null} */ public static Map<String, AnnotationValue> getValues(CompileEnvironment environment, AnnotationMirror annotation) { Objects.requireNonNull(environment, "environment must not be null"); //$NON-NLS-1$ Objects.requireNonNull(annotation, "annotation must not be null"); //$NON-NLS-1$ Elements elements = environment.getProcessingEnvironment().getElementUtils(); Map<? extends ExecutableElement, ? extends AnnotationValue> map = elements.getElementValuesWithDefaults(annotation); Map<String, AnnotationValue> results = new HashMap<>(); for (Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : map.entrySet()) { results.put(entry.getKey().getSimpleName().toString(), entry.getValue()); } return results; } /** * Returns the value of annotation member. * @param environment current environment * @param annotation target annotation * @param name target annotation member name * @return the related value (may be default value), or {@code null} if the member is not declared * @throws IllegalArgumentException if some parameters were {@code null} */ public static AnnotationValue getValue( CompileEnvironment environment, AnnotationMirror annotation, String name) { Objects.requireNonNull(environment, "environment must not be null"); //$NON-NLS-1$ Objects.requireNonNull(annotation, "annotation must not be null"); //$NON-NLS-1$ Objects.requireNonNull(name, "name must not be null"); //$NON-NLS-1$ Map<? extends ExecutableElement, ? extends AnnotationValue> values = environment.getProcessingEnvironment().getElementUtils().getElementValuesWithDefaults(annotation); for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : values.entrySet()) { if (entry.getKey().getSimpleName().contentEquals(name)) { return entry.getValue(); } } return null; } /** * Converts the value into component list. * If target value does not represents a list, this returns just consists of the target value. * @param environment current environment * @param value target annotation value * @return the component list * @throws IllegalArgumentException if some parameters were {@code null} */ public static List<AnnotationValue> toValueList(CompileEnvironment environment, AnnotationValue value) { Objects.requireNonNull(environment, "environment must not be null"); //$NON-NLS-1$ Objects.requireNonNull(value, "value must not be null"); //$NON-NLS-1$ Object component = value.getValue(); if (component instanceof List<?>) { List<AnnotationValue> results = new ArrayList<>(); for (Object componentValue : (Iterable<?>) component) { results.add((AnnotationValue) componentValue); } return results; } else { return Collections.singletonList(value); } } /** * Extracts component values in the target list. * @param <T> component value type * @param environment current environment * @param componentValueType target value type, the returning list only includes values with this type * @param values target annotation values * @return component values in the list * @throws IllegalArgumentException if some parameters were {@code null} */ public static <T> List<T> extractList( CompileEnvironment environment, Class<T> componentValueType, List<? extends AnnotationValue> values) { Objects.requireNonNull(environment, "environment must not be null"); //$NON-NLS-1$ Objects.requireNonNull(componentValueType, "componentValueType must not be null"); //$NON-NLS-1$ Objects.requireNonNull(values, "values must not be null"); //$NON-NLS-1$ List<T> results = new ArrayList<>(); for (AnnotationValue componentHolder : values) { Object componentValue = componentHolder.getValue(); if (componentValueType.isInstance(componentValue)) { results.add(componentValueType.cast(componentValue)); } } return results; } }