Open GoogleCodeExporter opened 9 years ago
Issue 170 has been merged into this issue.
Original comment by limpbizkit
on 28 Aug 2010 at 6:03
It would be more robust to support a custom JSON schema that serializes runtime
type information explicitly (akin to xsi:type in XML) rather than trying to
guess the type by field name matching (if two unrelated classes had the same
fields the guess might be wrong). For example, you could have
Gson.setRuntimeTypeProperty(String) and say
gson.setRuntimeTypeProperty("$type");
Thanks,
Adrian Price
Senior Architect
TIBCO Software Inc.
Original comment by adrianp....@gtempaccount.com
on 1 Oct 2010 at 1:10
Issue 237 has been merged into this issue.
Original comment by limpbizkit
on 6 Oct 2010 at 5:49
Issue 238 has been merged into this issue.
Original comment by limpbizkit
on 6 Oct 2010 at 5:57
Issue 209 has been merged into this issue.
Original comment by limpbizkit
on 6 Oct 2010 at 6:35
I concur with Adrian, except that it would be best if the JSON property holding
the explicit runtime type were not configurable at all, just for simplicity's
sake. However, you can only do that if the prop name is something that can't be
a Java identifier name, to avoid clashing. I'm guessing the serializer would
have to be configured for whether or not to output that information, maybe only
on particular fields or classes. But the deserializer would not have to
configured; it would simply use the runtime type if present, and behave the old
way if not.
At any rate, I would also like to see this done. Not being able to handle
polymorphism is pretty much a non-starter for a rich data model. Is there a
workaround, even if painful? If so, could you post something showing how it
could be done?
- Ray A. Conner
Original comment by ray.a.co...@gmail.com
on 27 Oct 2010 at 9:25
Issue 129 has been merged into this issue.
Original comment by limpbizkit
on 4 Nov 2010 at 10:44
Let me give another counter-example (pseudo-code), which I would really like to
turn into json:
class AllPredicate< T > implements Predicate< T > {
List< Predicate< T > > operands;
}
I always avoid specifying a concrete type if an appropriate interface exists.
Original comment by ray.a.co...@gmail.com
on 11 Nov 2010 at 12:10
I disagree with the suggestion in Comment#6 that the type property name should
be hard-coded. We're talking about a *custom* JSON schema so IMO such a
property needs to be configurable (just as the mechanism for resolving and
deresolving the type name needs to be extensible, to allow use of other
metamodels besides Java, e.g., XSD, UML, EMF). I suppose you could store the
custom type property name in some hard-coded property on the root JSON object
(e.g., gson:type_property) and of course there should be a sensible default
type property name (e.g., gson:type) and a usable default metamodel (e.g.,
JavaTypeSystem).
By the way there are other custom JSON schema extensions that are also required
to support *formal modelling* semantics properly, such as the notion of element
identity and the distinction between UML-style composition aggregation
associations versus non-aggregating associations. As things currently stand a
Java object graph in which multiple elements refer to a single object, the
referenced object will be replicated in the serialized JSON and will
deserialize into multiple identical objects rather than a single instance as in
the original. Not at all what is required of a non-aggregating association!
Adrian Price
Original comment by adrianp....@gtempaccount.com
on 11 Nov 2010 at 2:12
I'll admit it's a bad idea to hard-code that. My main concern was keeping the
number of things that the programmer has to do to a minimum, convention over
configuration. I've found that the more you make a programmer do, especially if
it has to be consistent in two or more places, the more likely it will be done
incorrectly.
Original comment by ray.a.co...@gmail.com
on 11 Nov 2010 at 2:46
You should try the Hierarchical Type Adapter feature to see if this helps
simplify your problem. Basically, it appears that you will need to push the
sub-classing logic into it.
The official announcement for the release is here:
http://groups.google.com/group/google-gson/browse_thread/thread/6272c9be58676e47
Original comment by joel.leitch@gmail.com
on 13 Apr 2011 at 4:22
Fixed in r828.
Original comment by joel.leitch@gmail.com
on 20 Apr 2011 at 10:35
Issue 321 has been merged into this issue.
Original comment by limpbizkit
on 4 May 2011 at 9:31
This wasn't fixed by r828. But I'm going to implement this. Here's my proposed
API:
RuntimeTypeAdapter<BillingInstrument> grta
= new RuntimeTypeAdapter(BillingInstrument.class, "type");
grta.registerSubtype(CreditCard.class, "CC");
grta.registerSubtype(Paypal.class, "PayPal");
grta.registerSubtype(BankTransfer.class); // defaults to the simple name, "BankTransfer"
This would synthesize a type field in the emitted JSON as a hint during
deserialization:
/*
* "billingInstruments": [
* {
* "type": "CC",
* "cvv": 234
* },
* {
* "type": "PayPal",
* "email", "jesse@swank.ca"
* }
* ]
*/
Original comment by limpbizkit
on 5 May 2011 at 7:00
Again, I urgently entreat you *not* to hard code the custom schema in the way
suggested by comment #14. For a start, the namespace for 'meta-type' attributes
like this *must* be something that won't collide with application metamodels.
If you hard code it as 'type' then you won't be able to serialize any object
that has a legitimate 'type' attribute. They made the same mistake in SDO and
it ruined an otherwise lovely specification. At the very least, provide a
mechanism for customizing such meta-attribute names.
Original comment by adrianp....@gtempaccount.com
on 7 May 2011 at 12:51
@adrianp agreed. Thats howhy 'new RuntimeTypeAdapter' takes two arguments!
Original comment by limpbizkit
on 7 May 2011 at 3:54
Ahh... I get it now. Sorry, I should have studied the code snippet more
carefully. Looks good! :-)
Original comment by adrianp....@gtempaccount.com
on 7 May 2011 at 5:42
@comment 13: is there a build available ? I really need polymorphism when
serialising. The 1.7.1 release does not seem to support it correctly.
Original comment by david.nouls
on 1 Jun 2011 at 2:12
It isn't done yet! But you can take a look at RuntimeTypeAdapter.java in svn if
you'd like something urgently.
Original comment by jessewil...@google.com
on 1 Jun 2011 at 8:27
I tried with a build of trunk and it fixes my serialisation issues. So
hopefully there will be a new release coming soon. There were 4 unittest
failing in the trunk.
Original comment by david.nouls
on 6 Jun 2011 at 8:41
[deleted comment]
[deleted comment]
Yes, comment 14 would be very useful! Another way that you can get around this
solution as a coder, if you are using polymorphism in a List: for your
abstract class, keep a counter variable in it, and save separate "subclasses"
in the counter for order. When serializing, create separate saved files as
Json strings to keep track of what subclass you are using. Then when you
deserialize the data to information and load it into each of your classes, load
the data to each of your subclasses in the order your abstract class detailed
the order as.
Original comment by jshlcl...@gmail.com
on 28 Jun 2011 at 8:29
Would be great to see something like Comment #14 appear :)
What would happen if "type" : "..." was not in the json example? It should
still be possible determine the correct subtype based on the contents of the
json. Could the API outsource this test? The only other alternative is that
multiple RuntimeTypeAdapter's are created... and that seems very problematic
too...
Don't read too deeply into this code, I'm shooting from the hip...
RuntimeTypeAdapter<BillingInstrument> grta = new
RuntimeTypeAdapter(BillingInstrument.class);
grta.registerSubtype(CreditCard.class, new IsSubtype(){
@override
public boolean isSubType(JsonElement jsonElement){
//if the json has a "cvv" then yes, its a CreditCard. But this could be something far more complicated...
return jsonElement.getAsJsonObject().get("cvv") != null;
}
});
Other notes, would reflection/introspection be of use to produce re-usable
IsSubType's? If so, then the IsSubtype should probably have access to the class
also (and not just the jsonElement alone).
Original comment by ahhug...@gmail.com
on 29 Jun 2011 at 12:33
@ahhughes: detecting based on the fields is possible but definitely not very
reliable. If you'd like to do that, you should write your own type adapter!
Original comment by jessewil...@google.com
on 29 Jun 2011 at 4:16
Is it possible to divide serialization to jsonTree from deserialization from
jsonTree? Implementation of serialization looking to be very straightforward
(without using marker field), and in some cases it is enough to just serialize
bean and not deserialize.
In my case (website) I'm using strictly typed deserialization to bean (ajax
posts) and dynamic typed serialization (event mechanism - events are sent back
to client and processed via JS).
Original comment by oxygene.core
on 31 Aug 2011 at 12:44
[deleted comment]
I notice that the "RuntimeTypeAdapterFactory" class is at the moment in
"extras", will it be part of the next release anyway?
Original comment by klov...@virtuoz.com
on 19 Oct 2011 at 8:19
RuntimeTypeAdapterFactory won't be in GSON 2.0.
Original comment by limpbizkit
on 19 Oct 2011 at 5:54
There is a simple solution for this..override the default CollectionTypeAdapter
to not use the defined parameterized type.
for example:
private class RunTimeTypeCollectionAdapter implements JsonSerializer<Collection> {
@Override
public JsonElement serialize(Collection src, Type typeOfSrc,
JsonSerializationContext context) {
if (src == null) {
return null;
}
JsonArray array = new JsonArray();
for (Object child : src) {
JsonElement element = context.serialize(child);
array.add(element);
}
return array;
}
}
in your gson builder, use this:
new GsonBuilder().registerTypeHierarchyAdapter(Collection.class, new
RunTimeTypeCollectionAdapter())
Original comment by tommytcc...@gmail.com
on 9 Nov 2011 at 11:46
In the current implementation of RuntimeTypeAdapterFactory, the Shape class is
forbidden to have a field that can be used as type. This is sometimes desirable
when you know the limited number of shapes you are going to use:
enum ShapeType {
RECTANGLE, CIRCLE
}
static class Shape {
private final ShapeType shapeType;
protected Shape(ShapeType shapeType) {
this.shapeType = shapeType;
}
}
Now, if I use:
RuntimeTypeAdapterFactory shapeTypeAdapterFactory =
RuntimeTypeAdapterFactory.of(Shape.class, "shapeType");
shapeTypeAdapterFactory.registerSubType(Rectangle.class);
shapeTypeAdapterFactory.registerSubType(Circle.class);
new GsonBuilder().registerTypeAdapaterFactory(shapeTypeAdapterFactory).create();
This will result in a runtime error:
com.google.gson.JsonParseException: cannot serialize Rectangle because it
already defines a field named shapeType
at com.trymph.definition.gson.RuntimeTypeAdapterFactory$1.write(RuntimeTypeAdapterFactory.java:228)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:240)
at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:1)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
at com.google.gson.Gson.toJson(Gson.java:582)
at com.google.gson.Gson.toJson(Gson.java:561)
at com.google.gson.Gson.toJson(Gson.java:516)
Suggestions on how to revise RuntimeTypeAdapterFactory which will take care of
this situation better?
Original comment by inder123
on 14 Apr 2012 at 7:21
What about pre-pending a character that is illegal in a java field so there
won't be collisions?
Original comment by l...@ghue.net
on 15 Apr 2012 at 3:37
Hi,
I need to know how we can deserialize an object which contains a list of type
abstract class as an attribute using gson
code eg:
class A{
List<B> list;
}
public abstract class B{
}
..
Original comment by chinju18...@gmail.com
on 24 May 2012 at 8:28
Any movement on this? Comment #14 seems like an option. Not sure if #30 made it
in either. I thought gson would have had this down easy due to its popularity.
Original comment by m...@foursquare.com
on 30 Jun 2012 at 5:18
Implemented by:
http://code.google.com/p/google-gson/source/browse/trunk/extras/src/main/java/co
m/google/gson/typeadapters/RuntimeTypeAdapterFactory.java
We aren't (yet) including this in the core API so your best bet is to include
the source in your app.
Original comment by limpbizkit
on 5 Jul 2012 at 7:37
The current javadoc is incorrect. One should read the following:
RuntimeTypeAdapterFactory<Shape> shapeAdapter = RuntimeTypeAdapterFactory.of(Shape.class)
.registerSubtype(Rectangle.class)
.registerSubtype(Circle.class)
.registerSubtype(Diamond.class);
Gson gson = new GsonBuilder().registerTypeAdapterFactory(shapeAdapter).create();
Shape rectangle = new Rectangle(..);
jsonString = gson.toJson(rectangle, Shape.class);
Original comment by pjpi...@gmail.com
on 27 Jul 2012 at 12:02
Dear all,
This RuntimeTypeAdapterFactory is the solution for registering the Type and
subType.
As per our requirement : if custom object comes from server then i will define
only one top level type which is pass as in fromJson() api's second parameter,
Runtime it will manage all suptypes.
Does it possible to manage this without type and subtype registration ?
Lets take one example.
Class A{
// fields
}
Class B extends A{
// fields
}
Class C extends A{
// fields
}
Class D extends A{
// fields
}
Class Test extends A{
public List<A> contents = new ArrayList<A>(); // it may contain A, B, C etc.
private boolean isHeader = false;
private String myTestString = "test";
}
Is there any way to write without registering type and subtype?
as here define runtimeTypeAdapter in TypeAdapterRuntimeTypeWrapper,
is there any other solution put logic here or other place?
is in read logic as per "type" can we create runtime adapter as per "type"
coming?
it coming in ReflectiveTypeAdapterFactory in read() of Adapter<T>
Original comment by pareshpv...@gmail.com
on 11 Sep 2012 at 2:33
If I understand this Issue (231) correctly (which i may not), are we not
talking about the limitation of not being able to deserialize arbitary
collections of objects? If that is the case, a reasonable solution would seem
to be easy enough: just have a config option to (optionally) serialize an
object's java class along with its other fields. The field could be named
something like com_google_gson_java_class and simply be a string with the class
name. Easy to serialize. Easy to deserialize.
Original comment by rhd...@gmail.com
on 26 Apr 2013 at 4:25
Re. #38, we're not talking specifically about collections per se, the principle
applies as much to single-valued as multi-valued properties. It's more about
preserving runtime type information in the JSON so that the original object
class can be re-instantiated by custom type adapters when deserializing the
JSON. As I mentioned in #9, the type scheme needs to be extensible so that it
can be made to work with XSD, UML, EMF, not specifically the Java type system.
For example, I'd like to be able to serialize dynamic EMF EObjects - these are
all instances of org.eclipse.emf.ecore.impl.DynamicEObjectImpl but their eClass
is different and it is their qualified EClass name (e.g., as
package-ns-prefix:type) that one would wish to serialize as the runtime type
name.
Original comment by adrianp....@gtempaccount.com
on 27 Apr 2013 at 6:13
Thanks for the RuntimeTypeAdapterFactory guys, been using it in some production
code and it is working quickly and as expected for handling a collection of
JSON objects which can be one of many types.
Original comment by DavidTP...@gmail.com
on 24 Sep 2013 at 1:11
Hey guys.
A simple case I try to solve with RuntimeTypeAdapterFactory of yours.
JSON field can be either an JSONObject or String.
How would I parse it?
Original comment by kamui.ji...@gmail.com
on 3 Feb 2014 at 7:19
What's the hold up on this - it seems like there were perfectly good
suggestions made, and implementation created. Can you share the thinking
behind why its not yet in the library?
Original comment by nbpr...@gmail.com
on 6 Feb 2014 at 3:33
Check out https://github.com/julman99/gson-fire, it has this feature and other
ones that personally I think they are missing from Gson.
Original comment by julio.vi...@gmail.com
on 27 Feb 2014 at 5:36
Hi!
I've tried using the RuntimeTypeAdapterFactory, and it works fine, except for
one small caveat: when serializing objects within lists within objects, the
type field is left out. For example, this is what I expect:
{"$type":"Area","locations":[{"$type":"Location",
"coordinateX":34.0,"coordinateY":57.0,"wifiMorsels":[...]}
But this is what I get:
{"$type":"Area","locations":[{"coordinateX":34.0,"coordinateY":57.0,"wifiMorsels
":[...]}
Note that the Area object is also within an object (meaning that simple nested
objects works) and that wifiMorsels is another list where the contained objects
lack the type field and value.
In my case I'll be using the same code on both sides of the JSON-based
communication, so I require the $type field to work.
Any help is greatly appreciated!
Original comment by tamino.h...@gmail.com
on 17 Mar 2014 at 6:24
Hi!
Very cool feature! I've found just a little problem: suppose to have:
public class Person {}
public class Student extends Person {}
And suppose to have a Jersey resource like this:
@Path("/")
public class PersonController {
@GET
@Path("/student1")
@Produces(MediaType.APPLICATION_JSON)
public Student getStudent1() {
return new Student();
}
@GET
@Path("/student2")
@Produces(MediaType.APPLICATION_JSON)
public Person getStudent2() {
return new Student();
}
}
In this example, only the second method will work, because into
RuntimeTypeAdapterFactory this condition return false (first instruction of
create method):
if (type.getRawType() != baseType)
I suggest to change that line with
if (!baseType.isAssignableFrom(type.getRawType()))
In this way, I think RuntimeTypeAdapterFactory is more transparent, because
doesn't require to always use the super type to serialize the object.
Original comment by canemacc...@gmail.com
on 31 Mar 2015 at 10:33
GSON always operates on the static type of an object. It has no mechanism to operate on the object's runtime type. It would be handy if GsonBuilder permitted a way to specify the known subclasses of a type. Then at serialization/deserialization these fields could be included: public void testPolymorphism() { Rectangle r = new Rectangle(); r.width = 5; r.height = 7; Circle c = new Circle(); c.radius = 3; List<Shape> shapes = new ArrayList<Shape>(); shapes.add(r); shapes.add(c); Gson gson = new GsonBuilder() .create(); String json = gson.toJson(shapes, new TypeToken<List<Shape>>() {}.getType()); assertEquals("[{\"width\":5,\"height\":7},{\"radius\":3}]", json); } static class Shape {} static class Rectangle extends Shape { int width; int height; } static class Circle extends Shape { int radius; } It would be extra awesome if it could use the set of fields in a stream to infer the type to instantiate. In the example above, it could use that the 'radius' field as evidence that the runtime type should be a Circle. Or perhaps this could be user-configured too, such as this: new GsonBuilder() .runtimeType(Shape.class, Circle.class, "radius") .runtimeType(Shape.class, Rectangle.class, "width", "height") .create();
Original issue reported on code.google.com by
limpbizkit
on 28 Aug 2010 at 6:00