How to express XML with mixed content using Jackson XmlMapper

53 views Asked by At

I need write a Java program that will generate a XML with mixed content. It should more or less like this:

   <foo>
       <bar><a></a>Some text<b></b></bar>
    </foo>

I would like to use Jackson XML Mapper to serialize Java objects to XML but I don't know how to build an object equivalent to above XML.

2

There are 2 answers

0
Paweł Adamski On BEST ANSWER

Eventually I was able to generated expected XML using following Java record:

record foo(
        @JacksonXmlProperty
        Bar bar
){};

@JsonPropertyOrder({"a", "content", "b"})
record Bar(
        @JsonInclude
        @JacksonXmlProperty
        String a,
        @JacksonXmlText
        String content,
        @JsonInclude
        @JacksonXmlProperty
        String b
) {
};
0
devatherock On

This cannot be done with Jackson as per its known limitations. But this can be done with JAXB by declaring the contents of the bar field/class as @XmlMixed. You can find the code below:

Gradle dependencies:

implementation group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.1'
implementation group: 'org.glassfish.jaxb', name: 'jaxb-runtime', version: '2.3.1'

Foo.java:

import lombok.Setter;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@Setter
@XmlRootElement(name = "foo")
public class Foo {
    @XmlElement
    private Bar bar;
}

Bar.java:

import lombok.Setter;

import javax.xml.bind.annotation.XmlMixed;
import java.io.Serializable;
import java.util.List;

@Setter
public class Bar {
    @XmlMixed
    private List<Serializable> content;
}

XML Serialization code:

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.namespace.QName;
import java.io.Serializable;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

// ...Class and method declaration omitted

List<Serializable> content = new ArrayList<>();
content.add(new JAXBElement(new QName("a"), String.class, "value-a"));
content.add("Some text");
content.add(new JAXBElement(new QName("b"), String.class, "value-b"));
Bar bar = new Bar();
bar.setContent(content);
Foo foo = new Foo();
foo.setBar(bar);

StringWriter writer = new StringWriter();
JAXBContext context = JAXBContext.newInstance(Foo.class, Bar.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
marshaller.marshal(foo, writer);
String xmlString = writer.toString();

The XML generated by the above code will look like the below:

<foo><bar><a>value-a</a>Some text<b>value-b</b></bar></foo>

You can find the complete working sample on github.