|
package com.github.xizzhu.auto.value.sharedpreferences; |
|
|
|
import com.google.auto.service.AutoService; |
|
import com.google.auto.value.extension.AutoValueExtension; |
|
import com.squareup.javapoet.ClassName; |
|
import com.squareup.javapoet.CodeBlock; |
|
import com.squareup.javapoet.JavaFile; |
|
import com.squareup.javapoet.MethodSpec; |
|
import com.squareup.javapoet.ParameterSpec; |
|
import com.squareup.javapoet.ParameterizedTypeName; |
|
import com.squareup.javapoet.TypeName; |
|
import com.squareup.javapoet.TypeSpec; |
|
|
|
import java.util.ArrayList; |
|
import java.util.List; |
|
import java.util.Map; |
|
|
|
import javax.lang.model.element.AnnotationMirror; |
|
import javax.lang.model.element.ExecutableElement; |
|
import javax.lang.model.element.Modifier; |
|
import javax.lang.model.type.TypeMirror; |
|
|
|
@AutoService(AutoValueExtension.class) |
|
public final class AutoValueSharedPreferencesExtension extends AutoValueExtension { |
|
private static final ClassName SHARED_PREFERENCES_CLASS = ClassName.get("android.content", "SharedPreferences"); |
|
|
|
private static final String FACTORY_METHOD_NAME = "createFromSharedPreferences"; |
|
|
|
@Override |
|
public boolean applicable(Context context) { |
|
TypeMirror annotationType = context.processingEnvironment().getElementUtils() |
|
.getTypeElement(KeyName.class.getName()).asType(); |
|
for (ExecutableElement element : context.properties().values()) { |
|
for (AnnotationMirror annotation : element.getAnnotationMirrors()) { |
|
if (annotation.getAnnotationType().equals(annotationType)) { |
|
return true; |
|
} |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
@Override |
|
public String generateClass(Context context, String className, String classToExtend, boolean isFinal) { |
|
final String packageName = context.packageName(); |
|
final Map<String, ExecutableElement> properties = context.properties(); |
|
|
|
TypeSpec subclass = TypeSpec.classBuilder(className) |
|
.addModifiers(isFinal ? Modifier.FINAL : Modifier.ABSTRACT) |
|
.superclass(ClassName.get(packageName, classToExtend)) |
|
.addMethod(generateConstructor(properties)) |
|
.addMethod(generateFactoryMethod(context, properties)) |
|
.build(); |
|
|
|
return JavaFile.builder(packageName, subclass).build().toString(); |
|
} |
|
|
|
private static MethodSpec generateConstructor(Map<String, ExecutableElement> properties) { |
|
List<ParameterSpec> params = new ArrayList<>(); |
|
for (Map.Entry<String, ExecutableElement> entry : properties.entrySet()) { |
|
TypeName typeName = TypeName.get(entry.getValue().getReturnType()); |
|
params.add(ParameterSpec.builder(typeName, entry.getKey()).build()); |
|
} |
|
|
|
StringBuilder body = new StringBuilder("super("); |
|
for (int i = properties.size(); i > 0; --i) { |
|
body.append("$N"); |
|
if (i > 1) body.append(", "); |
|
} |
|
body.append(")"); |
|
|
|
return MethodSpec.constructorBuilder() |
|
.addParameters(params) |
|
.addStatement(body.toString(), properties.keySet().toArray()) |
|
.build(); |
|
} |
|
|
|
private static MethodSpec generateFactoryMethod(Context context, Map<String, ExecutableElement> properties) { |
|
MethodSpec.Builder factoryMethod = MethodSpec.methodBuilder(FACTORY_METHOD_NAME) |
|
.addModifiers(Modifier.STATIC) |
|
.addParameter(SHARED_PREFERENCES_CLASS, "sharedPreferences"); |
|
|
|
String classSimpleName = "AutoValue_" + context.autoValueClass().getSimpleName().toString(); |
|
factoryMethod.returns(ClassName.get(context.packageName(), classSimpleName)); |
|
|
|
for (Map.Entry<String, ExecutableElement> entry : properties.entrySet()) { |
|
String name = entry.getKey(); |
|
ExecutableElement element = entry.getValue(); |
|
TypeName typeName = TypeName.get(element.getReturnType()); |
|
KeyName keyName = element.getAnnotation(KeyName.class); |
|
String key = keyName != null ? keyName.key() : ""; |
|
String defaultValue = keyName != null ? keyName.defaultValue() : ""; |
|
|
|
if (typeName.equals(TypeName.BOOLEAN) || typeName.equals(TypeName.BOOLEAN.box())) { |
|
factoryMethod.addStatement("boolean $N = sharedPreferences.getBoolean($S, $L)", |
|
name, key, Boolean.parseBoolean(defaultValue)); |
|
} else if (typeName.equals(TypeName.FLOAT) || typeName.equals(TypeName.FLOAT.box())) { |
|
factoryMethod.addStatement("float $N = sharedPreferences.getFloat($S, $LF)", |
|
name, key, Float.parseFloat(defaultValue)); |
|
} else if (typeName.equals(TypeName.INT) || typeName.equals(TypeName.INT.box())) { |
|
factoryMethod.addStatement("int $N = sharedPreferences.getInt($S, $L)", |
|
name, key, Integer.parseInt(defaultValue)); |
|
} else if (typeName.equals(TypeName.LONG) || typeName.equals(TypeName.LONG.box())) { |
|
factoryMethod.addStatement("long $N = sharedPreferences.getLong($S, $LL)", |
|
name, key, Long.parseLong(defaultValue)); |
|
} else if (typeName.equals(TypeName.get(String.class))) { |
|
factoryMethod.addStatement("String $N = sharedPreferences.getString($S, $S)", |
|
name, key, defaultValue); |
|
} else if (typeName.equals(ParameterizedTypeName.get(ClassName.get("java.util", "Set"), TypeName.get(String.class)))) { |
|
factoryMethod.addStatement("Set<String> $N = sharedPreferences.getStringSet($S, null)", |
|
name, key); |
|
} else { |
|
// TODO support other types |
|
} |
|
} |
|
|
|
Object[] propertyNames = properties.keySet().toArray(); |
|
StringBuilder construct = new StringBuilder("new ").append(classSimpleName).append("("); |
|
for (int i = 0; i < propertyNames.length; ++i) { |
|
construct.append("$N").append(", "); |
|
} |
|
construct.setLength(construct.length() - 2); |
|
construct.append(")"); |
|
factoryMethod.addCode("return ") |
|
.addCode(CodeBlock.builder().addStatement(construct.toString(), propertyNames).build()); |
|
|
|
return factoryMethod.build(); |
|
} |
|
} |