Package org.eclipse.persistence.oxm

Source Code of org.eclipse.persistence.oxm.XMLMarshaller

/*******************************************************************************
* Copyright (c) 1998, 2011 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
*     Oracle - initial API and implementation from Oracle TopLink
******************************************************************************/
package org.eclipse.persistence.oxm;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Map.Entry;
import java.util.Properties;

import javax.xml.namespace.QName;
import javax.xml.transform.Result;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamResult;
import javax.xml.validation.Schema;

import org.eclipse.persistence.exceptions.XMLMarshalException;
import org.eclipse.persistence.internal.helper.ClassConstants;
import org.eclipse.persistence.internal.oxm.FragmentContentHandler;
import org.eclipse.persistence.internal.oxm.TreeObjectBuilder;
import org.eclipse.persistence.internal.oxm.XMLConversionManager;
import org.eclipse.persistence.internal.oxm.XMLObjectBuilder;
import org.eclipse.persistence.internal.oxm.XPathEngine;
import org.eclipse.persistence.internal.oxm.XPathFragment;
import org.eclipse.persistence.internal.oxm.record.DOMReader;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.mappings.DatabaseMapping.WriteType;
import org.eclipse.persistence.oxm.NamespaceResolver;
import org.eclipse.persistence.oxm.XMLConstants;
import org.eclipse.persistence.oxm.XMLField;
import org.eclipse.persistence.oxm.attachment.*;
import org.eclipse.persistence.oxm.documentpreservation.DocumentPreservationPolicy;
import org.eclipse.persistence.oxm.record.ContentHandlerRecord;
import org.eclipse.persistence.oxm.record.FormattedOutputStreamRecord;
import org.eclipse.persistence.oxm.record.FormattedWriterRecord;
import org.eclipse.persistence.oxm.record.MarshalRecord;
import org.eclipse.persistence.oxm.record.NodeRecord;
import org.eclipse.persistence.oxm.record.OutputStreamRecord;
import org.eclipse.persistence.oxm.record.ValidatingMarshalRecord;
import org.eclipse.persistence.oxm.record.WriterRecord;
import org.eclipse.persistence.oxm.record.XMLRecord;
import org.eclipse.persistence.oxm.schema.XMLSchemaReference;
import org.eclipse.persistence.platform.xml.XMLPlatform;
import org.eclipse.persistence.platform.xml.XMLPlatformException;
import org.eclipse.persistence.platform.xml.XMLPlatformFactory;
import org.eclipse.persistence.platform.xml.XMLTransformer;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.ContentHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.ext.LexicalHandler;

/**
* <p>Class used to marshal object to XML.
*
* <p>Create an XMLMarshaller from an XMLContext.<br>
<em>Code Sample</em><br>
<code>
*  XMLContext context = new XMLContext("mySessionName");<br>
*  XMLMarshaller marshaller = context.createMarshaller();<br>
<code>
*
* <p>Objects can be marshalled to the following outputs:<ul>
* <li>java.io.OutputStream</li>
* <li>java.io.Writer</li>
* <li>javax.xml.transform.Result</li>
* <li>org.w3c.dom.Node</li>
* <li>org.xml.sax.ContentHandler</li>
* </ul>
*
* <p>Objects that can be marshalled are those which are mapped in the
* TopLink project associated with the XMLContext, and which are mapped
* to an XMLDescriptor that has a default root element specified.
*
* @see org.eclipse.persistence.oxm.XMLContext
*/
public class XMLMarshaller implements Cloneable {
    private final static String DEFAULT_XML_VERSION = "1.0";
    private String schemaLocation;
    private String noNamespaceSchemaLocation;
    private XMLTransformer transformer;
    private XMLContext xmlContext;
    private XMLMarshalListener marshalListener;
    private XMLAttachmentMarshaller attachmentMarshaller;
    private ErrorHandler errorHandler;
    private Properties marshalProperties;
    private Schema schema;
   
    private static final String STAX_RESULT_CLASS_NAME = "javax.xml.transform.stax.StAXResult";
    private static final String GET_XML_STREAM_WRITER_METHOD_NAME = "getXMLStreamWriter";
    private static final String GET_XML_EVENT_WRITER_METHOD_NAME = "getXMLEventWriter";
    private static final String XML_STREAM_WRITER_RECORD_CLASS_NAME = "org.eclipse.persistence.oxm.record.XMLStreamWriterRecord";
    private static final String XML_EVENT_WRITER_RECORD_CLASS_NAME = "org.eclipse.persistence.oxm.record.XMLEventWriterRecord";
    private static final String XML_STREAM_WRITER_CLASS_NAME = "javax.xml.stream.XMLStreamWriter";
    private static final String XML_EVENT_WRITER_CLASS_NAME = "javax.xml.stream.XMLEventWriter";
    private static final String DOM_TO_STREAM_WRITER_CLASS_NAME = "org.eclipse.persistence.internal.oxm.record.DomToXMLStreamWriter";
    private static final String DOM_TO_EVENT_WRITER_CLASS_NAME = "org.eclipse.persistence.internal.oxm.record.DomToXMLEventWriter";
    private static final String WRITE_TO_STREAM_METHOD_NAME = "writeToStream";
    private static final String WRITE_TO_EVENT_WRITER_METHOD_NAME = "writeToEventWriter";

    private static Class staxResultClass;
    private static Method staxResultGetStreamWriterMethod;
    private static Method staxResultGetEventWriterMethod;
    private static Constructor xmlStreamWriterRecordConstructor;
    private static Constructor xmlEventWriterRecordConstructor;
    private static Method writeToStreamMethod;
    private static Method writeToEventWriterMethod;
    private static Class domToStreamWriterClass;
    private static Class domToEventWriterClass;

    static {
        try {
            staxResultClass = PrivilegedAccessHelper.getClassForName(STAX_RESULT_CLASS_NAME);
            if(staxResultClass != null) {
                staxResultGetStreamWriterMethod = PrivilegedAccessHelper.getDeclaredMethod(staxResultClass, GET_XML_STREAM_WRITER_METHOD_NAME, new Class[]{});
                staxResultGetEventWriterMethod = PrivilegedAccessHelper.getDeclaredMethod(staxResultClass, GET_XML_EVENT_WRITER_METHOD_NAME, new Class[]{});
            }
            Class streamWriterRecordClass = PrivilegedAccessHelper.getClassForName(XML_STREAM_WRITER_RECORD_CLASS_NAME);
            Class streamWriterClass = PrivilegedAccessHelper.getClassForName(XML_STREAM_WRITER_CLASS_NAME);
            xmlStreamWriterRecordConstructor = PrivilegedAccessHelper.getConstructorFor(streamWriterRecordClass, new Class[]{streamWriterClass}, true);

            Class eventWriterRecordClass = PrivilegedAccessHelper.getClassForName(XML_EVENT_WRITER_RECORD_CLASS_NAME);
            Class eventWriterClass = PrivilegedAccessHelper.getClassForName(XML_EVENT_WRITER_CLASS_NAME);
            xmlEventWriterRecordConstructor = PrivilegedAccessHelper.getConstructorFor(eventWriterRecordClass, new Class[]{eventWriterClass}, true);
           
            domToStreamWriterClass = PrivilegedAccessHelper.getClassForName(DOM_TO_STREAM_WRITER_CLASS_NAME);
            writeToStreamMethod = PrivilegedAccessHelper.getMethod(domToStreamWriterClass, WRITE_TO_STREAM_METHOD_NAME, new Class[] {ClassConstants.NODE, streamWriterClass}, true);
           
            domToEventWriterClass = PrivilegedAccessHelper.getClassForName(DOM_TO_EVENT_WRITER_CLASS_NAME);
            writeToEventWriterMethod = PrivilegedAccessHelper.getMethod(domToEventWriterClass, WRITE_TO_EVENT_WRITER_METHOD_NAME, new Class[] {ClassConstants.NODE, eventWriterClass}, true);
           
        } catch (Exception ex) {
            // Do nothing
        }
    }

    /**
    * Create a new XMLMarshaller based on the specified session
    * @param session A single session
    */
    public XMLMarshaller(XMLContext xmlContext) {
        setXMLContext(xmlContext);
        initialize();
    }

    private void initialize() {
        XMLPlatform xmlPlatform = XMLPlatformFactory.getInstance().getXMLPlatform();
        transformer = xmlPlatform.newXMLTransformer();
        setEncoding(XMLConstants.DEFAULT_XML_ENCODING);
        setFormattedOutput(true);
        marshalProperties = new Properties();
    }

    /**
     * Return the instance of XMLContext that was used to create this instance
     * of XMLMarshaller.
     */
    public XMLContext getXMLContext() {
        return xmlContext;
    }

    /**
     * Set the XMLContext used by this instance of XMLMarshaller.
     */
    public void setXMLContext(XMLContext value) {
        xmlContext = value;
    }

    public ErrorHandler getErrorHandler() {
        return errorHandler;
    }

    public void setErrorHandler(ErrorHandler errorHandler) {
        this.errorHandler = errorHandler;
    }

    /**
    * Returns if this XMLMarshaller should format the XML
    * By default this is set to true and the XML marshalled will be formatted.
    * @return if this XMLMarshaller should format the XML
    */
    public boolean isFormattedOutput() {
        return transformer.isFormattedOutput();
    }

    /**
    * Set if this XMLMarshaller should format the XML
    * By default this is set to true and the XML marshalled will be formatted.
    * @param shouldFormat if this XMLMarshaller should format the XML
    */
    public void setFormattedOutput(boolean shouldFormat) {
        transformer.setFormattedOutput(shouldFormat);
    }

    /**
       * Get the encoding set on this XMLMarshaller
       * If the encoding has not been set the default UTF-8 will be used
       * @return the encoding set on this XMLMarshaller
       */
    public String getEncoding() {
        return transformer.getEncoding();
    }

    /**
       * Set the encoding on this XMLMarshaller
       * If the encoding is not set the default UTF-8 will be used
       * @param newEncoding the encoding to set on this XMLMarshaller
       */
    public void setEncoding(String newEncoding) {
        transformer.setEncoding(newEncoding);       
    }

    /**
      * Get the schema location set on this XMLMarshaller
      * @return the schema location specified on this XMLMarshaller
      */
    public String getSchemaLocation() {
        return schemaLocation;
    }

    /**
      * Set the schema location on this XMLMarshaller
      * @param newSchemaLocation the schema location to be seton this XMLMarshaller
      */
    public void setSchemaLocation(String newSchemaLocation) {
        schemaLocation = newSchemaLocation;
    }

    /**
      * Get the no namespace schema location set on this XMLMarshaller
      * @return the no namespace schema location specified on this XMLMarshaller
      */
    public String getNoNamespaceSchemaLocation() {
        return noNamespaceSchemaLocation;
    }

    /**
     * Return a properties object for a given instance of the
     * XMLMarshaller.
     *
     * @return
     */
    public Properties getProperties() {
        return marshalProperties;
    }

    /**
     * Return the property for a given key, if one exists.
     *
     * @parm key
     * @return
     */
    public Object getProperty(Object key) {
        return marshalProperties.get(key);
    }

    /**
      * Set the no namespace schema location on this XMLMarshaller
      * @param newNoNamespaceSchemaLocation no namespace schema location to be seton this XMLMarshaller
      */
    public void setNoNamespaceSchemaLocation(String newNoNamespaceSchemaLocation) {
        noNamespaceSchemaLocation = newNoNamespaceSchemaLocation;
    }

    public void setXMLMarshalHandler(XMLMarshalListener marshalListener) {
        this.marshalListener = marshalListener;
    }

    public XMLMarshalListener getMarshalListener() {
        return this.marshalListener;
    }

    public void setMarshalListener(XMLMarshalListener listener) {
        this.marshalListener = listener;
    }

    /**
    * PUBLIC:
    * Convert the given object to XML and update the given result with that XML Document
    * @param object the object to marshal
    * @param result the result to marshal the object to
    * @throws XMLMarshalException if an error occurred during marshalling
    */
    public void marshal(Object object, Result result) throws XMLMarshalException {
        if ((object == null) || (result == null)) {
            throw XMLMarshalException.nullArgumentException();
        }

        boolean isXMLRoot = (object instanceof XMLRoot);
        XMLDescriptor xmlDescriptor = getDescriptor(object, isXMLRoot);

        AbstractSession session = xmlContext.getSession(xmlDescriptor);
        //if this is a simple xml root, the session and descriptor will be null
        if (!(isXMLRoot && ((XMLRoot)object).getObject() instanceof Node) && ((session == null) || !xmlContext.getDocumentPreservationPolicy(session).shouldPreserveDocument())) {
            if (result instanceof DOMResult) {
                DOMResult domResult = (DOMResult) result;
                // handle case where the node is null
                if (domResult.getNode() == null) {
                    domResult.setNode(this.objectToXML(object));
                } else {
                    marshal(object, domResult.getNode());
                }
            } else if (result instanceof SAXResult) {
                SAXResult saxResult = (SAXResult) result;
                marshal(object, saxResult.getHandler());
            } else if (result instanceof StreamResult) {
                StreamResult streamResult = (StreamResult) result;
                Writer writer = streamResult.getWriter();
                if (writer != null) {
                    marshal(object, writer);
                } else if (streamResult.getOutputStream() != null) {
                    marshal(object, streamResult.getOutputStream());
                } else {
                    try {
                        File f = new File(new URL(streamResult.getSystemId()).toURI());
                        writer = new FileWriter(f);
                        try {
                            marshal(object, writer);
                        } finally {
                            writer.close();
                        }
                    } catch (Exception e) {
                        throw XMLMarshalException.marshalException(e);
                    }
                }
            } else {
                if (result.getClass().equals(staxResultClass)) {
                    try {
                        Object xmlStreamWriter = PrivilegedAccessHelper.invokeMethod(staxResultGetStreamWriterMethod, result);
                        if (xmlStreamWriter != null) {
                            MarshalRecord record = (MarshalRecord)PrivilegedAccessHelper.invokeConstructor(xmlStreamWriterRecordConstructor, new Object[]{xmlStreamWriter});
                            record.setMarshaller(this);
                            marshal(object, record, session, xmlDescriptor, isXMLRoot);                           
                            return;
                        } else {
                            Object xmlEventWriter = PrivilegedAccessHelper.invokeMethod(staxResultGetEventWriterMethod, result);
                            if(xmlEventWriter != null) {
                                MarshalRecord record = (MarshalRecord)PrivilegedAccessHelper.invokeConstructor(xmlEventWriterRecordConstructor, new Object[]{xmlEventWriter});
                                record.setMarshaller(this);
                                marshal(object, record, session, xmlDescriptor, isXMLRoot);
                                return;
                            }
                        }
                    } catch (Exception e) {
                        throw XMLMarshalException.marshalException(e);
                    }
                }
                java.io.StringWriter writer = new java.io.StringWriter();
                marshal(object, writer);
                javax.xml.transform.stream.StreamSource source = new javax.xml.transform.stream.StreamSource(new java.io.StringReader(writer.toString()));
                transformer.transform(source, result);
            }
            return;
        }
        try {
            Document document = null;
            if(isXMLRoot && session == null) {
                document = ((Node)((XMLRoot)object).getObject()).getOwnerDocument();
            } else {
                document = objectToXML(object, xmlDescriptor, isXMLRoot);
            }
            if ((result instanceof SAXResult) && (isFragment())) {
                FragmentContentHandler fragmentHandler = new FragmentContentHandler(((SAXResult) result).getHandler());
                if (isXMLRoot) {
                    String oldEncoding = transformer.getEncoding();
                    String oldVersion = transformer.getVersion();
                    if (((XMLRoot) object).getEncoding() != null) {
                        transformer.setEncoding(((XMLRoot) object).getEncoding());
                    }
                    if (((XMLRoot) object).getXMLVersion() != null) {
                        transformer.setVersion(((XMLRoot) object).getXMLVersion());
                    }
                    transformer.transform(document, fragmentHandler);
                    transformer.setEncoding(oldEncoding);
                    transformer.setVersion(oldVersion);
                } else {
                    transformer.transform(document, fragmentHandler);

                }
            } else {
                if (result.getClass().equals(staxResultClass)) {
                    try {
                        Object xmlStreamWriter = PrivilegedAccessHelper.invokeMethod(staxResultGetStreamWriterMethod, result);
                        if (xmlStreamWriter != null) {
                            Object domtostax = PrivilegedAccessHelper.newInstanceFromClass(domToStreamWriterClass);
                            PrivilegedAccessHelper.invokeMethod(writeToStreamMethod, domtostax, new Object[]{document, xmlStreamWriter});
                            return;
                        } else {
                            Object xmlEventWriter = PrivilegedAccessHelper.invokeMethod(staxResultGetEventWriterMethod, result);
                            if(xmlEventWriter != null) {
                                Object domToEventWriter = PrivilegedAccessHelper.newInstanceFromClass(domToEventWriterClass);
                                PrivilegedAccessHelper.invokeMethod(writeToEventWriterMethod, domToEventWriter, new Object[]{document, xmlEventWriter});
                                return;
                            }
                        }

                    } catch(Exception e) {
                        throw XMLMarshalException.marshalException(e);
                    }
                }
                if (isXMLRoot) {
                    String oldEncoding = transformer.getEncoding();
                    String oldVersion = transformer.getVersion();
                    if (((XMLRoot) object).getEncoding() != null) {
                        transformer.setEncoding(((XMLRoot) object).getEncoding());
                    }
                    if (((XMLRoot) object).getXMLVersion() != null) {
                        transformer.setVersion(((XMLRoot) object).getXMLVersion());
                    }
                    transformer.transform(document, result);
                    transformer.setEncoding(oldEncoding);
                    transformer.setVersion(oldVersion);
                } else {
                    transformer.transform(document, result);
                }
            }
        } catch (XMLPlatformException e) {
            throw XMLMarshalException.marshalException(e);
        }
    }

    /**
    * PUBLIC:
    * Convert the given object to XML and update the given outputStream with that XML Document
    * @param object the object to marshal
    * @param outputStream the outputStream to marshal the object to
    * @throws XMLMarshalException if an error occurred during marshalling
    */
    public void marshal(Object object, OutputStream outputStream) throws XMLMarshalException {
        if ((object == null) || (outputStream == null)) {
            throw XMLMarshalException.nullArgumentException();
        }
        try {
            boolean isXMLRoot = false;
            String version = DEFAULT_XML_VERSION;
            String encoding = getEncoding();
            if (object instanceof XMLRoot) {
                isXMLRoot = true;
                XMLRoot xroot = (XMLRoot) object;
                version = xroot.getXMLVersion() != null ? xroot.getXMLVersion() : version;
                encoding = xroot.getEncoding() != null ? xroot.getEncoding() : encoding;
            }
           
            if(encoding.equals(XMLConstants.DEFAULT_XML_ENCODING)){
                AbstractSession session = null;
                XMLDescriptor xmlDescriptor = null;
                if(isXMLRoot){
                    try{
                      session = xmlContext.getSession(((XMLRoot)object).getObject());
                      if(session != null){
                          xmlDescriptor = getDescriptor(((XMLRoot)object).getObject(), session);
                      }
                   }catch (XMLMarshalException marshalException) {
                        if (!isSimpleXMLRoot((XMLRoot) object)) {
                          throw marshalException;   
                        }               
                    }
                }else{
                  session = xmlContext.getSession(object.getClass());
                  xmlDescriptor = getDescriptor(object.getClass(), session);
                }
           
                OutputStreamRecord record;
                if (isFormattedOutput()) {
                  record = new FormattedOutputStreamRecord();                 
                } else {
                  record = new OutputStreamRecord();                 
                }
                      
                record.setMarshaller(this);
                record.setOutputStream(outputStream);
           
                //if this is a simple xml root, the session and descriptor will be null
                if (!(isXMLRoot && ((XMLRoot)object).getObject() instanceof Node) && ((session == null) || !xmlContext.getDocumentPreservationPolicy(session).shouldPreserveDocument())) {
                    marshal(object, record, session, xmlDescriptor, isXMLRoot);   
                } else {
                    try {
                        Node xmlDocument = null;
                        if(isXMLRoot && session == null) {
                            xmlDocument = (Node)((XMLRoot)object).getObject();
                        } else {
                            xmlDocument = objectToXMLNode(object, session, xmlDescriptor, isXMLRoot);
                        }
                        record.setSession(session);
                        if (isFragment()) {
                            record.node(xmlDocument, xmlDescriptor.getNamespaceResolver());
                        } else {
                            record.startDocument(encoding, version);
                            record.node(xmlDocument, record.getNamespaceResolver());
                            record.endDocument();
                        }
                    } catch (XMLPlatformException e) {
                        throw XMLMarshalException.marshalException(e);
                    }
                }
                record.flush();
            }else{
              OutputStreamWriter writer = new OutputStreamWriter(outputStream, encoding);
                marshal(object, writer);
                writer.flush();
            }
        } catch (UnsupportedEncodingException exception) {
            throw XMLMarshalException.marshalException(exception);
        } catch (Exception ex) {
            throw XMLMarshalException.marshalException(ex);
        }
    }

    /**
    * PUBLIC:
    * Convert the given object to XML and update the given writer with that XML Document
    * @param object the object to marshal
    * @param writer the writer to marshal the object to
    * @throws XMLMarshalException if an error occurred during marshalling
    */
    public void marshal(Object object, Writer writer) throws XMLMarshalException {
        if ((object == null) || (writer == null)) {
            throw XMLMarshalException.nullArgumentException();
        }
        boolean isXMLRoot = false;
        String version = DEFAULT_XML_VERSION;
        String encoding = getEncoding();
        if (object instanceof XMLRoot) {
            isXMLRoot = true;
            XMLRoot xroot = (XMLRoot) object;
            version = xroot.getXMLVersion() != null ? xroot.getXMLVersion() : version;
            encoding = xroot.getEncoding() != null ? xroot.getEncoding() : encoding;
        }

       
        AbstractSession session = null;
        XMLDescriptor xmlDescriptor = null;
        if(isXMLRoot){
          try{
              session = xmlContext.getSession(((XMLRoot)object).getObject());
              if(session != null){
                  xmlDescriptor = getDescriptor(((XMLRoot)object).getObject(), session);
              }
          }catch (XMLMarshalException marshalException) {
                if (!isSimpleXMLRoot((XMLRoot) object)) {
                  throw marshalException;   
                }               
            }
        }else{
          session = xmlContext.getSession(object.getClass());
          xmlDescriptor = getDescriptor(object.getClass(), session);
        }

        WriterRecord writerRecord;
        if (isFormattedOutput()) {
            writerRecord = new FormattedWriterRecord();
        } else {
            writerRecord = new WriterRecord();
        }
        writerRecord.setMarshaller(this);
        writer = new BufferedWriter(writer);       
        writerRecord.setWriter(writer);

        //if this is a simple xml root, the session and descriptor will be null
        if (!(isXMLRoot && ((XMLRoot)object).getObject() instanceof Node) && ((session == null) || !xmlContext.getDocumentPreservationPolicy(session).shouldPreserveDocument())) {
            marshal(object, writerRecord, session, xmlDescriptor, isXMLRoot);   
        } else {
            try {
                Node xmlDocument = null;
                if(isXMLRoot && session == null) {
                    xmlDocument = (Node)((XMLRoot)object).getObject();
                } else {
                    xmlDocument = objectToXMLNode(object, session, xmlDescriptor, isXMLRoot);
                }
                writerRecord.setSession(session);
                if (isFragment()) {
                    writerRecord.node(xmlDocument, xmlDescriptor.getNamespaceResolver());
                } else {
                    writerRecord.startDocument(encoding, version);
                    writerRecord.node(xmlDocument, writerRecord.getNamespaceResolver());
                    writerRecord.endDocument();
                }
            } catch (XMLPlatformException e) {
                throw XMLMarshalException.marshalException(e);
            }
        }
        try {
            writer.flush();
        } catch (IOException e) {
            throw XMLMarshalException.marshalException(e);
        }
    }

    /**
    * PUBLIC:
    * Convert the given object to XML and update the given contentHandler with that XML Document
    * @param object the object to marshal
    * @param contentHandler the contentHandler which the specified object should be marshalled to
    * @throws XMLMarshalException if an error occurred during marshalling
    */
    public void marshal(Object object, ContentHandler contentHandler) throws XMLMarshalException {
        marshal(object, contentHandler, null);
    }

    /**
     * PUBLIC:
     * Convert the given object to XML and update the given contentHandler with that XML Document
     * @param object the object to marshal
     * @param contentHandler the contentHandler which the specified object should be marshalled to
     * @throws XMLMarshalException if an error occurred during marshalling
     */
    public void marshal(Object object, ContentHandler contentHandler, LexicalHandler lexicalHandler) throws XMLMarshalException {
        if ((object == null) || (contentHandler == null)) {
            throw XMLMarshalException.nullArgumentException();
        }
        boolean isXMLRoot = (object instanceof XMLRoot);
       
        AbstractSession session = null;
        XMLDescriptor xmlDescriptor = null;
        if(isXMLRoot){
          try{
              session = xmlContext.getSession(((XMLRoot)object).getObject());             
              if(session != null){
                  xmlDescriptor = getDescriptor(((XMLRoot)object).getObject(), session);
              }
          }catch (XMLMarshalException marshalException) {
                if (!isSimpleXMLRoot((XMLRoot) object)) {
                  throw marshalException;   
                }               
            }
        }else{
          session = xmlContext.getSession(object.getClass());
          xmlDescriptor = getDescriptor(object.getClass(), session);
        }
       
        //if it's a simple xml root then session and descriptor will be null
        if (!(isXMLRoot && ((XMLRoot)object).getObject() instanceof Node) && ((session == null) || !xmlContext.getDocumentPreservationPolicy(session).shouldPreserveDocument())) {
            ContentHandlerRecord contentHandlerRecord = new ContentHandlerRecord();
            contentHandlerRecord.setMarshaller(this);
            contentHandlerRecord.setContentHandler(contentHandler);
            contentHandlerRecord.setLexicalHandler(lexicalHandler);
            marshal(object, contentHandlerRecord, session, xmlDescriptor,isXMLRoot);
            return;
        }

        try {
            Node xmlDocument = null;
            if(session == null) {
                //indicated we're marshalling a node
                xmlDocument = (Node)((XMLRoot)object).getObject();
            } else {
                xmlDocument = objectToXML(object, xmlDescriptor, isXMLRoot);
            }
            DOMReader reader = new DOMReader();
            reader.setProperty("http://xml.org/sax/properties/lexical-handler", lexicalHandler);
            if (isFragment()) {
                FragmentContentHandler fragmentHandler = new FragmentContentHandler(contentHandler);
                reader.setContentHandler(fragmentHandler);
            } else {
                reader.setContentHandler(contentHandler);
            }
            reader.parse(xmlDocument);
        } catch (XMLPlatformException e) {
            throw XMLMarshalException.marshalException(e);
        } catch (org.xml.sax.SAXNotRecognizedException e) {
            //won't be thrown
        } catch (SAXNotSupportedException e) {
            //won't be thrown
        } catch (org.xml.sax.SAXException e) {
            throw XMLMarshalException.marshalException(e);
        }
    }

    /**
    * PUBLIC:
    * Convert the given object to XML and update the given node with that XML Document
    * @param object the object to marshal
    * @param node the node which the specified object should be marshalled to
    * @throws XMLMarshalException if an error occurred during marshalling
    */
    public void marshal(Object object, Node node) throws XMLMarshalException {
        if ((object == null) || (node == null)) {
            throw XMLMarshalException.nullArgumentException();
        }
        try {
            boolean isXMLRoot = (object instanceof XMLRoot);
                                  
            AbstractSession session = null;
            XMLDescriptor xmlDescriptor = null;
            if(isXMLRoot){
              try{
                  session = xmlContext.getSession(((XMLRoot)object).getObject());
                  if(session != null){
                      xmlDescriptor = getDescriptor(((XMLRoot)object).getObject(), session);
                  }
              }catch (XMLMarshalException marshalException) {
                    if (!isSimpleXMLRoot((XMLRoot) object)) {
                      throw marshalException;   
                    }               
                }
            }else{
              session = xmlContext.getSession(object.getClass());
              xmlDescriptor = getDescriptor(object.getClass(), session);
            }
           
           
            //if this is a simple xml root, descriptor and session will be null
            if (!(isXMLRoot && ((XMLRoot)object).getObject() instanceof Node) && ((session == null) || !xmlContext.getDocumentPreservationPolicy(session).shouldPreserveDocument())) {
                NodeRecord nodeRecord = new NodeRecord(node);
                nodeRecord.setMarshaller(this);

                if (!isXMLRoot) {
                    if ((null == xmlDescriptor.getDefaultRootElement()) && (node.getNodeType() == Node.ELEMENT_NODE) && (xmlDescriptor.getSchemaReference() != null) && (xmlDescriptor.getSchemaReference().getType() == XMLSchemaReference.COMPLEX_TYPE)) {
                        Attr typeAttr = ((Element) node).getAttributeNodeNS(XMLConstants.SCHEMA_INSTANCE_URL, XMLConstants.SCHEMA_TYPE_ATTRIBUTE);
                        if (typeAttr == null) {
                            NamespaceResolver namespaceResolver = xmlDescriptor.getNamespaceResolver();
                            String xsiPrefix = null;
                            if (null == namespaceResolver) {
                                namespaceResolver = new NamespaceResolver();
                                xmlDescriptor.setNamespaceResolver(namespaceResolver);
                            } else {
                                xsiPrefix = namespaceResolver.resolveNamespaceURI(XMLConstants.SCHEMA_INSTANCE_URL);
                            }

                            if (null == xsiPrefix) {
                                xsiPrefix = namespaceResolver.generatePrefix(XMLConstants.SCHEMA_INSTANCE_PREFIX);
                            }

                            String value = xmlDescriptor.getSchemaReference().getSchemaContext();

                            ((Element) node).setAttributeNS(XMLConstants.XMLNS_URL, XMLConstants.XMLNS + XMLConstants.COLON + xsiPrefix, XMLConstants.SCHEMA_INSTANCE_URL);
                            ((Element) node).setAttributeNS(XMLConstants.SCHEMA_INSTANCE_URL, xsiPrefix + XMLConstants.COLON + XMLConstants.SCHEMA_TYPE_ATTRIBUTE, value);

                        } else {
                            String value = xmlDescriptor.getSchemaReference().getSchemaContext();
                            typeAttr.setValue(value);
                        }
                    }
                }
                marshal(object, nodeRecord, session, xmlDescriptor, isXMLRoot);
                return;
            }

            //If preserving document, may return the cached doc. Need to
            //Copy contents of the cached doc to the supplied node.
            Node doc = null;
            if(isXMLRoot && session == null) {
                doc = (Node)((XMLRoot)object).getObject();
            } else {
                doc = objectToXMLNode(object, node, session, xmlDescriptor, isXMLRoot);
            }
            DOMResult result = new DOMResult(node);
            if (isXMLRoot) {
                String oldEncoding = transformer.getEncoding();
                String oldVersion = transformer.getVersion();
                if (((XMLRoot) object).getEncoding() != null) {
                    transformer.setEncoding(((XMLRoot) object).getEncoding());
                }
                if (((XMLRoot) object).getXMLVersion() != null) {
                    transformer.setVersion(((XMLRoot) object).getXMLVersion());
                }
                transformer.transform(doc, result);
                transformer.setEncoding(oldEncoding);
                transformer.setVersion(oldVersion);
            } else {
                transformer.transform(doc, result);
            }
        } catch (Exception exception) {
            if (exception instanceof XMLMarshalException) {
                throw (XMLMarshalException) exception;
            } else {
                throw XMLMarshalException.marshalException(exception);
            }
        }
    }

    /**
     * Convert the given object to XML and update the given marshal record with
     * that XML Document.
     * @param object the object to marshal
     * @param marshalRecord the marshalRecord to marshal the object to
     */
    public void marshal(Object object, MarshalRecord marshalRecord) {
        boolean isXMLRoot = (object instanceof XMLRoot);
       
        AbstractSession session = null;
        XMLDescriptor xmlDescriptor = null;
        if(isXMLRoot){
          try{
              session = xmlContext.getSession(((XMLRoot)object).getObject());
              if(session != null){
                  xmlDescriptor = getDescriptor(((XMLRoot)object).getObject(), session);
              }
          }catch (XMLMarshalException marshalException) {
                if (!isSimpleXMLRoot((XMLRoot) object)) {
                  throw marshalException;   
                }               
            }
        }else{
          session = xmlContext.getSession(object);
          xmlDescriptor = getDescriptor(object, session);
        }
       
        marshal(object, marshalRecord, session, xmlDescriptor, isXMLRoot);
    }
   
    /**
     * Convert the given object to XML and update the given marshal record with
     * that XML Document.
     * @param object the object to marshal
     * @param marshalRecord the marshalRecord to marshal the object to
     */
    protected void marshal(Object object, AbstractSession session, MarshalRecord marshalRecord) {
        boolean isXMLRoot = (object instanceof XMLRoot);
        marshal(object, marshalRecord, session, getDescriptor(object, isXMLRoot), isXMLRoot);
    }

    /**
     * Convert the given object to XML and update the given marshal record with
     * that XML Document.
     * @param object the object to marshal
     * @param marshalRecord the marshalRecord to marshal the object to
     * @param descriptor the XMLDescriptor for the object being marshalled
     */
    private void marshal(Object object, MarshalRecord marshalRecord, AbstractSession session, XMLDescriptor descriptor, boolean isXMLRoot) {
        if(null != schema) {
            marshalRecord = new ValidatingMarshalRecord(marshalRecord, this);
        }
        if (getAttachmentMarshaller() != null) {
            marshalRecord.setXOPPackage(getAttachmentMarshaller().isXOPPackage());
        }

        addDescriptorNamespacesToXMLRecord(descriptor, marshalRecord);
        NamespaceResolver nr = marshalRecord.getNamespaceResolver();
        XMLRoot root = null;
        if(isXMLRoot) {
            root = (XMLRoot)object;
        }
        marshalRecord.beforeContainmentMarshal(object);
        if (!isFragment()) {
            String encoding = getEncoding();
            String version = DEFAULT_XML_VERSION;
            if (!isXMLRoot) {
                marshalRecord.setLeafElementType(descriptor.getDefaultRootElementType());
            } else {
                if (root.getEncoding() != null) {
                    encoding = root.getEncoding();
                }
                if (root.getXMLVersion() != null) {
                    version = root.getXMLVersion();
                }
            }
            marshalRecord.startDocument(encoding, version);
        }
        if(isXMLRoot) {
            if(root.getObject() instanceof Node) {
                marshalRecord.node((Node)root.getObject(), new NamespaceResolver());
                marshalRecord.endDocument();
                return;
            }
        }
        XPathFragment rootFragment = buildRootFragment(object, descriptor, isXMLRoot, marshalRecord);
       
        String schemaLocation = getSchemaLocation();
        String noNsSchemaLocation = getNoNamespaceSchemaLocation();
        boolean isNil = false;
        if (isXMLRoot) {
            object = root.getObject();
            if (root.getSchemaLocation() != null) {
                schemaLocation = root.getSchemaLocation();
            }
            if (root.getNoNamespaceSchemaLocation() != null) {
                noNsSchemaLocation = root.getNoNamespaceSchemaLocation();
            }
            marshalRecord.setLeafElementType(root.getSchemaType());
            isNil = root.isNil();
        }
          
        String xsiPrefix = null;
        if ((null != getSchemaLocation()) || (null != getNoNamespaceSchemaLocation()) || (isNil)) {
            xsiPrefix = nr.resolveNamespaceURI(XMLConstants.SCHEMA_INSTANCE_URL);
            if (null == xsiPrefix) {
                xsiPrefix = XMLConstants.SCHEMA_INSTANCE_PREFIX;
                nr.put(XMLConstants.SCHEMA_INSTANCE_PREFIX, XMLConstants.SCHEMA_INSTANCE_URL);
            }
        }       

        TreeObjectBuilder treeObjectBuilder = null;
        if (descriptor != null) {
          treeObjectBuilder = (TreeObjectBuilder) descriptor.getObjectBuilder();    
        }
        if(session == null){
          session = (AbstractSession) xmlContext.getSession(0);
        }
        marshalRecord.setSession(session);
       
        if (null != rootFragment) {
            marshalRecord.startPrefixMappings(nr);
            if (!isXMLRoot && descriptor.getNamespaceResolver() == null && rootFragment.hasNamespace()) {
                // throw an exception if the name has a : in it but the namespaceresolver is null
                throw XMLMarshalException.namespaceResolverNotSpecified(rootFragment.getShortName());
            }
           
            marshalRecord.openStartElement(rootFragment, nr);
           
            if (null != schemaLocation) {
                marshalRecord.attribute(XMLConstants.SCHEMA_INSTANCE_URL, XMLConstants.SCHEMA_LOCATION, xsiPrefix + XMLConstants.COLON + XMLConstants.SCHEMA_LOCATION, schemaLocation);
            }
            if (null != noNsSchemaLocation) {
                marshalRecord.attribute(XMLConstants.SCHEMA_INSTANCE_URL, XMLConstants.NO_NS_SCHEMA_LOCATION, xsiPrefix + XMLConstants.COLON + XMLConstants.NO_NS_SCHEMA_LOCATION, noNsSchemaLocation);
            }
            if (isNil) {
                marshalRecord.attribute(XMLConstants.SCHEMA_INSTANCE_URL, XMLConstants.SCHEMA_NIL_ATTRIBUTE, xsiPrefix + XMLConstants.COLON + XMLConstants.SCHEMA_NIL_ATTRIBUTE, "true");
            }

            marshalRecord.namespaceDeclarations(nr);
           
            if (descriptor != null && !isNil) {                          
              treeObjectBuilder.addXsiTypeAndClassIndicatorIfRequired(marshalRecord, descriptor, null, descriptor.getDefaultRootElementField(), root, object, isXMLRoot, true);
                treeObjectBuilder.marshalAttributes(marshalRecord, object, session);
            }
           
            marshalRecord.closeStartElement();
        }
        if (treeObjectBuilder != null && !isNil) {
            treeObjectBuilder.buildRow(marshalRecord, object, session, this, rootFragment, WriteType.UNDEFINED);
        } else if (isXMLRoot) {
            //if(null == object) {
                //marshalRecord.attribute(XMLConstants.XMLNS_URL, XMLConstants.SCHEMA_INSTANCE_PREFIX, XMLConstants.XMLNS + XMLConstants.COLON + XMLConstants.SCHEMA_INSTANCE_PREFIX, XMLConstants.SCHEMA_INSTANCE_URL);
                //marshalRecord.attribute(XMLConstants.SCHEMA_INSTANCE_URL, XMLConstants.SCHEMA_NIL_ATTRIBUTE, XMLConstants.SCHEMA_INSTANCE_PREFIX + XMLConstants.COLON + XMLConstants.SCHEMA_NIL_ATTRIBUTE, "true");
            if(object != null && !isNil) {
               if(root.getDeclaredType() != null && root.getObject() != null && root.getDeclaredType() != root.getObject().getClass()) {
                   
                  QName type = (QName)XMLConversionManager.getDefaultJavaTypes().get(object.getClass());
                      if(type != null) {
                        xsiPrefix = nr.resolveNamespaceURI(XMLConstants.SCHEMA_INSTANCE_URL);
                          if (null == xsiPrefix) {
                              xsiPrefix = XMLConstants.SCHEMA_INSTANCE_PREFIX;
                            marshalRecord.attribute(XMLConstants.XMLNS_URL, xsiPrefix, XMLConstants.XMLNS + ':' + xsiPrefix, XMLConstants.SCHEMA_INSTANCE_URL);
                          }
                       
                          marshalRecord.attribute(XMLConstants.XMLNS_URL, XMLConstants.SCHEMA_PREFIX, XMLConstants.XMLNS + ':' + XMLConstants.SCHEMA_PREFIX, XMLConstants.SCHEMA_URL);
                          marshalRecord.attribute(XMLConstants.SCHEMA_INSTANCE_URL, XMLConstants.SCHEMA_TYPE_ATTRIBUTE, xsiPrefix + ":" + XMLConstants.SCHEMA_TYPE_ATTRIBUTE, "xsd:" + type.getLocalPart());
                      }
               }
             
                String value = (String) XMLConversionManager.getDefaultXMLManager().convertObject(object, String.class, root.getSchemaType());
                marshalRecord.characters(value);
            }
        }

        if (null != rootFragment) {
            marshalRecord.endElement(rootFragment, nr);
            marshalRecord.endPrefixMappings(nr);
        }
        if (!isFragment()) {
            marshalRecord.endDocument();
        }
        marshalRecord.afterContainmentMarshal(null, object);
    }

    private XPathFragment buildRootFragment(Object object, XMLDescriptor descriptor, boolean isXMLRoot, MarshalRecord marshalRecord) {
        XPathFragment rootFragment = null;
        if (isXMLRoot) {
            rootFragment = ((XMLRoot) object).getRootFragment();
            String xmlRootUri = ((XMLRoot) object).getNamespaceURI();
            String xmlRootLocalName = ((XMLRoot) object).getLocalName();
            if (xmlRootUri != null) {
                if (descriptor != null) {
                    String xmlRootPrefix = marshalRecord.getNamespaceResolver().resolveNamespaceURI(xmlRootUri);
                    if (xmlRootPrefix == null && !(xmlRootUri.equals(marshalRecord.getNamespaceResolver().getDefaultNamespaceURI()))) {
                        xmlRootPrefix = marshalRecord.getNamespaceResolver().generatePrefix();
                        marshalRecord.getNamespaceResolver().put(xmlRootPrefix, xmlRootUri);
                    }
                    if(xmlRootPrefix == null) {
                        rootFragment.setXPath(xmlRootLocalName);
                    } else {
                        rootFragment.setXPath(xmlRootPrefix + XMLConstants.COLON + xmlRootLocalName);
                    }
                } else {
                    String xmlRootPrefix = "ns0";
                    marshalRecord.getNamespaceResolver().put(xmlRootPrefix, xmlRootUri);
                    rootFragment.setXPath(xmlRootPrefix + XMLConstants.COLON + xmlRootLocalName);
                }
            }
        } else {
            XMLField defaultRootField = descriptor.getDefaultRootElementField();
            if(defaultRootField != null){             
              rootFragment = defaultRootField.getXPathFragment();             
            }
        }
        return rootFragment;
    }
   
    private boolean isSimpleXMLRoot(XMLRoot xmlRoot) {
        Class xmlRootObjectClass = xmlRoot.getObject().getClass();

        if (XMLConversionManager.getDefaultJavaTypes().get(xmlRootObjectClass) != null || ClassConstants.List_Class.isAssignableFrom(xmlRootObjectClass) || ClassConstants.XML_GREGORIAN_CALENDAR.isAssignableFrom(xmlRootObjectClass) || ClassConstants.DURATION.isAssignableFrom(xmlRootObjectClass)) {
            return true;
        } else if(xmlRoot.getObject() instanceof org.w3c.dom.Node) {
            return true;
        }
        return false;
    }

    /**
    * PUBLIC:
    * Convert the given object to an XML Document
    * @param object the object to marshal
    * @return the document which the specified object has been marshalled to
    * @throws XMLMarshalException if an error occurred during marshalling
    */
    public Document objectToXML(Object object) throws XMLMarshalException {
        boolean isXMLRoot = (object instanceof XMLRoot);
        XMLDescriptor xmlDescriptor = getDescriptor(object, isXMLRoot);
        return objectToXML(object, xmlDescriptor, isXMLRoot);
    }

    /**
    * INTERNAL:
    * Convert the given object to an XML Document
    * @param object the object to marshal
    * @return the document which the specified object has been marshalled to
    * @param descriptor the XMLDescriptor for the object being marshalled
    * @throws XMLMarshalException if an error occurred during marshalling
    */
    protected Document objectToXML(Object object, XMLDescriptor descriptor, boolean isXMLRoot) throws XMLMarshalException {
        AbstractSession session = xmlContext.getSession(descriptor);
        DocumentPreservationPolicy docPresPolicy = xmlContext.getDocumentPreservationPolicy(session);
        if (docPresPolicy != null && docPresPolicy.shouldPreserveDocument()) {
            XMLRecord xmlRow = null;
            if (!isXMLRoot) {
                xmlRow = (XMLRecord) ((XMLObjectBuilder) descriptor.getObjectBuilder()).createRecordFor(object, xmlContext.getDocumentPreservationPolicy(session));
                xmlRow.setMarshaller(this);
                if (getAttachmentMarshaller() != null) {
                    xmlRow.setXOPPackage(getAttachmentMarshaller().isXOPPackage());
                }
                addDescriptorNamespacesToXMLRecord(descriptor, xmlRow);
            }
            return objectToXML(object, descriptor, xmlRow, isXMLRoot, docPresPolicy);
        }
        MarshalRecord marshalRecord = new NodeRecord();
        marshalRecord.setMarshaller(this);
        marshal(object, marshalRecord, session, descriptor, isXMLRoot);
        return marshalRecord.getDocument();
    }

    /**
     * INTERNAL:
     * Like ObjectToXML but is may also return a document fragment instead of a document in the
     * case of a non-root object.
     */
    protected Node objectToXMLNode(Object object, AbstractSession session, XMLDescriptor descriptor, boolean isXMLRoot) throws XMLMarshalException {
        return objectToXMLNode(object, null, session, descriptor, isXMLRoot);
    }

    protected Node objectToXMLNode(Object object, Node rootNode, AbstractSession session,XMLDescriptor descriptor, boolean isXMLRoot) throws XMLMarshalException {
        DocumentPreservationPolicy docPresPolicy = xmlContext.getDocumentPreservationPolicy(session);
        if (docPresPolicy != null && docPresPolicy.shouldPreserveDocument()) {
            XMLRecord xmlRow = null;
            if (!isXMLRoot) {
                xmlRow = (XMLRecord) ((XMLObjectBuilder) descriptor.getObjectBuilder()).createRecordFor(object, xmlContext.getDocumentPreservationPolicy(session));
                xmlRow.setMarshaller(this);
                if (getAttachmentMarshaller() != null) {
                    xmlRow.setXOPPackage(getAttachmentMarshaller().isXOPPackage());
                }
                if (xmlRow.getDOM().getNodeType() == Node.ELEMENT_NODE) {
                    addDescriptorNamespacesToXMLRecord(descriptor, xmlRow);
                }
            }
            Document doc = objectToXML(object, rootNode, descriptor, xmlRow, isXMLRoot, docPresPolicy);
            if ((xmlRow != null) && (xmlRow.getDOM().getNodeType() == Node.DOCUMENT_FRAGMENT_NODE)) {
                return xmlRow.getDOM();
            } else {
                return doc;
            }
        }
        MarshalRecord marshalRecord = new NodeRecord();
        marshalRecord.setMarshaller(this);
        marshalRecord.getNamespaceResolver().setDOM(rootNode);
        marshal(object, marshalRecord, session, descriptor, isXMLRoot);
        return marshalRecord.getDocument();
    }

    private void addDescriptorNamespacesToXMLRecord(XMLDescriptor xmlDescriptor, XMLRecord record) {
        if (null == xmlDescriptor) {
            return;
        }
        copyNamespaces(xmlDescriptor.getNamespaceResolver(), record.getNamespaceResolver());
    }
   
    private void copyNamespaces(NamespaceResolver source, NamespaceResolver target) {
        if (null != source && null != target) {           
            target.getPrefixesToNamespaces().putAll(source.getPrefixesToNamespaces());           
            target.setDefaultNamespaceURI(source.getDefaultNamespaceURI());
        }
    }
   
    /**
    * PUBLIC:
    * Convert the given object to descendants of the parent element
    * @param object the object to marshal
    * @param parent the node to marshal the object to
    * @return the document which the specified object has been marshalled to
    * @throws XMLMarshalException if an error occurred during marshalling
    * @deprecated
    */
    public Document objectToXML(Object object, Node parent) throws XMLMarshalException {
        return objectToXML(object, parent, null);
    }

    public Document objectToXML(Object object, Node parent, DocumentPreservationPolicy docPresPolicy) {
        boolean isXMLRoot = (object instanceof XMLRoot);
       
        AbstractSession session = null;
        XMLDescriptor descriptor = null;
        if(isXMLRoot){
          try{
              session = xmlContext.getSession(((XMLRoot)object).getObject());
              if(session != null){
                  descriptor = getDescriptor(((XMLRoot)object).getObject(), session);
              }
          }catch (XMLMarshalException marshalException) {
                if (!isSimpleXMLRoot((XMLRoot) object)) {
                  throw marshalException;   
                }               
            }
        }else{
          session = xmlContext.getSession(object);
          descriptor = getDescriptor(object, session);
        }
       
       

        String localRootName = descriptor.getDefaultRootElement();
        if (null == localRootName) {
            throw XMLMarshalException.defaultRootElementNotSpecified(descriptor);
        }

        if(docPresPolicy == null) {
            docPresPolicy = xmlContext.getDocumentPreservationPolicy(session);
        }
        if (docPresPolicy != null && docPresPolicy.shouldPreserveDocument()) {
            XMLRecord xmlRow = (XMLRecord) ((XMLObjectBuilder) descriptor.getObjectBuilder()).createRecord(localRootName, parent, session);
            xmlRow.setMarshaller(this);
            if (getAttachmentMarshaller() != null) {
                xmlRow.setXOPPackage(getAttachmentMarshaller().isXOPPackage());
            }
            return objectToXML(object, descriptor, xmlRow, isXMLRoot, docPresPolicy);
        }
        MarshalRecord marshalRecord = new NodeRecord(localRootName, parent);
        marshalRecord.setMarshaller(this);
        marshal(object, marshalRecord, session, descriptor, isXMLRoot);
        return marshalRecord.getDocument();

    }

    /**
    * INTERNAL:
    * Convert the given object to an XML Document
    */
    public Document objectToXML(Object object, XMLDescriptor descriptor, XMLRecord xmlRow, boolean isXMLRoot, DocumentPreservationPolicy docPresPolicy) {
        return objectToXML(object, null, descriptor, xmlRow, isXMLRoot, docPresPolicy);
    }

    public Document objectToXML(Object object, Node rootNode, XMLDescriptor descriptor, XMLRecord xmlRow, boolean isXMLRoot, DocumentPreservationPolicy docPresPolicy) {
        if(null != rootNode) {
            int rootNodeType = rootNode.getNodeType();
            if(rootNodeType != Node.DOCUMENT_NODE && rootNodeType != Node.ELEMENT_NODE && rootNodeType != Node.DOCUMENT_FRAGMENT_NODE ) {
                throw XMLMarshalException.marshalException(null);
            }
        }
        Document document = null;
        NamespaceResolver resolver = new NamespaceResolver();
        resolver.setDOM(rootNode);
        this.copyNamespaces(descriptor.getNamespaceResolver(), resolver);
        boolean shouldCallSetAttributeNS = false;
        boolean isRootDocumentFragment = false;
        AbstractSession session = xmlContext.getSession(descriptor);
        if (xmlRow != null) {
            isRootDocumentFragment = (xmlRow.getDOM().getNodeType() == Node.DOCUMENT_FRAGMENT_NODE);
        }
        Object originalObject = object;
        if (isXMLRoot) {
            String xmlRootUri = ((XMLRoot) object).getNamespaceURI();
            String xmlRootPrefix = null;
            if (xmlRow == null) {
                String recordName = ((XMLRoot) object).getLocalName();
                if (xmlRootUri != null) {
                    xmlRootPrefix = resolver.resolveNamespaceURI(xmlRootUri);
                    if (xmlRootPrefix == null && !(xmlRootUri.equals(resolver.getDefaultNamespaceURI()))) {
                        xmlRootPrefix = resolver.generatePrefix();
                        resolver.put(xmlRootPrefix, xmlRootUri);
                        shouldCallSetAttributeNS = true;
                    }
                    if(xmlRootPrefix != null) {
                        recordName = xmlRootPrefix + XMLConstants.COLON + recordName;
                    }
                }
                xmlRow = (XMLRecord) ((XMLObjectBuilder) descriptor.getObjectBuilder()).createRecordFor(((XMLRoot) object).getObject(), docPresPolicy, recordName, xmlRootUri);
                xmlRow.setMarshaller(this);
                if (getAttachmentMarshaller() != null) {
                    xmlRow.setXOPPackage(getAttachmentMarshaller().isXOPPackage());
                }
                if (!isRootDocumentFragment) {
                    if (shouldCallSetAttributeNS) {
                        if (xmlRootPrefix != null) {
                            ((Element) xmlRow.getDOM()).setAttributeNS(XMLConstants.XMLNS_URL, XMLConstants.XMLNS + XMLConstants.COLON + xmlRootPrefix, xmlRootUri);
                        }
                        shouldCallSetAttributeNS = false;
                    }
                }
            }

            copyNamespaces(resolver, xmlRow.getNamespaceResolver());
            document = xmlRow.getDocument();
            Element docElement = document.getDocumentElement();
            object = ((XMLRoot) object).getObject();
        }

        XMLObjectBuilder bldr = (XMLObjectBuilder) descriptor.getObjectBuilder();

        AbstractSession objectSession = xmlContext.getSession(object);
        xmlRow.setSession(objectSession);
        bldr.addXsiTypeAndClassIndicatorIfRequired(xmlRow, descriptor, null, null, originalObject, object, isXMLRoot, true);
        xmlRow = (XMLRecord) bldr.buildRow(xmlRow, object,  objectSession, isXMLRoot);
               
        xmlRow.setMarshaller(this);
        if (shouldCallSetAttributeNS && !isRootDocumentFragment) {
            ((Element) xmlRow.getDOM()).setAttributeNS(XMLConstants.XMLNS_URL, XMLConstants.XMLNS + XMLConstants.COLON + XMLConstants.SCHEMA_INSTANCE_PREFIX, XMLConstants.SCHEMA_INSTANCE_URL);
        }
        document = xmlRow.getDocument();

        addSchemaLocations(document, session);
        return document;
    }

    private void addSchemaLocations(Document document, AbstractSession session) {
        Element docElement = document.getDocumentElement();

        NamespaceResolver resolver = new NamespaceResolver();
        resolver.put(XMLConstants.XMLNS, XMLConstants.XMLNS_URL);
        resolver.put(XMLConstants.SCHEMA_INSTANCE_PREFIX, XMLConstants.SCHEMA_INSTANCE_URL);

        if ((getSchemaLocation() != null) || (getNoNamespaceSchemaLocation() != null)) {
            XMLField field = new XMLField("@xmlns:xsi");
            field.setNamespaceResolver(resolver);
            XPathEngine.getInstance().create(field, docElement, XMLConstants.SCHEMA_INSTANCE_URL, session);
        }
        if (getSchemaLocation() != null) {
            XMLField field = new XMLField("@xsi:" + XMLConstants.SCHEMA_LOCATION);
            field.setNamespaceResolver(resolver);
            XPathEngine.getInstance().create(field, docElement, getSchemaLocation(), session);
        }
        if (getNoNamespaceSchemaLocation() != null) {
            XMLField field = new XMLField("@xsi:" + XMLConstants.NO_NS_SCHEMA_LOCATION);
            field.setNamespaceResolver(resolver);
            XPathEngine.getInstance().create(field, docElement, getNoNamespaceSchemaLocation(), session);
        }
    }

    /**
    * INTERNAL:
    * Return the descriptor for the root object.
    */
    protected XMLDescriptor getDescriptor(Object object) throws XMLMarshalException {
        XMLDescriptor descriptor = (XMLDescriptor) xmlContext.getSession(object).getDescriptor(object);
        if (descriptor == null) {
            throw XMLMarshalException.descriptorNotFoundInProject(object.getClass().getName());
        }

        return descriptor;
    }

    /**
     * INTERNAL:
     * Return the descriptor for the root object.
     */
     protected XMLDescriptor getDescriptor(Object object, AbstractSession session) throws XMLMarshalException {
         XMLDescriptor descriptor = (XMLDescriptor) session.getDescriptor(object);
         if (descriptor == null) {
             throw XMLMarshalException.descriptorNotFoundInProject(object.getClass().getName());
         }

         return descriptor;
     }
    
     /**
      * INTERNAL:
      * Return the descriptor for the root object.
      */
      private XMLDescriptor getDescriptor(Class clazz, AbstractSession session) throws XMLMarshalException {
          XMLDescriptor descriptor = (XMLDescriptor) session.getDescriptor(clazz);
          if (descriptor == null) {
              throw XMLMarshalException.descriptorNotFoundInProject(clazz.getName());
          }

          return descriptor;
      }
   
    protected XMLDescriptor getDescriptor(Object object, boolean isXMLRoot) {
        if (isXMLRoot) {
            return getDescriptor((XMLRoot) object);
        } else {
            return getDescriptor(object);
        }
    }
   
    protected XMLDescriptor getDescriptor(Object object, AbstractSession session, boolean isXMLRoot) {
        if (isXMLRoot) {
            return getDescriptor((XMLRoot) object, session);
        } else {
            return getDescriptor(object, session);
        }
    }
   
    protected XMLDescriptor getDescriptor(XMLRoot object) throws XMLMarshalException {
        XMLDescriptor descriptor = null;

        try {
            AbstractSession session = xmlContext.getSession(object.getObject());
            if(null == session) {
                return null;
            }
            descriptor = (XMLDescriptor) session.getDescriptor(object.getObject());
        } catch (XMLMarshalException marshalException) {
            if ((descriptor == null) && isSimpleXMLRoot(object)) {
                return null;
            }
            throw marshalException;
        }

        if (descriptor == null) {
            throw XMLMarshalException.descriptorNotFoundInProject(object.getClass().getName());
        }

        return descriptor;
    }
   
    protected XMLDescriptor getDescriptor(XMLRoot object, AbstractSession session) throws XMLMarshalException {
        XMLDescriptor descriptor = null;

        try {
            if(null == session) {
                return null;
            }
            descriptor = (XMLDescriptor) session.getDescriptor(object.getObject());
        } catch (XMLMarshalException marshalException) {
            if ((descriptor == null) && isSimpleXMLRoot(object)) {
                return null;
            }
            throw marshalException;
        }

        if (descriptor == null) {
            throw XMLMarshalException.descriptorNotFoundInProject(object.getClass().getName());
        }

        return descriptor;
    }

    /**
    * PUBLIC:
    * Set if this should marshal to a fragment.  If true an XML header string is not written out.
    * @param fragment if this should marshal to a fragment or not
    */
    public void setFragment(boolean fragment) {
        transformer.setFragment(fragment);
    }

    /**
    * PUBLIC:
    * Returns if this should marshal to a fragment.  If true an XML header string is not written out.
    * @return if this should marshal to a fragment or not
    */
    public boolean isFragment() {
        return transformer.isFragment();
    }

    public void setAttachmentMarshaller(XMLAttachmentMarshaller atm) {
        this.attachmentMarshaller = atm;
    }

    public XMLAttachmentMarshaller getAttachmentMarshaller() {
        return this.attachmentMarshaller;
    }

    /**
     * INTERNAL
     * @return the transformer instance for this marshaller
     */
    public XMLTransformer getTransformer() {
        return transformer;
    }

    public Schema getSchema() {
        return schema;
    }

    public void setSchema(Schema schema) {
        this.schema = schema;
    }

    @Override
    public XMLMarshaller clone() {
        XMLMarshaller clone = new XMLMarshaller(xmlContext);
        clone.setAttachmentMarshaller(attachmentMarshaller);
        clone.setEncoding(getEncoding());
        clone.setFormattedOutput(isFormattedOutput());
        clone.setFragment(isFragment());
        clone.setMarshalListener(marshalListener);
        clone.setNoNamespaceSchemaLocation(noNamespaceSchemaLocation);
        for(Entry entry : marshalProperties.entrySet()) {
            clone.getProperties().put(entry.getKey(), entry.getValue());
        }
        if(null != schema) {
            clone.setSchema(schema);
        }
        clone.setSchemaLocation(schemaLocation);
        return clone;
    }

}
TOP

Related Classes of org.eclipse.persistence.oxm.XMLMarshaller

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.