Jackson ConstructorProperties 忽略属性名称

Jackson ConstructorProperties ignores properties names

我真的很困惑 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;
        }

这是魔法吗?杰克逊如何处理这个注释? jackson 注释中 ConstructorProperties 的等价物是什么?

它通过了,因为 JaxbAnnotationIntrospector 可以从 @XmlAttribute 注释中确定 属性 名称。

AnnotationIntrospectorPair 上的文档说:

Helper class that allows using 2 introspectors such that one introspector acts as the primary one to use; and second one as a fallback used if the primary does not provide conclusive or useful result for a method.

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

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

如果你想这样做 "the jackson way",然后完全删除 JAXB 注释和 JaxbAnnotationIntrospector(只需放弃对 setAnnotationIntrospector 的调用,映射器将默认使用 JacksonAnnotationIntrospector).

反序列化会起作用,但如果您想获得相同的序列化形式,则必须添加一些 jackson 原生注释:

@JacksonXmlRootElement(localName = "person")
static class Person {
    @JacksonXmlProperty(isAttribute = true)
    final int age;

    @JacksonXmlProperty(isAttribute = true)
    final String name;

    @JacksonXmlProperty(isAttribute = true)
    final LocalDate dateOfBirth;

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

    //...