Skip to content

Add support for MutableSortedMap/ImmutableSortedMap deserialization (2.x only!) #198

@tampix

Description

@tampix

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).

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions