Skip to content

Yasson 3.0.3 - Serialization of a Map fails if the key is of a type implemented as SupportedMapKey and using a csutom Serializer #663

Description

@jbaesner

Describe the bug
Define a custom Serializer for a LocalDate object like the following:

public static class LocalDateSerializer implements JsonbSerializer<LocalDate> {

    private static final DateTimeFormatter SHORT_FORMAT = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT);

    @Override
    public void serialize(LocalDate obj, JsonGenerator generator, SerializationContext ctx) {
        generator.write(SHORT_FORMAT.format(obj));
    }
}

Note: This LocalDate is also included in the TypeSerializers.SUPPORTED_MAP_KEYS as default serialization implementation.

Now use a Pojo class that contains a Map field with LocalDate as the key:

public class TestObject {
  private Map<LocalDate, String> localDateKeyMap;
  ...
}

If you try to serialize it with current version 3.0.3 like the following:

        Jsonb jsonb = JsonbBuilder.create(new JsonbConfig()
                .withSerializers(new LocalDateSerializer())
                .withDeserializers(new LocalDateDeserializer()));
        TestObject o = new TestObject();
        o.getLocalDateKeyMap().put(LocalDate.now(), "today");
        jsonb.toJson(o);

The following exception is thrown:

jakarta.json.bind.JsonbException: Unable to serialize property 'values' from test.MapObjectTest.MapObjectLocalDateString
        at org.eclipse.yasson.internal.serializer.ObjectSerializer.lambda$serialize$0(ObjectSerializer.java:43)
        at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:684) 
        at org.eclipse.yasson.internal.serializer.ObjectSerializer.serialize(ObjectSerializer.java:38)
        at org.eclipse.yasson.internal.serializer.RecursionChecker.serialize(RecursionChecker.java:38)
        at org.eclipse.yasson.internal.serializer.KeyWriter.serialize(KeyWriter.java:41)
        at org.eclipse.yasson.internal.serializer.NullVisibilitySwitcher.serialize(NullVisibilitySwitcher.java:40)
        at org.eclipse.yasson.internal.serializer.NullSerializer.serialize(NullSerializer.java:67)
        at org.eclipse.yasson.internal.SerializationContextImpl.serializeObject(SerializationContextImpl.java:197)
        at org.eclipse.yasson.internal.SerializationContextImpl.marshall(SerializationContextImpl.java:133)                                  
        at org.eclipse.yasson.internal.SerializationContextImpl.marshall(SerializationContextImpl.java:159)
        at org.eclipse.yasson.internal.JsonBinding.toJson(JsonBinding.java:131)                                                                     
        at test.MapObjectTest.test1(MapObjectTest.java:102)                                                                                             
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566) 
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)           
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)                                                                                                                                                                                                                     
        at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
        at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
        at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329) 
        at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
        at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
        at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:316)
        at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:240)
        at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:214)
        at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:155)
        at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385)
        at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162)
        at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507)
        at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495)
        Suppressed: jakarta.json.stream.JsonGenerationException: Generating incomplete JSON
                at org.eclipse.parsson.JsonGeneratorImpl.close(JsonGeneratorImpl.java:519)
                at org.eclipse.yasson.internal.JsonBinding.toJson(JsonBinding.java:130)
                ... 29 more
Caused by: jakarta.json.stream.JsonGenerationException: Illegal method during JSON generation, not valid in current context IN_OBJECT
        at org.eclipse.parsson.JsonGeneratorImpl.checkContextForValue(JsonGeneratorImpl.java:405)
        at org.eclipse.parsson.JsonGeneratorImpl.write(JsonGeneratorImpl.java:357)
        at org.eclipse.yasson.internal.serializer.YassonGenerator.write(YassonGenerator.java:161)
        at test.MapObjectTest$LocalDateSerializer.serialize(MapObjectTest.java:36)
        at test.MapObjectTest$LocalDateSerializer.serialize(MapObjectTest.java:30)
        at org.eclipse.yasson.internal.serializer.UserDefinedSerializer.serialize(UserDefinedSerializer.java:35)
        at org.eclipse.yasson.internal.serializer.RecursionChecker.serialize(RecursionChecker.java:38)
        at org.eclipse.yasson.internal.serializer.KeyWriter.serialize(KeyWriter.java:41)
        at org.eclipse.yasson.internal.serializer.NullSerializer.serialize(NullSerializer.java:67)
        at org.eclipse.yasson.internal.serializer.MapSerializer$StringKeyMapSerializer.lambda$serialize$0(MapSerializer.java:108)
        at java.base/java.util.HashMap.forEach(HashMap.java:1337)
        at org.eclipse.yasson.internal.serializer.MapSerializer$StringKeyMapSerializer.serialize(MapSerializer.java:107)
        at org.eclipse.yasson.internal.serializer.KeyWriter.serialize(KeyWriter.java:41)
        at org.eclipse.yasson.internal.serializer.NullVisibilitySwitcher.serialize(NullVisibilitySwitcher.java:40)
        at org.eclipse.yasson.internal.serializer.NullSerializer.serialize(NullSerializer.java:67)
        at org.eclipse.yasson.internal.serializer.ValueGetterSerializer.serialize(ValueGetterSerializer.java:43)
        at org.eclipse.yasson.internal.serializer.ObjectSerializer.lambda$serialize$0(ObjectSerializer.java:41)
        ... 39 more

To Reproduce

unzip issue-map-local-date-key.zip
cd issue-map-local-date-key
mvn clean test

Expected behavior
The test should pass as with earlier yasson versions and the LocalDateSerializer should be used to serialize the LocalDate key into a String.

System information:

  • OS: any
  • Java Version: 11, 17
  • Yasson Version: 3.0.3

Additional context
The same was working in previous yasson versions.

Reproducer project: issue-map-local-date-key.zip

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working right

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions