D.Tomov
D.Tomov

Reputation: 1168

XmlMapper deserializing XmlProperty as XmlElement

I am writing an application that needs to make a POST request with XML. I have generated XML classes from XSD schema and am now trying to generate the body of said request with XmlMapper.

I have the following classes:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "header", propOrder = {
    "createdOn"
})
public class MessageHeader {

    @XmlElement(required = true)
    protected MessageCreatedOn createdOn;

    ...
    ...
    ...
}

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "messageCreatedOn")
public class MessageCreatedOn {

    @XmlAttribute(name = "value", required = true)
    @XmlSchemaType(name = "dateTime")
    protected XMLGregorianCalendar value;
    
    ...
    ...
    ...
}

And the following XmlMapper configuration:

final XmlMapper objectMapper = XmlMapper.builder()
        .defaultUseWrapper(false)
        .build();
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"));
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);


String result = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(messageBase);

With dependency:

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.10.3</version>
</dependency>

I want result to be:

<header>
    <createdOn value="2021-08-18T14:06:14.493+03:00"/>
</header>

But the result is:

  <header>
    <createdOn>
      <value>2021-08-18T14:06:14.493+03:00</value>
    </createdOn>
  </header>

What should I change to get the value to be an attribute to createdOn element.

Upvotes: 2

Views: 1733

Answers (1)

M. Deinum
M. Deinum

Reputation: 125232

As you are using JAXB annotations as the metadata you need to instruct Jackson to use those. Else it will use the default, the Jackson annotations for XML or when absent, everything will become an element.

To enable JAXB annotation processing add the JaxbAnnotationModule to the XmlMapper. This lets Jackson use the JAXB annotation to provide the mapping metadata.

final XmlMapper objectMapper = XmlMapper.builder()
        .defaultUseWrapper(false)
        .defaultDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"))
        .serializationInclusion(JsonInclude.Include.NON_EMPTY)
        .addModule(new JaxbAnnotationModule())
        .build();

Also ideally your XmlMapper should be a singleton bean and not created each time you need it. Another note if you are using Spring, you should really be using a RestTemplate which handles the (un)marshalling for you.

Upvotes: 3

Related Questions