Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix factory method with generics. #142

Merged
merged 1 commit into from Nov 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -36,7 +36,6 @@
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
Expand Down Expand Up @@ -176,8 +175,7 @@ public IncrementalExtensionType incrementalType(ProcessingEnvironment processing
boolean shouldCreateGenerics = typeParams != null && typeParams.size() > 0;

ClassName classNameClass = ClassName.get(context.packageName(), className);
ClassName autoValueClass = ClassName.get(context.autoValueClass());
TypeName autoValueClassName = autoValueClass;
ClassName autoValueClassName = ClassName.get(context.autoValueClass());
TypeVariableName[] genericTypeNames = null;

TypeName superclass;
Expand All @@ -187,10 +185,8 @@ public IncrementalExtensionType incrementalType(ProcessingEnvironment processing
for (int i = 0; i < typeParams.size(); i++) {
genericTypeNames[i] = TypeVariableName.get(typeParams.get(i));
}

superclass = ParameterizedTypeName.get(ClassName.get(context.packageName(), classToExtend),
(TypeName[]) genericTypeNames);
autoValueClassName = ParameterizedTypeName.get(autoValueClass, (TypeName[]) genericTypeNames);
genericTypeNames);
} else {
superclass = TypeVariableName.get(classToExtend);
}
Expand Down Expand Up @@ -270,10 +266,14 @@ private MethodSpec generateConstructor(List<Property> properties) {
return builder.build();
}

private TypeSpec createTypeAdapter(ClassName className, TypeName autoValueClassName,
private TypeSpec createTypeAdapter(ClassName className, ClassName autoValueClassName,
TypeVariableName[] genericTypeNames, List<Property> properties, @Nullable BuilderContext builderContext,
ProcessingEnvironment processingEnvironment) {

TypeName typeAdapterClass = ParameterizedTypeName.get(ADAPTER_CLASS_NAME, autoValueClassName);
final TypeName autoValueTypeName = genericTypeNames != null && genericTypeNames.length > 0
? ParameterizedTypeName.get(autoValueClassName, genericTypeNames)
: autoValueClassName;

ImmutableMap<Property, FieldSpec> adapters = createFields(properties);

Expand Down Expand Up @@ -323,7 +323,6 @@ private TypeSpec createTypeAdapter(ClassName className, TypeName autoValueClassN

// if the property is @Nullable, we append a .nullSafe() to the adapter
String nullableOrNothing = prop.nullable() ? ".nullSafe()" : "";

if (!usedDeclaredGenericTypeNames.isEmpty() && usesJsonQualifier) {
// Property uses generics and JsonQualifiers
needsAdapterWithQualifierMethod = true;
Expand Down Expand Up @@ -359,13 +358,16 @@ && getTypeIndexInArray(genericTypeNames, prop.type) >= 0) {
}
}

ClassName jsonAdapterClassName = ClassName.get(JsonAdapter.class);
ParameterizedTypeName superClass = ParameterizedTypeName.get(jsonAdapterClassName, autoValueTypeName);
TypeSpec.Builder classBuilder = TypeSpec.classBuilder("MoshiJsonAdapter")
.addModifiers(PUBLIC, STATIC, FINAL)
.superclass(typeAdapterClass)
.superclass(superClass)
.addFields(adapters.values())
.addMethod(constructor.build())
.addMethod(createReadMethod(className, autoValueClassName, properties, adapters, names, builderContext, processingEnvironment))
.addMethod(createWriteMethod(autoValueClassName, adapters));
.addMethod(createReadMethod(className, autoValueClassName, autoValueTypeName, properties,
adapters, names, builderContext, processingEnvironment))
.addMethod(createWriteMethod(autoValueTypeName, adapters));

ArrayTypeName stringArray = ArrayTypeName.of(String.class);
ClassName optionsCN = ClassName.get(JsonReader.Options.class);
Expand Down Expand Up @@ -394,12 +396,12 @@ && getTypeIndexInArray(genericTypeNames, prop.type) >= 0) {
}

private int getTypeIndexInArray(TypeVariableName[] array, TypeName typeName) {
return Arrays.binarySearch(array, typeName, new Comparator<TypeName>() {
@Override
public int compare(TypeName typeName, TypeName t1) {
return typeName.equals(t1) ? 0 : -1;
for (int i = 0; i < array.length ; i++) {
if (typeName.equals(array[i])) {
return i;
}
});
}
return -1;
}

private MethodSpec createAdapterMethod() {
Expand Down Expand Up @@ -461,12 +463,12 @@ private MethodSpec createAdapterWithQualifierMethod(TypeName autoValueClassName)
.build();
}

private MethodSpec createWriteMethod(TypeName autoValueClassName,
private MethodSpec createWriteMethod(TypeName autoValueTypeName,
ImmutableMap<Property, FieldSpec> adapters) {
String writerName = "writer";
String valueName = "value";
ParameterSpec writer = ParameterSpec.builder(JsonWriter.class, writerName).build();
ParameterSpec value = ParameterSpec.builder(autoValueClassName, valueName).build();
ParameterSpec value = ParameterSpec.builder(autoValueTypeName, valueName).build();
MethodSpec.Builder writeMethod = MethodSpec.methodBuilder("toJson")
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
Expand Down Expand Up @@ -502,16 +504,17 @@ private MethodSpec createWriteMethod(TypeName autoValueClassName,
return writeMethod.build();
}

private MethodSpec createReadMethod(ClassName className, TypeName autoValueClassName, List<Property> properties,
ImmutableMap<Property, FieldSpec> adapters, List<String> names, @Nullable BuilderContext builderContext,
private MethodSpec createReadMethod(ClassName className, ClassName autoValueClassName, TypeName autoValueTypeName,
List<Property> properties, ImmutableMap<Property, FieldSpec> adapters,
List<String> names, @Nullable BuilderContext builderContext,
ProcessingEnvironment processingEnvironment) {
NameAllocator nameAllocator = new NameAllocator();
ParameterSpec reader = ParameterSpec.builder(JsonReader.class, nameAllocator.newName("reader"))
.build();
MethodSpec.Builder readMethod = MethodSpec.methodBuilder("fromJson")
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.returns(autoValueClassName)
.returns(autoValueTypeName)
.addParameter(reader)
.addException(IOException.class);
// Validate the builderContext if there is one.
Expand Down Expand Up @@ -560,7 +563,7 @@ private MethodSpec createReadMethod(ClassName className, TypeName autoValueClass
// Will be absent if not using AutoValue builder
Optional<FieldSpec> builderField = Optional.ofNullable(builderContext)
.map(ctx -> FieldSpec
.builder(ClassName.get(ctx.builderType()), "builder")
.builder(TypeName.get(ctx.builderType().asType()), "builder")
.build());

if (builderField.isPresent()) {
Expand Down Expand Up @@ -588,8 +591,8 @@ private MethodSpec createReadMethod(ClassName className, TypeName autoValueClass
}
}

readMethod.addStatement("$T $N = $T.$L", builderField.get().type, builderField.get(),
autoValueClassName, builderMethod);
readMethod.addStatement("$T $N = $T.$N()", builderField.get().type, builderField.get(),
autoValueClassName, builderMethod.getSimpleName());
}
} else {
// add the properties
Expand Down
@@ -0,0 +1,30 @@
package com.ryanharter.auto.value.moshi.example;

import com.google.auto.value.AutoValue;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;

import java.lang.reflect.Type;

@AutoValue public abstract class GenericsExample<A, B, C> {

public abstract A a();
public abstract B b();
public abstract C c();

@AutoValue.Builder
public interface Builder<A, B, C> {
Builder<A, B, C> a(A a);
Builder<A, B, C> b(B b);
Builder<A, B, C> c(C c);
GenericsExample<A, B, C> build();
}

public static <A, B, C> Builder<A, B, C> builder() {
return new AutoValue_GenericsExample.Builder<A, B, C>();
}

public static <A, B, C> JsonAdapter<GenericsExample<A, B, C>> jsonAdapter(Moshi moshi, Type[] types) {
return new AutoValue_GenericsExample.MoshiJsonAdapter(moshi, types);
}
}