com.neenbedankt.bundles.processor.FragmentArgumentsProcessor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of argument Show documentation
Show all versions of argument Show documentation
Bundles is a set of annotation processors for Android source code
The newest version!
package com.neenbedankt.bundles.processor;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import javax.annotation.processing.Filer;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.JavaFileObject;
import com.neenbedankt.bundles.annotation.Argument;
import com.squareup.javawriter.JavaWriter;
@SupportedAnnotationTypes("com.neenbedankt.bundles.annotation.Argument")
public class FragmentArgumentsProcessor extends BaseProcessor {
private Set collectArgumentsForType(Types typeUtil, TypeElement type,
Map> fieldsByType, boolean requiredOnly, boolean processSuperClass) {
Set arguments = new TreeSet();
if (processSuperClass) {
TypeMirror superClass = type.getSuperclass();
if (superClass.getKind() != TypeKind.NONE) {
arguments.addAll(collectArgumentsForType(typeUtil, (TypeElement) typeUtil.asElement(superClass),
fieldsByType, requiredOnly, true));
}
}
Set fields = fieldsByType.get(type);
if (fields == null) {
return arguments;
}
for (Element element : fields) {
if (requiredOnly) {
Argument arg = element.getAnnotation(Argument.class);
if (!arg.required()) {
continue;
}
}
arguments.add(new ArgumentAnnotatedField(element));
}
return arguments;
}
@Override
public boolean process(Set extends TypeElement> type, RoundEnvironment env) {
Elements elementUtils = processingEnv.getElementUtils();
Types typeUtils = processingEnv.getTypeUtils();
Filer filer = processingEnv.getFiler();
TypeMirror fragmentType = elementUtils.getTypeElement("android.app.Fragment").asType();
TypeMirror supportFragmentType = elementUtils.getTypeElement("android.support.v4.app.Fragment").asType();
Map> fieldsByType = new HashMap>(100);
for (Element element : env.getElementsAnnotatedWith(Argument.class)) {
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
if (!typeUtils.isSubtype(enclosingElement.asType(), fragmentType)
&& !typeUtils.isSubtype(enclosingElement.asType(), supportFragmentType)) {
error(element, "@Argument can only be used on fragment fields (%s.%s)",
enclosingElement.getQualifiedName(), element);
continue;
}
if (element.getModifiers().contains(Modifier.FINAL) || element.getModifiers().contains(Modifier.STATIC)
|| element.getModifiers().contains(Modifier.PRIVATE)
|| element.getModifiers().contains(Modifier.PROTECTED)) {
error(element, "@Argument fields must not be private, protected, final or static (%s.%s)",
enclosingElement.getQualifiedName(), element);
continue;
}
Set fields = fieldsByType.get(enclosingElement);
if (fields == null) {
fields = new LinkedHashSet(10);
fieldsByType.put(enclosingElement, fields);
}
fields.add(element);
}
for (Entry> entry : fieldsByType.entrySet()) {
try {
String builder = entry.getKey().getSimpleName() + "Builder";
List originating = new ArrayList(10);
originating.add(entry.getKey());
TypeMirror superClass = entry.getKey().getSuperclass();
while (superClass.getKind() != TypeKind.NONE) {
TypeElement element = (TypeElement) typeUtils.asElement(superClass);
if (element.getQualifiedName().toString().startsWith("android.")) {
break;
}
originating.add(element);
superClass = element.getSuperclass();
}
JavaFileObject jfo = filer.createSourceFile(entry.getKey().getQualifiedName() + "Builder",
originating.toArray(new Element[originating.size()]));
Writer writer = jfo.openWriter();
JavaWriter jw = new JavaWriter(writer);
writePackage(jw, entry.getKey());
jw.emitImports("android.os.Bundle");
jw.beginType(builder, "class", EnumSet.of(Modifier.PUBLIC, Modifier.FINAL));
jw.emitField("Bundle", "mArguments", EnumSet.of(Modifier.PRIVATE, Modifier.FINAL), "new Bundle()");
jw.emitEmptyLine();
Set required = collectArgumentsForType(typeUtils, entry.getKey(), fieldsByType, true,
true);
String[] args = new String[required.size() * 2];
int index = 0;
for (AnnotatedField arg : required) {
args[index++] = arg.getType();
args[index++] = arg.getVariableName();
}
jw.beginMethod(null, builder, EnumSet.of(Modifier.PUBLIC), args);
for (AnnotatedField arg : required) {
writePutArguments(jw, arg.getVariableName(), "mArguments", arg);
}
jw.endMethod();
if (!required.isEmpty()) {
writeNewFragmentWithRequiredMethod(builder, entry.getKey(), jw, args);
}
Set allArguments = collectArgumentsForType(typeUtils, entry.getKey(), fieldsByType,
false, true);
Set optionalArguments = new HashSet(allArguments);
optionalArguments.removeAll(required);
for (AnnotatedField arg : optionalArguments) {
writeBuilderMethod(builder, jw, arg);
}
writeInjectMethod(jw, entry.getKey(),
collectArgumentsForType(typeUtils, entry.getKey(), fieldsByType, false, false));
writeBuildMethod(jw, entry.getKey());
jw.endType();
jw.close();
} catch (IOException e) {
error(entry.getKey(), "Unable to write builder for type %s: %s", entry.getKey(), e.getMessage());
throw new RuntimeException(e);
}
}
return true;
}
private void writeNewFragmentWithRequiredMethod(String builder, TypeElement element, JavaWriter jw, String[] args)
throws IOException {
jw.beginMethod(element.getQualifiedName().toString(), "new" + element.getSimpleName(),
EnumSet.of(Modifier.STATIC, Modifier.PUBLIC), args);
StringBuilder argNames = new StringBuilder();
for (int i = 1; i < args.length; i += 2) {
argNames.append(args[i]);
if (i < args.length - 1) {
argNames.append(", ");
}
}
jw.emitStatement("return new %1$s(%2$s).build()", builder, argNames);
jw.endMethod();
}
private void writeBuildMethod(JavaWriter jw, TypeElement element) throws IOException {
jw.beginMethod(element.getSimpleName().toString(), "build", EnumSet.of(Modifier.PUBLIC));
jw.emitStatement("%1$s fragment = new %1$s()", element.getSimpleName().toString());
jw.emitStatement("fragment.setArguments(mArguments)");
jw.emitStatement("return fragment");
jw.endMethod();
}
private void writeInjectMethod(JavaWriter jw, TypeElement element, Set allArguments)
throws IOException {
jw.beginMethod("void", "injectArguments", EnumSet.of(Modifier.STATIC, Modifier.FINAL),
element.getSimpleName().toString(), "fragment");
jw.emitStatement("Bundle args = fragment.getArguments()");
jw.beginControlFlow("if (args == null)");
jw.emitStatement("throw new IllegalStateException(\"No arguments set\")");
jw.endControlFlow();
for (AnnotatedField type : allArguments) {
String op = getOperation(type);
if (op == null) {
error(element, "Can't write injector, the bundle getter is unknown");
return;
}
String cast = "Serializable".equals(op) ? "(" + type.getType() + ") " : "";
if (!type.isRequired()) {
jw.beginControlFlow("if (args.containsKey("+JavaWriter.stringLiteral(type.getKey())+"))");
} else {
jw.beginControlFlow("if (!args.containsKey("+JavaWriter.stringLiteral(type.getKey())+"))");
jw.emitStatement("throw new IllegalStateException(\"required argument %1$s is not set\")", type.getKey());
jw.endControlFlow();
}
jw.emitStatement("fragment.%1$s = %4$sargs.get%2$s(\"%3$s\")", type.getName(), op, type.getKey(), cast);
if (!type.isRequired()) {
jw.endControlFlow();
}
}
jw.endMethod();
}
private void writeBuilderMethod(String type, JavaWriter writer, AnnotatedField arg) throws IOException {
writer.emitEmptyLine();
writer.beginMethod(type, arg.getVariableName(),EnumSet.of(Modifier.PUBLIC), arg.getType(),
arg.getVariableName());
writePutArguments(writer, arg.getVariableName(), "mArguments", arg);
writer.emitStatement("return this");
writer.endMethod();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy