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 + '"'

Reply via email to