1

How can I wrap certain values when serializing an object model to JSON with GSON? Example model:

class Order {
  Customer cust;
}

class Customer {
  String name;
  int age;
}

Serializing a Customer would normally yield something like:

{cust:{name:joe, age:21}}

What I would like to do is wrap the Order and Customer values in an additional element with the class name. So the expected JSON would be:

{Order:{cust:Customer:{name:joe, age:21}}}

The actual classes that I'll be serializing could be anything, so I can't hardcode specific properties in a serializer. But I will want to wrap certain properties with their class name.

How can I do this?

Josh
  • 875
  • 1
  • 13
  • 25
  • Do you *absolutely* need the wrapping part, or can you achieve a similar functionality by adding a "clazz" field to your model objects? – Raffaele Apr 05 '12 at 08:26
  • I don't own the objects I'll be serializing and deserializing, so no I can't add anything to them. – Josh Apr 05 '12 at 15:27
  • Sure, but at serialization time you can add a `clazz` field holding the fully qualified class name, so when deserializing you can read that `clazz` and get back the Java type with `Class.forName`. You only need to do this for the root element, since then you can use the standard Gson routines. I looked deeply into the Gson API and sources, and it seems that the kind of *decoration* you are looking for is impossible to do (at least I didn't find an easy way without modifying the sources). There are other libraries, of course, and you could try to specify why the type of the response is unknown – Raffaele Apr 05 '12 at 20:04
  • It's easy to decorate an element: new JsonObject().add(rootElementName, gson.toJsonTree(object, targetType))...What I can't sort out is how to do this for arbitrary elements within a document. In other words, it's easy to do for the root element, but how would I do this for some element 5 levels deep? – Josh Apr 05 '12 at 21:12
  • Sure, I meant that the harder part is doing for arbitrairly deep nesting levels :-) still I can't figure out why you need this. Once you have the root type, Gson can deserialize and build the object via reflection – Raffaele Apr 05 '12 at 21:36
  • Gson can only deserialize objects using reflection if you tell it what the type is. I can unwrap the top level type and see that it's an Order, and tell Gson to deserialize it as an order, but if there's a customer several levels deep, Gson won't know how to deserialize that unless there's a TypeAdapter or Deserializer registered for that specific type. That's the problem. – Josh Apr 05 '12 at 22:12
  • maybe I don't uderstand your point. See [this paste](http://pastebin.com/pGfybjAp) and tell me if your problem is a different one – Raffaele Apr 06 '12 at 13:20
  • Try making Customer an interface with different implementations. Gson won't know which implementation to deserialize with. – Josh Apr 06 '12 at 16:43
  • This is a different question :) see [Deserializing in Gson](http://stackoverflow.com/questions/3629596/deserializing-an-abstract-class-in-gson) or [Polymorphism with Gson](http://stackoverflow.com/questions/5800433/polymorphism-with-gson) and finally [this issue](http://code.google.com/p/google-gson/issues/detail?id=231) Basically you have to write serializers and deserializers for fields defined with an abstract type – Raffaele Apr 06 '12 at 17:53

1 Answers1

0

This is not a valid json string though:

{Order:{cust:Customer:{name:joe, age:21}}}

In you application, you have to model/implement your domain class properly before it can be used for serializing/deserializing json string, in another word, the domain class should be known before calling toJson/fromJson method. However the actual domain class type can be determined dynamically at runtime, By using Java Generic Type.

Check out the section Serializing and Deserializing Generic Types from Gson User Guide:

public class Foo<T> {
  public T value;
}

To serialize it:

Gson gson = new Gson();
Type fooType = new TypeToken<Foo<Bar>>() {}.getType();
gson.toJson(foo, fooType);

To deserialize it:

Gson gson = new Gson();
Type fooType = new TypeToken<Foo<Bar>>() {}.getType();
gson.fromJson(json, fooType);
yorkw
  • 40,926
  • 10
  • 117
  • 130
  • The point of this is that I *don't* know what class I'm deserializing to - that's why I want to wrap certain elements in the class name. – Josh Apr 05 '12 at 15:31
  • If the class type is unknown, it is unnecessary to deserialize this part of json string to a concrete java object. Probably you can alter you json string and organize multiple json fileds/infos as a raw string, when serialize/deserialize with gson, these multiple json fields/infos are treated as regular java string type. – yorkw Apr 05 '12 at 21:42