package pocketknife.internal.codegen;
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.JavaFile;
import pocketknife.BindArgument;
import pocketknife.BundleBuilder;
import pocketknife.FragmentBuilder;
import pocketknife.BindExtra;
import pocketknife.IntentBuilder;
import pocketknife.SaveState;
import pocketknife.internal.codegen.builder.BuilderGenerator;
import pocketknife.internal.codegen.builder.BuilderProcessor;
import pocketknife.internal.codegen.binding.BundleBindingAdapterGenerator;
import pocketknife.internal.codegen.binding.BundleBindingProcessor;
import pocketknife.internal.codegen.binding.IntentBindingAdapterGenerator;
import pocketknife.internal.codegen.binding.IntentBindingProcessor;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
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.TypeElement;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Map;
import java.util.Set;
import static javax.tools.Diagnostic.Kind.ERROR;
public class PocketKnifeProcessor extends AbstractProcessor {
private Messager messager;
private Filer filer;
private BundleBindingProcessor bundleBindingProcessor;
private IntentBindingProcessor intentBindingProcessor;
private BuilderProcessor builderProcessor;
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
messager = processingEnv.getMessager();
filer = processingEnv.getFiler();
Elements elements = processingEnv.getElementUtils();
Types types = processingEnv.getTypeUtils();
bundleBindingProcessor = new BundleBindingProcessor(messager, elements, types);
intentBindingProcessor = new IntentBindingProcessor(messager, elements, types);
builderProcessor = new BuilderProcessor(messager, elements, types);
}
@Override
public Set<String> getSupportedAnnotationTypes() {
return ImmutableSet.of(
SaveState.class.getCanonicalName(),
BindArgument.class.getCanonicalName(),
BindExtra.class.getCanonicalName(),
IntentBuilder.class.getCanonicalName(),
BundleBuilder.class.getCanonicalName(),
FragmentBuilder.class.getCanonicalName()
);
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
// Bundle bindings
Map<TypeElement, BundleBindingAdapterGenerator> bundleBindingMap = bundleBindingProcessor.findAndParseTargets(roundEnv);
for (Map.Entry<TypeElement, BundleBindingAdapterGenerator> entry : bundleBindingMap.entrySet()) {
TypeElement typeElement = entry.getKey();
BundleBindingAdapterGenerator generator = entry.getValue();
try {
JavaFile javaFile = generator.generate();
javaFile.writeTo(filer);
} catch (Exception e) {
error(typeElement, "Unable to write adapter for type %s: %s", typeElement, e.getMessage());
}
}
// Intent bindings
Map<TypeElement, IntentBindingAdapterGenerator> intentBindingMap = intentBindingProcessor.findAndParseTargets(roundEnv);
for (Map.Entry<TypeElement, IntentBindingAdapterGenerator> entry : intentBindingMap.entrySet()) {
TypeElement typeElement = entry.getKey();
IntentBindingAdapterGenerator generator = entry.getValue();
try {
JavaFile javaFile = generator.generate();
javaFile.writeTo(filer);
} catch (Exception e) {
error(typeElement, "Unable to write adapter for type %s: %s", typeElement, e.getMessage());
}
}
// Builders
Map<TypeElement, BuilderGenerator> builderMap = builderProcessor.findAndParseTargets(roundEnv);
for (Map.Entry<TypeElement, BuilderGenerator> entry : builderMap.entrySet()) {
TypeElement typeElement = entry.getKey();
BuilderGenerator generator = entry.getValue();
try {
JavaFile javaFile = generator.generate();
javaFile.writeTo(filer);
} catch (Exception e) {
StringWriter stackTrace = new StringWriter();
e.printStackTrace(new PrintWriter(stackTrace));
error(typeElement, "Unable to write builder for type %s: %s", typeElement, stackTrace.toString());
}
}
return false;
}
private void error(Element element, String message, Object... args) {
if (args.length > 0) {
message = String.format(message, args);
}
messager.printMessage(ERROR, message, element);
}
}