我真的很困惑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等效吗?
答案 0 :(得分:1)
之所以能够通过,是因为JaxbAnnotationIntrospector
可以从@XmlAttribute
批注中确定属性名称。
AnnotationIntrospectorPair
上的文档说:
Helper类,允许使用2个自省者,例如一个 内省者是主要使用者;第二个 作为备用广告,如果主要广告不提供结论性的广告 或对方法有用的结果。
根本没有使用JacksonAnnotationIntrospector
(可以理解@ConstructorProperties
注释)。
如果删除所有JAXB批注,则只有在@ConstructorProperties
中指定了正确的名称时,测试才能通过。
如果您想以“杰克逊的方式”进行操作,然后完全删除JAXB注释和JaxbAnnotationIntrospector
(只需将调用放到setAnnotationIntrospector
,映射器将默认使用{{1 }}。
反序列化将起作用,但是如果您要获得相同的序列化格式,则必须添加一些jackson本机注释:
JacksonAnnotationIntrospector