/**
  * INTERNAL: When using the SAX or DOM Platform, this method is responsible for marshalling null
  * values for the XML Direct Mapping.
  *
  * @param xPathFragment
  * @param marshalRecord
  * @param object
  * @param session
  * @param namespaceResolver
  * @return true if this method caused any nodes to be marshaled, else false.
  */
 public boolean directMarshal(
     XPathFragment xPathFragment,
     MarshalRecord marshalRecord, //
     Object object,
     CoreSession session,
     NamespaceResolver namespaceResolver) {
   // Handle attributes - XSI_NIL, ABSENT_NODE have the same behavior
   if (xPathFragment.isAttribute()) {
     // Write out an empty attribute
     if (marshalNullRepresentation == XMLNullRepresentationType.EMPTY_NODE) {
       marshalRecord.emptyAttribute(xPathFragment, namespaceResolver);
       return true;
     } else {
       // XSI_NIL attributes are invalid - and are ignored
       // ABSENT_NODE - Write out nothing
       return false;
     }
   } else {
     // Nillable: write out xsi:nil="true" attribute in empty element
     if (marshalNullRepresentation == XMLNullRepresentationType.XSI_NIL) {
       marshalRecord.nilSimple(namespaceResolver);
       return true;
     } else {
       // EMPTY_NODE - Write out empty element
       if (marshalNullRepresentation == XMLNullRepresentationType.EMPTY_NODE) {
         marshalRecord.emptySimple(namespaceResolver);
         return true;
       } else {
         // ABSENT_NODE - Write out nothing
         return false;
       }
     }
   }
 }
 /**
  * INTERNAL: Private function to process or create an entry in the NamespaceResolver for the xsi
  * prefix.
  *
  * @param namespaceResolver
  * @return xsi prefix
  */
 protected String processNamespaceResolverForXSIPrefix(
     NamespaceResolver namespaceResolver, MarshalRecord marshalRecord) {
   String xsiPrefix;
   if (null == namespaceResolver) {
     // add new xsi entry into the properties map
     xsiPrefix = Constants.SCHEMA_INSTANCE_PREFIX;
     marshalRecord.namespaceDeclaration(
         xsiPrefix, javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI);
   } else {
     // find an existing xsi entry in the map
     xsiPrefix =
         namespaceResolver.resolveNamespaceURI(
             javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI);
     if (null == xsiPrefix) {
       xsiPrefix = namespaceResolver.generatePrefix(Constants.SCHEMA_INSTANCE_PREFIX);
       marshalRecord.namespaceDeclaration(
           xsiPrefix, javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI);
     }
   }
   return xsiPrefix;
 }
 /**
  * INTERNAL: When using the SAX Platform, this method is responsible for marshalling null values
  * for the XML Composite Object Mapping.
  *
  * @param xPathFragment
  * @param marshalRecord
  * @param object
  * @param session
  * @param namespaceResolver
  * @return true if this method caused any nodes to be marshaled, else false.
  */
 public boolean compositeObjectMarshal(
     XPathFragment xPathFragment,
     MarshalRecord marshalRecord, //
     Object object,
     CoreSession session,
     NamespaceResolver namespaceResolver) {
   if (marshalNullRepresentation == XMLNullRepresentationType.ABSENT_NODE) {
     return false;
   }
   // Nillable
   else if (marshalNullRepresentation == XMLNullRepresentationType.XSI_NIL) {
     marshalRecord.nilComplex(xPathFragment, namespaceResolver);
     return true;
   } else if (marshalNullRepresentation == XMLNullRepresentationType.EMPTY_NODE) {
     // Optional and Required
     // This call is really only valid when using DOM - TBD false
     // Write out empty element - we need to differentiate between
     // object=null and object=new Object() with null fields and 0-numeric primitive values
     // EMPTY_NODE - Write out empty element - Required
     marshalRecord.emptyComplex(xPathFragment, namespaceResolver);
     return true;
   }
   return false;
 }
  @Override
  public boolean marshalAttributes(
      MarshalRecord marshalRecord, Object object, CoreAbstractSession session) {
    lazyInitialize();
    boolean hasValue = false;
    NamespaceResolver namespaceResolver = ((Descriptor) descriptor).getNamespaceResolver();

    List<XPathNode> attributeChildren = rootXPathNode.getAttributeChildren();
    if (null != attributeChildren) {
      ObjectMarshalContext objectMarshalContext = ObjectMarshalContext.getInstance();
      for (XPathNode anAttributeChildren : attributeChildren) {
        hasValue =
            anAttributeChildren.marshal(
                    marshalRecord,
                    object,
                    session,
                    namespaceResolver,
                    null,
                    objectMarshalContext,
                    null)
                || hasValue;
      }
    }

    if (rootXPathNode.getAnyAttributeNode() != null) {
      hasValue =
          rootXPathNode
                  .getAnyAttributeNode()
                  .marshal(
                      marshalRecord,
                      object,
                      session,
                      namespaceResolver,
                      null,
                      ObjectMarshalContext.getInstance(),
                      null)
              || hasValue;
    }

    List<XPathNode> selfChildren = rootXPathNode.getSelfChildren();
    if (null != selfChildren) {
      for (XPathNode selfXPathNode : selfChildren) {
        NodeValue marshalNodeValue = selfXPathNode.getMarshalNodeValue();
        if (marshalNodeValue instanceof MappingNodeValue) {
          Mapping selfMapping = ((MappingNodeValue) marshalNodeValue).getMapping();
          Object value = selfMapping.getAttributeValueFromObject(object);
          Descriptor referenceDescriptor = (Descriptor) selfMapping.getReferenceDescriptor();
          Descriptor valueDescriptor;
          if (value != null
              && (referenceDescriptor == null || referenceDescriptor.hasInheritance())) {
            valueDescriptor = (Descriptor) session.getDescriptor(value.getClass());
          } else {
            valueDescriptor = referenceDescriptor;
          }
          if (null != valueDescriptor) {
            marshalRecord.addXsiTypeAndClassIndicatorIfRequired(
                valueDescriptor, referenceDescriptor, (Field) selfMapping.getField(), false);
          }
        }
        selfXPathNode.marshalSelfAttributes(
            marshalRecord, object, session, namespaceResolver, marshalRecord.getMarshaller());
      }
    }

    return hasValue;
  }
  @Override
  public XMLRecord buildRow(
      XMLRecord record,
      Object object,
      CoreAbstractSession session,
      Marshaller marshaller,
      XPathFragment rootFragment) {
    lazyInitialize();
    XPathNode textNode = rootXPathNode.getTextNode();
    List<XPathNode> nonAttributeChildren = rootXPathNode.getNonAttributeChildren();
    if (null == textNode && null == nonAttributeChildren) {
      return record;
    }

    Descriptor xmlDescriptor = (Descriptor) descriptor;
    XPathNode node = rootXPathNode;
    MarshalRecord marshalRecord = (MarshalRecord) record;
    QName schemaType = null;

    if (marshalRecord.getCycleDetectionStack().contains(object, marshaller.isEqualUsingIdenity())) {
      if (cycleRecoverableClass == null) {
        initCycleRecoverableClasses();
      }
      if (cycleRecoverableClass != null
          && cycleRecoverableClass.isAssignableFrom(object.getClass())) {
        try {
          Object jaxbMarshaller = marshaller.getProperty(Constants.JAXB_MARSHALLER);
          // Create a proxy instance of CycleRecoverable$Context, a parameter to
          // the onCycleDetected method
          Object contextProxy =
              CycleRecoverableContextProxy.getProxy(cycleRecoverableContextClass, jaxbMarshaller);
          // Invoke onCycleDetected method, passing in proxy, and reset
          // 'object' to the returned value
          Method onCycleDetectedMethod =
              object
                  .getClass()
                  .getMethod(ON_CYCLE_DETECTED, new Class[] {cycleRecoverableContextClass});
          object =
              PrivilegedAccessHelper.invokeMethod(
                  onCycleDetectedMethod, object, new Object[] {contextProxy});
        } catch (Exception e) {
          throw XMLMarshalException.marshalException(e);
        }

        // Returned object might have a different descriptor
        xmlDescriptor = (Descriptor) session.getDescriptor(object.getClass());
        if (xmlDescriptor != null) {
          node = ((ObjectBuilder) xmlDescriptor.getObjectBuilder()).getRootXPathNode();
        } else {
          node = null;
        }

        // Push new object
        marshalRecord.getCycleDetectionStack().push(object);

        // Write xsi:type if onCycleDetected returned an object of a type different than the one
        // mapped
        if (xmlDescriptor != descriptor) {
          if (xmlDescriptor == null) {
            schemaType = record.getConversionManager().schemaType(object.getClass());
          } else {
            schemaType = xmlDescriptor.getSchemaReference().getSchemaContextAsQName();
          }
          marshalRecord.writeXsiTypeAttribute(
              xmlDescriptor,
              schemaType.getNamespaceURI(),
              schemaType.getLocalPart(),
              schemaType.getPrefix(),
              false);
        }
      } else {
        // Push the duplicate object anyway, so that we can get the complete cycle string
        marshalRecord.getCycleDetectionStack().push(object);
        throw XMLMarshalException.objectCycleDetected(
            marshalRecord.getCycleDetectionStack().getCycleString());
      }
    } else {
      marshalRecord.getCycleDetectionStack().push(object);
    }

    NamespaceResolver namespaceResolver = null;
    if (xmlDescriptor != null) {
      namespaceResolver = xmlDescriptor.getNamespaceResolver();
    }
    MarshalContext marshalContext = null;
    if (xmlDescriptor != null && xmlDescriptor.isSequencedObject()) {
      SequencedObject sequencedObject = (SequencedObject) object;
      marshalContext = new SequencedMarshalContext(sequencedObject.getSettings());
    } else {
      marshalContext = ObjectMarshalContext.getInstance();
    }
    if (null == nonAttributeChildren) {
      textNode.marshal(
          (MarshalRecord) record,
          object,
          session,
          namespaceResolver,
          marshaller,
          marshalContext,
          rootFragment);
    } else {
      if (node == null) {
        // No descriptor for this object, so manually create a MappingNodeValue and marshal it
        XPathNode n = new XPathNode();
        CompositeObjectMapping m = new XMLCompositeObjectMapping();
        m.setXPath(".");
        XMLCompositeObjectMappingNodeValue nv = new XMLCompositeObjectMappingNodeValue(m);
        n.setMarshalNodeValue(nv);
        nv.marshalSingleValue(
            new XPathFragment("."),
            marshalRecord,
            null,
            object,
            session,
            namespaceResolver,
            marshalContext);
      } else {
        for (int x = 0, size = marshalContext.getNonAttributeChildrenSize(node); x < size; x++) {
          XPathNode xPathNode = (XPathNode) marshalContext.getNonAttributeChild(x, node);
          xPathNode.marshal(
              (MarshalRecord) record,
              object,
              session,
              namespaceResolver,
              marshaller,
              marshalContext.getMarshalContext(x),
              rootFragment);
        }
      }
    }
    marshalRecord.getCycleDetectionStack().pop();
    return record;
  }