nmorel / gwt-jackson

gwt-jackson is a JSON parser for GWT. It uses Jackson 2.x annotations to customize the serialization/deserialization process.
Apache License 2.0
111 stars 54 forks source link

Question: How can I get access to specific serializers/deserializers in a custom one #96

Open dnouls opened 8 years ago

dnouls commented 8 years ago

I'm trying to implement a custom serializer/deserializer for a project specific object type that uses a generic parameter.

we have a class FilterCriteria Defined like this: class FilterCriteria<V> { String key; FilterOperation operation; List<V> parameters; } Right now the V generic parameter causes gwt-jackson to start building serializers for all Object types, and for Deserialisation I need to declare a whitelist so that the deserializer can work.

The key attribute actually is a name for a type that defines what the V generic parameter will be. So I would like to somehow use this to make a smarter deserializer.

In pure Java with Jackson we can use introspection, so we can make the serializer/deserializer smart. We have a mapping between key and the actual expected types for V. Users of the API need to subclass a specific FilterKey class that will build up a registry of supported types. Using this we can use introspection to decide what the actual type for V will be and as such we can serialize and deserialize properly.

But with gwt-jackson we can't use introspection so my idea was to use an annotation processor. The annotation processor would generate a custom serializer/deserializer for this type. At generation time it would lookup all subtypes of IFilterKey to determine what serializers/deserializers it needs.

However ... question is now ... how can I do that in a gwt-jackson. My assumption is that I can first read the name of the IFilterKey and based on that find back the expected type for V. But how can I instantiate a Deserializer for this type ? Can I just create/generate a static method to create an instance of the CriteriaFilterDeserializer with a large list of parameters which contain the deserializers for the detected V types ?

nmorel commented 8 years ago

All the V are a subtype of IFilterKey ?
Can you change FilterCriteria<V> to FilterCriteria<V extends IFilterKey> ?

dnouls commented 8 years ago

No IFilterKey has a generic parameter V. The IFilterKey is actually used in an API to make the filter parameters type safe (using a query builder API).

That is why I would like to lookup all subtypes of IFilterKey because they fill in this parameter V and based on that I have a limited list of types for V. The key in the JSON payload I can use to find back the IFilterKey subtype and with generics I can determine the actual type of the generic parameter, That is what we do in the Jackson serializer in Java.

nmorel commented 8 years ago

Creating the custom deserializer should not be too hard. If you use an annotation processor or a gwt generator, you can easily build a map with the key being the type and the value, an instance of JsonDeserializer (or a class that lazily creates one).

To get a JsonDeserializer, you can create an ObjectReader, cast it to AbstractObjectReader and call getDeserializer : https://github.com/nmorel/gwt-jackson/blob/master/gwt-jackson/src/main/java/com/github/nmorel/gwtjackson/client/AbstractObjectMapper.java#L88 It's ugly but it's the only way to get an instance of JsonDeserializer currently.

The problem is to tell gwt-jackson to use the custom deserializer for FilterCriteria. Since it has a generic parameter, it will look for a static method or a constructor taking as argument a JsonDeserializer and will create the deserializer for Object.
I don't have any workaround for that and it might be hard to change in the code.

dnouls commented 8 years ago

Without a workaround it would make no sense for me to even try. Would it not be possible somehow to add a new gwt-jackson annotation to FilterCriteria to indicate that we want to fine-tune the list of allowed types for V ? Maybe allow a reference to a class that will be used at compile time to find the types from the compilation classpath ?

Right now gwt-jackson just picks up the V generic parameter and tries to find all types that extend or implement V.

nmorel commented 8 years ago

I can guide you if want to try implementing it.
To instantiate a class, you can look at the code I use for the configuration class here : https://github.com/nmorel/gwt-jackson/blob/master/gwt-jackson/src/main/java/com/github/nmorel/gwtjackson/rebind/RebindConfiguration.java#L258

And to use your type instead of the generic parameter V, the first method to look I think is : https://github.com/nmorel/gwt-jackson/blob/master/gwt-jackson/src/main/java/com/github/nmorel/gwtjackson/rebind/AbstractCreator.java#L718