There are multiple problems
First of all this code
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.sun.xml.bind.marshaller.CharacterEscapeHandler;
import org.w3c.dom.ls.LSResourceResolver;
import org.xml.sax.*;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.xml.validation.Schema;
import javax.xml.validation.TypeInfoProvider;
import javax.xml.validation.Validator;
import javax.xml.validation.ValidatorHandler;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
public class TestObjectNode {
@XmlRootElement(name = "moo")
@XmlAccessorType(XmlAccessType.FIELD)
static class Moo {
@JsonProperty("obj")
@XmlElement
@XmlJavaTypeAdapter(ObjMarshaller.class)
JsonNode obj;
}
static final ObjectMapper JSON_MAPPER = new ObjectMapper();
static final XmlMapper XML_MAPPER = (XmlMapper) new XmlMapper()
.disable(SerializationFeature.WRAP_ROOT_VALUE)
.disable(DeserializationFeature.UNWRAP_ROOT_VALUE);
public static void main(String[] args) throws Exception {
final String value = "{\"obj\": {\"my\": \"custom\", \"object\": 1, \"here\": [1, 2, 3] } }";
Moo moo = JSON_MAPPER.readValue(value, Moo.class);
System.out.println(moo.obj);
saveToFile(moo);
System.out.println(XML_MAPPER.writeValueAsString(moo));
moo = readFromFile();
System.out.println(moo.obj);
}
private static void saveToFile(Moo moo) throws Exception {
File file = new File("moo.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Moo.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.setProperty(CharacterEscapeHandler.class.getName(),
new CharacterEscapeHandler() {
@Override
public void escape(char[] chars, int i, int i1, boolean b, Writer writer) throws IOException {
writer.write(chars, i, i1);
}
});
jaxbMarshaller.marshal(moo, file);
jaxbMarshaller.marshal(moo, System.out);
}
private static Moo readFromFile() throws Exception {
File file = new File("moo.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Moo.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
MySchema mySchema = new MySchema();
unmarshaller.setSchema(mySchema);
Moo moo = (Moo) unmarshaller.unmarshal(file);
String objectNode = mySchema.validatorHandler.getObjectNodeString();
System.out.println("objectNode = " + objectNode);
JsonNode jsonNode = XML_MAPPER.readValue(objectNode, ObjectNode.class);
moo.obj = jsonNode;
return moo;
}
private static class ObjMarshaller extends XmlAdapter<String, JsonNode> {
@Override
public JsonNode unmarshal(String v) throws Exception {
throw new IllegalArgumentException("i'm never here///");
}
@Override
public String marshal(JsonNode v) throws Exception {
return XML_MAPPER.writeValueAsString(v);
}
}
static class MySchema extends Schema {
final ValidatorHandlerImpl validatorHandler = new ValidatorHandlerImpl();
@Override
public Validator newValidator() {
return null;
}
@Override
public ValidatorHandler newValidatorHandler() {
return validatorHandler;
}
}
static class ValidatorHandlerImpl extends ValidatorHandler {
private final StringBuilder objectNode = new StringBuilder();
private boolean insideObjectNode = false;
public String getObjectNodeString() {
return objectNode.toString();
}
@Override
public void setContentHandler(ContentHandler receiver) {
}
@Override
public ContentHandler getContentHandler() {
return null;
}
@Override
public void setErrorHandler(ErrorHandler errorHandler) {
}
@Override
public ErrorHandler getErrorHandler() {
return null;
}
@Override
public void setResourceResolver(LSResourceResolver resourceResolver) {
}
@Override
public LSResourceResolver getResourceResolver() {
return null;
}
@Override
public TypeInfoProvider getTypeInfoProvider() {
return null;
}
@Override
public void setDocumentLocator(Locator locator) {
}
@Override
public void startDocument() throws SAXException {
}
@Override
public void endDocument() throws SAXException {
}
@Override
public void startPrefixMapping(String prefix, String uri) throws SAXException {
}
@Override
public void endPrefixMapping(String prefix) throws SAXException {
}
@Override
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
if(localName.equals("ObjectNode")) {
insideObjectNode = true;
}
if (insideObjectNode) {
objectNode.append("<" + localName + ">");
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (insideObjectNode) {
objectNode.append("</" + localName + ">");
}
if(localName.equals("ObjectNode")) {
insideObjectNode = false;
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (insideObjectNode) {
objectNode.append(ch, start, length);
}
}
@Override
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
}
@Override
public void processingInstruction(String target, String data) throws SAXException {
}
@Override
public void skippedEntity(String name) throws SAXException {
}
}
}
Provides following output
{"my":"custom","object":1,"here":[1,2,3]}
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<moo>
<obj><ObjectNode><my>custom</my><object>1</object><here>1</here><here>2</here><here>3</here></ObjectNode></obj>
</moo>
<Moo><obj><my>custom</my><object>1</object><here>1</here><here>2</here><here>3</here></obj></Moo>
objectNode = <ObjectNode><my>custom</my><object>1</object><here>1</here><here>2</here><here>3</here></ObjectNode>
{"my":"custom","object":"1","here":"3"}
So, this because Jackson XML could not parse "here" as array, unfortunately.
So, we should serialize it in different way:
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.sun.xml.bind.marshaller.CharacterEscapeHandler;
import org.w3c.dom.ls.LSResourceResolver;
import org.xml.sax.*;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.xml.validation.Schema;
import javax.xml.validation.TypeInfoProvider;
import javax.xml.validation.Validator;
import javax.xml.validation.ValidatorHandler;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
public class TestObjectNode {
@XmlRootElement(name = "moo")
@XmlAccessorType(XmlAccessType.FIELD)
static class Moo {
@JsonProperty("obj")
@XmlElement
@XmlJavaTypeAdapter(ObjMarshaller.class)
JsonNode obj;
}
static final ObjectMapper JSON_MAPPER = new ObjectMapper();
static final XmlMapper XML_MAPPER = (XmlMapper) new XmlMapper()
.disable(SerializationFeature.WRAP_ROOT_VALUE)
.disable(DeserializationFeature.UNWRAP_ROOT_VALUE);
public static void main(String[] args) throws Exception {
final String value = "{\"obj\": {\"my\": \"custom\", \"object\": 1, \"here\": [1, 2, 3] } }";
Moo moo = JSON_MAPPER.readValue(value, Moo.class);
System.out.println(moo.obj);
saveToFile(moo);
System.out.println(XML_MAPPER.writeValueAsString(moo));
moo = readFromFile();
System.out.println(moo.obj);
}
private static void saveToFile(Moo moo) throws Exception {
File file = new File("moo.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Moo.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.setProperty(CharacterEscapeHandler.class.getName(),
new CharacterEscapeHandler() {
@Override
public void escape(char[] chars, int i, int i1, boolean b, Writer writer) throws IOException {
writer.write(chars, i, i1);
}
});
jaxbMarshaller.marshal(moo, file);
jaxbMarshaller.marshal(moo, System.out);
}
private static Moo readFromFile() throws Exception {
File file = new File("moo.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Moo.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
MySchema mySchema = new MySchema();
unmarshaller.setSchema(mySchema);
Moo moo = (Moo) unmarshaller.unmarshal(file);
String objectNode = mySchema.validatorHandler.getObjectNodeString();
System.out.println("objectNode = " + objectNode);
JsonNode jsonNode = XML_MAPPER.readValue(objectNode, ObjectNode.class);
Object hereObject = jsonNode.get("here");
if (hereObject instanceof TextNode) {
String hereArray = ((TextNode) hereObject).asText().replace("<![CDATA[", "").replace("]]>", "");
ArrayNode here = JSON_MAPPER.readValue(hereArray, ArrayNode.class);
((ObjectNode) jsonNode).put("here", here);
}
moo.obj = jsonNode;
return moo;
}
private static class ObjMarshaller extends XmlAdapter<String, JsonNode> {
@Override
public JsonNode unmarshal(String v) throws Exception {
return null;
}
@Override
public String marshal(JsonNode v) throws Exception {
Object hereObject = v.get("here");
if (hereObject instanceof ArrayNode) {
ArrayNode here = (ArrayNode) hereObject;
final StringBuilder value = new StringBuilder("<![CDATA[").append('[');
for (int i = 0; i < here.size(); ++i) {
if (i > 0) {
value.append(',');
}
value.append(here.get(i));
}
value.append(']').append("]]>");
((ObjectNode) v).put("here", value.toString());
}
return XML_MAPPER.writeValueAsString(v);
}
}
static class MySchema extends Schema {
final ValidatorHandlerImpl validatorHandler = new ValidatorHandlerImpl();
@Override
public Validator newValidator() {
return null;
}
@Override
public ValidatorHandler newValidatorHandler() {
return validatorHandler;
}
}
static class ValidatorHandlerImpl extends ValidatorHandler {
private final StringBuilder objectNode = new StringBuilder();
private boolean insideObjectNode = false;
public String getObjectNodeString() {
return objectNode.toString();
}
@Override
public void setContentHandler(ContentHandler receiver) {
}
@Override
public ContentHandler getContentHandler() {
return null;
}
@Override
public void setErrorHandler(ErrorHandler errorHandler) {
}
@Override
public ErrorHandler getErrorHandler() {
return null;
}
@Override
public void setResourceResolver(LSResourceResolver resourceResolver) {
}
@Override
public LSResourceResolver getResourceResolver() {
return null;
}
@Override
public TypeInfoProvider getTypeInfoProvider() {
return null;
}
@Override
public void setDocumentLocator(Locator locator) {
}
@Override
public void startDocument() throws SAXException {
}
@Override
public void endDocument() throws SAXException {
}
@Override
public void startPrefixMapping(String prefix, String uri) throws SAXException {
}
@Override
public void endPrefixMapping(String prefix) throws SAXException {
}
@Override
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
if(localName.equals("ObjectNode")) {
insideObjectNode = true;
}
if (insideObjectNode) {
objectNode.append("<" + localName + ">");
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (insideObjectNode) {
objectNode.append("</" + localName + ">");
}
if(localName.equals("ObjectNode")) {
insideObjectNode = false;
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (insideObjectNode) {
objectNode.append(ch, start, length);
}
}
@Override
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
}
@Override
public void processingInstruction(String target, String data) throws SAXException {
}
@Override
public void skippedEntity(String name) throws SAXException {
}
}
}
Results:
{"my":"custom","object":1,"here":[1,2,3]}
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<moo>
<obj><ObjectNode><my>custom</my><object>1</object><here><![CDATA[[1,2,3]]]></here></ObjectNode></obj>
</moo>
<Moo><obj><my>custom</my><object>1</object><here><![CDATA[[1,2,3]]]></here></obj></Moo>
objectNode = <ObjectNode><my>custom</my><object>1</object><here><![CDATA[[1,2,3]]]></here></ObjectNode>
{"my":"custom","object":"1","here":[1,2,3]}
This is only example, how the exact your task could be achieved. You see that it needed some hard coding, so maybe it's better to think about another approach. Maybe @XmlAnyElement could help you. Or use text variant from previous answer.
Also if you delete CharacterEscapeHandler.class you would receive escaped xml string.