首页 > 解决方案 > 从杰克逊的一个对象到另一个对象的深层属性副本?

问题描述

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

前任:

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即仅覆盖已设置的那些属性destpersonsourcePerson保持其他属性不变。

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

我搜索了杰克逊以找到杰克逊的merge功能:

mapper.setDefaultMergeable(true);

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

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

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

这可以用jackson干净的方式实现吗?

标签: jsonserializationjacksondeserializationjackson-databind

解决方案


您可以首先启用关于合并的错误报告

com.fasterxml.jackson.databind.MapperFeature#IGNORE_MERGE_FOR_UNMERGEABLE

这必须是假的。

这种作品确实很奇怪mapper.configOverride(),但不是mapper.setDefaultMergeable()

在您的示例中,我没有看到二传手。你不是在课堂上使用@JsonSetter注释吗?Person然后他们将覆盖映射器配置。

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课堂上使用。


推荐阅读