Estoy muy confundido cómo Jackson (2.9.6 versión) ObjectMapper
trabaja con @ConstructorProperties
anotación.
Parece que los nombres de los ignorados asignador de propiedad que están presentes en un @ConstructorProperties
método de valor de anotación.
Lo que es más interesante, - asignador funciona correctamente, independientemente de los nombres de propiedades.
Lo que estoy hablando?
Consideremos XmlMapper personalizado:
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);
y transferencia sencilla de datos de objetos (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 +
'}';
}
}
Creé prueba para reproducir el problema:
@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());
}
Es extraño para mí por qué se pasa la prueba, independientemente de @ConstructorProperties
anotación. La prueba se ha superado con la anotación
@ConstructorProperties({"a","b","c"})
public Person(int age, String name, LocalDate dateOfBirth) {
this.age = age;
this.name = name;
this.dateOfBirth = dateOfBirth;
}
Es una magia? Cómo Jackson procesa esta anotación? Lo que es un equivalente en anotaciones a Jackson ConstructorProperties?
Se pasa porque el JaxbAnnotationIntrospector
puede determinar los nombres de las propiedades de las @XmlAttribute
anotaciones.
El documento sobre AnnotationIntrospectorPair
dice:
Clase auxiliar que permite el usar 2 introspectors tal que uno introspector actúa como el principal de usar; y segundo ona como un fallback utiliza si la principal no ofrece resultados concluyentes, o útil para un método.
El JacksonAnnotationIntrospector
(que comprende la @ConstructorProperties
anotación) no se utiliza en absoluto.
Si se quita toda la JAXB anotaciones de la prueba sólo pasará cuando los nombres correctos se especifican en @ConstructorProperties
.
Si desea hacerlo "la forma en Jackson", a continuación, quitar las anotaciones JAXB y el JaxbAnnotationIntrospector
completo (apenas caer la llamada a setAnnotationIntrospector
, el asignador utilizará por defecto el JacksonAnnotationIntrospector
).
Deserialización va a trabajar, pero vas a tener que agregar algunas anotaciones nativos Jackson si se quiere lograr el mismo forma serializada:
@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;
}
//...