Skip to content

Nullable String property deserializes null as "null" for JsonTypeInfo.As.EXTERNAL_PROPERTY #335

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jonatan-bengtsson opened this issue May 8, 2020 · 9 comments
Labels

Comments

@jonatan-bengtsson
Copy link

Hi! 👋
I noticed that nullable String propery field for for JsonTypeInfo.As.EXTERNAL_PROPERTY deserializes null as "null" String, while I expected it to return null.

class NullableTypeIdTest {

  companion object {
    val mapper = jacksonObjectMapper()
  }

  interface Payload
  data class UniquePayload(val data: String) : Payload

  data class MyEntity(
    val type: String?,

    @JsonTypeInfo(
      use = JsonTypeInfo.Id.NAME,
      include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
      property = "type"
    )
    @JsonSubTypes(
      JsonSubTypes.Type(value = UniquePayload::class, name = "UniquePayload")
    )
    val payload: Payload?
  )

  @Test
  fun serializeAndDeserializeTypeable() {
    val oldEntity = MyEntity(null, null)
    val json = mapper.writeValueAsString(oldEntity)
    val newEntity = mapper.readValue<MyEntity>(json)

    // Returns false: "null" String instead of null
    assertThat(newEntity.type).isNull()
  }
}

I have also tried using
ObjectMapper().registerModule(KotlinModule(nullIsSameAsDefault = true))
and setting
val type: String? = null
but without any result.

Versions
Kotlin: 1.3.72
Jackson-module-kotlin: 2.11.0
Jackson-databind: 2.11.0

@hkakutalua
Copy link

Any update on this?

@dinomite dinomite added the 2.12 label Jan 2, 2021
dinomite added a commit that referenced this issue Jan 2, 2021
@dinomite
Copy link
Member

dinomite commented Jan 2, 2021

I added a failing test for this; haven't looked into where it's happening, though. This could be an issue in jackson-databind, I'm not sure how the internals of Jackson's polymorphic bits work

@dinomite
Copy link
Member

dinomite commented Jan 2, 2021

@cowtowncoder I can look deeper into this, but do you know if it's possible that this is part of -core or -databind?

@cowtowncoder
Copy link
Member

@dinomite Yes, I suspect it could be something wrt jackson-databind (not likely wrt jackson-core as that is just streaming parser / generator... although there is a bit of Type Id reading/writing code in there).
If test could be devised for java-only reproduction, would be happy to include in databind, see what is happening.

@cowtowncoder
Copy link
Member

One quick question for @jonatan-bengtsson: does this occur with 2.11.4 / 2.12.0 too?

@dinomite dinomite added 2.11 and removed 2.12 labels Jan 5, 2021
@jonatan-bengtsson
Copy link
Author

The test fails for 2.11.4 and 2.12.0.
I was able to create a failing test in Java also!

public class ExternalPropertyTypeShouldBeNullTest {

    static class Box {
        public String type;
        public Fruit fruit;

        public Box(@JsonProperty("type") String type,

                   @JsonTypeInfo(use = Id.NAME, include = As.EXTERNAL_PROPERTY, property = "type")
                   @JsonSubTypes({@Type(value = Orange.class, name = "orange")})
                   @JsonProperty("fruit") Fruit fruit) {
            this.type = type;
            this.fruit = fruit;
        }
    }

    interface Fruit{}

    static class Orange implements Fruit {
        public String name;
        public String color;

        public Orange(@JsonProperty("name") String name, @JsonProperty("name") String color) {
            this.name = name;
            this.color = color;
        }
    }

    private final ObjectMapper MAPPER = new ObjectMapper();

    @Test
    public void testDeserializationNull() throws Exception {
        MAPPER.disable(DeserializationFeature.FAIL_ON_MISSING_EXTERNAL_TYPE_ID_PROPERTY);
        Box deserOrangeBox = MAPPER.readValue("{\"type\":null,\"fruit\":null}}", Box.class);
        assertNull(deserOrangeBox.fruit);
        assertNull(deserOrangeBox.type); // error: "expected null, but was:<null>"
    }
}

@cowtowncoder
Copy link
Member

Ok, I'll create a new issue for databind (could transfer but I think there is probably need to verify Kotlin side if and when databind is fixed).

@cowtowncoder
Copy link
Member

Created:

FasterXML/jackson-databind#3008

@dinomite
Copy link
Member

This issue was fixed by FasterXML/jackson-databind#3008

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants