Skip to content

Removing "type" attribute with Mixin not taken in account if using ObjectMapper.copy() #1998

@SBKila

Description

@SBKila

Hi,

Objectif

I'd like to remove several attributes and in particular type from serialization output

What I'm doing

I'm using Mixin concept to remove the attribute 'type' like follow.
@JsonTypeInfo(use = JsonTypeInfo.Id.NONE, include = JsonTypeInfo.As.EXISTING_PROPERTY)

I have a static ObjectMapper created with all my default settings and I clone it .copy(); each time I need to use a new one.

  1. When only one object is used all perfectly working. testA_OK
  2. But if I use more than one mapper, Mixin are taken in account expect @JsonTypeInfo(use = JsonTypeInfo.Id.NONE, include = JsonTypeInfo.As.EXISTING_PROPERTY) testB_OK
  3. If I replace ObjectMapper.copy() by a new ObjectMapper(), all perfectly working testC_OK

JUnit Test class

`
public class ObjectMapperCopyTest {

private static final ObjectMapper DEFAULT_MAPPER;
final static String FULLMODEL="{\"format\":\"1.0\",\"child\":{\"type\":\"CHILD_B\",\"name\":\"testB\"},\"notVisible\":\"should not be present\"}";
final static String EXPECTED="{\"format\":\"1.0\",\"child\":{\"name\":\"testB\"}}";
static {
    DEFAULT_MAPPER = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_EMPTY)
            .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
            .configure(MapperFeature.ALLOW_COERCION_OF_SCALARS, false)
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true)
            .configure(JsonParser.Feature.ALLOW_COMMENTS, true)
            .registerModule(new JavaTimeModule())
            .findAndRegisterModules();
}

public class MyModelView {
}

interface MixinConfig {
    interface MyModelRoot {
        @JsonView(MyModelView.class)
        public String getFormat();

        @JsonView(MyModelView.class)
        public MyModelChildBase getChild();
    }

    @JsonTypeInfo(use = JsonTypeInfo.Id.NONE, include = JsonTypeInfo.As.EXISTING_PROPERTY) interface MyModelChildBase {
        @JsonView(MyModelView.class)
        public String getName();
    }

}

class MyModelRoot {
    @JsonProperty
    @NotNull
    private String format = "1.0";

    public String getFormat() {
        return format;
    }
    @JsonProperty
    private MyModelChildBase child;

    public MyModelChildBase getChild() {
        return child;
    }

    public void setChild(MyModelChildBase child) {
        this.child = child;
    }

    @JsonProperty
    @NotNull
    private String notVisible = "should not be present";

    public String getNotVisible() {
        return notVisible;
    }
}

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
        @JsonSubTypes.Type(value = MyChildA.class, name = "CHILD_A")
        ,
        @JsonSubTypes.Type(value = MyChildB.class, name = "CHILD_B")
})
abstract class MyModelChildBase {
    @JsonProperty
    private String name;

    public String getName() {
        return name;
    }

    @JsonIgnore
    public void setName(String name) {
        this.name = name;
    }
}

class MyChildA extends MyModelChildBase {
    public MyChildA(String name) {
        setName(name);
    }

}

class MyChildB extends MyModelChildBase {
    public MyChildB(String name) {
        setName(name);
    }
}

@Test
public void testA_OK() {

    MyModelRoot myModelInstance = new MyModelRoot();
    myModelInstance.setChild(new MyChildB("testB"));

    ObjectMapper myObjectMapper = DEFAULT_MAPPER.copy();

    myObjectMapper.addMixIn(MyModelRoot.class, MixinConfig.MyModelRoot.class)
            .addMixIn(MyModelChildBase.class, MixinConfig.MyModelChildBase.class)
            .disable(MapperFeature.DEFAULT_VIEW_INCLUSION)
            .setConfig(myObjectMapper.getSerializationConfig().withView(MyModelView.class));

    String result = getString(myModelInstance, myObjectMapper);
    System.out.println("result: "+result);
    Assert.assertEquals(EXPECTED, result);

}


@Test
public void testB_KO() {

    MyModelRoot myModelInstance = new MyModelRoot();
    myModelInstance.setChild(new MyChildB("testB"));

    ObjectMapper myObjectMapper = DEFAULT_MAPPER.copy();

    String postResult = getString(myModelInstance, myObjectMapper);
    Assert.assertEquals(FULLMODEL, postResult);
    System.out.println("postResult: "+postResult);

    myObjectMapper = DEFAULT_MAPPER.copy();
    myObjectMapper.addMixIn(MyModelRoot.class, MixinConfig.MyModelRoot.class)
            .addMixIn(MyModelChildBase.class, MixinConfig.MyModelChildBase.class)
            .disable(MapperFeature.DEFAULT_VIEW_INCLUSION)
            .setConfig(myObjectMapper.getSerializationConfig().withView(MyModelView.class));

    String result = getString(myModelInstance, myObjectMapper);
    System.out.println("result: "+result);
    Assert.assertEquals(EXPECTED, result);

}

@Test
public void testC_OK() {

    MyModelRoot myModelInstance = new MyModelRoot();
    myModelInstance.setChild(new MyChildB("testB"));

    ObjectMapper myObjectMapper = getObjectMapper();

    String postResult = getString(myModelInstance, myObjectMapper);
    Assert.assertEquals(FULLMODEL, postResult);
    System.out.println("postResult: "+postResult);

    myObjectMapper = getObjectMapper();

    myObjectMapper.addMixIn(MyModelRoot.class, MixinConfig.MyModelRoot.class)
            .addMixIn(MyModelChildBase.class, MixinConfig.MyModelChildBase.class)
            .disable(MapperFeature.DEFAULT_VIEW_INCLUSION)
            .setConfig(myObjectMapper.getSerializationConfig().withView(MyModelView.class));

    String result = getString(myModelInstance, myObjectMapper);
    System.out.println("result: "+result);
    Assert.assertEquals(EXPECTED, result);

}

private ObjectMapper getObjectMapper() {
    return new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_EMPTY)
            .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
            .configure(MapperFeature.ALLOW_COERCION_OF_SCALARS, false)
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true)
            .configure(JsonParser.Feature.ALLOW_COMMENTS, true)
            .registerModule(new JavaTimeModule())
            .findAndRegisterModules();
}

private String getString(MyModelRoot myModelInstance, ObjectMapper myObjectMapper) {
    CharArrayWriter writer = new CharArrayWriter();
    try {
        myObjectMapper.writerFor(MyModelRoot.class).writeValue(writer, myModelInstance);

    } catch (IOException e) {
        e.printStackTrace();
    }
    return writer.toString();
}

}
`

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions