Skip to content
This repository has been archived by the owner on Aug 26, 2021. It is now read-only.

Type being known at runtime. #25

Open
anirudhramanan opened this issue Dec 6, 2016 · 11 comments
Open

Type being known at runtime. #25

anirudhramanan opened this issue Dec 6, 2016 · 11 comments

Comments

@anirudhramanan
Copy link
Contributor

anirudhramanan commented Dec 6, 2016

Problem Statement : While parsing the model object, if any class which has subclasses is being used as a field, and its type is known at runtime, stag will not be able to get the corresponding type adapter, and hence it will not able to serialize the fields of the subtypes/subclasses.

Solution : Since the type is known at runtime, we have to fallback to gson to parse that particular field.

Proposed Fix : We can have another annotation named @WriteRuntimeType, and the if the classes which has subclasses or subtypes is being used as a field in another model should be annotated with this. This will enable stag to dynamically fallback to gson for parsing such fields.

@anthonycr Will this work ?

@anirudhramanan
Copy link
Contributor Author

We came across this while one of our model class that had few subclasses was being used as a field in another class. While debugging we found out that although the type of field was one of the subclasses, the adapter that was being used to parse the same was of the super class type, hence not able to serialize the fields of subclasses

@anthonycr
Copy link
Contributor

anthonycr commented Dec 6, 2016

I'm not sure I completely understand the situation.

Is this the sort of structure you're referring to?

class ClassA<T> {
    T unknownField;
}

class ClassB extends ClassA<ClassA<String>> {
    // some more fields
}

We have a similar use case, which isn't experiencing any problems (see https://github.com/vimeo/vimeo-networking-java/blob/v2.0.0/vimeo-networking/src/main/java/com/vimeo/networking/model/Category.java). But our example uses a Category class which itself contains a field of type ArrayList<Category>, rather than inheriting from a parameterized class and using that class as the type.

@anirudhramanan
Copy link
Contributor Author

anirudhramanan commented Dec 6, 2016

Lets assume we have subclasses of class User, say UserWithAddress, and UserWithoutAddress

public class User {
   public String name;
}

public class UserWithAddress extends User {
   public String address;
}

public class UserWithoutAddress extends User {
   public String location;
}

Now, in Video class, we have User class as a field

public class Video {
   public User user;
}

Suppose the type of User field is known at runtime ie, it may be UserWithAddress or UserWithoutAddress or can be User simply. If it is of type User, everything will be work fine. But if its one of UserWithAddress or UserWithoutAddress, since stag does not know the actual type, and assumes it to be of type User, it will use the typeadapter of User to serialize it which will result in fields of the actual type not getting serialized.

Let me know if this helps

@anthonycr
Copy link
Contributor

Okay that's a much simpler scenario than I thought, thanks for the clarification.

This is definitely an important use case, i'll think on it.

@anirudhramanan
Copy link
Contributor Author

anirudhramanan commented Dec 6, 2016

Sure. We fixed this using the annotation, looking forward for an alternative solution :)

Thank you

@anirudhramanan
Copy link
Contributor Author

@anthonycr Any updates on this ? Would be great if this gets resolved in the upcoming release.

@anthonycr
Copy link
Contributor

anthonycr commented Dec 19, 2016

Okay, so if we introduce a WriteRuntimeType annotation, then the generated writing code could look like the following:

class Parent {
    String name;
}

class Child extends Parent {
    String name1;
}

class Other {
    Parent parent;
}

// generated
class Other$TypeAdapter {
    void write() {
        // other stuff

        // if (parent field annotated with RuntimeType)
	        mGson.getAdapter(object.mParentType.getClass()).write();
        // else
                mStagFactory.getParentType$TypeAdapter(mGson).write();
    }
}

This doesn't solve the whole problem, because the type isn't known when parsing the json, so then when you parse the correct json it will just lose the field because it will try to parse it as a parent type. Of course, if you don't need to deserialize it once it's been serialized then it will work fine.

@anirudhramanan
Copy link
Contributor Author

Yes. You're right. I tried the same thing with Gson as well, it does not deserialize it with the correct type.

@anthonycr
Copy link
Contributor

Do you think it's worth implementing the serialization half of this anyway? That would at least mirror gson's behavior, but at the same time I feel like it's not worth adding in new stuff for a half solve

@yasirmhd
Copy link
Contributor

yasirmhd commented Jan 6, 2017

Ideal case would be that people use

class Other {
T parent;
}

This is a better way to represent it anyways where there are no run time checks for the type.

I guess a more generic requirement that might exists (for certain other corner/unknown/unhandled/stag-being-buggy scenario) is to allow certain fields of a class to be defaulted to Gson parsing.

Since this would be an exception we can call this annotation as @UseGson which is a field level annotation only.

Thoughts?

@yasirmhd
Copy link
Contributor

yasirmhd commented Feb 7, 2017

I guess this is in a way the same as putting a wrapper adapter which is achieved in gson by TypeAdapterRuntimeTypeWrapper.java

If you look at the implementation of this function it does not do any specific logic in the read part. In the write part it does look at the type of the object and then makes an appropriate decision.

@anthonycr , do you think we should add a field level support for something like this?

The implementation in #56 is not entirely going to solve this case.

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

No branches or pull requests

3 participants