Skip to content
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

JsonTypeInfo and Optional #44

Closed
matstatman opened this issue Nov 8, 2017 · 3 comments
Closed

JsonTypeInfo and Optional #44

matstatman opened this issue Nov 8, 2017 · 3 comments

Comments

@matstatman
Copy link

I think i have found a bug, while upgrading my project from 2.8.7 -> 2.8.8. The classname is no longer part of the serialized json string. The test testWithOptional below fails in 2.8.8:

import static org.junit.Assert.assertTrue;

import java.io.IOException;
import java.util.Optional;

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;

public class Test {
    ObjectMapper mapper = new ObjectMapper().registerModule(new Jdk8Module());

    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
    @JsonSubTypes({@JsonSubTypes.Type(name = "Container", value = ChildClass.class)})
    public static class Base {
    }

    public static class ChildClass extends Base {
    }

    @org.junit.Test
    public void testWithOptional() throws IOException {
        String json = mapper.writeValueAsString(Optional.of(new ChildClass()));
        // breaks in com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.8.8 and above
        assertTrue(json, json.contains("type"));
    }

    @org.junit.Test
    public void test() throws IOException {
        String json = mapper.writeValueAsString(new ChildClass());
        assertTrue(json, json.contains("type"));
    }
}
@cowtowncoder
Copy link
Member

I don't know how it could have worked differently before, but I don't think type information should be included in this case. Problem is Java Type Erasure, and the type Jackson sees is simply Optional<?>, which does not allow determination of base type as anything other than Object.
This is different from case of directly serializing ChildClass since it is non-generic class and runtime type is used as is.

This is different from having a POJO with such Optional: if you had

public class Wrapper {
   public Optional<Base> value;
}

type information would be included.

So, this is really FAQ, although more commonly encountered with Lists and Collections.

Unfortunate part is if earlier versions did make this appear to work: it should not have behaved that way. I think change is probably due to fix for #15.

As to work-around: two common methods are:

  1. Sub-classing, something like

    public class BaseOptional extends Optional { }
    // is above possible wrt factory methods?

  2. Declaring of full generic type

    mapper.writerFor(new TypeReference<Optional>() { })
    .writeValueAsString(value);

I hope this helps.

@matstatman
Copy link
Author

Ok, thanks a lot!

@alexism
Copy link

alexism commented Jan 4, 2019

FYI This is the root cause of the deserialization issue described at #59

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

No branches or pull requests

3 participants