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

make AbstractObjectMapper.getSerializer / getDeserializer public? #40

Closed
pkolaric opened this issue Jan 13, 2015 · 10 comments
Closed

make AbstractObjectMapper.getSerializer / getDeserializer public? #40

pkolaric opened this issue Jan 13, 2015 · 10 comments
Assignees
Milestone

Comments

@pkolaric
Copy link

It would be nice if
com.github.nmorel.gwtjackson.client.AbstractObjectMapper
methods
protected JsonSerializer getSerializer()
and
protected JsonDeserializer getDeserializer()
were public. Then a custom serializer/deserializer could delegate object deserialization/serialization.

For example if we're deserializing a typed map (Map<String,Object>) where map key defines value type and the values are POJOs.

Or is there a better way to do it?

@nmorel
Copy link
Owner

nmorel commented Jan 13, 2015

You can take a look here to define custom serializer/deserializer : https://github.com/nmorel/gwt-jackson/wiki/Custom-serializers-and-deserializers

@pkolaric
Copy link
Author

I already did it, but i had to make the mentioned methods public so i could do:
protected T doDeserialize(JsonReader reader, JsonDeserializationContext ctx, JsonDeserializerParameters params) {
....
map.put(key, GWTDeserializers.getDeserializer(key.getType()).deserialize(reader, ctx));
}

where GWTDeserializers holds a class to deserializer map:

private static final Map<Class, JsonDeserializer> mapTypeToDeserializer = new HashMap>();

@nmorel
Copy link
Owner

nmorel commented Jan 13, 2015

I don't understand what you are trying to achieve.
Which type are you deserializing ?

@pkolaric
Copy link
Author

I'm deserializing a map Map<String,Object>, where key defines value type. For example let's call it 'Settings'.

class Settings extends Map<String,Object> {
}

json example:
"settings": {
"minValue": 2,
"maxValue": 10,
"label": "someLabel",
"tags": ["tag1", "tag2", "tag3"],
"someSettingWhichIsAPojo": {
"property1":"value1", "property2": 233}
}

minValue, maxValue, label, tags all work because they're primitives and i can easily create a Class -> JsonDeserializer map, which will map Long -> LongJsonDeserializer.getInstance(), String -> .. etc.

The problem is with custom classes, for example, the property someSettingWhichIsAPojo (that maps to MyClass). Deserialization can't be delegated to a gwt-jackson deserializer:

class MyClass {
String property1;
Long property2;
}

public static interface MyMapper extends ObjectReader, ObjectWriter {}
private static final AbstractObjectMapper MAPPER_MYCLASS = GWT.create(MyMapper .class);
MAPPER_MYCLASS.getDeserializer() <-- is protected, so it doesn't work. If it was public i could delegate deserialization to it

Everything works fine if i make those two methods (getSerializer and getDeserializer) public, so i'm suggesting that they're made public in the API.

@nmorel
Copy link
Owner

nmorel commented Jan 13, 2015

Ok I see your problem now.

If you know all the keys, you can add setter and in the setter, use the put method.
Your Settings class will be considered as a POJO.

In the current snapshot, the annotation @JsonAnySetter is also supported. You can have something like this :

class Settings extends Map {
  void setAPojo(APojo aPojo) {
    put("aPojo", aPojo);
  }

  void setAnotherPojo(AnotherPojo anotherPojo) {
    put("anotherPojo", anotherPojo);
  }

  @JsonAnySetter
  void setAllOtherProperties(String key, Object value) {
    put(key, value);
  }
}

@nmorel
Copy link
Owner

nmorel commented Jan 13, 2015

You can also use JsonReader.nextValue() to retrieve the string and then call ObjectMapper.read(String).

@nmorel
Copy link
Owner

nmorel commented Jan 13, 2015

If these workarounds don't work for you, I will maybe add some kind of provider/factory to get access to the JsonSerializer/JsonDeserializer directly like :

public interface JsonDeserializerProvider<T> {
  JsonDeserializer<T> get();
}

public interface MyClassDeserializer extends JsonDeserializerProvider<MyClass> {}

MyClassDeserializer deserializer = GWT.create(MyClassDeserializer.class);

or

public interface JsonMapperFactory {}

public interface MyJsonFactory extends JsonMapperFactory {
  JsonSerializer<MyClass> getMyClassSerializer();
  JsonDeserializer<MyClass> getMyClassDeserializer();
  JsonSerializer<OtherClass> otherClass();
}

MyJsonFactory factory = GWT.create(MyJsonFactory.class);

I don't like making public stuff like your proposal. It's hard to maintain the compatibility after.

@pkolaric
Copy link
Author

1.) Custom setters + @JsonAnySetter would work but i'd have to create setters for all non-primitive keys and getters for all keys (@JsonAnyGetter only works for primitives)
2.) ObjectMapper.read(String) would work for ObjectMappers, what about delegating to custom deserializers created in GWT or deserializing primitives?

@pkolaric
Copy link
Author

I think i'll go with protected setters/getters this time. I still think there should be access to generated serializers/deserializers. If i had to vote i would prefer your 2nd proposal (with JsonMapperFactory).

nmorel added a commit that referenced this issue Jan 18, 2015
…ublic

There are a few use cases where having a direct access to the JsonSerializer and JsonDeserializer can be useful.
For example, when you implement a custom JsonSerializer that uses a generated one.
 In the future, a factory interface will be added to gain access to any number of ObjectMapper/ObjectReader/ObjectWriter/JsonSerializer/JsonDeserializer.
@nmorel
Copy link
Owner

nmorel commented Jan 18, 2015

Finally, I made them public. I'll add the factory interface later and probably put them back protected before the 1.0.0 release.

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

2 participants