julman99 / gson-fire

A java library that adds some very useful features to Gson, like Date serializing to unix timestamp or RFC3339, method (getters) serialization, pre/post processors and many others. Check out the documentation to learn how to use it!
http://gsonfire.io
Other
229 stars 37 forks source link

Type Selector question #20

Closed iwarapter closed 9 years ago

iwarapter commented 9 years ago

I have a large hierarchy of classes with a common base, but i don't appear to be able to use my common base, i'd need to specify each object that is extended. Is this correct?

e.g. say i have: Class Base A extends Base B extends A C extends B (etc)

Can i not create a type selector from the base class for the extended model

.registerTypeSelector(Base.class, new TypeSelector<Base>() {
      @Override
      public Class<? extends Base> getClassForElement(JsonElement readElement) {
      ...
julman99 commented 9 years ago

You should be able to register that type selector. I don't think I fully understand the issue you are facing, can you elaborate a bit more on the problem?

iwarapter commented 9 years ago

Put together a quick groovy example: https://gist.github.com/iwarapter/8e1369ed0ed6d159a5b9

I can add more type selectors for the hierarchy e.g.

GsonFireBuilder builder = new GsonFireBuilder()
    .registerTypeSelector(Base.class, new TypeSelector<Base>() {
        @Override
        public Class<? extends Base> getClassForElement(JsonElement readElement) {
            String type = readElement.getAsJsonObject().get("type").getAsString()
            return Class.forName(type)
        }
    })
    .registerTypeSelector(A.class, new TypeSelector<A>() {
        @Override
        public Class<? extends A> getClassForElement(JsonElement readElement) {
            String type = readElement.getAsJsonObject().get("type").getAsString()
            return Class.forName(type)
        }
    })
Gson gson = builder.createGsonBuilder().setPrettyPrinting().create()

Essentially I want to use one TypeSelector for ALL classes that extend from Base without needing to add one for each class (there are hundreds!).

julman99 commented 9 years ago

As long as the fully qualified class name is on the field type, you should be able to do:

GsonFireBuilder builder = new GsonFireBuilder()
    .registerTypeSelector(Base.class, new TypeSelector<Base>() {
        @Override
        public Class<? extends Base> getClassForElement(JsonElement readElement) {
            String type = readElement.getAsJsonObject().get("type").getAsString()
            return Class.forName(type)
        }
    })
Gson gson = builder.createGsonBuilder().setPrettyPrinting().create()

Check out this test, it does something similar to what you want to achieve.

Now, in order to have the type field in all Json objects, one thing you could do is register a PostProcessor for Base and inject the type field there.

iwarapter commented 9 years ago

All the classes inherit a type field from my base class, the problem I have is when I have my class C which contains an field of type A which is abstract and so in the example groovy script is actually a B object. The problem is unless i specifically register a type selector for A it will attempt to cast it directly as an A object, and fail :(

julman99 commented 9 years ago

It think I understand the problem now! When you register a type selector for the class Base it is only applying to that class and not to its sub-classes. I would consider this a bug since the rest of the GsonFireBuilder registrations happen for the specified class and it subclasses. Did I get it right?

iwarapter commented 9 years ago

Yes!

iwarapter commented 9 years ago

Any ideas for this?

julman99 commented 9 years ago

This will be deployed before October 13th. Thanks for reporting it

julman99 commented 9 years ago

Fixed in version 1.4.0