private boolean includeField()

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


    private boolean includeField(final Place place, final Vector<String> fieldNames, final String annotation) {

        if (log.isDebugEnabled()) {
            log.debug("includeField(: {}{}{})", log("place", place), andlog("fieldNames", fieldNames),
                    andlog("annotation", annotation));
        }

        final ManagedObject object = place.getObject();
        final Element xmlElement = place.getXmlElement();

        // we use a copy of the path so that we can safely traverse collections
        // without side-effects
        final Vector<String> originalNames = fieldNames;
        final Vector<String> names = new Vector<>();
        for (final Enumeration<String> e = originalNames.elements(); e.hasMoreElements();) {
            names.addElement(e.nextElement());
        }

        // see if we have any fields to process
        if (names.size() == 0) {
            return true;
        }

        // take the first field name from the list, and remove
        final String fieldName = names.elementAt(0);
        names.removeElementAt(0);

        if (log.isDebugEnabled()) {
            log.debug("includeField(Pl, Vec, Str):{}{}", log("processing field", fieldName),
                    andlog("left", "" + names.size()));
        }

        // locate the field in the object's class
        final ObjectSpecification nos = object.getSpecification();
        // HACK: really want a ObjectSpecification.hasField method to
        // check first.
        val field = nos.getAssociation(fieldName).orElse(null);
        if (field == null) {
            if (log.isInfoEnabled()) {
                log.info("includeField(Pl, Vec, Str): could not locate field, skipping");
            }
            return false;
        }

        // locate the corresponding XML element
        // (the corresponding XSD element will later be attached to xmlElement
        // as its userData)
        if (log.isDebugEnabled()) {
            log.debug("includeField(Pl, Vec, Str): locating corresponding XML element");
        }
        val xmlFieldElements = elementsUnder(xmlElement, field.getId());
        if (xmlFieldElements.size() != 1) {
            if (log.isInfoEnabled()) {
                log.info("includeField(Pl, Vec, Str): could not locate {}",
                        log("field", field.getId()) + andlog("xmlFieldElements.size", "" + xmlFieldElements.size()));
            }
            return false;
        }
        final Element xmlFieldElement = xmlFieldElements.elementAt(0);

        if (names.size() == 0 && annotation != null) {
            // nothing left in the path, so we will apply the annotation now
            causewayMetaModel.setAnnotationAttribute(xmlFieldElement, annotation);
        }

        final Place fieldPlace = new Place(object, xmlFieldElement);

        if (field instanceof OneToOneAssociation) {

            if (field.getElementType().streamAssociations(MixedIn.INCLUDED).limit(1).count() == 0L) {
                if (log.isDebugEnabled()) {
                    log.debug("includeField(Pl, Vec, Str): field is value; done");
                }
                return false;
            }

            if (log.isDebugEnabled()) {
                log.debug("includeField(Pl, Vec, Str): field is 1->1");
            }

            final OneToOneAssociation oneToOneAssociation = ((OneToOneAssociation) field);

            if(oneToOneAssociation.isExcludedFromSnapshots()) {
                return false;
            }
            final ManagedObject referencedObject = oneToOneAssociation.get(fieldPlace.getObject(),
                    InteractionInitiatedBy.FRAMEWORK);

            if (referencedObject == null) {
                return true; // not a failure if the reference was null
            }

            final boolean appendedXml = appendXmlThenIncludeRemaining(fieldPlace, referencedObject, names, annotation);
            if (log.isDebugEnabled()) {
                log.debug("includeField(Pl, Vec, Str): 1->1: invoked appendXmlThenIncludeRemaining for {}{}",
                        log("referencedObj", referencedObject), andlog("returned", "" + appendedXml));
            }

            return appendedXml;

        } else if (field instanceof OneToManyAssociation) {
            if (log.isDebugEnabled()) {
                log.debug("includeField(Pl, Vec, Str): field is 1->M");
            }

            final OneToManyAssociation oneToManyAssociation = (OneToManyAssociation) field;
            final ManagedObject collection = oneToManyAssociation.get(fieldPlace.getObject(),
                    InteractionInitiatedBy.FRAMEWORK);

            if (log.isDebugEnabled()) {
                log.debug("includeField(Pl, Vec, Str): 1->M: {}",
                        log("collection.size", "" + CollectionFacet.elementCount(collection)));
            }

            final boolean[] allFieldsNavigated = { true }; // fast non-thread-safe value reference

            CollectionFacet.streamAdapters(collection).forEach(referencedObject -> {
                final boolean appendedXml = appendXmlThenIncludeRemaining(fieldPlace, referencedObject, names,
                        annotation);
                if (log.isDebugEnabled()) {
                    log.debug("includeField(Pl, Vec, Str): 1->M: + invoked appendXmlThenIncludeRemaining for {}{}",
                            log("referencedObj", referencedObject), andlog("returned", "" + appendedXml));
                }
                allFieldsNavigated[0] = allFieldsNavigated[0] && appendedXml;
            });

            log.debug("includeField(Pl, Vec, Str): {}", log("returning", "" + allFieldsNavigated));
            return allFieldsNavigated[0];
        }

        return false; // fall through, shouldn't get here but just in
        // case.
    }