-
Notifications
You must be signed in to change notification settings - Fork 57
Closed
Description
What
Currently, SortedMap
and ImmutableSortedMap
can be serialized, but can't be deserialized.
It would be desirable to have that feature, even though it's somewhat of a niche use-case.
How to reproduce
@Test
void foo() throws Exception {
final var mapper = new ObjectMapper();
mapper.registerModule(new EclipseCollectionsModule());
final var foo = new Foo(SortedMaps.immutable.empty());
final var json = mapper.writeValueAsString(foo);
assertThatThrownBy(() -> mapper.readValue(json, Foo.class))
.isInstanceOf(JsonMappingException.class);
}
@Test
void bar() throws Exception {
final var mapper = new ObjectMapper();
mapper.registerModule(new EclipseCollectionsModule());
final var bar = new Bar(SortedMaps.mutable.empty());
final var json = mapper.writeValueAsString(bar);
assertThatThrownBy(() -> mapper.readValue(json, Bar.class))
.isInstanceOf(JsonMappingException.class);
}
private record Foo(ImmutableSortedMap<String, Object> values) {
}
private record Bar(MutableSortedMap<String, Object> values) {
}
Analysis
Deserializers are initalized in a static block in com.fasterxml.jackson.datatype.eclipsecollections.deser.map.EclipseMapDeserializers
.
While Object to Object maps can be SortedMapIterable, there are no such equivalent for primitives.
As such, the fix could be as simple as adding a new constant in com.fasterxml.jackson.datatype.eclipsecollections.deser.map.TypeHandlerPair
:
TypeHandlerPair<MutableSortedMap<Object, Object>, RefKeyHandler, RefValueHandler> COMPARABLE_OBJECT =
new TypeHandlerPair<MutableSortedMap<Object, Object>, RefKeyHandler, RefValueHandler>() {
@Override
public RefKeyHandler keyHandler(JavaType type) {
return new RefKeyHandler(type, null);
}
@Override
public RefValueHandler valueHandler(JavaType type) {
return new RefValueHandler(type, null, null);
}
@Override
public MutableMap<Object, Object> createEmpty() {
return SortedMaps.mutable.empty();
}
@Override
public void add(
MutableSortedMap<Object, Object> target,
RefKeyHandler kh, RefValueHandler vh,
DeserializationContext ctx, String k, JsonParser v
) throws IOException {
target.put(kh.key(ctx, k), vh.value(ctx, v));
}
};
And then, in EclipseMapDeserializers
:
static {
add(MutableMap.class, TypeHandlerPair.OBJECT_OBJECT);
add(MutableMapIterable.class, TypeHandlerPair.OBJECT_OBJECT);
add(MapIterable.class, TypeHandlerPair.OBJECT_OBJECT);
add(UnsortedMapIterable.class, TypeHandlerPair.OBJECT_OBJECT);
add(ImmutableMap.class, TypeHandlerPair.OBJECT_OBJECT, MutableMap::toImmutable);
add(ImmutableMapIterable.class, TypeHandlerPair.OBJECT_OBJECT, MutableMap::toImmutable);
+ add(MutableSortedMap.class, TypeHandlerPair.COMPARABLE_OBJECT);
+ add(SortedMapIterable.class, TypeHandlerPair.COMPARABLE_OBJECT);
+ add(ImmutableSortedMap.class, TypeHandlerPair.COMPARABLE_OBJECT, MutableSortedMap::toImmutable);
Note that this solution only handles java.lang.Comparable
keys, as we can't rely on SortedMaps.mutable.empty(Comparator<? super K> comparator)
.