Reputation: 1138
How do I convert a Java Map
to XML using Jackson?
Version:
'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.9.8'
Code:
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
public class MainApp {
public static void main(String[] args) throws JsonProcessingException {
Map<String, Object> map = new HashMap<String, Object>();
map.put("key1", "value1");
map.put("key2", "value2");
Application app = new Application();
app.setEntry(map);
// xml output format
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true);
System.out.println(xmlMapper.writerWithDefaultPrettyPrinter().writeValueAsString(app));
}
@JacksonXmlRootElement(localName = "headers")
public static class Application {
private Map<String, Object> entry;
public Map<String, Object> getEntry() {
return Collections.unmodifiableMap(entry);
}
public void setEntry(Map<String, Object> entry) {
this.entry = entry;
}
}
}
Actual output:
<?xml version='1.0' encoding='UTF-8'?>
<headers>
<entry>
<key1>value1</key1>
<key2>value2</key2>
</entry>
</headers>
Desired output:
<?xml version='1.0' encoding='UTF-8'?>
<headers>
<entry key="key1">value1</entry>
<entry key="key2">value2</entry>
</headers>
Upvotes: 5
Views: 6604
Reputation: 1138
I found another solution
import org.apache.camel.Body;
import org.apache.camel.Exchange;
import org.apache.camel.Handler;
import org.apache.camel.Headers;
import lombok.Data;
import lombok.Setter;
....
@Override
@Handler
public void record(Exchange exchange, @Headers Map<String, Object> headers, @Body String payload) {
XmlMapper xmlMapper = new XmlMapper(); // XmlMapper is the main class from Jackson 2.x that helps us in serialization
// Convert Camel headers HashMap to xml format
String headersXml = "";
try {
MessageMapHolder messageMapHolder = new MessageMapHolder(headers);
headersXml = xmlMapper.writeValueAsString(messageMapHolder);
} catch (JsonProcessingException e) {
log.error("Error during xml serialization", e);
}
....
}
/**
* Serialise to write Map entry into the below structure
* e.g.
* <headers>
* <entry key="key1">value1</entry>
* <entry key="key2">value2</entry>
* </headers>
*/
@JacksonXmlRootElement(localName = "headers")
@Data
private static class MessageMapHolder {
@Setter
@JacksonXmlProperty(localName = "entry")
private List<Entry> entries;
MessageMapHolder(Map<String, Object> headers) {
try {
entries = new ArrayList<>();
headers.forEach((k, v) -> {
entries.add(new Entry(k, String.valueOf(v)));
});
} catch (Exception e) {
log.warn("Error in converting Camel Header to String: {}", e.getMessage());
}
}
@Data
@AllArgsConstructor
private static class Entry {
@JacksonXmlProperty(isAttribute = true)
private String key;
@JacksonXmlText
private String value;
}
}
Upvotes: 0
Reputation: 38720
You need to implement custom serialiser to write Map
entry like this. Example implementation:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class XmlApp {
public static void main(String[] args) throws IOException {
Map<String, Object> map = new HashMap<>();
map.put("key1", "value1");
map.put("key2", "value2");
Application app = new Application();
app.setEntry(map);
// xml output format
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true);
System.out.println(xmlMapper.writerWithDefaultPrettyPrinter().writeValueAsString(app));
}
}
@JacksonXmlRootElement(localName = "headers")
@JsonSerialize(using = ApplicationJsonSerializer.class)
class Application {
private Map<String, Object> entry;
public Map<String, Object> getEntry() {
return Collections.unmodifiableMap(entry);
}
public void setEntry(Map<String, Object> entry) {
this.entry = entry;
}
}
class ApplicationJsonSerializer extends JsonSerializer<Application> {
@Override
public void serialize(Application value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
ToXmlGenerator xmlGen = (ToXmlGenerator) gen;
xmlGen.writeStartObject();
for (Map.Entry<String, Object> entry : value.getEntry().entrySet()) {
xmlGen.writeObjectFieldStart("entry");
writeAttributes(xmlGen, entry.getKey());
xmlGen.writeRaw(entry.getValue().toString());
xmlGen.writeEndObject();
}
xmlGen.writeEndObject();
}
private void writeAttributes(ToXmlGenerator gen, String key) throws IOException {
gen.setNextIsAttribute(true);
gen.writeFieldName("key");
gen.writeString(key);
gen.setNextIsAttribute(false);
}
}
Above code prints:
<?xml version='1.0' encoding='UTF-8'?>
<headers>
<entry key="key1">value1</entry>
<entry key="key2">value2</entry>
</headers>
Upvotes: 4