com.mobgen.halo.android.content.generated.HaloContentDatabaseProcessor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of halo-content-processor Show documentation
Show all versions of halo-content-processor Show documentation
Processor to generate compile time information that allows us to perform queries on sync
package com.mobgen.halo.android.content.generated;
import com.google.auto.service.AutoService;
import com.mobgen.halo.android.content.annotations.HaloConstructor;
import com.mobgen.halo.android.content.annotations.HaloField;
import com.mobgen.halo.android.content.annotations.HaloQueries;
import com.mobgen.halo.android.content.annotations.HaloQuery;
import com.mobgen.halo.android.content.annotations.HaloSearchable;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeSpec;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.JavaFileObject;
import static javax.lang.model.element.ElementKind.FIELD;
@AutoService(Processor.class)
@SupportedAnnotationTypes({"com.mobgen.halo.android.content.annotations.HaloQuery",
"com.mobgen.halo.android.content.annotations.HaloQueries",
"com.mobgen.halo.android.content.annotations.HaloField",
"com.mobgen.halo.android.content.annotations.HaloSearchable",
"com.mobgen.halo.android.content.annotations.HaloConstructor"})
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class HaloContentDatabaseProcessor extends AbstractProcessor {
private Types typeUtils;
private Elements elementUtils;
private Filer filer;
private Messager messager;
private List databaseTables = new ArrayList();
private List databaseVersion = new ArrayList<>();
private List constructorElements = new ArrayList<>();
private List queriesElments = new ArrayList<>();
private HashMap> indexableFields = new HashMap<>();
//CONSTANTS
private String PACKAGE_GENERATED = "com.mobgen.halo.android.app.generated";
private String CLASS_NAME_GENERATED = "com.mobgen.halo.android.app.generated.";
//classes
private ClassName halo = ClassName.get("com.mobgen.halo.android.sdk.api","Halo");
private ClassName haloPulgin = ClassName.get("com.mobgen.halo.android.sdk.api","HaloPluginApi");
private ClassName thisClass = ClassName.get(PACKAGE_GENERATED,"HaloContentQueryApi");
private ClassName keepClass = ClassName.get("android.support.annotation", "Keep");
private ClassName dateClass = ClassName.get("java.util","Date");
private ClassName tableAnnotationClass = ClassName.get("com.mobgen.halo.android.framework.storage.database.dsl.annotations", "Table");
private ClassName tableClass = ClassName.get(" com.mobgen.halo.android.framework.storage.database.dsl", "HaloTable");
private ClassName sqLite = ClassName.get("android.database.sqlite", "SQLiteDatabase");
private ClassName columnClass = ClassName.get("com.mobgen.halo.android.framework.storage.database.dsl.annotations", "Column");
private ClassName generatedHaloDatabase = ClassName.get("com.mobgen.halo.android.content.generated", "GeneratedHaloDatabase");
private ClassName createQuery = ClassName.get("com.mobgen.halo.android.framework.storage.database.dsl.queries", "Create");
private ClassName selectQuery = ClassName.get("com.mobgen.halo.android.framework.storage.database.dsl.queries", "Select");
private ClassName dropQuery = ClassName.get("com.mobgen.halo.android.framework.storage.database.dsl.queries", "Drop");
private ClassName contentValues = ClassName.get("android.content", "ContentValues");
private ClassName contentSelectorFactory = ClassName.get("com.mobgen.halo.android.content.selectors","HaloContentSelectorFactory");
private ClassName cursor = ClassName.get("android.database","Cursor");
private ClassName paginated = ClassName.get("com.mobgen.halo.android.content.models","Paginated");
private ClassName generatedContentQueriesInteractorInstance = ClassName.get("com.mobgen.halo.android.content.generated","GeneratedContentQueriesInteractor");
private ClassName generatedContentQueriesRepositoryInstance = ClassName.get("com.mobgen.halo.android.content.generated","GeneratedContentQueriesRepository");
private ClassName generatedContentQueriesLocalDataSource = ClassName.get("com.mobgen.halo.android.content.generated","GeneratedContentQueriesLocalDataSource");
private ClassName cursor2ContentInstanceGeneratedModelConverter = ClassName.get("com.mobgen.halo.android.content.generated","Cursor2ContentInstanceGeneratedModelConverter");
private ClassName cursor2GeneratedModelClassConverterFactory = ClassName.get("com.mobgen.halo.android.content.generated","Cursor2GeneratedModelClassConverterFactory");
private ClassName storageData = ClassName.get("com.mobgen.halo.android.framework.toolbox.data","Data");
private ClassName checkResult = ClassName.get("android.support.annotation","CheckResult");
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
typeUtils = processingEnv.getTypeUtils();
elementUtils = processingEnv.getElementUtils();
filer = processingEnv.getFiler();
messager = processingEnv.getMessager();
}
@Override
public Set getSupportedAnnotationTypes() {
Set annotataions = new LinkedHashSet();
annotataions.add(HaloQuery.class.getCanonicalName());
annotataions.add(HaloQueries.class.getCanonicalName());
annotataions.add(HaloField.class.getCanonicalName());
annotataions.add(HaloSearchable.class.getCanonicalName());
annotataions.add(HaloConstructor.class.getCanonicalName());
return annotataions;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
@Override
public boolean process(Set extends TypeElement> set, RoundEnvironment roundEnvironment) {
for (Element query : roundEnvironment.getElementsAnnotatedWith(HaloQueries.class)) {
queriesElments.add(query);
}
generateHaloQueryClass();
//add all constructor to dabase
for (Element constructor : roundEnvironment.getElementsAnnotatedWith(HaloConstructor.class)) {
constructorElements.add(constructor);
}
//add all annotated query elements
int haloConstructorIndex = 0;
for (Element element : roundEnvironment.getElementsAnnotatedWith(HaloSearchable.class)) {
String haloTableName = generateHaloSearchableClass(element,constructorElements.get(haloConstructorIndex));
databaseTables.add(haloTableName);
//get index fields
List indexFields = new ArrayList<>();
for(Element encloseElements : element.getEnclosedElements()){
if(encloseElements.getAnnotation(HaloField.class)!=null && encloseElements.getAnnotation(HaloField.class).index()) {
indexFields.add(encloseElements.getAnnotation(HaloField.class).columnName());
}
}
indexableFields.put(haloTableName,indexFields);
databaseVersion.add(element.getAnnotation(HaloSearchable.class).version());
haloConstructorIndex++;
}
//generate version table and database generated model creation
if(databaseTables.size()>0) {
generateHaloContentVersionTable();
generateDatabaseMigration(roundEnvironment,1);
}
return true;
}
/**
* Generate Halo query class with all the HaloQuery annotation
*
*/
private void generateHaloQueryClass(){
String className = "HaloContentQueryApi";
TypeSpec.Builder contentQueryBuilder = TypeSpec.classBuilder(className);
contentQueryBuilder.addModifiers(Modifier.PUBLIC);
contentQueryBuilder.superclass(haloPulgin);
contentQueryBuilder.addJavadoc("This class was autogenerated to perfom queries.");
//prepare method
MethodSpec.Builder constructorBuilder = MethodSpec.constructorBuilder()
.addJavadoc("Internal private constructor for the halo plugin.")
.addModifiers(Modifier.PRIVATE)
.addParameter(halo,"halo")
.addStatement("super(halo)");
contentQueryBuilder.addMethod(constructorBuilder.build());
MethodSpec.Builder withMethod = MethodSpec.methodBuilder("with")
.addJavadoc("Creates the Content Query Api instance with the reference to a yet created HALO instance")
.addModifiers(Modifier.PUBLIC)
.addModifiers(Modifier.STATIC)
.addParameter(halo,"halo")
.returns(thisClass)
.addStatement("return new $T(halo)",thisClass);
contentQueryBuilder.addMethod(withMethod.build());
AnnotationSpec checkResultAnnontation = AnnotationSpec.builder(checkResult)
.addMember("suggest","\"You may want to call execute() to run the task\"")
.build();
//add all annotated query elements for all elements with halo queries
for(int w=0;w paramNames = new ArrayList<>();
//create the query method
for (int i = 0; i < query.length(); i++) {
if (query.charAt(i) == '@') {
i++;//skip { char
String param = query.substring(i + 1);
paramNames.add(param.substring(0, param.indexOf(":")));
methodBuilder.addParameter(resolveDataType(param.substring(param.indexOf(":") + 1, param.indexOf("}"))), param.substring(0, param.indexOf(":")));
query = query.replace("@{" + param.substring(0, param.indexOf("}") + 1), "?");
}
}
//return statement of the query method
methodBuilder.addStatement("String query = $S", query);
methodBuilder.addStatement("Object[] bindArgs = new Object[$L]", paramNames.size());
for (int j = 0; j < paramNames.size(); j++) {
methodBuilder.addStatement("bindArgs[$L]=$L", j, paramNames.get(j));
}
methodBuilder.returns(ParameterizedTypeName.get(contentSelectorFactory, ParameterizedTypeName.get(paginated, modelClass), cursor))
.addStatement("return new HaloContentSelectorFactory<>(\n" +
"\thalo(),\n" +
"\tnew $1T(new $2T(new $3T(halo().framework())),query,bindArgs),\n" +
"\tnew $4T($5T.class),\n" +
"\tnew $6T(halo().framework().parser()),\n" +
"\tnull,\n" +
"\t$7T.STORAGE_ONLY,\n" +
"\t\"generatedModelQuery with method $8L\")", generatedContentQueriesInteractorInstance, generatedContentQueriesRepositoryInstance,
generatedContentQueriesLocalDataSource, cursor2ContentInstanceGeneratedModelConverter,
modelClass, cursor2GeneratedModelClassConverterFactory, storageData, methodName);
MethodSpec queryDatabase = methodBuilder.build();
contentQueryBuilder.addMethod(queryDatabase);
}
}
TypeSpec contentQueryClass = contentQueryBuilder.build();
generatedJavaFile(className, contentQueryClass);
}
/**
* Create a class per model annotated with HaloSearchable annotation
* @param element Element to generate halo database table.
* @param constructorElement Constructor model annotation with column names.
* @return The database table name.
*/
private String generateHaloSearchableClass(Element element, Element constructorElement){
String className = "HaloTable$$" + element.getAnnotation(HaloSearchable.class).tableName();
String tableAnnotationName = element.getAnnotation(HaloSearchable.class).tableName();
TypeSpec.Builder tableClassBuilder = TypeSpec.classBuilder(className);
tableClassBuilder.addModifiers(Modifier.PUBLIC);
tableClassBuilder.addJavadoc("This class was autogenerated to perfom queries.");
AnnotationSpec tableAnnotation = AnnotationSpec.builder(tableAnnotationClass)
.addMember("value","$S",tableAnnotationName)
.build();
//create table
TypeSpec.Builder constructorBuilder = TypeSpec.interfaceBuilder(className)
.addJavadoc("Constructor of the class to create table")
.addSuperinterface(tableClass)
.addAnnotation(keepClass)
.addAnnotation(tableAnnotation)
.addModifiers(Modifier.PUBLIC);
//prepare all fields to convert to columns on halotable
int haloConstructorFieldIndex = 0;
for(int k=0;k indexFields = indexableFields.get(databaseTables.get(i));
for(int j=0;j