According to JSON-B Specification v3 chapter 3.1.1 all implementations MUST support serialization of java.util.Map. While Yasson does serialize maps, it does it in an inconsistent way:
Map<String, V> is correctly serialized as a JSON map where String is key and serialized V is value.
System.out.println(jsonb.toJson(Map.of(k.toString(), v))); // correctly prints `{"k":<v>}`
Map<K, V> is rather unexpectedly serialized as a JSON list holding one JSON map per entry inside that list, all having a key name of literally the word key, and a value of literally the word value.
System.out.println(jsonb.toJson(Map.of(k, v))); // prints `[{"key":<k>,"value":<v>}]`, but should print `{<k>: <v>}`
public static final void main(final String[] arguments) throws IOException {
final var cfg = new JsonbConfig().withAdapters(new CAdapter());
final var jsonb = JsonbBuilder.newBuilder().withConfig(cfg).build();
final var k = new C();
final var v = new C();
System.out.println(jsonb.toJson(Map.of(k.toString(), v))); // correctly prints {"C":"C"}]
System.out.println(jsonb.toJson(Map.of(k, v))); // prints [{"key":"C","value":"C"}], but should print {"C": "C"}
}
public static final class C {
@Override
public final String toString() {
return "C";
}
}
public static final class CAdapter implements JsonbAdapter<C, String> {
@Override
public final String adaptToJson(final C obj) throws Exception {
return obj.toString();
}
@Override
public final C adaptFromJson(final String obj) throws Exception {
throw new UnsupportedOperationException("Unimplemented method 'adaptFromJson'");
}
}
}
**Expected behavior**
`System.out.println(jsonb.toJson(Map.of(k, v)));` should print print `{<k>: <v>}`, i. e. a map with serialized `k` as key and serialized `v` as value, to be consistent with the behaviour of `Map<String, V>`.
**System information:**
- OS: Windows
- Java Version: 19
- Yasson Version: 3.0.3
**Additional context**
N/A
Not sure what the correct behaviour is in this case, but the serializer selection happens here in MapSerializer.java.
According to this code only using Enum keys or the types defined in TypeSerializers.java are supported as keys.
Describe the bug
According to JSON-B Specification v3 chapter 3.1.1 all implementations MUST support serialization of
java.util.Map
. While Yasson does serialize maps, it does it in an inconsistent way:Map<String, V>
is correctly serialized as a JSON map whereString
is key and serializedV
is value.Map<K, V>
is rather unexpectedly serialized as a JSON list holding one JSON map per entry inside that list, all having a key name of literally the wordkey
, and a value of literally the wordvalue
.To Reproduce
import java.io.IOException; import java.util.Map;
import jakarta.json.bind.JsonbBuilder; import jakarta.json.bind.JsonbConfig; import jakarta.json.bind.adapter.JsonbAdapter;
public final class YassonBugs {
public static final void main(final String[] arguments) throws IOException { final var cfg = new JsonbConfig().withAdapters(new CAdapter()); final var jsonb = JsonbBuilder.newBuilder().withConfig(cfg).build(); final var k = new C(); final var v = new C(); System.out.println(jsonb.toJson(Map.of(k.toString(), v))); // correctly prints
{"C":"C"}]
System.out.println(jsonb.toJson(Map.of(k, v))); // prints[{"key":"C","value":"C"}]
, but should print{"C": "C"}
}public static final class C { @Override public final String toString() { return "C"; } }
public static final class CAdapter implements JsonbAdapter<C, String> {
}
}