Giter Club home page Giter Club logo

auto-value-gson's Introduction

AutoValue: Gson Extension

An extension for Google's AutoValue that creates a simple Gson TypeAdapterFactory for each AutoValue annotated object.

Usage

Simply include auto-value-gson in your project and add a public static method to your @AutoValue annotated class returning a TypeAdapter. You can also annotate your properties using @SerializedName to define an alternate name for de/serialization.

@AutoValue public abstract class Foo {
  abstract String bar();
  @SerializedName("Baz") abstract String baz();
  abstract int quux();
  abstract String with_underscores();

  // The public static method returning a TypeAdapter<Foo> is what
  // tells auto-value-gson to create a TypeAdapter for Foo.
  public static TypeAdapter<Foo> typeAdapter(Gson gson) {
    return new AutoValue_Foo.GsonTypeAdapter(gson);
  }
}

Now build your project and de/serialize your Foo.

The TypeAdapter

To trigger TypeAdapter generation, you need include a non-private static factory method that accepts a Gson parameter and returns a TypeAdapter for your AutoValue type. From within this method you can instantiate a new GsonTypeAdapter which will have been generated as an inner class of your AutoValue generated implementation.

@AutoValue public abstract class Foo {
  // properties...
  
  public static TypeAdapter<Foo> typeAdapter(Gson gson) {
    return new AutoValue_Foo.GsonTypeAdapter(gson);
  }
}

Generics support

If your annotated class uses generics, you'll have to modify your static method a little so AutoValue will know how to generate an appropriate adapter. Simply add a TypeToken<?> parameter and pass it to the generated GsonTypeAdapter class.

To have support for fields with generic parameters (eg. List<B>) you need to upgrade your Gson dependency to at least 2.8.0, which introduces the helper TypeToken.getParameterized() see Gson Changelog.

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

  abstract A data();
  abstract List<B> dataList();
  abstract Map<String, List<C>> dataMap();

  public static <A, B, C> TypeAdapter<Foo<A, B, C>> typeAdapter(Gson gson,
      Type[] types) {
    return new AutoValue_Foo.GsonTypeAdapter<>(gson, types);
  }
}

Note that the types is an array of the Type representations of the given type's generics. If Foo is parameterized as Foo<String, Integer, Boolean>, then the Type array passed in should be an array of {String.class, Integer.class, Boolean.class}.

Transient types

To ignore certain properties from serialization, you can use the @AutoTransient annotation. This comes from a shared transience annotations library and is an api dependency of the runtime artifact. You can annotate a property and it will be treated as transient for both serialization and deserialization. Note that this should only be applied to nullable properties.

Builder Support

If your @AutoValue class has a builder, auto-value-gson will use the builder to instantiate the class. If the @AutoValue class has a static no-argument factory method for its builder, it will be used. If there are multiple factory methods, the one annotated @AutoValueGsonBuilder will be used. This can be useful for setting default values.

@AutoValue public abstract class Foo {
  abstract int bar();
  abstract String quux();

  public static Builder builder() {
    return new AutoValue_Foo.Builder();
  }

  @AutoValueGsonBuilder
  public static Builder builderWithDefaults() {
    return new builder().quux("QUUX");
  }
}

Field name policy

If you want the generated adapter classes to use the input Gson instance's field name policy, you can enable this via autovaluegson.useFieldNamePolicy processor option. This acts as a flag (any value is ignored) and can be set like any other annotation processor option.

In Gradle, this could look like this:

tasks.withType(JavaCompile) {
    options.compilerArgs += "-Aautovaluegson.useFieldNamePolicy"
}

Factory

Optionally, auto-value-gson can create a single TypeAdapterFactory so that you don't have to add each generated TypeAdapter to your Gson instance manually.

To generate a TypeAdapterFactory for all of your auto-value-gson classes, simply create an abstract class that implements TypeAdapterFactory and annotate it with @GsonTypeAdapterFactory, and auto-value-gson will create an implementation for you. You simply need to provide a static factory method, just like your AutoValue classes, and you can use the generated TypeAdapterFactory to help Gson de/serialize your types.

@GsonTypeAdapterFactory
public abstract class MyAdapterFactory implements TypeAdapterFactory {

  // Static factory method to access the package
  // private generated implementation
  public static TypeAdapterFactory create() {
    return new AutoValueGson_MyAdapterFactory();
  }
  
}

Then you simply need to register the Factory with Gson.

Gson gson = new GsonBuilder()
    .registerTypeAdapterFactory(MyAdapterFactory.create())
    .create();

@GenerateTypeAdapter

There is an annotation in the auto-value-gson-runtime artifact called @GenerateTypeAdapter. This annotation can be set on types to indicate to the extension that you want the generated adapter to be a top level class in the same package. The name of this class will be the AutoValue class's name plus _GsonTypeAdapter suffix.

Types annotated with this can also be (de)serialized dynamically at runtime with a provided runtime TypeAdapterFactory implementation in the annotation called FACTORY. The type name and generated typeadapter class's name must not be obfuscated for this to work. The extension that runs during annotation processing will automatically generate custom .pro rules for Proguard/R8 for this, so it should require no extra configuration.

When this annotation is used, there will be no intermediate AutoValue class generated (as opposed to the default logic, which generates an intermediate class and generates the TypeAdapter as a static inner class of it). There is no need to declare a static TypeAdapter<...> typeAdapter() method anymore for this case, though you can optionally define one if you still want to use the @GsonTypeAdapterFactory generator for them.

@GenerateTypeAdapter is compatible with the factory approach above, just make your static method's implementation point to it. It can also be an alternative to it if you use the runtime factory, particularly if you have a multimodule project and are willing to accept a small amount of (heavily cached) reflection.

The generated class will have the same parameters as if it were the inner class. If it's generic, its constructor accepts a Gson instance and TypeToken of the generics. If it's not generic, it's just a Gson instance.

Example usage:

@GenerateTypeAdapter
@AutoValue
public class Foo {
  // ...
}

// Generates
public final class Foo_GsonTypeAdapter extends TypeAdapter<Foo> {
  public Foo_GsonTypeAdapter(Gson gson) {
    //...
  }
}

// Or with generics
@GenerateTypeAdapter
@AutoValue
public class Foo<T> {
  // ...
}

// Generates
public final class Foo_GsonTypeAdapter extends TypeAdapter<Foo> {
  public Foo_GsonTypeAdapter(Gson gson, TypeToken<? extends Foo<T>> typeToken) {
    //...
  }
}

// Using the runtime FACTORY
new GsonBuilder()
    .registerTypeAdapterFactory(GenerateTypeAdapter.FACTORY)
    .create()
    .toJson(myFooInstance);

Download

Add a Gradle dependency to the annotationProcessor/kapt and implementation/api configuration.

annotationProcessor("com.ryanharter.auto.value:auto-value-gson-extension:1.3.1")
implementation("com.ryanharter.auto.value:auto-value-gson-runtime:1.3.1")

// Optional @GsonTypeAdapterFactory support
annotationProcessor("com.ryanharter.auto.value:auto-value-gson-factory:1.3.1")

// Legacy generic artifact that includes both -extension and -factory above. This exists to not
// break existing users, but shouldn't be used because it includes both the -factory artifact as
// well as the -extension artifact. This can have a negative impact on build times if you don't
// actually use the factory support, as it is an aggregating incremental processor thus slower
// compared to just using the isolating incremental behavior of the extension.
annotationProcessor("com.ryanharter.auto.value:auto-value-gson:1.3.1")

Snapshots of the latest development version are available in Sonatype's snapshots repository.

License

Copyright 2015 Ryan Harter.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

auto-value-gson's People

Contributors

3flex avatar ansman avatar autonomousapps avatar bejibx avatar bryanstern avatar cushon avatar dmitry-timofeev avatar eamonnmcmanus avatar ersin-ertan avatar fabiocollini avatar gabrielittner avatar jakekdodd avatar jakewharton avatar jettbow avatar jffiorillo avatar kmenager avatar lgawin avatar luciofm avatar mik9 avatar mseele avatar nightlynexus avatar oguzbabaoglu avatar piasy avatar prempalsingh avatar rharter avatar ronshapiro avatar timfreiheit avatar xmiketx avatar zacsweers avatar zsavely avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

auto-value-gson's Issues

Ability to work with Hal JSON

Hi I was wondering how you think about adding functionality to handle support for HAL json, gson doesn't support it in a workable way. When you model all the classes as the json it works with gson but that means you would have to write a lot of model classes or really big model classes. There is a library halarious that works with gson to enable parsing of hal json but it doesn't work properly with AutoValue gson since it works with runtime reflection and adding JsonSerializer/JsonDeserializer for the same classes as the generated AutoValue. This defeats the purpose of creating the generated streaming parsers in the TypeAdapters.

I forked your extension and added 2 Annotations that are basically copies of SerializedName when adding those to your abstract methods instead of the SerializedName the code generation is a little bit different.

Do you think this would be a nice functionality to have or do you have other recommendations to get this working?

Support toBuilder method

AutoValue-gson generates a class which does not compile when I have a toBuilder method in my class. It seems to confuse it for a property and generates an constructor for it:

@AutoValue public abstract class Foo {

    abstract long id();

    public static TypeAdapter<Foo> typeAdapter(Gson gson) {
        return new AutoValue_Foo.GsonTypeAdapter(gson);
    }

    abstract Builder toBuilder();

    @AutoValue.Builder
    static abstract class Builder {
        abstract Builder id(long id);
        abstract Foo build();
    }
}

AutoValueGsonAdapterFactoryProcessor doesn't account for projects with multiple modules

AutoValueGsonAdapterFactoryProcessor generated a class called com.ryanharter.auto.value.gson.AutoValueGsonTypeAdapterFactory. This obviously doesn't work when auto-value-gson is used in multiple modules. It would be nice if auto-value-gson would either allow modules to change the package/class name via an annotation processor argument or have some other way to workaround this.

NoSuchMethodError com.squareup.javapoet.TypeSpec.classBuilde on 0.3.1

After upgrading to 0.3.1, building the project throws this error

Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
> java.lang.NoSuchMethodError: com.squareup.javapoet.TypeSpec.classBuilder(Lcom/squareup/javapoet/ClassName;)Lcom/squareup/javapoet/TypeSpec$Builder;

Reverting to 0.2.5 fixes the issue. These are the build.gradle lines concerning auto-value

apt 'com.ryanharter.auto.value:auto-value-gson:0.3.1'
apt 'com.ryanharter.auto.value:auto-value-parcel:0.2.1'
apt 'com.google.auto.value:auto-value:1.2'
provided 'com.google.auto.value:auto-value:1.2'
provided 'javax.annotation:jsr250-api:1.0'

There are many more dependencies (retrofit2, picasso, rx, etc.). Let me know if you need the full list.

Thanks!

Android Studio multiple modules- NoClassDefFoundError Parcelable

I couldn't figure out what's causing this. I have a 3 module project two of which have the third as a dependency. When I build module_one everything works fine, but when I try building module_two I get this weird error. Running with stacktrace makes me guess that android/os/Parcelable should've been android.os.Parcelable.

Anyone else faced this before?

:module_two:compileMockDebugJavaWithJavac FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':consumer:compileMockDebugJavaWithJavac'.
> java.lang.NoClassDefFoundError: android/os/Parcelable

* Try:
Run with --info or --debug option to get more log output.

* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':consumer:compileMockDebugJavaWithJavac'.
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:69)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:46)
    at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:35)
    at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:66)
    at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
    at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:52)
    at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
    at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:53)
    at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:203)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:185)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:66)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:50)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
    at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
Caused by: java.lang.RuntimeException: java.lang.NoClassDefFoundError: android/os/Parcelable
    at com.sun.tools.javac.main.Main.compile(Main.java:553)
    at com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:129)
    at com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:138)
    at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:46)
    at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:33)
    at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.delegateAndHandleErrors(NormalizingJavaCompiler.java:104)
    at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:53)
    at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:38)
    at org.gradle.api.internal.tasks.compile.CleaningJavaCompilerSupport.execute(CleaningJavaCompilerSupport.java:35)
    at org.gradle.api.internal.tasks.compile.CleaningJavaCompilerSupport.execute(CleaningJavaCompilerSupport.java:25)
    at org.gradle.api.tasks.compile.JavaCompile.performCompilation(JavaCompile.java:163)
    at org.gradle.api.tasks.compile.JavaCompile.compile(JavaCompile.java:145)
    at org.gradle.api.tasks.compile.JavaCompile.compile(JavaCompile.java:93)
    at com.android.build.gradle.tasks.factory.AndroidJavaCompile.compile(AndroidJavaCompile.java:49)
    at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:75)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$IncrementalTaskAction.doExecute(AnnotationProcessingTaskFactory.java:245)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:221)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$IncrementalTaskAction.execute(AnnotationProcessingTaskFactory.java:232)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:210)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:80)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:61)
    ... 14 more
Caused by: java.lang.NoClassDefFoundError: android/os/Parcelable
    at com.ryanharter.auto.value.gson.AutoValueGsonExtension.getDefaultValue(AutoValueGsonExtension.java:465)
    at com.ryanharter.auto.value.gson.AutoValueGsonExtension.createReadMethod(AutoValueGsonExtension.java:380)
    at com.ryanharter.auto.value.gson.AutoValueGsonExtension.createTypeAdapter(AutoValueGsonExtension.java:312)
    at com.ryanharter.auto.value.gson.AutoValueGsonExtension.generateClass(AutoValueGsonExtension.java:185)
    at com.google.auto.value.processor.AutoValueProcessor.writeExtensions(AutoValueProcessor.java:474)
    at com.google.auto.value.processor.AutoValueProcessor.processType(AutoValueProcessor.java:460)
    at com.google.auto.value.processor.AutoValueProcessor.process(AutoValueProcessor.java:150)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:794)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:705)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.access$1800(JavacProcessingEnvironment.java:91)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1035)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1176)
    at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1170)
    at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:856)
    at com.sun.tools.javac.main.Main.compile(Main.java:523)
    ... 34 more
Caused by: java.lang.ClassNotFoundException: android.os.Parcelable
    ... 49 more


BUILD FAILED

Total time: 4.085 secs

Compilation error if AutoValue class has toBuilder method

If AutoValue class has toBuilder method to initialize a builder to the same property values as an existing value instance(#to_builder), generated constructor for AutoValue_CommentModel has one redundant parameter: CommentModel.Builder toBuilder

Example:

@AutoValue
public abstract class CommentModel {
    ...
    public abstract Builder toBuilder();
    ...

Generated class:

final class AutoValue_CommentModel extends $AutoValue_CommentModel {
    AutoValue_CommentModel(..., CommentModel.Builder toBuilder) {
        super(..., toBuilder);
    }
...

Add support for field naming policies

Gson has support for different field naming policies which does not seem to work with this library. For example, by setting LOWER_CASE_WITH_UNDERSCORES while creating the gson object, all field names with lowercase and underscore separated format will automatically mapped to their camel case formats in the Java classes.

Gson gson = new GsonBuilder()
    .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
    .create();

public class Dog {
    public String makeNoise;
}

And its equivalent json:

{
    "make_noise": "bark"
}

We can use @SerializedName annotation for this but it becomes tedious if all the field names are to be converted from the same underscore format.

Problems when using with auto-value-parcel

Whe I use this auto-value-gson version 0.3.1 together with auto-value-parcel 0.2.1 I end with exception with multiple warnings before. Probably trying to process parcelable methods as well?

When I revert to verzion 0.2.5 of auto-value-gson it works fine. But I expected TypeAdapterFactory to be generated by the new version.

warning: @autovalue classes cannot have abstract methods other than property getters and Builder converters

Caused by: java.lang.NoSuchMethodError: com.squareup.javapoet.TypeSpec.classBuilder(Lcom/squareup/javapoet/ClassName;)Lcom/squareup/javapoet/TypeSpec$Builder;
at com.ryanharter.auto.value.gson.AutoValueGsonAdapterFactoryProcessor.createTypeAdapterFactory(AutoValueGsonAdapterFactoryProcessor.java:82)
at com.ryanharter.auto.value.gson.AutoValueGsonAdapterFactoryProcessor.process(AutoValueGsonAdapterFactoryProcessor.java:67)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:794)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:705)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.access$1800(JavacProcessingEnvironment.java:91)
at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1035)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1176)
at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1170)
at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:856)
at com.sun.tools.javac.main.Main.compile(Main.java:523)
... 88 more

Respect gson.serializeNulls()

The API I'm working with requires null attributes to be sent and the generated type adapter never writes attributes which are null.

Generated TypeAdapterFactory and null safety

As of 0.2.5, My custom AutoValueTypeAdapterFactory would call nullSafe() on every type adapter I return in the create() method. Refer #28 (comment).

Class<? super T> rawType = type.getRawType();
if (rawType.equals(User.class)) {
    return (TypeAdapter<T>) User.typeAdapter(gson).nullSafe();
}

Beginning from 0.3.0, the generated AutoValueGsonTypeAdapterFactory does not call nullSafe() by default, which is the appropriate way for sure.

So, how'd I go about ensuring null-safety when using the generated TypeAdapterFactory.

Ship a default "MyAdapterFactory" with `auto-value-gson`.

Can a default, "basic", TypeAdapterFactory be shipped with auto-value-gson? Such as the one from https://github.com/rharter/auto-value-gson#factory.

Code:

@GsonTypeAdapterFactory
public abstract class MyAdapterFactory implements TypeAdapterFactory {

  // Static factory method to access the package
  // private generated implementation
  public static TypeAdapterFactory create() {
    return new AutoValueGson_MyAdapterFactory();
  }

}

Generated Code:

public final class AutoValueGson_MyAdapterFactory extends MyAdapterFactory {
  @Override
  @SuppressWarnings("unchecked")
  public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
    Class<T> rawType = (Class<T>) type.getRawType();
    if (Media.class.isAssignableFrom(rawType)) {
      return (TypeAdapter<T>) Media.typeAdapter(gson);
    } else {
      return null;
    }
  }
}

We can add a new module with this class to add to the compile configuration.

Generics with parameterized fields

A model with a parameterized field such as this one:

@AutoValue
public abstract class ListResponse<T> {
  public abstract List<T> results();
}

Will produce:

this.resultsAdapter = gson.getAdapter(new TypeToken<List<T>>(){});

This doesn't work since T is erased during runtime.

Problem creating under a package with UpperCases

Hi,

I found this error this morning using it.

Reproduce Step:

  • Create a package named MyPackage
  • Create a autovalue MyPackage.MyAutoValue.class
@AutoValue public abstract class MyAutoValue {
    @SerializedName("test") public abstract String test();
    @SerializedName("test_2") public abstract String test2();

    public static MyAutoValue create() {
        return null;
    }
}

-> this compiles

  • add the TypeAdapter
@AutoValue public abstract class MyAutoValue {
    @SerializedName("test") public abstract String test();
    @SerializedName("test_2") public abstract String test2();

    public static MyAutoValue create() {
        return null;
    }

    public static TypeAdapter<MyAutoValue> typeAdapter(Gson gson) {
        return new AutoValue_TestAutoValueGson.GsonTypeAdapter(gson);
    }
}
Error:(8, 40) error: cannot find symbol class MyPackage
Error:(18, 78) error: package MyPackage does not exist
Error:(26, 59) error: package MyPackage does not exist
Error:(35, 25) error: package MyPackage does not exist

I had another error looking like this
Could not find best guess class for .MyPackage.MyAutoValue.class on line 144

   ClassName autoValueClass = ClassName.bestGuess(context.autoValueClass().getQualifiedName().toString());

How to avoid the problem using this release

Put all packages in lowercase

?

Does get qualified name is returning a path with lowercase and another package is looking to an uppercase path?

It was an error by my part using an uppercase in a package but I had hard time to pinpoint the problem.

I hope it helps

Make it work with @JsonAdapter

Given model class:

@AutoValue
@JsonAdapter(AutoValue_Item.ItemTypeAdapter.class)
public abstract class Item {
  public static Builder builder() {
    return new AutoValue_Item.Builder();
  }

  public abstract long id();
  public abstract String name();

  @AutoValue.Builder
  public static abstract class Builder {
    public abstract Builder id(long id);
    public abstract Builder name(String name);
    public abstract Item build();
  }
}

Following test will fail:

public class ItemTest {
  @Test public void gson() {
    final Item i0 = Item.builder().id(1).name("Awesome!").build();
    final Gson gson = new Gson();
    final String json = gson.toJson(i0);
    final Item i1 = gson.fromJson(json, Item.class); // Will fail!
    assertThat(i1).isEqualTo(i0);
  }
}

With stack trace:

java.lang.NullPointerException
    at com.thuytrinh.android.autosamples.AutoValue_Item$ItemTypeAdapter.read(AutoValue_Item.java:61)
    at com.thuytrinh.android.autosamples.AutoValue_Item$ItemTypeAdapter.read(AutoValue_Item.java:32)
    at com.google.gson.Gson.fromJson(Gson.java:861)
    at com.google.gson.Gson.fromJson(Gson.java:826)
    at com.google.gson.Gson.fromJson(Gson.java:775)
    at com.google.gson.Gson.fromJson(Gson.java:747)

ZipException in IntelliJ/Android Studio multiple modules

If I have two IntelliJ/Studio modules, both containing AutoValue classes, and one depends on the other. The generated com.ryanharter.auto.value.gson.AutoValueGsonTypeAdapterFactory class is present in both the modules and this causes a ZipException when building the project.

Unsupported major.minor version 52.0

Hello,

Thanks for your great extensions.

But while trying auto-value-gson, I got an error during the build.

java.lang.UnsupportedClassVersionError: com/ryanharter/auto/value/gson/AutoValueGsonExtension : Unsupported major.minor version 52.0 

Here is my build.gradle AutoValue related content

final AutoValueVersion = '1.2-SNAPSHOT'
final AutoValueGson = '0.1-SNAPSHOT'
final AutoValueParcel= '0.2-SNAPSHOT'

compile "com.google.auto.value:auto-value:$AutoValueVersion"
apt "com.google.auto.value:auto-value:$AutoValueVersion"
apt "com.ryanharter.auto.value:auto-value-gson:$AutoValueGson"
apt "com.ryanharter.auto.value:auto-value-parcel:$AutoValueParcel"

Here is my class code

@AutoValue
public abstract class Partner implements Parcelable {
    public abstract String name();
    public abstract String logoUrl();
}

I'm using Java 7 JDK in my Android Project. And If I removed the AutoValue Gson extension, the class is generated without problems, that means I guess that the Gson extension is the problem.

Boolean: is naming convention: Cannot find symbol

I have a very simple class:

@AutoValue public abstract class PurchaseStateModel {

    @NonNull public static PurchaseStateModel of(boolean isPurchased) {
        return new AutoValue_PurchaseStateModel(isPurchased);
    }

    public abstract boolean isPurchased();
}

Which causes an exception at compile time. It transformed "isPurchased" to "purchased".

@Override
    public void write(JsonWriter jsonWriter, PurchaseStateModel object) throws IOException {
      jsonWriter.beginObject();
      jsonWriter.name("purchased");
      purchasedAdapter.write(jsonWriter, object.purchased());
      jsonWriter.endObject();
    }

parameterized types

code with parameterized types, for example a Map results in:
gson.getAdapter(Map<String, String>.class).write(jsonWriter, object.map());
and
map = gson.getAdapter(Map<String, String>.class).read(jsonReader);
which results in a compile time error

Android studio multiple modules and Generated TypeAdapterFactory

I've been using AutoValueGson 0.2.5 in my android project which consists of two modules A and B. B has a compile dependency on A, and both A and B contain AutoValue classes.

I created two TypeAdapterFactorys for both the modules: AFactory and BFactory. I, however, made BFactory extend AFactory so I could use it in GsonBuilder.registerTypeAdapterFactory(new BFactory()) and have all my AutoValue typeAdapters included.

The idea is that I can have module A be used by a certain module C and follow the same pattern.

I am not sure how 0.3.0's generated AutoValueGsonTypeAdapterFactorys in both modules can accommodate what I was doing with a custom Factory class.

Support for Enum type

Hi,

I would like to know if there is a support for enum type with the library

@AutoValue
public abstract class Facility implements Parcelable {

    public enum Codes {
        @SerializedName("CPF") FREE,
        @SerializedName("COP") CHARGEABLE,
        @SerializedName("CPP") CHARGEABLE_ONSITE
    }

    @SerializedName("code")
    public abstract Codes code();

    @SerializedName("legend")
    public abstract String legend();

    @NonNull
    public static TypeAdapter<Facility> typeAdapter(Gson gson) {
        return new AutoValue_Facility.GsonTypeAdapter(gson);
    }
}

According to this answer http://stackoverflow.com/a/18851314 on stackoverflow, this is a valid syntax for Gson, but when I try it I get a null pointer exception.

Thanks

Gson 2.4 now supports @SerializedName on methods, description should be updated

Since recent release gson-2.4, it supports @SerializedName on methods (see CHANGELOG).

So I guess this part of README.md should be updated somehow:

Note: Since Gson's built in SerializedName annotation can't be used on methods, you'll have to change your SerializedName import to com.ryanharter.auto.value.gson.SerializedName.

I am not sure how exactly you want to handle this - either by dropping your version of @SerializedName and removing respective note from README or by leaving this custom annotation for those who use earlier Gson version and just mentioning that since gson-2.4 it is not needed.

So I didn't send PR :)

buildUpon() not working

The generated constructor contains a field for a builder:

AutoValue_Message(String text, Message.Builder buildUpon) {
super(text, buildUpon);
}

(This results in a compile time error)

Would be useful to restrict serialization/deserialization with gson @Expose annotation

We conditionally expose fields in our models with the @Expose annotation. GsonBuilder can be configured to recognize. Is there a plan to enable this feature with auto-value-gson extension?

public class MyModel {
   private long doNotExpose;   
  @Expose @SerializedName("expose_me") private long exposeMe;  
...
}
final Gson gson = new GsonBuilder()
   .excludeFieldsWithoutExposeAnnotation()
...
   .create();

When use SerializedName

@AutoValue
public abstract class Topic {

    public abstract String getId();

    @SerializedName("lastupdate")
    public abstract String getLastUpdate();

    public static TypeAdapter<Topic> typeAdapter(Gson gson) {
        return new AutoValue_Topic.GsonTypeAdapter(gson);
    }
}

// in $AutoValue_Topic.java
...
jsonWriter.name("getId"); // "getId" This is not what I expect
...
jsonWriter.name("lastupdate");

Why "getId" is not "id"? How to fix it?

Support single TypeAdapterFactory for all AutoValue generated type adapters.

The currently TypeAdapterFactory mechanism requires users to add each individual TypeAdapterFactory to each Gson instance in order to de/serialize objects. This can be cumbersome, especially when you have a large number of model objects.

As long as we're already generating code, we could alleviate this by generating a single AutoValueTypeAdapterFactory that will serve as TypeAdapterFactory for all AutoValue: Gson generated type adapters. This can use the standard TypeAdapterFactory mechanism to check the class type and delegate the request to the appropriate TypeAdapter.

The challenge I see here is that the AutoValue Extension mechanism processes classes serially, meaning this would require an additional annotation process that processes the same @AutoValue annotation, checks applicability, and generates a single AutoValueTypeAdapterFactory for all applicable classes.

This would reduce the code needed to configure your Gson instance to the following:

Gson gson = new GsonBuilder()
  .registerTypeAdapterFactory(new AutoValueTypeAdapterFactory())
  .build();

Causes to generate TypeAdapter

First of all, thank you for the #19—it greatly simplified things. Just wanted to ask—is it possible to eliminate the need of static method returning TypeAdapter? For example, the processor can go over the class signature and detect if any methods have @SerializedName annotation and, if it does, generate TypeAdapter automagically. It is not an ideal solution of course because @SerializedName is not mandatory at this point. Wanted to ask about this because after #19 implementation it feels a little cumbersome to keep a static method in every model.

GsonTypeAdapterFactory not found

Android Studio can't find @GsonTypeAdapterFactory annotation.
I am using apt 'com.ryanharter.auto.value:auto-value-gson:0.4.0', I also have tried with apt 'com.ryanharter.autogson:auto-gson:0.1-SNAPSHOT' from maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }.

Not sure if I should use apt, provided or compile for importing.

Support mechanism to exclude some classes

Default behavior of this extension is create TypeAdapterFactory for every AutoValue classes. But maybe not all of AutoValue classes need it. So it'd be great if we have a mechanism to exclude or include a specific AutoValue class. A @gson Annotation is a good idea.

Problem with Generics and AdapterFactory

If I add the example with generics to my code:

@AutoValue
public abstract class Foo<A, B, C> {
    // properties...

    public static <A, B, C> TypeAdapter<Foo<A, B, C>> typeAdapter(Gson gson,
                                                                  TypeToken<? extends Foo<A, B, C>> typeToken) {
        return new AutoValue_Foo.GsonTypeAdapter(gson, typeToken);
    }
}

I have this error on my AdapterFactory:

/path/app/build/generated/source/apt/staging/debug/package/AutoValueGson_MyAdapterFactory.java
Error:(33, 78) error: cannot find symbol class A
Error:(33, 81) error: cannot find symbol class B
Error:(33, 84) error: cannot find symbol class C

To fix it I must change TypeToken<? extends Foo<A, B, C>> typeToken to TypeToken<? extends Foo> typeToken:

@AutoValue
public abstract class Foo<A, B, C> {
    // properties...

    public static <A, B, C> TypeAdapter<Foo<A, B, C>> typeAdapter(Gson gson,
                                                                  TypeToken<? extends Foo> typeToken) {
        return new AutoValue_Foo.GsonTypeAdapter(gson, typeToken);
    }
}

What's the problem? The example? Am I missing anything? Is my "fix" correct?

Add @SuppressWarnings to AutoValueGsonTypeAdapterFactory's method create

Hello, I'm getting compilation warnings about unchecked or unsafe casts whenever i use your library.

I did a pull request about what need to be changed but travis gives error on test, and it's ok because generated files changes.

Anyways, please consider add these lines to AutoValueGsonAdapterFactoryProcessor, under MethodSpec.Builder create = MethodSpec.methodBuilder("create"):

.addAnnotation(AnnotationSpec.builder(SuppressWarnings.class)
.addMember("value", "$S", "unchecked")
.build())

does it working on the customize nested object?

for example :

import android.os.Parcelable;
import com.google.auto.value.AutoValue;
import com.google.gson.annotations.SerializedName;

@AutoValue
public abstract class FbAlbum implements Parcelable {
    @SerializedName("id") public abstract String id();
    @SerializedName("name") public abstract String name();
    @SerializedName("count") public abstract int count();
    @SerializedName("picture") public abstract Picture picture();

    public static FbAlbum create(String id, String name, int count, Picture picture) {
        return new AutoValue_FbAlbum(id, name, count, picture);
    }

    public FbAlbum() {}

    @AutoValue
    public abstract static class Picture implements Parcelable {
        @SerializedName("data") abstract PictureData data();

        public static Picture create(String url) {
            return new AutoValue_FbAlbum_Picture(PictureData.create(url));
        }
    }

    @AutoValue
    public abstract static class PictureData implements Parcelable {
        @SerializedName("url") abstract String url();

        public static PictureData create(String url) {
            return new AutoValue_FbAlbum_PictureData(url);
        }
    }
}

I will get the error message at runtime

Process: com.cardinalblue.android.piccollage.multitouch.photoproto, PID: 28821
java.lang.RuntimeException: Failed to invoke public com.cardinalblue.android.piccollage.model.gson.FbAlbum$Picture() with no args
   at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:111)
   at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:206)
   at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:116)
   at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:216)
   at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40)
   at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82)
   at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61)
   at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:116)
   at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:216)
   at com.google.gson.Gson.fromJson(Gson.java:879)
   at com.google.gson.Gson.fromJson(Gson.java:844)
   at com.google.gson.Gson.fromJson(Gson.java:793)
   at com.cardinalblue.android.utils.Utils.parseWithGson(Utils.java:500)
   at com.cardinalblue.android.utils.Utils.parseWithGson(Utils.java:468)
   at com.cardinalblue.android.piccollage.model.gson.FbJsonParser.parse(FbJsonParser.java:33)
   at com.cardinalblue.android.piccollage.model.gson.FbJsonParser.parseAlbums(FbJsonParser.java:22)
   at com.cardinalblue.android.piccollage.view.adapters.FbAlbumListAdapter.parseAlbumList(FbAlbumListAdapter.java:228)
   at com.cardinalblue.android.piccollage.view.adapters.FbAlbumListAdapter.access$300(FbAlbumListAdapter.java:36)
   at com.cardinalblue.android.piccollage.view.adapters.FbAlbumListAdapter$2.onCompleted(FbAlbumListAdapter.java:198)
   at com.facebook.GraphRequest$5.run(GraphRequest.java:1379)
   at android.os.Handler.handleCallback(Handler.java:739)
   at android.os.Handler.dispatchMessage(Handler.java:95)
   at android.os.Looper.loop(Looper.java:148)
   at android.app.ActivityThread.main(ActivityThread.java:5417)
   at java.lang.reflect.Method.invoke(Native Method)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.InstantiationException: Can't instantiate abstract class com.cardinalblue.android.piccollage.model.gson.FbAlbum$Picture
   at java.lang.reflect.Constructor.newInstance(Native Method)
   at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:108)
   at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:206) 
   at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:116) 
   at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:216) 
   at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40) 
   at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82) 
   at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61) 
   at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:116) 
   at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:216) 
   at com.google.gson.Gson.fromJson(Gson.java:879) 
   at com.google.gson.Gson.fromJson(Gson.java:844) 
   at com.google.gson.Gson.fromJson(Gson.java:793) 
   at com.cardinalblue.android.utils.Utils.parseWithGson(Utils.java:500) 
   at com.cardinalblue.android.utils.Utils.parseWithGson(Utils.java:468) 
   at com.cardinalblue.android.piccollage.model.gson.FbJsonParser.parse(FbJsonParser.java:33) 
   at com.cardinalblue.android.piccollage.model.gson.FbJsonParser.parseAlbums(FbJsonParser.java:22) 
   at com.cardinalblue.android.piccollage.view.adapters.FbAlbumListAdapter.parseAlbumList(FbAlbumListAdapter.java:228) 
   at com.cardinalblue.android.piccollage.view.adapters.FbAlbumListAdapter.access$300(FbAlbumListAdapter.java:36) 
   at com.cardinalblue.android.piccollage.view.adapters.FbAlbumListAdapter$2.onCompleted(FbAlbumListAdapter.java:198) 
   at com.facebook.GraphRequest$5.run(GraphRequest.java:1379) 
   at android.os.Handler.handleCallback(Handler.java:739) 
   at android.os.Handler.dispatchMessage(Handler.java:95) 
   at android.os.Looper.loop(Looper.java:148) 
   at android.app.ActivityThread.main(ActivityThread.java:5417) 

Serializing null AutoValue object

I am converting slowly my value objects to AutoValue with Gson extension.
I am having an issue for the following case:
(Pseudo code)

// Not an AutoValue (yet)
class A{
 B b;
}

@AutoValue
class B{
  public abstract Boolean enabled();

  public static TypeAdapter<B> typeAdapter(Gson gson) {
    return new AutoValue_B.GsonTypeAdapter(gson);
  }
}

When I am trying to serialize A with gson and B is null I am getting a NPE on the following line if (object.enabled() != null) inside $AutoValue_B:

    @Override
    public void write(JsonWriter jsonWriter, B object) throws IOException {
      jsonWriter.beginObject();
      if (object.enabled() != null) {
        jsonWriter.name("enabled");
        enabledAdapter.write(jsonWriter, object.enabled());
      }
      jsonWriter.endObject();
    }

because object is null.

How would I go about using an ExclusionStrategy of a custom annotation targeted to a Field?

Trying to do something along the lines of:

    // The fields I want to exclude from serialization/deserialization 
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD, ElementType.METHOD}) // FIXME: remove method
    public @interface Exclude {
    }
    public static class ExcludeAnnotationExclusionStrategy implements ExclusionStrategy {
        @Override
        public boolean shouldSkipField(FieldAttributes f) {
            return f.getAnnotation(Exclude.class) != null;
        }

        @Override
        public boolean shouldSkipClass(Class<?> clazz) {
            return false;
        }
    }
    Gson gson = new GsonBuilder()
            .registerTypeAdapterFactory(new AutoValueTypeAdapterFactory())
            .serializeNulls()
            .setExclusionStrategies(new ExcludeAnnotationExclusionStrategy())
            .create();

I tried simply implementing the derived property style where I define the field in the abstract class with its own accessor method and annotate this property with @Exclude, but this doesn't work as it is not included in the generated GsonTypeAdapter. Also, it will not be included in the generated parcelable implementation using auto-value-parcel.

Ignore(BOTH) isn't respected

Provide an annotation that lets us specify the fields not to be included in the generated TypeAdapter for the @AutoValue annotated class.

For Example:

@AutoValue public abstract class Foo {
  @Gson.Ignore abstract String bar();
  @SerializedName("Baz") abstract String baz();

  // The public static method returning a TypeAdapter<Foo> is what
  // tells auto-value-gson to create a TypeAdapter for Foo.
  public static TypeAdapter<Foo> typeAdapter(Gson gson) {
    return new AutoValue_Foo.GsonTypeAdapter(gson);
  }
}

Generated Class:

public static final class GsonTypeAdapter extends TypeAdapter<Foo> {
    private final TypeAdapter<String> bazAdapter;
    public GsonTypeAdapter(Gson gson) {
      this.bazAdapter = gson.getAdapter(String.class);
    }

   // ...
}

Possible to extend the deserializer to add additional custom value decoding?

Hi,
In my use case I have an auto-value object with that looks something like:

class Foo {
String a;
String b;
String c;
String d;
CustomObject e;
}

I'd like to extend the auto-value deserializer to automatically parse a,b,c,d but let me add additional logic to manually parse the CustomObject at the end.

Is this possible?

Thanks

Unable to Serialize null field

I have a need to serialize a null field. When I mark the field as @Nullable, I see the GsonTypeAdapter write(JsonWriter, Object) method wrap the field adapter's write() call in a null check. But if I remove @Nullable, my builder/factory methods complain about the null value. Is there any way around this?

It looks like 23 could be related?

For clarity, I am calling serializeNulls in my GsonBuilder. Perhaps the write method's GsonTypeAdapter could check that flag in the JsonWriter to bypass the above mentioned null check?

Generated TypeAdapters using Reflection

The TypeAdapterFactories generated by auto-value-gson are using reflection, which is inefficient on Android. Since Android apps usually need to register type adapter factories at application start up this causes a significant delay in app start up.

For example for List<String> the following is generated in the TypeAdapterFactories constructor:
stringAdapter = gson.getAdapter(new TypeToken<List<String>(){})

Inside the default TypeToken constructor is where the reflection happens:
this.type = getSuperclassTypeParameter(getClass());

A better way would be to create an instance of java.lang.reflect.ParameterizedType and pass it into gson.getAdapter(). Unfortunately the only implementations of java.lang.reflect.ParameterizedType are either in Guava or are in internal packages in Gson. In Gson you can create one by calling com.google.gson.internal.$Gson$Types#newParameterizedTypeWithOwner(null, List.class, String.class). Again this is an internal class so probably don't want to rely on it.

The only other solution would be to create an implementation of ParameterizedType and use it. This would have to be a compile time dependency of the client library or application.

Here is a hacky method I created that would use the com.google.gson.internal.$Gson$Types#newParameterizedTypeWithOwner(null, List.class, String.class) solution. Unfortunately it doesn't handle more complicated scenarios where the ParameterizedType includes another ParameterizedType like List<Set<String>> or Map<String, Set<String>>

private CodeBlock getParameterizedTypeConstructorStatement(ParameterizedTypeName type, FieldSpec field, ParameterSpec gsonParam) {
    CodeBlock.Builder block = CodeBlock.builder();
    try {
      int typeArgsSize = type.typeArguments.size();
      int argsIndex = 0;
      Object[] args = new Object[5 + (typeArgsSize)];
      args[argsIndex++] = field;
      args[argsIndex++] = type;
      args[argsIndex++] = gsonParam;
      args[argsIndex++] = ClassName.get($Gson$Types.class);
      args[argsIndex++] = type.rawType;
      String[] genericTypesFormatWithClass = new String[typeArgsSize];
      for (int i = 0; i < typeArgsSize; i++) {
        args[argsIndex++] = type.typeArguments.get(i);
        genericTypesFormatWithClass[i] = "$T.class";
      }
      StringBuilder blockString = new StringBuilder("this.$N = (TypeAdapter<$T>) $N.getAdapter(TypeToken.get($T.newParameterizedTypeWithOwner(null,$T.class,");
      Joiner.on(",").appendTo(blockString, genericTypesFormatWithClass);
      blockString.append(")))");
      block.addStatement(blockString.toString(), args);
    }catch (Exception e){
      //Fall back on using reflection
      block.addStatement("this.$N = $N.getAdapter(new TypeToken<$T>(){})", field,gsonParam, type);
    }

ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast

I made model from example of WebResponse where i'm using Type parameter like so :

@AutoValue
public abstract class SocialStream<T> {
  public abstract int id();
  ......
  ......

  public abstract List<T> messages();

  public static <T> TypeAdapter<SocialStream<T>> typeAdapter(Gson gson, TypeToken<? extends SocialStream<T>> typeToken) {
    return new AutoValue_SocialStream.GsonTypeAdapter(gson, typeToken);
  }
}

As you can see i also passed typetoken to AutoValue typeAdapter, and everything seems to work, i already logged whole json, but problem occurs when i try to use it as my model.

SocialStream<FacebookPost> post = getList().get(0);

method getList() returns array of these messages and this is the line where i'm getting exception:

java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.example.model.FacebookPost

What should the default collection policy be?

Recently the functionality of collections was changed to default to empty collections, instead of null (#71), but this technically breaks the contract with AutoValue, since the property is not annotation with @Nullable. That means that it should technically exist in the JSON. This potentially masks JSON encoding issues.

IMHO, the issue here is that deserializing and serializing are now no longer compatible, i.e. if you deserialize JSON that has a null collection property then serialize it using this extension, you won't be able to reproduce the original JSON, potentially with different meaning.

Recognizing the usefulness of this functionality, @hzsweers has proposed making this a non-default option configurable using apt arguments. This ticket is to discuss the implications and determine what the default collection policy should be.

JSON field annotation

If it is not possible to use the SerializedName annotation from Gson itself, why not use something (probably) better named? Like Json from Moshi.

giphy

Add support for custom TypeAdapters

I need to modify some fields before sending my objects and after parsing them. More precisely, I convert from epoch seconds to epoch milliseconds and viceversa.

Before adding auto-value I was using custom TypeAdapters to do this conversion, but I can't do that anymore, since AutoValue_Foo.GsonTypeAdapter is final.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.