JAXB / Jersey - JSONObject as XmlElement JAXB / Jersey - JSONObject as XmlElement json json

JAXB / Jersey - JSONObject as XmlElement


If I got it right, you want to embedd a raw json for free-from values.

@XmlRootElement(name="moo")@XmlAccessorType(XmlAccessType.FIELD)public class Moo {    Object json;    @JsonRawValue    public String getJson() {        // default raw value: null or "[]"        return json == null ? null : json.toString();    }    public void setJson(JsonNode node) {        this.json = node;    }}

Taken from here.


There are multiple problemsFirst 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.