Skip to content

Deserialization Failed when Unknown Property is added in JSON string when using Afterburner Module #343

@leowongkh

Description

@leowongkh

I have added an unknown property to the JSON string to deserialize, which the property i is not in the TestPOJO class.
The deserialization feature FAIL_ON_UNKNOWN_PROPERTIES is disabled. The test is expected to pass, but fails actually with the stack trace at the bottom.

Jackson Databind and Afterburner versions: 3.1.0, 3.1.1
JUnit Jupiter version: 6.0.3

JUnit test code:

package json;

import com.fasterxml.jackson.annotation.JsonProperty;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import tools.jackson.core.StreamReadFeature;
import tools.jackson.databind.DeserializationFeature;
import tools.jackson.databind.MapperFeature;
import tools.jackson.databind.ObjectReader;
import tools.jackson.databind.introspect.VisibilityChecker;
import tools.jackson.databind.json.JsonMapper;
import tools.jackson.module.afterburner.AfterburnerModule;

import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.PUBLIC_ONLY;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

public class JacksonAfterburnerDeserializeTest {
    private ObjectReader reader;

    @BeforeEach
    public void initialize() {
        // refer to com.fasterxml.jackson.databind.ObjectMapper.DEFAULT_BASE for default settings, e.g. cacheProvider
        var mapper = JsonMapper.builder()
                // disable value class loader to avoid jdk illegal reflection warning, requires JSON class/fields must be public
                .addModule(new AfterburnerModule().setUseValueClassLoader(false))
                // only detect public fields, refer to com.fasterxml.jackson.databind.introspect.VisibilityChecker.Std
                .changeDefaultVisibility(_ -> new VisibilityChecker(PUBLIC_ONLY, NONE, NONE, NONE, NONE, NONE))
                .enable(StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION)
                .disable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY)
                .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                // e.g. disable convert empty string to Integer null
                .deactivateDefaultTyping().build();

        reader = mapper.readerFor(TestPOJO.class);
    }

    @Test
    void deserializeWithExtraFields() {
        String json = """
                {
                    "a": "a",
                    "b": "b",
                    "c": "c",
                    "d": "d",
                    "e": "e",
                    "f": "f",
                    "g": "g",
                    "h": "h",
                    "i": "i"
                }
                """;
        assertDoesNotThrow(() -> reader.readValue(json));
    }

    public static class TestPOJO {
        @JsonProperty("a")
        public String a;
        @JsonProperty("b")
        public String b;
        @JsonProperty("c")
        public String c;
        @JsonProperty("d")
        public String d;
        @JsonProperty("e")
        public String e;
        @JsonProperty("f")
        public String f;
        @JsonProperty("g")
        public String g;
        @JsonProperty("h")
        public String h;
    }
}

The test method deserializeWithExtraFields() fails with the following stack trace:

org.opentest4j.AssertionFailedError: Unexpected exception thrown: tools.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `json.JacksonAfterburnerDeserializeTest$TestPOJO` from Object value (token `JsonToken.PROPERTY_NAME`)
 at [Source: (String)"{
    "a": "a",
    "b": "b",
    "c": "c",
    "d": "d",
    "e": "e",
    "f": "f",
    "g": "g",
    "h": "h",
    "i": "i"
}
"; line: 10, column: 5]

	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:159)
	at org.junit.jupiter.api.AssertDoesNotThrow.createAssertionFailedError(AssertDoesNotThrow.java:90)
	at org.junit.jupiter.api.AssertDoesNotThrow.assertDoesNotThrow(AssertDoesNotThrow.java:80)
	at org.junit.jupiter.api.AssertDoesNotThrow.assertDoesNotThrow(AssertDoesNotThrow.java:61)
	at org.junit.jupiter.api.Assertions.assertDoesNotThrow(Assertions.java:3355)
	at json.JacksonAfterburnerDeserializeTest.deserializeWithExtraFields(JacksonAfterburnerDeserializeTest.java:53)
Caused by: tools.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `json.JacksonAfterburnerDeserializeTest$TestPOJO` from Object value (token `JsonToken.PROPERTY_NAME`)
 at [Source: (String)"{
    "a": "a",
    "b": "b",
    "c": "c",
    "d": "d",
    "e": "e",
    "f": "f",
    "g": "g",
    "h": "h",
    "i": "i"
}
"; line: 10, column: 5]
	at tools.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
	at tools.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1863)
	at tools.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1659)
	at tools.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1608)
	at tools.jackson.databind.deser.bean.BeanDeserializer._handleUnexpectedWithin(BeanDeserializer.java:1464)
	at tools.jackson.module.afterburner.deser.SuperSonicBeanDeserializer.deserializeFromObject(SuperSonicBeanDeserializer.java:335)
	at tools.jackson.databind.deser.bean.BeanDeserializer.deserialize(BeanDeserializer.java:200)
	at tools.jackson.module.afterburner.deser.SuperSonicBeanDeserializer.deserialize(SuperSonicBeanDeserializer.java:80)
	at tools.jackson.databind.deser.DeserializationContextExt.readRootValue(DeserializationContextExt.java:266)
	at tools.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1888)
	at tools.jackson.databind.ObjectReader.readValue(ObjectReader.java:1304)
	at json.JacksonAfterburnerDeserializeTest.lambda$deserializeWithExtraFields$0(JacksonAfterburnerDeserializeTest.java:53)
	at org.junit.jupiter.api.AssertDoesNotThrow.assertDoesNotThrow(AssertDoesNotThrow.java:76)
	... 3 more

The bug seems to stem from Afterburner Module in SuperSonicBeanDeserializer.java:335. Please have a look. Thank you!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions