
com.gabrielittner.auto.value.util.AutoValueUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of auto-value-extension-util Show documentation
Show all versions of auto-value-extension-util Show documentation
Utilities for AutoValue extensions
package com.gabrielittner.auto.value.util;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.AutoValueExtension;
import com.google.auto.value.extension.AutoValueExtension.Context;
import com.google.common.collect.Lists;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
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 com.squareup.javapoet.TypeVariableName;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import javax.annotation.processing.Messager;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.tools.Diagnostic;
import static javax.lang.model.element.Modifier.ABSTRACT;
import static javax.lang.model.element.Modifier.FINAL;
import static javax.tools.Diagnostic.Kind.ERROR;
/**
* Convenience and boilerplate methods for implementations of {@link AutoValueExtension}.
*/
public final class AutoValueUtil {
/**
* Returns the {@link ClassName} of the class annotated with {@link AutoValue}.
*/
public static ClassName getAutoValueClassClassName(Context context) {
return ClassName.get(context.autoValueClass());
}
private static String getFinalClassSimpleName(Context context) {
TypeElement autoValueClass = context.autoValueClass();
String name = autoValueClass.getSimpleName().toString();
Element enclosingElement = autoValueClass.getEnclosingElement();
while (enclosingElement instanceof TypeElement) {
name = enclosingElement.getSimpleName().toString() + "_" + name;
enclosingElement = enclosingElement.getEnclosingElement();
}
return "AutoValue_" + name;
}
/**
* Returns the {@link ClassName} of the last class in the chain of generated implementations,
* which is final. This can be used for creating new instances.
*/
public static ClassName getFinalClassClassName(Context context) {
return ClassName.get(context.packageName(), getFinalClassSimpleName(context));
}
/**
* Creates a new {@link TypeSpec.Builder} for the class that is generated by the extension. It
* will add a final or abstract modifier, the superclass and a constructor that calls super. The
* returned TypeSpec will also include all TypeVariables if the AutoValue class is generic.
*/
public static TypeSpec.Builder newTypeSpecBuilder(
Context context, String className, String classToExtend, boolean isFinal) {
TypeVariableName[] typeVariables = getTypeVariables(context.autoValueClass());
return TypeSpec.classBuilder(className)
.addModifiers(isFinal ? FINAL : ABSTRACT)
.addTypeVariables(Arrays.asList(typeVariables))
.superclass(getSuperClass(context.packageName(), classToExtend, typeVariables))
.addMethod(newConstructor(context.properties()));
}
private static TypeVariableName[] getTypeVariables(TypeElement autoValueClass) {
List extends TypeParameterElement> parameters = autoValueClass.getTypeParameters();
TypeVariableName[] typeVariables = new TypeVariableName[parameters.size()];
for (int i = 0, length = typeVariables.length; i < length; i++) {
typeVariables[i] = TypeVariableName.get(parameters.get(i));
}
return typeVariables;
}
private static TypeName getSuperClass(
String packageName, String classToExtend, TypeName[] typeVariables) {
ClassName superClassWithoutParameters = ClassName.get(packageName, classToExtend);
if (typeVariables.length > 0) {
return ParameterizedTypeName.get(superClassWithoutParameters, typeVariables);
} else {
return superClassWithoutParameters;
}
}
private static MethodSpec newConstructor(Map properties) {
List params = Lists.newArrayList();
for (Map.Entry entry : properties.entrySet()) {
TypeName typeName = TypeName.get(entry.getValue().getReturnType());
params.add(ParameterSpec.builder(typeName, entry.getKey()).build());
}
CodeBlock code = newConstructorCall(CodeBlock.of("super"), properties.keySet().toArray());
return MethodSpec.constructorBuilder().addParameters(params).addCode(code).build();
}
/**
* Creates a {@link CodeBlock} that calls the constructor of the final generated class
* {@link AutoValueUtil#getFinalClassClassName(Context)}. The given {@code properties} array
* should either contain plain {@code String}'s or JavaPoet Names.
*/
public static CodeBlock newFinalClassConstructorCall(Context context, Object[] properties) {
CodeBlock constructorName = CodeBlock.of("new $T", getFinalClassClassName(context));
return newConstructorCall(constructorName, properties);
}
private static CodeBlock newConstructorCall(CodeBlock constructorName, Object[] properties) {
StringBuilder params = new StringBuilder("(");
for (int i = properties.length; i > 0; i--) {
params.append("$N");
if (i > 1) params.append(", ");
}
params.append(")");
return CodeBlock.builder()
.add(constructorName)
.addStatement(params.toString(), properties)
.build();
}
/**
* Will call {@link Messager#printMessage(Diagnostic.Kind, CharSequence, Element)} with
* {@link Diagnostic.Kind#ERROR} and the given {@code message} for {@code property}. This will
* ultimately fail the build, but will not abort it right now.
*/
public static void error(Context context, Property property, String message) {
context.processingEnvironment()
.getMessager()
.printMessage(ERROR, message, property.element());
}
/**
* Will call {@link Messager#printMessage(Diagnostic.Kind, CharSequence, Element)} with
* {@link Diagnostic.Kind#ERROR} and the given {@code message} formatted using {@code args} for
* {@code property}. This will ultimately fail the build, but will not abort it right now.
*/
public static void error(Context context, Property property, String message, Object... args) {
error(context, property, String.format(message, args));
}
private AutoValueUtil() {
throw new AssertionError("No instances.");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy