Thanks for the quick reply. I mainly asked my questions because they
are problems I ran into while considering the deserialization problem.
(Just to clarify, I'm not actually a Gson developer; we just use it
heavily at my workplace.)
On Wed, May 23, 2012 at 4:22 PM, Pawel <
pawel....@gmail.com> wrote:
>> 1. What would the Gson-using code look like (i.e., describe a call to fromJson)?
>
> fromJsonToInstance(JsonElement, Object);
> fromJsonToInstnace(JsonReader, Object);
> fromJsonToInstance(Reader, Object);
> fromJsonToInstance(String, Object);
That seems pretty straightforward, except...
>> 2. When deserializing a JsonObject into an arbitrary class, how would
>> a deserialized-into-root-object field be created?
>
> It will not be created. My thinking is to use exactly the same logic
> as it is used now, except for instantiation. Superficially, the code
> for fromJson(jsonish, Class cls) calls cls.newInstance() and then
> attempts to fit fields from json at this level into the instantiated
> object. This proposal is to allow the instantiation step to be done by
> the caller, instead of having it being done solely by Gson.
...that this seems like a pretty big departure from the way Gson works
right now. An illustrative example of what I'm concerned about is:
public interface JsonObject {
void setFromJson(JsonElement json, Gson gson);
}
class Foo implements JsonObject {
String foo;
Bar bar;
@Override
public void setFromJson(JsonElement json, Gson gson) {
foo = json.getAsJsonObject().get("foo").getAsString();
bar = new Bar(); // These two lines seem troublesome to me
gson.fromJsonToInstance(json.getAsJsonObject().get("bar"), gson);
}
}
class Bar implements JsonObject { ... }
(I've changed some method names and approaches, but the basic
mechanism seems to be the same.)
In this model, every class that includes a JsonObject field has to
manually construct and call fromJsonToInstance on it. As soon as an
object includes an embedded JsonObject field, it also must implement
JsonObject and construct the nested object manually. This just doesn't
seem like a win to me versus the current TypeAdapter-based (or my
JsonDeserialization<FooDeserializer> interface-based) deserialization
paradigm.
>> 4. How would you deserialize into an instance that is immutable (e.g.,
>> a Boolean), that has no notion of a base root object (i.e., no
>> sensible default constructor), or no runtime-constructed instances at
>> all (e.g., an enum)?
>
> To keep it simple, the same code that is used to populate an instance
> created by Gson, should be applied to the instance passed to the
> caller, as if json has created it. I understand it that Gson will
> still manipulate immutable classes all the same, purely because of how
> it's implemented. This won't work for enums, but enums are static
> classes, and are not instantiable.
>
> If I look through implementation of TypeAdapter, I see these things
> instantiate classes somewhere in their read() methods (and I can see
> changing this will have quite an avalanche effect); now suppose each
> type adapter could also have an instance that was passed to it
> separately, and it will attempt, to it's best, use that instance,
> instead of creating one of it's own.
Note that a TypeAdapter doesn't always construct an instance. Therein
lies its power: it doesn't have to create a new instance. It can use a
static valueOf method to fetch an instance. It can call a getInstance
method that returns cached objects which are constructed only when
necessary. It can call a non-default constructor. The default
implementation that magically builds class instances does call
newInstance. But for your own types, you can create a JsonDeserializer
class that builds your class from a JsonElement in whatever way you
wish. That seems to enable some of the same ideas that you're looking
for with your approach.
Don't get me wrong. Your approach seems like it can simplify things
for a simple, flat class. It can also afford the interesting
possibility of updating an existing instance with new JSON data.
Unfortunately, it seems to break down--becoming at least as cumbersome
as the existing solution--when a JsonObject instance is a field in
another class. Do you disagree?
Thanks for sharing your ideas. You've given me some interesting things
to think about. In an ideal world, deserialization would be performed
by instances so that the methods can be overridden. What if a certain
interface indicated that Gson should construct a default instance and
then call its fromJson method? That seems to get at the most
interesting part of your proposal while still allowing reasonable
behavior when the class is nested.
Let me know if you run into any difficulties,
Brandon
p.s. If you think your idea as it is now will simplify your codebase,
I definitely recommend taking a shot at implementing it. Our codebase
includes a Json utility class that provides convenience methods which
delegate to a static internal Gson instance. You could definitely do
something similar yourself, adding your fromJsonToInstance methods to
do what you like and delegating to a Gson instance when necessary.