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

io.ebean.querybean.generator.SimpleQueryBeanWriter Maven / Gradle / Ivy

There is a newer version: 15.8.1
Show newest version
package io.ebean.querybean.generator;


import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.tools.JavaFileObject;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import static io.ebean.querybean.generator.Constants.AT_GENERATED;
import static io.ebean.querybean.generator.Constants.AT_TYPEQUERYBEAN;
import static io.ebean.querybean.generator.Constants.DATABASE;
import static io.ebean.querybean.generator.Constants.DB;
import static io.ebean.querybean.generator.Constants.FETCHGROUP;
import static io.ebean.querybean.generator.Constants.QUERY;
import static io.ebean.querybean.generator.Constants.TQASSOCBEAN;
import static io.ebean.querybean.generator.Constants.TQPROPERTY;
import static io.ebean.querybean.generator.Constants.TQROOTBEAN;
import static io.ebean.querybean.generator.Constants.TYPEQUERYBEAN;

/**
 * A simple implementation that generates and writes query beans.
 */
class SimpleQueryBeanWriter {

  private final Set importTypes = new TreeSet<>();

  private final List properties = new ArrayList<>();

  private final TypeElement element;

  private final ProcessingContext processingContext;

  private final String dbName;
  private final String beanFullName;
  private final boolean isEntity;
  private boolean writingAssocBean;

  private String destPackage;
  private String origDestPackage;

  private String shortName;
  private String origShortName;
  private Append writer;

  SimpleQueryBeanWriter(TypeElement element, ProcessingContext processingContext) {
    this.element = element;
    this.processingContext = processingContext;
    this.beanFullName = element.getQualifiedName().toString();
    this.destPackage = derivePackage(beanFullName) + ".query";
    this.shortName = deriveShortName(beanFullName);
    this.isEntity = processingContext.isEntity(element);
    this.dbName = findDbName();
  }

  private String findDbName() {
    return processingContext.findDbName(element);
  }

  private boolean isEntity() {
    return isEntity;
  }

  private void gatherPropertyDetails() {
    final String generated = processingContext.getGeneratedAnnotation();
    if (generated != null) {
      importTypes.add(generated);
    }
    importTypes.add(beanFullName);
    importTypes.add(TQROOTBEAN);
    importTypes.add(TYPEQUERYBEAN);
    importTypes.add(DATABASE);
    importTypes.add(FETCHGROUP);
    importTypes.add(QUERY);
    if (dbName != null) {
      importTypes.add(DB);
    }
    addClassProperties();
  }

  /**
   * Recursively add properties from the inheritance hierarchy.
   * 

* Includes properties from mapped super classes and usual inheritance. *

*/ private void addClassProperties() { for (VariableElement field : processingContext.allFields(element)) { PropertyType type = processingContext.getPropertyType(field); if (type != null) { type.addImports(importTypes); properties.add(new PropertyMeta(field.getSimpleName().toString(), type)); } } } /** * Write the type query bean (root bean). */ void writeRootBean() throws IOException { gatherPropertyDetails(); if (isEntity()) { writer = new Append(createFileWriter()); writePackage(); writeImports(); writeClass(); writeAlias(); writeFields(); writeConstructors(); writeStaticAliasClass(); writeClassEnd(); writer.close(); } } /** * Write the type query assoc bean. */ void writeAssocBean() throws IOException { writingAssocBean = true; origDestPackage = destPackage; destPackage = destPackage + ".assoc"; origShortName = shortName; shortName = "Assoc" + shortName; prepareAssocBeanImports(); writer = new Append(createFileWriter()); writePackage(); writeImports(); writeClass(); writeFields(); writeConstructors(); writeClassEnd(); writer.close(); } /** * Prepare the imports for writing assoc bean. */ private void prepareAssocBeanImports() { importTypes.remove(DB); importTypes.remove(TQROOTBEAN); importTypes.remove(DATABASE); importTypes.remove(FETCHGROUP); importTypes.remove(QUERY); importTypes.add(TQASSOCBEAN); if (isEntity()) { importTypes.add(TQPROPERTY); importTypes.add(origDestPackage + ".Q" + origShortName); } // remove imports for the same package Iterator importsIterator = importTypes.iterator(); String checkImportStart = destPackage + ".QAssoc"; while (importsIterator.hasNext()) { String importType = importsIterator.next(); if (importType.startsWith(checkImportStart)) { importsIterator.remove(); } } } /** * Write constructors. */ private void writeConstructors() { if (writingAssocBean) { writeAssocBeanFetch(); writeAssocBeanConstructor(); } else { writeRootBeanConstructor(); } } /** * Write the constructors for 'root' type query bean. */ private void writeRootBeanConstructor() { writer.eol(); writer.append(" /**").eol(); writer.append(" * Return a query bean used to build a FetchGroup.").eol(); writer.append(" */").eol(); writer.append(" public static Q%s forFetchGroup() {", shortName).eol(); writer.append(" return new Q%s(FetchGroup.queryFor(%s.class));", shortName, shortName).eol(); writer.append(" }").eol(); writer.eol(); writer.eol(); writer.append(" /**").eol(); writer.append(" * Construct with a given Database.").eol(); writer.append(" */").eol(); writer.append(" public Q%s(Database server) {", shortName).eol(); writer.append(" super(%s.class, server);", shortName).eol(); writer.append(" }").eol(); writer.eol(); String name = (dbName == null) ? "default" : dbName; writer.append(" /**").eol(); writer.append(" * Construct using the %s Database.", name).eol(); writer.append(" */").eol(); writer.append(" public Q%s() {", shortName).eol(); if (dbName == null) { writer.append(" super(%s.class);", shortName).eol(); } else { writer.append(" super(%s.class, DB.byName(\"%s\"));", shortName, dbName).eol(); } writer.append(" }").eol(); writer.eol(); writer.append(" /**").eol(); writer.append(" * Construct for Alias.").eol(); writer.append(" */").eol(); writer.append(" private Q%s(boolean dummy) {", shortName).eol(); writer.append(" super(dummy);").eol(); writer.append(" }").eol(); writer.eol(); writer.append(" /**").eol(); writer.append(" * Private constructor for FetchGroup building.").eol(); writer.append(" */").eol(); writer.append(" private Q%s(Query<%s> fetchGroupQuery) {", shortName, shortName).eol(); writer.append(" super(fetchGroupQuery);").eol(); writer.append(" }").eol(); } private void writeAssocBeanFetch() { if (isEntity()) { writeAssocBeanFetch("", "Eagerly fetch this association loading the specified properties."); writeAssocBeanFetch("Query", "Eagerly fetch this association using a 'query join' loading the specified properties."); writeAssocBeanFetch("Cache", "Eagerly fetch this association using L2 cache."); writeAssocBeanFetch("Lazy", "Use lazy loading for this association loading the specified properties."); } } private void writeAssocBeanFetch(String fetchType, String comment) { writer.append(" /**").eol(); writer.append(" * ").append(comment).eol(); writer.append(" */").eol(); writer.append(" @SafeVarargs @SuppressWarnings(\"varargs\")").eol(); writer.append(" public final R fetch%s(TQProperty... properties) {", fetchType, origShortName).eol(); writer.append(" return fetch%sProperties(properties);", fetchType).eol(); writer.append(" }").eol(); writer.eol(); } /** * Write constructor for 'assoc' type query bean. */ private void writeAssocBeanConstructor() { writer.append(" public Q%s(String name, R root) {", shortName).eol(); writer.append(" super(name, root);").eol(); writer.append(" }").eol().eol(); writer.append(" public Q%s(String name, R root, String prefix) {", shortName).eol(); writer.append(" super(name, root, prefix);").eol(); writer.append(" }").eol(); } /** * Write all the fields. */ private void writeFields() { for (PropertyMeta property : properties) { property.writeFieldDefn(writer, shortName, writingAssocBean); writer.eol(); } writer.eol(); } /** * Write the class definition. */ private void writeClass() { if (writingAssocBean) { writer.append("/**").eol(); writer.append(" * Association query bean for %s.", shortName).eol(); writer.append(" * ").eol(); writer.append(" * THIS IS A GENERATED OBJECT, DO NOT MODIFY THIS CLASS.").eol(); writer.append(" */").eol(); if (processingContext.isGeneratedAvailable()) { writer.append(AT_GENERATED).eol(); } writer.append(AT_TYPEQUERYBEAN).eol(); writer.append("public class Q%s extends TQAssocBean<%s,R> {", shortName, origShortName).eol(); } else { writer.append("/**").eol(); writer.append(" * Query bean for %s.", shortName).eol(); writer.append(" * ").eol(); writer.append(" * THIS IS A GENERATED OBJECT, DO NOT MODIFY THIS CLASS.").eol(); writer.append(" */").eol(); if (processingContext.isGeneratedAvailable()) { writer.append(AT_GENERATED).eol(); } writer.append(AT_TYPEQUERYBEAN).eol(); writer.append("public class Q%s extends TQRootBean<%1$s,Q%1$s> {", shortName).eol(); } writer.eol(); } private void writeAlias() { if (!writingAssocBean) { writer.append(" private static final Q%s _alias = new Q%1$s(true);", shortName).eol().eol(); writer.append(" /**").eol(); writer.append(" * Return the shared 'Alias' instance used to provide properties to ").eol(); writer.append(" * select() and fetch() ").eol(); writer.append(" */").eol(); writer.append(" public static Q%s alias() {", shortName).eol(); writer.append(" return _alias;").eol(); writer.append(" }").eol(); writer.eol(); } } private void writeStaticAliasClass() { writer.eol(); writer.append(" /**").eol(); writer.append(" * Provides static properties to use in select() and fetch() ").eol(); writer.append(" * clauses of a query. Typically referenced via static imports. ").eol(); writer.append(" */").eol(); writer.append(" public static class Alias {").eol(); for (PropertyMeta property : properties) { property.writeFieldAliasDefn(writer, shortName); writer.eol(); } writer.append(" }").eol(); } private void writeClassEnd() { writer.append("}").eol(); } /** * Write all the imports. */ private void writeImports() { for (String importType : importTypes) { writer.append("import %s;", importType).eol(); } writer.eol(); } private void writePackage() { writer.append("package %s;", destPackage).eol().eol(); } private Writer createFileWriter() throws IOException { JavaFileObject jfo = processingContext.createWriter(destPackage + "." + "Q" + shortName, element); return jfo.openWriter(); } private String derivePackage(String name) { int pos = name.lastIndexOf('.'); if (pos == -1) { return ""; } return name.substring(0, pos); } private String deriveShortName(String name) { int pos = name.lastIndexOf('.'); if (pos == -1) { return name; } return name.substring(pos + 1); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy