Place objectToElement()

in core/metamodel/src/main/java/org/apache/causeway/core/metamodel/util/snapshot/XmlSnapshot.java [625:815]


    Place objectToElement(final ManagedObject adapter) {

        if (log.isDebugEnabled()) {
            log.debug("objectToElement({})", log("object", adapter));
        }

        final ObjectSpecification spec = adapter.objSpec();

        if (log.isDebugEnabled()) {
            log.debug("objectToElement(NO): create element and causeway:title");
        }
        final Element element = schema.createElement(getXmlDocument(), spec.getShortIdentifier(),
                spec.getFullIdentifier(), spec.getSingularName());
        causewayMetaModel.appendCausewayTitle(element, adapter.getTitle());

        if (log.isDebugEnabled()) {
            log.debug("objectToElement(NO): create XS element for Causeway class");
        }
        final Element xsElement = schema.createXsElementForNofClass(getXsdDocument(), element, topLevelElementWritten,
                FacetUtil.getFacetsByType(spec));

        // hack: every element in the XSD schema apart from first needs minimum
        // cardinality setting.
        topLevelElementWritten = true;

        final Place place = new Place(adapter, element);

        causewayMetaModel.setAttributesForClass(element, oidAsString(adapter).toString());

        final List<ObjectAssociation> fields = spec.streamAssociations(MixedIn.INCLUDED)
                .collect(Collectors.toList());
        if (log.isDebugEnabled()) {
            log.debug("objectToElement(NO): processing fields");
        }
        eachField: for (int i = 0; i < fields.size(); i++) {
            final ObjectAssociation field = fields.get(i);
            final String fieldName = field.getId();

            if (log.isDebugEnabled()) {
                log.debug("objectToElement(NO): {}", log("field", fieldName));
            }

            // Skip field if we have seen the name already
            for (int j = 0; j < i; j++) {
                if (Objects.equals(fieldName, fields.get(i).getFriendlyName(adapter))) {
                    log.debug("objectToElement(NO): {} SKIPPED", log("field", fieldName));
                    continue eachField;
                }
            }

            Element xmlFieldElement = getXmlDocument().createElementNS(
                    schema.getUri(), // scoped by namespace of class
                    /* of containing object*/ schema.getPrefix() + ":" + fieldName);

            Element xsdFieldElement = null;

            if (field.getElementType().isValue()) {
                if (log.isDebugEnabled()) {
                    log.debug("objectToElement(NO): {} is value", log("field", fieldName));
                }

                final ObjectSpecification fieldSpec = field.getElementType();
                // skip fields of type XmlValue
                if (fieldSpec == null) {
                    continue eachField;
                }
                if (fieldSpec.getFullIdentifier() != null && fieldSpec.getFullIdentifier().endsWith("XmlValue")) {
                    continue eachField;
                }

                final OneToOneAssociation valueAssociation = ((OneToOneAssociation) field);
                if(valueAssociation.isExcludedFromSnapshots()) {
                    continue eachField;
                }
                final Element xmlValueElement = xmlFieldElement; // more meaningful locally scoped name

                ManagedObject value;
                try {
                    value = valueAssociation.get(adapter, InteractionInitiatedBy.PASS_THROUGH);

                    var valueSpec = value.objSpec();

                    // XML
                    causewayMetaModel.setAttributesForValue(xmlValueElement, valueSpec.getShortIdentifier());

                    // value as JSON
                    var valueStr = fieldSpec.valueFacetElseFail()
                            .enstring(Format.JSON, _Casts.uncheckedCast(value.getPojo()));

                    if (_Strings.isNotEmpty(valueStr)) {
                        xmlValueElement.appendChild(getXmlDocument().createTextNode(valueStr));
                    } else {
                        causewayMetaModel.setIsEmptyAttribute(xmlValueElement, true);
                    }

                } catch (final Exception ex) {
                    log.warn("objectToElement(NO): {}: getField() threw exception - skipping XML generation",
                            log("field", fieldName));
                }

                // XSD
                xsdFieldElement = schema.createXsElementForNofValue(xsElement, xmlValueElement,
                        FacetUtil.getFacetsByType(valueAssociation));

            } else if (field instanceof OneToOneAssociation) {

                if (log.isDebugEnabled()) {
                    log.debug("objectToElement(NO): {} is OneToOneAssociation", log("field", fieldName));
                }

                final OneToOneAssociation oneToOneAssociation = ((OneToOneAssociation) field);
                final String fullyQualifiedClassName = spec.getFullIdentifier();
                final Element xmlReferenceElement = xmlFieldElement; // more meaningful locally scoped name

                ManagedObject referencedObjectAdapter;

                try {
                    referencedObjectAdapter = oneToOneAssociation.get(adapter, InteractionInitiatedBy.PASS_THROUGH);

                    // XML
                    causewayMetaModel.setAttributesForReference(xmlReferenceElement, schema.getPrefix(),
                            fullyQualifiedClassName);

                    if (referencedObjectAdapter != null) {
                        causewayMetaModel.appendCausewayTitle(xmlReferenceElement, referencedObjectAdapter.getTitle());
                    } else {
                        causewayMetaModel.setIsEmptyAttribute(xmlReferenceElement, true);
                    }

                } catch (final Exception ex) {
                    log.warn("objectToElement(NO): {}: getAssociation() threw exception - skipping XML generation",
                            log("field", fieldName));
                }

                // XSD
                xsdFieldElement = schema.createXsElementForNofReference(xsElement, xmlReferenceElement,
                        oneToOneAssociation.getElementType().getFullIdentifier(),
                        FacetUtil.getFacetsByType(oneToOneAssociation));

            } else if (field instanceof OneToManyAssociation) {

                if (log.isDebugEnabled()) {
                    log.debug("objectToElement(NO): {} is OneToManyAssociation", log("field", fieldName));
                }

                final OneToManyAssociation oneToManyAssociation = (OneToManyAssociation) field;
                final Element xmlCollectionElement = xmlFieldElement; // more meaningful locally scoped name

                ManagedObject collection;
                try {
                    collection = oneToManyAssociation.get(adapter, InteractionInitiatedBy.PASS_THROUGH);
                    final ObjectSpecification referencedTypeNos = oneToManyAssociation.getElementType();
                    final String fullyQualifiedClassName = referencedTypeNos.getFullIdentifier();

                    // XML
                    causewayMetaModel.setCausewayCollection(xmlCollectionElement, schema.getPrefix(), fullyQualifiedClassName,
                            collection);
                } catch (final Exception ex) {
                    log.warn("objectToElement(NO): {}: get(obj) threw exception - skipping XML generation",
                            log("field", fieldName));
                }

                // XSD
                xsdFieldElement = schema.createXsElementForNofCollection(xsElement, xmlCollectionElement,
                        oneToManyAssociation.getElementType().getFullIdentifier(),
                        FacetUtil.getFacetsByType(oneToManyAssociation));

            } else {
                if (log.isInfoEnabled()) {
                    log.info("objectToElement(NO): {} is unknown type; ignored", log("field", fieldName));
                }
                continue;
            }

            Place.setXsdElement(xmlFieldElement, xsdFieldElement);

            // XML
            if (log.isDebugEnabled()) {
                log.debug("objectToElement(NO): invoking mergeTree for field");
            }
            xmlFieldElement = mergeTree(element, xmlFieldElement);

            // XSD
            if (log.isDebugEnabled()) {
                log.debug("objectToElement(NO): adding XS element for field to schema");
            }
            schema.addFieldXsElement(xsElement, xsdFieldElement);
        }

        return place;
    }