blob: f74e2bbdbb7284b423ce9332d50a3a2054b111d6 [file] [log] [blame]
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.appsearch.compiler;
import androidx.annotation.NonNull;
import com.google.auto.common.GeneratedAnnotationSpecs;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import java.io.File;
import java.io.IOException;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Modifier;
/**
* Generates java code for an {@link androidx.appsearch.app.AppSearchSchema} and a translator
* between the document class and a {@link androidx.appsearch.app.GenericDocument}.
*/
class CodeGenerator {
private final ProcessingEnvironment mEnv;
private final IntrospectionHelper mHelper;
private final DocumentModel mModel;
private final String mOutputPackage;
private final TypeSpec mOutputClass;
public static CodeGenerator generate(
@NonNull ProcessingEnvironment env, @NonNull DocumentModel model)
throws ProcessingException {
return new CodeGenerator(env, model);
}
private CodeGenerator(
@NonNull ProcessingEnvironment env, @NonNull DocumentModel model)
throws ProcessingException {
// Prepare constants needed for processing
mEnv = env;
mHelper = new IntrospectionHelper(env);
mModel = model;
// Perform the actual work of generating code
mOutputPackage = mEnv.getElementUtils().getPackageOf(mModel.getClassElement()).toString();
mOutputClass = createClass();
}
public void writeToFiler() throws IOException {
JavaFile.builder(mOutputPackage, mOutputClass).build().writeTo(mEnv.getFiler());
}
public void writeToFolder(@NonNull File folder) throws IOException {
JavaFile.builder(mOutputPackage, mOutputClass).build().writeTo(folder);
}
/**
* Creates factory class for any class annotated with
* {@link androidx.appsearch.annotation.Document}
* <p>Class Example 1:
* For a class Foo annotated with @Document, we will generated a
* $$__AppSearch__Foo.class under the output package.
* <p>Class Example 2:
* For an inner class Foo.Bar annotated with @Document, we will generated a
* $$__AppSearch__Foo$$__Bar.class under the output package.
*/
private TypeSpec createClass() throws ProcessingException {
// Gets the full name of target class.
String qualifiedName = mModel.getClassElement().getQualifiedName().toString();
String className = qualifiedName.substring(mOutputPackage.length() + 1);
ClassName genClassName = mHelper.getDocumentClassFactoryForClass(mOutputPackage, className);
TypeName genClassType = TypeName.get(mModel.getClassElement().asType());
TypeName factoryType = ParameterizedTypeName.get(
mHelper.getAppSearchClass("DocumentClassFactory"),
genClassType);
TypeSpec.Builder genClass = TypeSpec
.classBuilder(genClassName)
.addOriginatingElement(mModel.getClassElement())
.addModifiers(Modifier.PUBLIC)
.addSuperinterface(factoryType);
// Add the @Generated annotation to avoid static analysis running on these files
GeneratedAnnotationSpecs.generatedAnnotationSpec(
mEnv.getElementUtils(),
mEnv.getSourceVersion(),
AppSearchCompiler.class
).ifPresent(genClass::addAnnotation);
SchemaCodeGenerator.generate(mEnv, mModel, genClass);
ToGenericDocumentCodeGenerator.generate(mEnv, mModel, genClass);
FromGenericDocumentCodeGenerator.generate(mEnv, mModel, genClass);
return genClass.build();
}
}