All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.avaje.prism.internal.TargetPrism Maven / Gradle / Ivy

The newest version!
package io.avaje.prism.internal;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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.element.VariableElement;
import javax.lang.model.util.ElementFilter;

/** A Prism representing an {@code @java.lang.annotation.Target} annotation. */
class TargetPrism {
  /** store prism value of value */
  private final List _value;

  public static final String PRISM_TYPE = "java.lang.annotation.Target";

  /**
   * An instance of the Values inner class whose methods return the AnnotationValues used to build
   * this prism. Primarily intended to support using Messager.
   */
  final Values values;

  /**
   * Return a prism representing the {@code @java.lang.annotation.Target} annotation on 'e'. similar
   * to {@code element.getAnnotation(java.lang.annotation.Target.class)} except that an instance of
   * this class rather than an instance of {@code java.lang.annotation.Target} is returned.
   */
  static TargetPrism getInstanceOn(Element element) {
    final var mirror = getMirror(PRISM_TYPE, element);
    if (mirror == null) return null;
    return getInstance(mirror);
  }

  /**
   * Return a prism of the {@code @java.lang.annotation.Target} annotation whose mirror is mirror.
   */
  static TargetPrism getInstance(AnnotationMirror mirror) {
    if (mirror == null || !PRISM_TYPE.equals(mirror.getAnnotationType().toString())) return null;

    return new TargetPrism(mirror);
  }

  private TargetPrism(AnnotationMirror mirror) {
    for (final ExecutableElement key : mirror.getElementValues().keySet()) {
      memberValues.put(key.getSimpleName().toString(), mirror.getElementValues().get(key));
    }
    for (final ExecutableElement member :
        ElementFilter.methodsIn(mirror.getAnnotationType().asElement().getEnclosedElements())) {
      defaults.put(member.getSimpleName().toString(), member.getDefaultValue());
    }
    final List valueMirrors = getArrayValues("value", VariableElement.class);
    _value = new ArrayList<>(valueMirrors.size());
    for (final VariableElement valueMirror : valueMirrors) {
      _value.add(valueMirror.getSimpleName().toString());
    }
    this.values = new Values(memberValues);
    this.mirror = mirror;
    this.isValid = valid;
  }

  /**
   * Returns a List representing the value of the {@code value()} member of the Annotation.
   *
   * @see java.lang.annotation.Target#value()
   */
  List value() {
    return _value;
  }

  /**
   * Determine whether the underlying AnnotationMirror has no errors. True if the underlying
   * AnnotationMirror has no errors. When true is returned, none of the methods will return null.
   * When false is returned, a least one member will either return null, or another prism that is
   * not valid.
   */
  final boolean isValid;

  /**
   * The underlying AnnotationMirror of the annotation represented by this Prism. Primarily intended
   * to support using Messager.
   */
  final AnnotationMirror mirror;
  /**
   * A class whose members corespond to those of java.lang.annotation.Target but which each return
   * the AnnotationValue corresponding to that member in the model of the annotations. Returns null
   * for defaulted members. Used for Messager, so default values are not useful.
   */
  static class Values {
    private final Map values;

    private Values(Map values) {
      this.values = values;
    }
    /**
     * Return the AnnotationValue corresponding to the value() member of the annotation, or null
     * when the default value is implied.
     */
    AnnotationValue value() {
      return values.get("value");
    }
  }

  private final Map defaults = new HashMap<>(10);
  private final Map memberValues = new HashMap<>(10);
  private boolean valid = true;

  private  List getArrayValues(String name, final Class clazz) {
    final List result = TargetPrism.getArrayValues(memberValues, defaults, name, clazz);
    if (result == null) valid = false;
    return result;
  }

  private static AnnotationMirror getMirror(String fqn, Element target) {
    for (final AnnotationMirror m : target.getAnnotationMirrors()) {
      final CharSequence mfqn =
          ((TypeElement) m.getAnnotationType().asElement()).getQualifiedName();
      if (fqn.contentEquals(mfqn)) return m;
    }
    return null;
  }

  private static  List getArrayValues(
      Map memberValues,
      Map defaults,
      String name,
      final Class clazz) {
    var av = memberValues.get(name);
    if (av == null) av = defaults.get(name);
    if (av == null) {
      return java.util.List.of();
    }
    if (av.getValue() instanceof List) {
      final List result = new ArrayList<>();
      for (final AnnotationValue v : getValueAsList(av)) {
        if (clazz.isInstance(v.getValue())) {
          result.add(clazz.cast(v.getValue()));
        } else {
          return List.of();
        }
      }
      return result;
    } else {
      return List.of();
    }
  }

  @SuppressWarnings("unchecked")
  private static List getValueAsList(AnnotationValue av) {
    return (List) av.getValue();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy