Package com.antwerkz.critter

Source Code of com.antwerkz.critter.CriteriaBuilder$Field

package com.antwerkz.critter;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.QualifiedNameable;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;

import com.google.code.morphia.annotations.Embedded;
import com.google.code.morphia.annotations.Entity;
import com.google.code.morphia.annotations.NotSaved;
import com.google.code.morphia.annotations.Reference;
import com.google.code.morphia.annotations.Transient;
import freemarker.cache.ClassTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;

public class CriteriaBuilder extends AbstractProcessor {
  private ProcessingEnvironment env;

  @Override
  public SourceVersion getSupportedSourceVersion() {
    return SourceVersion.RELEASE_7;
  }

  @Override
  public Set<String> getSupportedOptions() {
    return Collections.singleton("outputDirectory");
  }

  @Override
  public Set<String> getSupportedAnnotationTypes() {
    return new HashSet<>(Arrays.asList(Entity.class.getName(), Embedded.class.getName()));
  }

  @Override
  public void init(final ProcessingEnvironment processingEnv) {
    env = processingEnv;
  }

  @Override
  public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    final TypeElement element = env.getElementUtils().getTypeElement(Entity.class.getName());
    if (annotations.contains(element)) {
      try {
        Configuration cfg = new Configuration();
        cfg.setObjectWrapper(new DefaultObjectWrapper());
        cfg.setTemplateLoader(new ClassTemplateLoader(getClass(), "/templates"));
        Template template = cfg.getTemplate("criteria.ftl");
        for (TypeElement typeElement : ElementFilter.typesIn(roundEnv.getElementsAnnotatedWith(Entity.class))) {
          generate(template, typeElement);
        }
        template = cfg.getTemplate("embedded.ftl");
        for (TypeElement typeElement : ElementFilter.typesIn(roundEnv.getElementsAnnotatedWith(Embedded.class))) {
          generate(template, typeElement);
        }
        return true;
      } catch (IOException | TemplateException e) {
        throw new RuntimeException(e.getMessage(), e);
      }
    } else {
      return false;
    }
  }

  private void generate(Template temp, TypeElement typeElement) throws TemplateException, IOException {
    String pkg = getPackageName(typeElement);
    String name = typeElement.getQualifiedName().toString().replace(pkg + ".", "");
    String enclosingElement = typeElement.getEnclosingElement().toString();
    if (name.indexOf('.') != -1) {
      // nested
      name = name.replace('.', '_');
    }
    TreeMap<String, Object> map = new TreeMap<>();
    map.put("name", name);
    map.put("package", pkg);
    map.put("fqcn", typeElement.getQualifiedName().toString());
    getFields(typeElement, map);
    File source = new File(getOutputDirectory(),
        String.format("%s/criteria/%sCriteria.java", pkg.replace('.', '/'), name));
    source.getParentFile().mkdirs();
    try (PrintWriter out = new PrintWriter(source)) {
      temp.process(map, out);
    }
  }

  private String getOutputDirectory() {
    String outputDirectory = env.getOptions().get("outputDirectory");
    return outputDirectory == null ? "src/main/java" : outputDirectory;
  }

  private void getFields(TypeElement typeElement, TreeMap<String, Object> map) {
    Set<Field> fields = new TreeSet<>();
    Set<Field> embeds = new TreeSet<>();
    Set<Field> references = new TreeSet<>();
    while (typeElement != null) {
      List<? extends Element> enclosedElements = typeElement.getEnclosedElements();
      for (Element enclosedElement : enclosedElements) {
        if (enclosedElement instanceof VariableElement) {
          VariableElement field = (VariableElement) enclosedElement;
          if (!field.getModifiers().contains(Modifier.STATIC)) {
            if (validField(field)) {
              fields.add(new Field(field.asType().toString(), field.getSimpleName().toString()));
            } else if (embedded(field)) {
              embeds.add(new Field(encodeEmbedName(field), field.getSimpleName().toString()));
            } else if (reference(field)) {
              references.add(new Field(field.asType().toString(), field.getSimpleName().toString()));
            }
          }

        }
      }
      TypeMirror superclass = typeElement.getSuperclass();
      typeElement = (TypeElement) env.getTypeUtils().asElement(superclass);
    }
    map.put("fields", fields);
    map.put("embeddeds", embeds);
    map.put("references", references);
  }

  private String encodeEmbedName(VariableElement field) {
    TypeMirror typeMirror = field.asType();
    String[] parts = typeMirror.toString().split("\\.");
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < parts.length; i++) {
      String part = parts[i];
      if (builder.length() != 0) {
        if (i == parts.length - 2) {
          builder.append(".criteria.");
        } else if (i == parts.length - 1) {
          builder.append("_");
        } else {
          builder.append(".");
        }
      }
      builder.append(part);
    }
    return builder.toString();
  }

  private String getPackageName(TypeElement typeElement) {
    QualifiedNameable enclosingElement = (QualifiedNameable) typeElement.getEnclosingElement();
    while (!(enclosingElement instanceof PackageElement)) {
      enclosingElement = (QualifiedNameable) enclosingElement.getEnclosingElement();
    }
    return enclosingElement.getQualifiedName().toString();
  }

  private boolean validField(VariableElement field) {
    Class[] types = {NotSaved.class, Transient.class, Embedded.class, Reference.class};
    for (Class type : types) {
      if (field.getAnnotation(type) != null) {
        return false;
      }
    }
    return true;
  }

  private boolean embedded(VariableElement field) {
    Set<Modifier> modifiers = field.getModifiers();
    return !modifiers.contains(Modifier.STATIC) && field.getAnnotation(Embedded.class) != null;
  }

  private boolean reference(VariableElement field) {
    Set<Modifier> modifiers = field.getModifiers();
    return !modifiers.contains(Modifier.STATIC) && field.getAnnotation(Reference.class) != null;
  }

  public static class Field implements Comparable<Field> {
    public String name;

    public String type;

    public Field(String type, String name) {
      this.name = name;
      this.type = type;
    }

    public String getName() {
      return name;
    }

    public String getType() {
      return type;
    }

    @Override
    public String toString() {
      final StringBuilder sb = new StringBuilder();
      sb.append("Field {");
      sb.append("name='").append(name).append('\'');
      sb.append(", type='").append(type).append('\'');
      sb.append('}');
      return sb.toString();
    }

    @Override
    public int compareTo(Field o) {
      return name.compareTo(o.name);
    }
  }
}
TOP

Related Classes of com.antwerkz.critter.CriteriaBuilder$Field

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.