Jackson ConstructorProperties会忽略属性名称

时间:2018-09-18 15:24:12

标签: java jackson deserialization xmlmapper

我真的很困惑jackson(2.9.6版)ObjectMapper@ConstructorProperties批注如何工作。

映射器似乎忽略了@ConstructorProperties注释值方法中存在的属性名称。

更有趣的是-无论属性名称如何,映射器都能正常工作。

我在说什么?

让我们考虑定制XmlMapper:

private static final ObjectMapper XML_MAPPER = new XmlMapper()
            .setAnnotationIntrospector(
                    AnnotationIntrospector.pair(
                            new JaxbAnnotationIntrospector(),
                            new JacksonAnnotationIntrospector()
                    )
            )
            .registerModule(new JavaTimeModule())
            .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
            .setPropertyNamingStrategy(PropertyNamingStrategy.KEBAB_CASE);

和简单的数据传输对象(DTO):

    @XmlRootElement(name = "person")
    @XmlAccessorType(XmlAccessType.NONE)
    static class Person {
        @XmlAttribute
        final int age;

        @XmlAttribute
        final String name;

        @XmlAttribute
        final LocalDate dateOfBirth;

        @ConstructorProperties({"age","name","dateOfBirth"})
        public Person(int age, String name, LocalDate dateOfBirth) {
            this.age = age;
            this.name = name;
            this.dateOfBirth = dateOfBirth;
        }

        @Override
        public String toString() {
            return "Person{" +
                    "age=" + age +
                    ", name='" + name + '\'' +
                    ", dateOfBirth=" + dateOfBirth +
                    '}';
        }
    }

我创建了测试来重现该问题:

@Test
@DisplayName("Check xml deseralization for Person class")
void deserialization() throws IOException {
    String xml = "<person age=\"26\" name=\"Fred\" date-of-birth=\"1991-11-07\"/>";
    Person person = XML_MAPPER.readValue(xml, Person.class);
    Assertions.assertEquals("Person{age=26, name='Fred', dateOfBirth=1991-11-07}", person.toString());
}

对于我来说很奇怪,为什么无论@ConstructorProperties批注如何都通过测试。测试通过注释

        @ConstructorProperties({"a","b","c"})
        public Person(int age, String name, LocalDate dateOfBirth) {
            this.age = age;
            this.name = name;
            this.dateOfBirth = dateOfBirth;
        }

这是魔术吗?杰克逊如何处理此注释?杰克逊注释与ConstructorProperties等效吗?

1 个答案:

答案 0 :(得分:1)

之所以能够通过,是因为JaxbAnnotationIntrospector可以从@XmlAttribute批注中确定属性名称。

AnnotationIntrospectorPair上的文档说:

  

Helper类,允许使用2个自省者,例如一个   内省者是主要使用者;第二个   作为备用广告,如果主要广告不提供结论性的广告   或对方法有用的结果。

根本没有使用JacksonAnnotationIntrospector(可以理解@ConstructorProperties注释)。

如果删除所有JAXB批注,则只有在@ConstructorProperties中指定了正确的名称时,测试才能通过。

如果您想以“杰克逊的方式”进行操作,然后完全删除JAXB注释和JaxbAnnotationIntrospector(只需将调用放到setAnnotationIntrospector,映射器将默认使用{{1 }}。

反序列化将起作用,但是如果您要获得相同的序列化格式,则必须添加一些jackson本机注释:

JacksonAnnotationIntrospector