pocketknife.internal.codegen.injection.BundleInjectionProcessor Maven / Gradle / Ivy
package pocketknife.internal.codegen.injection;
import android.os.Build;
import pocketknife.InjectArgument;
import pocketknife.NotRequired;
import pocketknife.SaveState;
import pocketknife.internal.codegen.InvalidTypeException;
import pocketknife.internal.codegen.BundleFieldBinding;
import pocketknife.internal.codegen.KeySpec;
import javax.annotation.processing.Messager;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import static pocketknife.internal.GeneratedAdapters.BUNDLE_ADAPTER_SUFFIX;
import static pocketknife.internal.codegen.BundleFieldBinding.AnnotationType.SAVE_STATE;
import static pocketknife.internal.codegen.BundleFieldBinding.SAVE_STATE_KEY_PREFIX;
public class BundleInjectionProcessor extends InjectionProcessor {
public BundleInjectionProcessor(Messager messager, Elements elements, Types types) {
super(messager, elements, types);
}
public Map findAndParseTargets(RoundEnvironment env) {
Map targetClassMap = new LinkedHashMap();
Set erasedTargetNames = new LinkedHashSet(); // used for parent lookup.
// Process each @SaveState
for (Element element : env.getElementsAnnotatedWith(SaveState.class)) {
try {
parseSaveState(element, targetClassMap, erasedTargetNames);
} catch (Exception e) {
StringWriter stackTrace = new StringWriter();
e.printStackTrace(new PrintWriter(stackTrace));
error(element, "Unable to generate bundle adapter for @SaveState.\n\n%s", stackTrace);
}
}
// Process each @InjectAnnotation
for (Element element : env.getElementsAnnotatedWith(InjectArgument.class)) {
try {
parseInjectAnnotation(element, targetClassMap, erasedTargetNames);
} catch (Exception e) {
StringWriter stackTrace = new StringWriter();
e.printStackTrace(new PrintWriter(stackTrace));
error(element, "Unable to generate bundle adapter for @InjectAnnotation.\n\n%s", stackTrace);
}
}
// Try to find a parent adapter for each adapter
for (Map.Entry entry : targetClassMap.entrySet()) {
TypeElement parentElement = findParent(entry.getKey(), erasedTargetNames);
if (parentElement != null) {
entry.getValue().setParentAdapter(getPackageName(parentElement), parentElement.getSimpleName() + BUNDLE_ADAPTER_SUFFIX);
}
}
return targetClassMap;
}
private void parseSaveState(Element element, Map targetClassMap, Set erasedTargetNames)
throws ClassNotFoundException, InvalidTypeException {
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
// Verify that the target has all the appropriate information for type
TypeMirror type = element.asType();
if (type instanceof TypeVariable) {
TypeVariable typeVariable = (TypeVariable) type;
type = typeVariable.getUpperBound();
}
validateNotRequiredArguments(element);
validateForCodeGeneration(SaveState.class, element);
validateBindingPackage(SaveState.class, element);
// Assemble information on the injection point.
String name = element.getSimpleName().toString();
String bundleType = typeUtil.getBundleType(type);
NotRequired notRequired = element.getAnnotation(NotRequired.class);
boolean required = notRequired == null;
int minSdk = Build.VERSION_CODES.FROYO;
if (!required) {
minSdk = notRequired.value();
}
boolean canHaveDefault = !required && canHaveDefault(type, minSdk);
boolean needsToBeCast = typeUtil.needToCastBundleType(type);
BundleInjectionAdapterGenerator bundleInjectionAdapterGenerator = getOrCreateTargetClass(targetClassMap, enclosingElement);
BundleFieldBinding binding = new BundleFieldBinding(SAVE_STATE, name, type, bundleType, new KeySpec(null, generateKey(SAVE_STATE_KEY_PREFIX, name)),
needsToBeCast, canHaveDefault, required);
bundleInjectionAdapterGenerator.addField(binding);
// Add the type-erased version to the valid targets set.
erasedTargetNames.add(enclosingElement.toString());
}
private void parseInjectAnnotation(Element element, Map targetClassMap, Set erasedTargetNames)
throws InvalidTypeException {
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
// Verify that the target has all the appropriate information for type
TypeMirror type = element.asType();
if (element instanceof TypeVariable) {
TypeVariable typeVariable = (TypeVariable) type;
type = typeVariable.getUpperBound();
}
validateNotRequiredArguments(element);
validateForCodeGeneration(InjectArgument.class, element);
validateBindingPackage(InjectArgument.class, element);
// Assemble information on the injection point
String name = element.getSimpleName().toString();
String bundleType = typeUtil.getBundleType(type);
KeySpec key = getKey(element);
NotRequired notRequired = element.getAnnotation(NotRequired.class);
boolean required = notRequired == null;
int minSdk = Build.VERSION_CODES.FROYO;
if (!required) {
minSdk = notRequired.value();
}
boolean canHaveDefault = !required && canHaveDefault(type, minSdk);
boolean needsToBeCast = typeUtil.needToCastBundleType(type);
BundleInjectionAdapterGenerator bundleInjectionAdapterGenerator = getOrCreateTargetClass(targetClassMap, enclosingElement);
BundleFieldBinding binding = new BundleFieldBinding(BundleFieldBinding.AnnotationType.ARGUMENT, name, type, bundleType, key,
needsToBeCast, canHaveDefault, required);
bundleInjectionAdapterGenerator.orRequired(required);
bundleInjectionAdapterGenerator.addField(binding);
// Add the type-erased version to the valid targets set.
erasedTargetNames.add(enclosingElement.toString());
}
private KeySpec getKey(Element element) {
if (isDefaultAnnotationElement(element, InjectArgument.class.getName(), "value")) {
return new KeySpec(null, generateKey(BundleFieldBinding.ARGUMENT_KEY_PREFIX, element.getSimpleName().toString()));
}
return new KeySpec(null, element.getAnnotation(InjectArgument.class).value());
}
private boolean canHaveDefault(TypeMirror type, int minSdk) {
return typeUtil.isPrimitive(type) || minSdk >= Build.VERSION_CODES.HONEYCOMB_MR1 && types.isAssignable(type, typeUtil.charSequenceType);
}
private BundleInjectionAdapterGenerator getOrCreateTargetClass(Map targetClassMap,
TypeElement enclosingElement) {
BundleInjectionAdapterGenerator bundleInjectionAdapterGenerator = targetClassMap.get(enclosingElement);
if (bundleInjectionAdapterGenerator == null) {
TypeMirror targetType = enclosingElement.asType();
String classPackage = getPackageName(enclosingElement);
String className = getClassName(enclosingElement, classPackage) + BUNDLE_ADAPTER_SUFFIX;
bundleInjectionAdapterGenerator = new BundleInjectionAdapterGenerator(classPackage, className, targetType, typeUtil);
targetClassMap.put(enclosingElement, bundleInjectionAdapterGenerator);
}
return bundleInjectionAdapterGenerator;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy