This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
commit 6841fb91cfe90b957cc53e33a6a23bbc74184be1 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Mon Nov 20 13:17:33 2023 +0100 In `DefaultConformanceResult`, retrofit the handling of nil reasons into the `nilReasons()` map. --- .../org/apache/sis/metadata/AbstractMetadata.java | 47 ++++++++++++++++++++++ .../org/apache/sis/metadata/MetadataStandard.java | 2 + .../apache/sis/metadata/ModifiableMetadata.java | 14 ++++++- .../org/apache/sis/metadata/iso/ISOMetadata.java | 3 +- .../iso/quality/DefaultConformanceResult.java | 42 +------------------ .../org/apache/sis/xml/bind/gco/GO_Boolean.java | 11 ++--- .../org/apache/sis/xml/bind/gco/PropertyType.java | 40 +++++++++++------- .../iso/quality/DefaultConformanceResultTest.java | 6 +-- 8 files changed, 100 insertions(+), 65 deletions(-) diff --git a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/AbstractMetadata.java b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/AbstractMetadata.java index 6b9c0ed5e0..f318e6658e 100644 --- a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/AbstractMetadata.java +++ b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/AbstractMetadata.java @@ -91,6 +91,7 @@ public abstract class AbstractMetadata implements LenientComparable, Emptiable { * still be done for removing entries that shouldn't be there. * * @see NilReasonMap + * @see #nilReasons() */ HashMap<Integer,NilReason> nilReasons; @@ -100,6 +101,24 @@ public abstract class AbstractMetadata implements LenientComparable, Emptiable { protected AbstractMetadata() { } + /** + * Creates an initially empty metadata with nil reasons copied from the given object. + * The given object should be a metadata of the same class. + * + * @param source the metadata from which to copy nil reasons, or {@code null} if none. + * + * @since 1.5 + */ + @SuppressWarnings("unchecked") + protected AbstractMetadata(final Object source) { + if (source instanceof AbstractMetadata) { + nilReasons = ((AbstractMetadata) source).nilReasons; + if (nilReasons != null) { + nilReasons = (HashMap<Integer,NilReason>) nilReasons.clone(); + } + } + } + /** * Returns the metadata standard implemented by subclasses. * Subclasses will typically return a hard-coded constant such as @@ -204,6 +223,34 @@ public abstract class AbstractMetadata implements LenientComparable, Emptiable { return getStandard().asValueMap(this, null, KeyNamePolicy.JAVABEANS_PROPERTY, ValueExistencePolicy.NON_EMPTY); } + /** + * Returns a view of the reasons why some properties are missing. + * The map is backed by the metadata object using Java reflection, so changes in the + * underlying metadata object are immediately reflected in the map and conversely. + * + * <h4>Mandatory and optional properties</h4> + * If a {@linkplain org.opengis.annotation.Obligation#MANDATORY mandatory} property has no value, + * then the property will have an entry in the map even if the associated {@link NilReason} is null. + * By contrast, {@linkplain org.opengis.annotation.Obligation#OPTIONAL optional} properties have + * entries in the map only if they have a non-null {@link NilReason}. + * + * <h4>Default implementation</h4> + * The default implementation is equivalent to the following: + * + * {@snippet lang="java" : + * return getStandard().asNilReasonMap(this, null, KeyNamePolicy.JAVABEANS_PROPERTY); + * } + * + * @return a view of the reasons why some properties are missing. + * + * @see MetadataStandard#asNilReasonMap(Object, Class, KeyNamePolicy) + * + * @since 1.5 + */ + public Map<String,NilReason> nilReasons() { + return getStandard().asNilReasonMap(this, null, KeyNamePolicy.JAVABEANS_PROPERTY); + } + /** * Returns the property types and values as a tree table. * The tree table is backed by the metadata object using Java reflection, so changes in the diff --git a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/MetadataStandard.java b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/MetadataStandard.java index 0240680033..1731a9a9e2 100644 --- a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/MetadataStandard.java +++ b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/MetadataStandard.java @@ -920,6 +920,8 @@ public class MetadataStandard implements Serializable { * @return a map view over the metadata object. * @throws ClassCastException if the metadata object does not implement a metadata interface of the expected package. * + * @see AbstractMetadata#nilReasons() + * * @since 1.5 */ public Map<String,NilReason> asNilReasonMap(final Object metadata, final Class<?> baseType, diff --git a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/ModifiableMetadata.java b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/ModifiableMetadata.java index 4c19747799..542777ca60 100644 --- a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/ModifiableMetadata.java +++ b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/ModifiableMetadata.java @@ -87,7 +87,7 @@ import static org.apache.sis.metadata.internal.ImplementationHelper.valueIfDefin * } * * @author Martin Desruisseaux (Geomatys) - * @version 1.4 + * @version 1.5 * @since 0.3 */ @XmlTransient @@ -139,6 +139,18 @@ public abstract class ModifiableMetadata extends AbstractMetadata { protected ModifiableMetadata() { } + /** + * Creates an initially empty metadata with nil reasons copied from the given object. + * The given object should be a metadata of the same class. + * + * @param source the metadata from which to copy nil reasons, or {@code null} if none. + * + * @since 1.5 + */ + protected ModifiableMetadata(final Object source) { + super(source); + } + /** * Whether the metadata is still editable or has been made final. * New {@link ModifiableMetadata} instances are initially {@link #EDITABLE} diff --git a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/ISOMetadata.java b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/ISOMetadata.java index bb0b40ad4c..c190478acb 100644 --- a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/ISOMetadata.java +++ b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/ISOMetadata.java @@ -59,7 +59,7 @@ import static org.apache.sis.metadata.internal.ImplementationHelper.valueIfDefin * </ul> * * @author Martin Desruisseaux (Geomatys) - * @version 1.4 + * @version 1.5 * @since 0.3 */ @XmlTransient @@ -90,6 +90,7 @@ public class ISOMetadata extends ModifiableMetadata implements IdentifiedObject, * @param object the metadata to copy values from, or {@code null} if none. */ protected ISOMetadata(final Object object) { + super(object); if (object instanceof IdentifiedObject) { if (object instanceof ISOMetadata && Containers.isNullOrEmpty(((ISOMetadata) object).identifiers)) { /* diff --git a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/quality/DefaultConformanceResult.java b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/quality/DefaultConformanceResult.java index 2c5641f5fb..6bf335d0f1 100644 --- a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/quality/DefaultConformanceResult.java +++ b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/quality/DefaultConformanceResult.java @@ -23,7 +23,6 @@ import org.opengis.util.InternationalString; import org.opengis.metadata.citation.Citation; import org.opengis.metadata.quality.ConformanceResult; import org.apache.sis.util.iso.Types; -import org.apache.sis.xml.NilReason; import org.apache.sis.xml.bind.gco.GO_Boolean; @@ -82,11 +81,6 @@ public class DefaultConformanceResult extends AbstractResult implements Conforma */ private Boolean pass; - /** - * If no result is provided, the reason why. - */ - private NilReason nilReason; - /** * Constructs an initially empty conformance result. */ @@ -124,9 +118,6 @@ public class DefaultConformanceResult extends AbstractResult implements Conforma specification = object.getSpecification(); explanation = object.getExplanation(); pass = object.pass(); - if (object instanceof DefaultConformanceResult) { - nilReason = ((DefaultConformanceResult) object).getNilReason(); - } } } @@ -218,35 +209,6 @@ public class DefaultConformanceResult extends AbstractResult implements Conforma pass = newValue; } - /** - * Returns the reason why the result is missing. - * This value is non-null only if {@link #pass()} is null. - * - * @return the reason why the result is missing, or {@code null} if the result is not missing. - * - * @see NilReason#forObject(Object) - * - * @since 1.5 - */ - public NilReason getNilReason() { - return (pass != null) ? null : (nilReason != null) ? nilReason : NilReason.UNKNOWN; - } - - /** - * Sets the reason why the result is missing. - * Invoking this method with a non-null value sets {@link #pass()} to {@code null}. - * - * @param newValue the reason why the result is missing, or {@code null} if the result is not missing. - * - * @since 1.5 - */ - public void setNilReason(final NilReason newValue) { - checkWritePermission(nilReason); - if ((nilReason = newValue) != null) { - pass = null; - } - } - @@ -268,7 +230,7 @@ public class DefaultConformanceResult extends AbstractResult implements Conforma */ @XmlElement(name = "pass", required = true) private GO_Boolean getResult() { - return new GO_Boolean(pass(), getNilReason()); + return new GO_Boolean(this, "pass", pass()); } /** @@ -278,6 +240,6 @@ public class DefaultConformanceResult extends AbstractResult implements Conforma */ private void setResult(final GO_Boolean result) { setPass(result.getElement()); - setNilReason(result.parseNilReason()); + result.getNilReason(this, "pass"); } } diff --git a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/bind/gco/GO_Boolean.java b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/bind/gco/GO_Boolean.java index 31bf1540e6..cfabbda482 100644 --- a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/bind/gco/GO_Boolean.java +++ b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/bind/gco/GO_Boolean.java @@ -19,7 +19,7 @@ package org.apache.sis.xml.bind.gco; import jakarta.xml.bind.annotation.XmlElement; import jakarta.xml.bind.annotation.XmlSchemaType; import jakarta.xml.bind.annotation.XmlType; -import org.apache.sis.xml.NilReason; +import org.apache.sis.metadata.AbstractMetadata; /** @@ -42,11 +42,12 @@ public final class GO_Boolean extends PropertyType<GO_Boolean, Boolean> { /** * Builds a wrapper for the specified value, which may be nil. * - * @param value the value to wrap. - * @param nilReason if the value is nil, the reason why. + * @param owner the metadata providing the value object. + * @param property UML identifier of the property for which a value is provided. + * @param value the property value, or {@code null} if none. */ - public GO_Boolean(final Boolean value, final NilReason nilReason) { - super(value, nilReason); + public GO_Boolean(final AbstractMetadata owner, final String property, final Boolean value) { + super(owner, property, value); } /** diff --git a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/bind/gco/PropertyType.java b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/bind/gco/PropertyType.java index 88a2888396..11bb222560 100644 --- a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/bind/gco/PropertyType.java +++ b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/bind/gco/PropertyType.java @@ -30,10 +30,11 @@ import org.apache.sis.xml.IdentifierMap; import org.apache.sis.xml.IdentifierSpace; import org.apache.sis.xml.IdentifiedObject; import org.apache.sis.xml.ReferenceResolver; -import org.apache.sis.util.SimpleInternationalString; -import org.apache.sis.util.internal.Strings; import org.apache.sis.xml.bind.Context; import org.apache.sis.xml.bind.FilterByVersion; +import org.apache.sis.metadata.AbstractMetadata; +import org.apache.sis.util.SimpleInternationalString; +import org.apache.sis.util.internal.Strings; import org.apache.sis.util.resources.Errors; @@ -142,14 +143,22 @@ public abstract class PropertyType<ValueType extends PropertyType<ValueType,Boun } /** - * Builds a {@code PropertyType} wrapper for an instance of a primitive wrapper. + * Builds a {@code PropertyType} wrapper for an instance of a value object. * Those property types are handled in a different way because final classes * cannot implement the {@link NilObject} interface. * - * @param value the primitive type wrapper. - * @param nilReason if the value is nil, the reason why. + * @param owner the metadata providing the value object. + * @param property UML identifier of the property for which a value is provided. + * @param value the property value, or {@code null} if none. */ - protected PropertyType(final BoundType value, final NilReason nilReason) { + protected PropertyType(final AbstractMetadata owner, final String property, final BoundType value) { + final NilReason nilReason; + if (value != null) { + nilReason = NilReason.forObject(value); + } else { + // May cause a `HashMap` to be created, so invoke only if necessary. + nilReason = owner.nilReasons().get(property); + } if (nilReason != null) { reference = nilReason.toString(); } else { @@ -305,19 +314,20 @@ public abstract class PropertyType<ValueType extends PropertyType<ValueType,Boun } /** - * The reason why a mandatory attribute if left unspecified, as a parsed object. + * Stores the reason why a mandatory attribute is left unspecified. + * The reason is stored in the property of the given name in the given metadata. + * If there is no nil reason, then this method does nothing. * - * @return the nil reason, or {@code null} if none. + * @param owner the metadata where to store the nil reason. + * @param property UML identifier of the property where to store the nil reason. */ - public final NilReason parseNilReason() { + public final void getNilReason(final AbstractMetadata owner, final String property) { final String reason = getNilReason(); - if (reason == null) { - return null; - } else try { - return NilReason.valueOf(reason); + if (reason != null) try { + final NilReason nilReason = NilReason.valueOf(reason); + owner.nilReasons().put(property, nilReason); } catch (URISyntaxException e) { - Context.warningOccured(Context.current(), getClass(), "parseNilReason", e, true); - return NilReason.OTHER; + Context.warningOccured(Context.current(), getClass(), "getNilReason", e, true); } } diff --git a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/iso/quality/DefaultConformanceResultTest.java b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/iso/quality/DefaultConformanceResultTest.java index 0b64e76994..1384da9a84 100644 --- a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/iso/quality/DefaultConformanceResultTest.java +++ b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/iso/quality/DefaultConformanceResultTest.java @@ -62,7 +62,7 @@ public final class DefaultConformanceResultTest extends TestCase { public void testXML() throws JAXBException { final var result = new DefaultConformanceResult(); result.setPass(true); - assertNull(result.getNilReason()); + assertNull(result.nilReasons().get("pass")); testXML(result, "<mdq:DQ_ConformanceResult xmlns:mdq=\"" + Namespaces.MDQ + '"' + " xmlns:gco=\"" + Namespaces.GCO + "\">\n" + @@ -83,7 +83,7 @@ public final class DefaultConformanceResultTest extends TestCase { @Test public void testUnknownReason() throws JAXBException { final var result = new DefaultConformanceResult(); - assertEquals(NilReason.UNKNOWN, result.getNilReason()); + assertNull(result.nilReasons().put("pass", NilReason.UNKNOWN)); testXML(result, "<mdq:DQ_ConformanceResult xmlns:mdq=\"" + Namespaces.MDQ + '"' + " xmlns:gco=\"" + Namespaces.GCO + "\">\n" + @@ -103,7 +103,7 @@ public final class DefaultConformanceResultTest extends TestCase { public void testTemplateReason() throws JAXBException { final var result = new DefaultConformanceResult(); result.setPass(true); - result.setNilReason(NilReason.TEMPLATE); + result.nilReasons().put("pass", NilReason.TEMPLATE); assertNull(result.pass()); testXML(result, "<mdq:DQ_ConformanceResult xmlns:mdq=\"" + Namespaces.MDQ + '"'