Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Use with Gson #6

Closed
f2prateek opened this issue Jun 4, 2014 · 24 comments
Closed

Use with Gson #6

f2prateek opened this issue Jun 4, 2014 · 24 comments

Comments

@f2prateek
Copy link

Could you annotate your model classes with AutoValue when using with Gson? Since Gson uses fields directly, I wasn't sure how it would work.

@f2prateek
Copy link
Author

@AutoValue
abstract class Foo implement Parcelable {
  public static Foo create(int id) {
    return new AutoValue_Foo(id);
  }

  abstract int id();
}

Foo foo = Foo.create(1);
Gson gson = new GsonBuilder().........build();
String json = gson.toJson(foo);
gson.fromJson(json, Foo.class);

@JakeWharton
Copy link

Outgoing serialization will work. Incoming serialization needs pointed at the generated class rather than the model class.

private class FooDeserializer implements JsonDeserializer<Foo> {
  public Foo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
      throws JsonParseException {
    return context.deserialize(json, AutoParcel_Foo.class);
  }
}

@f2prateek
Copy link
Author

I had something similar but is there a way to do it for all model classes rather than registering a JsonDeserializer for each model class?

@f2prateek
Copy link
Author

What I'm currently doing is look up the class name and prefix AutoValue_ for Gson to know about the generated class.

@JakeWharton
Copy link

No. You could write another annotation processor for @AutoParcel which generated the JsonDeserializer types and then an AutoParcelGsonRegistry which was a visitor for Gson.Builder to register them all.

@f2prateek
Copy link
Author

A code generator for a code generator? Nice!

@frankiesardo
Copy link
Owner

This is such a common use case that I guess the library should provide an auto-parcel-gson-processor. Jackson integration works out of the box thanks to @JsonConstructor but it's definitely too verbose and there are large margins of improvements that an auto-parcel-jackson-processor could address.
I'll reopen the issue to have point for discussion and a reference if somebody wants to push some code for it ;)

@frankiesardo frankiesardo reopened this Jun 5, 2014
@hvisser
Copy link

hvisser commented Jun 9, 2014

For Gson, this looks the preferred way to create an instance: http://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/InstanceCreator.html

@felipecsl
Copy link
Contributor

Looks like this would be useful here

@uknownothingsnow
Copy link

@JakeWharton, your solution works for most situations, but what if I want to use Gson annotations like SerializedName?

@f2prateek
Copy link
Author

That won't work out of the box, you would have to modify AutoParcel to recognize @SerializedName on the methods and add it to the fields in the generated class.

@uknownothingsnow
Copy link

@f2prateek yes, I am working on this approach now.

@JakeWharton
Copy link

That's not a very scalable or generalized solution.
On Oct 22, 2014 9:00 AM, "Bruce Lee" notifications@github.com wrote:

@f2prateek https://github.com/f2prateek yes, I am working on this
approach now.


Reply to this email directly or view it on GitHub
#6 (comment)
.

@felipecsl
Copy link
Contributor

@JakeWharton what would you recommend instead?

@JakeWharton
Copy link

I don't know. But you can't special Gson because, well, that's just not a reasonable solution. You can't blindly copy annotations from the methods to fields because the @Target of them might not allow placement on a field (or even placement on the method in the first place). The only other solution I can think of is extremely convoluted and complex for something that's otherwise trivial so I'm not even going to mention it.

Unless this library becomes AutoGsonParcel I don't think this should be done at all.

The fact that AutoParcel generates code to fulfill the immutability and Parcelable contract is an implementation detail. I should be able to swap out AutoParcel for something else without effecting the Gson serialization of these types.

@frankiesardo
Copy link
Owner

Personally quite against annotating your model object with anything that has to do with serialisation. The reason being that you complect data and representation of data (Gson, Jackson, Xml, Cursor). I'd like to freely swap between serialisers without re-annotating my model objects.

But the truth is those annotations are pretty convenient, so I'd like to find a lean way to provide the same semantic but with a different strategy. Jake, let's see how this scores as a fairly convoluted solution:

@GsonKeyMapper(GsonFooMapper.class)
@JacksonKeyMapper(JacksonFooMapper.class)
@ContentValueKeyMapper(ContentValueFooMapper.class)
public class Foo {...}

A specific annotation processor could generate the required Gson bindings for the Foo class using the GsonFooMapper. A mapper can use its library-specific dsl, like so:

public abstract class GsonFooMapper extends Foo {
  @SerialisedName("x")
  public abstract String y();
}

That way the serialisation mechanisms are composable and easy to refactor. I wish best of luck to anybody who wants to go down that path, tho.

@jkwiecien
Copy link

Gson also need an empty constructor, right? Those are abstract classes :)

@JakeWharton
Copy link

Not since version 2, no. And we are talking about deserialization using the
generated implementation class, not the abstract class.
On Oct 29, 2014 8:37 AM, "jkwiecien" notifications@github.com wrote:

Gson also need an empty constructor, right? Those are abstract classes :)


Reply to this email directly or view it on GitHub
#6 (comment)
.

@frankiesardo
Copy link
Owner

Gson would not directly construct a GsonFooMapper. An annotation processor will use the GsonFooMapper to generate the right deserializer for Foo

@frankiesardo
Copy link
Owner

It's even better if the model object is not annotated at all.
It should be safe to generate the Gson deserializers from external spec classes.

@GsonSerializationSpec(Foo.class)
public abstract class FooGsonSpec extends Foo {
  @SerialisedName("x")
  public abstract String y();
}

That way adding a new serialisation option / changing the serialisation logic for your models will leave your model classes untouched.
I hope that's less confusing.

@johnkil
Copy link

johnkil commented Jul 30, 2015

@frankiesardo what about this issue, can we expect in the near future the implementation based on GsonSerializationSpec annotation?

@frankiesardo
Copy link
Owner

@johnkil I don't think so. But using @AutoGson as described here gets the job done.

@JakeWharton
Copy link

I think this can be closed since the direction of AutoValue extensions will allow this to be accomplished with composition of extensions.

@frankiesardo
Copy link
Owner

Agree. This is now out of scope.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants