对对象的属性进行深层复制以从杰克逊身上汲取?

时间:2019-07-19 09:22:11

标签: json serialization jackson deserialization jackson-databind

我正在执行UPDATE操作,以便将传入POJO中设置的所有non-null属性都复制到另一个对象(相同类型)中,并且嵌套属性也会发生这种情况。

例如:

POJO:

    public class Person {

        private String homePhoneNumber;
        private String officePhoneNumber;

        private Address address;

        public String getHomePhoneNumber() {
            return homePhoneNumber;
        }

        // getter/setters


    }

    public class Address {

        private String street;
        private String houseNumber;

        public String getStreet() {
            return street;
        }
        // getter/setters
    }

    //  Source

        Person sourcePerson = new Person();
        sourcePerson.setHomePhone("123");

        Address address1 = new Address();
        address1.setStreet("Street");

        sourcePerson.setAddress(address1);

    //Dest person

        Person destPerson = new Person();
        destPerson.setOfficePhone("456");
        destPerson.setHomePhone("123");

        Address address2 = new Address();
        address2.setStreet("Street2");
        address2.setHouseNumber("246");

        destPerson.setAddress(address2);

        ObjectMapper mapper = new ObjectMapper();
       //skip setters for null values
mapper.setDefaultSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SKIP));

        Person result = mapper.updateValue(destPerson, sourcePerson);

因此,我想复制non-null中设置的所有sourcePerson属性,以复制到destPerson中,即覆盖destperson的那些属性, sourcePerson已设置,其他属性保持不变。

使用 Person result = mapper.updateValue(destPerson, sourcePerson); 对嵌套属性不起作用。它正在从源到目的地替换整个Address对象

我搜索了杰克逊(Jackson),找到了杰克逊(Jackson)的merge功能:

mapper.setDefaultMergeable(true);

但是,添加此配置会使null中的sourcePerson值也使destPerson中的值也无效,这似乎很奇怪。

mapper.configOverride(Address.class).setMergeable(true);

以上配置适用于我想要的。但是我有很多POJO嵌套资源,所以我不希望每个POJO都有特定的配置。

使用jackson可以做到这一点吗?

1 个答案:

答案 0 :(得分:0)

您可以首先启用关于合并

的错误报告
  

com.fasterxml.jackson.databind.MapperFeature#IGNORE_MERGE_FOR_UNMERGEABLE

这必须是错误的。

mapper.configOverride()确实很奇怪,但mapper.setDefaultMergeable()却不是。

在您的示例中我看不到二传手。您是否有机会在Person类中使用@JsonSetter注释?然后它们将覆盖映射器配置。

jackson-databind 单元测试中,我看到它们使用的是mapper.readerForUpdating()而不是mapper.updateValue

 private final ObjectMapper MAPPER = objectMapperBuilder()
            // 26-Oct-2016, tatu: Make sure we'll report merge problems by default
            .disable(MapperFeature.IGNORE_MERGE_FOR_UNMERGEABLE)
            .build();

    public void testBeanMergingWithNullDefault() throws Exception
    {
        // By default `null` should simply overwrite value
        ConfigDefault config = MAPPER.readerForUpdating(new ConfigDefault(5, 7))
                .readValue(aposToQuotes("{'loc':null}"));
        assertNotNull(config);
        assertNull(config.loc);

        // but it should be possible to override setting to, say, skip

        // First: via specific type override
        // important! We'll specify for value type to be merged
        ObjectMapper mapper = newObjectMapper();
        mapper.configOverride(AB.class)
            .setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SKIP));
        config = mapper.readerForUpdating(new ConfigDefault(137, -3))
                .readValue(aposToQuotes("{'loc':null}"));
        assertNotNull(config.loc);
        assertEquals(137, config.loc.a);
        assertEquals(-3, config.loc.b);

        // Second: by global defaults
        mapper = newObjectMapper();
        mapper.setDefaultSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SKIP));
        config = mapper.readerForUpdating(new ConfigDefault(12, 34))
                .readValue(aposToQuotes("{'loc':null}"));
        assertNotNull(config.loc);
        assertEquals(12, config.loc.a);
        assertEquals(34, config.loc.b);
    }

还值得尝试直接在com.fasterxml.jackson.annotation.JsonMerge类中使用Person