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