rharter / auto-value-gson Goto Github PK
View Code? Open in Web Editor NEWAutoValue Extension to add Gson De/Serializer support
License: Apache License 2.0
AutoValue Extension to add Gson De/Serializer support
License: Apache License 2.0
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);
}
...
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.
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?
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!
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.
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);
}
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
.
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.
Is it possiable to develop a plugin like this https://github.com/zzz40500/GsonFormat?
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();
}
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.
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)
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.
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 :)
For some reason, we generated AutoValueGsonTypeAdapterFactory
ourselves.
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
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
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();
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
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())
I do not want use @nullable
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.
The API I'm working with requires null attributes to be sent and the generated type adapter never writes attributes which are null.
Gson has a @JsonAdapter
annotation that allows you to specify a custom type adapter for just that field, that would be awesome to support :)
I would really like to use 1c0995d
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
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)
When creating a @GsonTypeAdapterFactory
, the constructor that should be available to use into the static create()
is not found.
For instance, see this project https://github.com/satoshun-example/android-architecture with Android Studio 2.2, upgraded to the latest gradle wrapper and gradle plugin.
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.
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.
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.
I am keeping this issue short as I notice in #17 (comment) that there is awareness about it.
The main reason I open this issue is to confirm the same.
Would you/this project be interested in the addition of a aar distribution containing a lint check which validates that an AutoValue annotated class has the typeAdapter method added?
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);
}
// ...
}
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();
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.
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.
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.
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();
}
}
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?
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
Hi,
I found this error this morning using it.
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
@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());
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
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.
0.4.1 doesn't seem to be on maven. Could you upload it?
http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22auto-value-gson%22
https://bintray.com/bintray/jcenter/com.ryanharter.auto.value%3Aauto-value-gson
Also couldn't see it in snapshots repo
https://oss.sonatype.org/content/repositories/snapshots/com/ryanharter/auto/value/auto-value-gson/
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?
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 TypeAdapterFactory
s 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 AutoValueGsonTypeAdapterFactory
s in both modules can accommodate what I was doing with a custom Factory class.
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)
@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?
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
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.