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

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

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

import java.io.PrintWriter;

import javax.lang.model.type.DeclaredType;

public class FactoryMethodWriter {
  private final String indent;
  private final PrintWriter out;
  private final String name;
  private final DeclaredType typeMirror;
  private final String access;
  private final String annName;
  private final boolean inner;
  private final boolean repeatable;
  private final boolean meta;
  private final String prismShortName;
  private final String annShortName;

  FactoryMethodWriter(GenerateContext ctx, boolean inner) {
    this.indent = ctx.indent();
    this.out = ctx.out();
    this.name = ctx.name();
    this.prismShortName = Util.shortName(ctx.name());
    this.typeMirror = ctx.typeMirror();
    this.access = ctx.access();
    this.annName = ctx.annName();
    this.annShortName = ctx.getShortName();
    this.inner = inner;
    this.repeatable = Util.isRepeatable(typeMirror);
    this.meta = Util.isMeta(typeMirror);
  }

  void write() {
    if (!inner) {
      writeIsInstance();
      writeIsPresent();
      writeGetInstanceOn();
      writeGetOptionalOn();

      if (repeatable) {
        writeGetAllInstances();
      }
      if (meta) {
        writeGetAllOnMeta();
      }
    }
    writeGetInstance();
    writeGetOptional();
  }

  private void writeIsInstance() {
	out.format("%s  /** Returns true if the mirror is an instance of {@link %s @%s} is present on the element, else false.\n", indent, annName, annShortName);
    out.format("%s   *\n", indent);
    out.format("%s   * @param mirror mirror. \n", indent);
    out.format("%s   * @return true if prism is present. \n", indent);
    out.format("%s   */\n", indent);
    out.format("%s  %sstatic boolean isInstance(AnnotationMirror mirror) {\n", indent, access);
    out.format("%s    return getInstance(mirror) != null;\n", indent);
    out.format("%s  }\n\n", indent);
  }

  private void writeIsPresent() {
    // Is Present
    out.format("%s  /** Returns true if {@link %s @%s} is present on the element, else false.\n", indent, annName, annShortName);
    out.format("%s   *\n", indent);
    out.format("%s   * @param element element. \n", indent);
	out.format("%s   * @return true if annotation is present on the element. \n", indent);
    out.format("%s   */\n", indent);
    out.format("%s  %sstatic boolean isPresent(Element element) {\n", indent, access);
    out.format("%s    return getInstanceOn(element) != null;\n", indent);
    out.format("%s  }\n\n", indent);
  }

  private void writeGetInstanceOn() {
    // get single instance
    out.format("%s  /** Return a prism representing the {@link %s @%s} annotation present on the given element. \n", indent, annName, annShortName);
    out.format("%s   * similar to {@code element.getAnnotation(%s.class)} except that \n", indent, annShortName);
    out.format("%s   * an instance of this class rather than an instance of {@link %s @%s}\n", indent, annName, annShortName);
	out.format("%s   * is returned.\n", indent);
	out.format("%s   *\n", indent);
    out.format("%s   * @param element element. \n", indent);
	out.format("%s   * @return prism on element or null if no annotation is found. \n", indent);
    out.format("%s   */\n", indent);
    out.format("%s  %sstatic %s getInstanceOn(Element element) {\n", indent, access, name);
    out.format("%s    final var mirror = getMirror(element);\n", indent);
    out.format("%s    if (mirror == null) return null;\n", indent);
    out.format("%s    return getInstance(mirror);\n", indent);
    out.format("%s  }\n\n", indent);
  }

  void writeGetOptionalOn() {

    // getOptionalOn
    out.format("%s  /** Return a Optional representing a nullable {@link %s @%s} annotation on the given element. \n", indent, annName, annShortName, annName, annShortName);
    out.format("%s   * similar to {@code element.getAnnotation(%s.class)} except that \n", indent, annName);
    out.format("%s   * an Optional of this class rather than an instance of {@link %s}\n", indent, annName);
    out.format("%s   * is returned.\n", indent);
	out.format("%s   *\n", indent);
	out.format("%s   * @param element element. \n", indent);
	out.format("%s   * @return prism optional for element. \n", indent);
    out.format("%s   */\n", indent);
    out.format("%s  %sstatic Optional<%s> getOptionalOn(Element element) {\n", indent, access, name);
    out.format("%s    final var mirror = getMirror(element);\n", indent);
    out.format("%s    if (mirror == null) return Optional.empty();\n", indent);
    out.format("%s    return getOptional(mirror);\n", indent);
    out.format("%s  }\n\n", indent);
  }

  private void writeGetAllOnMeta() {

    out.format("%s  /** Return a list of prisms representing the {@link %s @%s} meta annotation on all the annotations on the given element. \n", indent, annName, annShortName);
    out.format("%s   * this method will recursively search all the annotations on the element. \n", indent);
	out.format("%s   *\n", indent);
	out.format("%s   * @param element element. \n", indent);
	out.format("%s   * @return list of prisms on the element's annotation. \n", indent);
    out.format("%s   */\n", indent);
    out.format("%s  %sstatic List<%s> getAllOnMetaAnnotations(Element element) {\n",indent, access, name);
    out.format("%s    if (element == null || element.getAnnotationMirrors().isEmpty()) return List.of();\n\n",indent);
    out.format("%s    //use a hashset to keep track of seen annotations \n", indent);
    out.format("%s    return getAllOnMetaAnnotations(element, new HashSet<>()).collect(toList());\n", indent);
    out.format("%s  }\n\n", indent);


    out.format("%s  /** Recursively search annotation elements for prisms.\n", indent);
    out.format("%s   * Uses a set to keep track of known annotations to avoid repeats/recursive loop. \n", indent);
	out.format("%s   *\n", indent);
    out.format("%s   * @param element element. \n", indent);
    out.format("%s   * @param seen set that tracks seen elements. \n", indent);
	out.format("%s   * @return stream of prisms on the element's annotation. \n", indent);
    out.format("%s   */\n", indent);
    out.format("%s  private static Stream<%s> getAllOnMetaAnnotations(Element element, Set seen) {\n",indent, name);
    out.format("%s    if (element == null || element.getAnnotationMirrors().isEmpty()) return Stream.of();\n\n",indent);
    out.format("%s    return element.getAnnotationMirrors().stream()\n", indent);
    out.format("%s      .map(AnnotationMirror::getAnnotationType)\n", indent);
    out.format("%s      //only search annotations \n", indent);
    out.format("%s      .filter(t -> seen.add(t.toString()))\n", indent);
    out.format("%s        .map(DeclaredType::asElement)\n", indent);
    out.format("%s        .flatMap(\n", indent);
    out.format("%s            e ->\n", indent);
    out.format("%s                Stream.concat(\n", indent);
    out.format("%s                    getAllOnMetaAnnotations(e, seen),\n", indent);
    out.format("%s                    getMirrors(element).map(%s::getInstance)));\n", indent, name);
    out.format("%s  }\n\n", indent);
  }

  private void writeGetAllInstances() {
    // get multiple instances
    out.format("%s  /** Return a list of prisms representing the {@link %s @%s} annotation on 'e'. \n",indent, annName, annShortName);
    out.format("%s   * similar to {@code e.getAnnotationsByType(%s.class)} except that \n", indent, annName);
    out.format("%s   * instances of this class rather than instances of {@link %s}\n", indent, annName);
    out.format("%s   * is returned.\n", indent);
	out.format("%s   *\n", indent);
    out.format("%s   * @param element element. \n", indent);
	out.format("%s   * @return list of prisms on the element. \n", indent);
    out.format("%s   */\n", indent);
    out.format("%s  %sstatic List<%s> getAllInstancesOn(Element element) {\n", indent, access, name);
    out.format("%s    return getMirrors(element)\n", indent);
    out.format("%s        .map(%s::getInstance)\n", indent, name);
    out.format("%s        .collect(toList());\n", indent);
    out.format("%s  }\n\n", indent);
  }

  private void writeGetInstance() {
    out.format("%s  /** Return a prism of the {@link %s @%s} annotation from an annotation mirror. \n", indent, annName, annShortName);
	out.format("%s   *\n", indent);
    out.format("%s   * @param mirror mirror. \n", indent);
  	out.format("%s   * @return prism for mirror or null if mirror is an incorrect type. \n", indent);
    out.format("%s   */\n", indent);
    out.format("%s  %sstatic %s getInstance(AnnotationMirror mirror) {\n", indent, inner ? "private " : access, name);
    out.format("%s    if (mirror == null || !PRISM_TYPE.equals(mirror.getAnnotationType().toString())) return null;\n\n", indent);
    out.format("%s    return new %s(mirror);\n", indent, name);
    out.format("%s  }\n\n", indent);
  }

  private void writeGetOptional() {
    // getOptional
    out.format("%s  /** Return an Optional representing a nullable {@link %s @%s} from an annotation mirror. \n", indent, name, prismShortName, annName, annShortName);
    out.format("%s   * similar to {@code e.getAnnotation(%s.class)} except that \n", indent, annName);
    out.format("%s   * an Optional of this class rather than an instance of {@link %s @%s}\n", indent, annName, annShortName);
    out.format("%s   * is returned.\n", indent);
	out.format("%s   *\n", indent);
    out.format("%s   * @param mirror mirror. \n", indent);
	out.format("%s   * @return prism optional for mirror. \n", indent);
    out.format("%s   */\n", indent);
    out.format("%s  %sstatic Optional<%s> getOptional(AnnotationMirror mirror) {\n", indent, inner ? "private " : access, name);
    out.format("%s    if (mirror == null || !PRISM_TYPE.equals(mirror.getAnnotationType().toString())) return Optional.empty();\n\n", indent);
    out.format("%s    return Optional.of(new %s(mirror));\n", indent, name);
    out.format("%s  }\n\n", indent);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy