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

First class support for polymorphism (subclasses!) #231

Open
GoogleCodeExporter opened this issue Mar 19, 2015 · 51 comments
Open

First class support for polymorphism (subclasses!) #231

GoogleCodeExporter opened this issue Mar 19, 2015 · 51 comments

Comments

@GoogleCodeExporter
Copy link

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

@kiptoomm
Copy link

Was this ever released? I'm using Gson 2.3.1 and don't see it..

@Cy4n1d3
Copy link

Cy4n1d3 commented Nov 13, 2015

I don't think so.
Guess I'll either have to write some generic converters or switch back to Jackson, as I rely on loads of Collections filled with abstract classes for a project...

@JonasVautherin
Copy link

GsonFire does something that could help (see "Type Selectors" here)

@Cy4n1d3
Copy link

Cy4n1d3 commented Apr 7, 2016

Didn't know about that, thanks for the heads up!
Might come in handy some day 👍

@subha-sam
Copy link

subha-sam commented Jul 26, 2016

Hey guys ,
I have a similar usecase as this
Class A{
// fields
}

Class B extends A{
// fields
}

Class C extends A{
// fields
}

Class D extends A{
// fields
}

Class Test extends A{
public List contents = new ArrayList(); // it may contain A, B, C etc.
private boolean isHeader = false;
private String myTestString = "test";
}
I am trying to serialize "contents " collection using gson libarary.

can someone tell me whats the solution for this. I found using RuntimeTypeAdaptorFactory would solve it but, I using gson 2..5, in that version I dont see this class.

Struck with this issues for a past three days. writing custom serializations code for my usecase runs for pages.kindly help. whats the work around that the current gson library is having.

@inder123
Copy link
Collaborator

Copy over RuntimeTypeAdapterFactory code. It is meant to be used as copied source-code.

@mgerhardy
Copy link

mgerhardy commented Mar 27, 2017

Add pull request #1055 that shows a few issues regarding Collection. I would be glad about feedback.

My problem is that I need to deserialize Collections at runtime - thus I can't use the new TypeToken<List>() {}.getType() syntax. I only have a Class instance. Do I have to register some special type of Collection adapter or JsonDeserializer? I tried to add a deserializer but this wasn't possible because I lack needed types for fromJson calls.

	private class RunTimeTypeCollectionAdapter implements JsonDeserializer<Collection> {
		@Override
		@SuppressWarnings({ "rawtypes", "unchecked" })
		public Collection deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context)
				throws JsonParseException {
			if (json == null) {
				return null;
			}
			final TypeToken<?> typeToken = TypeToken.get(typeOfT);
			try {
				Class<?> collectionClass = typeToken.getRawType();
				if (collectionClass == List.class) {
					collectionClass = ArrayList.class;
				} else if (collectionClass == Set.class) {
					collectionClass = HashSet.class;
				} else if (collectionClass == Map.class) {
					collectionClass = HashMap.class;
				}
				final Collection collection = (Collection) Class.forName(collectionClass.getTypeName()).newInstance();
				final Class<?> rawType = typeToken.getRawType();
				if (json.isJsonArray()) {
					final JsonArray array = json.getAsJsonArray();
					for (int i = 0; i < array.size(); ++i) {
						final JsonElement element = array.get(i);
						final Object deserialize = context.deserialize(element, rawType);
						collection.add(deserialize);
					}
				} else {
					// final Object deserialize = context.deserialize(json,
					// rawType);
					// collection.add(deserialize);
				}
				return collection;
			} catch (final Exception e) {
				logger.error(e.getMessage(), e);
			}
			return null;
		}
	}

As you can see in this example, I am getting to a point where the deserializer doesn't get a json array - but MyClass (from Collection - this is a little bit weird for me - because I get those elements one by one, not via array.

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

No branches or pull requests

8 participants