I'm trying to set up code to create a node tree using Jackson
which can then be used to write either JSON
or XML
. I've created the node tree manually like so:
XmlMapper nodeMapper = new XmlMapper();
ObjectNode rootNode = nodeMapper.createObjectNode();
ObjectNode currentNode = rootNode.putObject("Examples");
currentNode.put("Puppy", TRUE)
.put("Apple", 2)
.put("Jet", "Li");
currentNode = rootNode.putObject("Single");
currentNode.put("One", 1);
String writePath = "C:/users/itsameamario/Documents/basicXMLtest.xml";
nodeMapper.writeValue(new File(writePath), rootNode);
My XML output is:
<?xml version="1.0"?>
<ObjectNode>
<Examples>
<Puppy>true</Puppy>
<Apple>2</Apple>
<Jet>Li</Jet>
</Examples>
<Single>
<One>1</One>
</Single>
</ObjectNode>
However for some parts of the XML I would like to add an attribute to one of the nodes like so:
<Examples overlyComplicated="yes">
<!--...-->
</Examples>
All the examples I've found that include attributes are applied to a pre-existing class. I have been unable to find a method to add attributes to a manually-built node-tree as above. Is it doable using Jackson
?
The @JacksonXmlRootElement has a similar role to the @JacksonXmlProperty but for the root element of the entire document. This can only adjust the Namespace and Local name – since the root element can never be serialized as an attribute. For example, let’s look at this Java POJO: When serialized, this will result in the following XML:
Mapping XML Property (Attribute / Element) Annotation @JacksonXmlProperty can be used to provide XML-specific configuration for properties, above and beyond what @JsonProperty contains. It is an alternative to using JAXB annotations. Using boolean property isAttribute can control if the target property is attribute or XML element.
Jackson also allows us to read the contents of an XML file and deserialize the XML String back into a Java object. In our example, we will read an XML document containing details about a phone, and use Jackson to extract this data and use it to create Java objects containing the same information.
Summary If you’re looking for a mature, flexible way of supporting and working with both JSON and XML for the same data, the Jackson XML module is a fantastic library to leverage. It’s not only a solid way to go on its own, but it also has the added benefit of being able to mostly reuse the same configuration for both XML as well as JSON.
It is not possible to mark given property as attribute
since ObjectNode
does not know anything about the serialisation. You can do that for POJO
class and com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator
will handle it only if @JacksonXmlProperty(isAttribute = true)
annotation is used for given property. I suggest to create POJO
for element where you need attribute and use Jackson
XML
annotations or implement JsonSerializable
interface. It could look like below:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializable;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
public class XmlMapperApp {
public static void main(String[] args) throws Exception {
Map<String, Object> map = new LinkedHashMap<>();
map.put("Puppy", Boolean.TRUE);
map.put("Apple", 2);
map.put("Jet", "Li");
Examples examples = new Examples();
examples.setOverlyComplicated("yes");
examples.setMap(map);
XmlMapper mapper = new XmlMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
ObjectNode rootNode = mapper.createObjectNode();
rootNode.putPOJO("Examples", examples);
ObjectNode currentNode = rootNode.putObject("Single");
currentNode.put("One", 1);
mapper.writeValue(System.out, rootNode);
}
}
class Examples implements JsonSerializable {
@Override
public void serialize(JsonGenerator gen, SerializerProvider serializers) throws IOException {
ToXmlGenerator toXmlGenerator = (ToXmlGenerator) gen;
toXmlGenerator.writeStartObject();
writeAttributes(toXmlGenerator);
writeMap(toXmlGenerator);
toXmlGenerator.writeEndObject();
}
private void writeAttributes(ToXmlGenerator gen) throws IOException {
if (overlyComplicated != null) {
gen.setNextIsAttribute(true);
gen.writeFieldName("overlyComplicated");
gen.writeString(overlyComplicated);
gen.setNextIsAttribute(false);
}
}
private void writeMap(ToXmlGenerator toXmlGenerator) throws IOException {
for (Map.Entry<String, Object> entry : map.entrySet()) {
toXmlGenerator.writeObjectField(entry.getKey(), entry.getValue());
}
}
@Override
public void serializeWithType(JsonGenerator gen, SerializerProvider serializers, TypeSerializer typeSer) throws IOException {
serialize(gen, serializers);
}
private String overlyComplicated;
private Map<String, Object> map;
// getters, setters, toString
}
Above code prints:
<ObjectNode>
<Examples overlyComplicated="yes">
<Puppy>true</Puppy>
<Apple>2</Apple>
<Jet>Li</Jet>
</Examples>
<Single>
<One>1</One>
</Single>
</ObjectNode>
In case you want to use the same Example
POJO
for JSON
serialisation you need to handle it in serialize
method or create another ObjectNode
instead of Examlples
object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With