code: /*******************************************************************************
   * Copyright 2018 572682
   * 
   * Licensed under the Apache License, Version 2.0 (the "License"); you may not
   * use this file except in compliance with the License.  You may obtain a copy
   * of the License at
   * 
   *   http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
   * License for the specific language governing permissions and limitations under
   * the License.
   ******************************************************************************/
  package us.dot.its.jpo.ode.util;
  
  import org.json.JSONObject;
  import org.json.XML;
  
  import com.fasterxml.jackson.core.JsonProcessingException;
  import com.fasterxml.jackson.databind.DeserializationFeature;
  import com.fasterxml.jackson.databind.JsonNode;
  import com.fasterxml.jackson.databind.node.ObjectNode;
  import com.fasterxml.jackson.dataformat.xml.XmlMapper;
  import com.fasterxml.jackson.dataformat.xml.XmlMapper.Builder;
  
  public class XmlUtils {
     public static class XmlUtilsException extends Exception {
  
        private static final long serialVersionUID = 1L;
  
        public XmlUtilsException(String string) {
           super(string);
        }
  
        public XmlUtilsException(String string, Exception e) {
           super(string, e);
        }
  
     }
  
     private XmlMapper xmlMapper = new XmlMapper();
     private static XmlMapper staticXmlMapper = new XmlMapper();
  
     static {
        var builder = new Builder(staticXmlMapper);
        builder.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        builder.defaultUseWrapper(true);
        staticXmlMapper = builder.build();
     }
  
     public XmlUtils() {
        super();
        var builder = new Builder(xmlMapper);
        builder.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        builder.defaultUseWrapper(true);
        xmlMapper = builder.build();
     }
  
     public String toXml(Object o) throws JsonProcessingException {
        String xml = xmlMapper.writeValueAsString(o);
        return xml;
     }
  
     // public static String toXml(Object o) throws XmlUtilsException {
     // try {
     // JSONObject root = new JSONObject();
     // JSONObject object = new JSONObject(o);
     // root.put(o.getClass().getSimpleName(), object);
     // return XML.toString(root);
     // } catch (JSONException e) {
     // throw new XmlUtilsException("Error encoding object to XML", e);
     // }
     // }
  
     public Object fromXml(String xml, Class<?> clazz) throws XmlUtilsException {
        try {
           return xmlMapper.readValue(xml, clazz);
        } catch (Exception e) {
           throw new XmlUtilsException("Error decoding " + xml + " to " + clazz.getName(), e);
        }
     }
  
     /**
      * Embeds the arrayNode into an ObjectNode with the given childKey. By default a
      * JSON array such as {"parent":[1, 2, 3,]} will be converted to:
      * <ObjectNode><parent>1</parent><parent>2</parent><parent>3</parent></ObjectNode>.
      * This is not often desired as there is no paren object to encompass the array.
      * By calling this method given childKey = "child" and arrayNode = [1, 2, 3,],
      * method will return {"parent":{"child":[1, 2, 3,]}} which as a result will be
      * encoded to
      * <ObjectNode><parent><child>1</child><child>2</child><child>3</child></parent></ObjectNode>.
      * Which is a more representative of the JSON ObjectNode.
      * 
      * @param childKey:  The key to be given to the child array object
      * @param arrayNode: The array node to be embedded in a ObjectNode
      * @return OBjectNode representation of the given arrayNode redy to be converted
      *         to XML
      */
     public static ObjectNode createEmbeddedJsonArrayForXmlConversion(String childKey, JsonNode arrayNode) {
        ObjectNode childNode = staticXmlMapper.createObjectNode();
        childNode.set(childKey, arrayNode);
        return childNode;
     }
  
     public static String toXmlStatic(Object o) throws XmlUtilsException {
        String xml;
        try {
           xml = staticXmlMapper.writeValueAsString(o);
        } catch (Exception e) {
           throw new XmlUtilsException("Error encoding object to XML", e);
        }
        return xml;
     }
  
     public static Object fromXmlS(String xml, Class<?> clazz) throws XmlUtilsException {
        try {
           return staticXmlMapper.readValue(xml, clazz);
        } catch (Exception e) {
           throw new XmlUtilsException("Error decoding " + xml + " to " + clazz.getName(), e);
        }
     }
  
     public static ObjectNode toObjectNode(String xml) throws XmlUtilsException {
        try {
           JSONObject jsonObject = XML.toJSONObject(xml, true);
           String jsonString = jsonObject.toString();
           return JsonUtils.toObjectNode(jsonString);
  
           /*
            * Due to issues with XmlMapper converting "xml arrays" to a valid DOM
            * collection we could not use it in this context. Hence the above workaround
            * was adopted. See:
            * https://github.com/FasterXML/jackson-dataformat-xml/issues/187
            * https://github.com/FasterXML/jackson-dataformat-xml/issues/205
            */
           // return (ObjectNode) staticXmlMapper.readTree(xml);
        } catch (Exception e) {
           throw new XmlUtilsException("Error decoding " + xml + "to ObjectNode", e);
        }
     }
  
     public static JSONObject toJSONObject(String xml) throws XmlUtilsException {
        try {
           return XML.toJSONObject(xml, true);
        } catch (Exception e) {
           throw new XmlUtilsException("Error decoding " + xml + "to JSONObject", e);
        }
     }
  
     public static JsonNode getJsonNode(String tree, String fieldName) throws XmlUtilsException {
        JsonNode jsonNode;
        try {
           jsonNode = staticXmlMapper.readTree(tree);
        } catch (Exception e) {
           throw new XmlUtilsException("Error getting field name " + fieldName + " from " + tree, e);
        }
        return jsonNode.get(fieldName);
     }
  
     public XmlMapper getXmlMapper() {
        return xmlMapper;
     }
  
     public static XmlMapper getStaticXmlMapper() {
        return staticXmlMapper;
     }
  
  }
  