sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1794138 [1/4] - in /sis/trunk: ./ core/sis-build-helper/src/main/java/org/apache/sis/internal/taglet/ core/sis-metadata/src/main/java/org/apache/sis/io/wkt/ core/sis-metadata/src/main/java/org/apache/sis/metadata/ core/sis-metadata/src/mai...
Date Sat, 06 May 2017 13:00:51 GMT
Author: desruisseaux
Date: Sat May  6 13:00:50 2017
New Revision: 1794138

URL: http://svn.apache.org/viewvc?rev=1794138&view=rev
Log:
Merge from JDK7 branch.

Added:
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/TitleProperty.java
      - copied unchanged from r1794136, sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/TitleProperty.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/DefinitionVerifier.java
      - copied unchanged from r1794136, sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/DefinitionVerifier.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicRedimension.java
      - copied unchanged from r1794136, sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicRedimension.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/DefinitionVerifierTest.java
      - copied unchanged from r1794136, sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/DefinitionVerifierTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/integration/CoordinateOperationTest.java
      - copied unchanged from r1794136, sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/test/integration/CoordinateOperationTest.java
Modified:
    sis/trunk/   (props changed)
    sis/trunk/core/sis-build-helper/src/main/java/org/apache/sis/internal/taglet/Preformat.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Parser.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/AbstractMetadata.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeNode.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeNodeChildren.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeTableView.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/ValueExistencePolicy.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultExtendedElementInformation.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultIdentifier.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/AbstractParty.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitation.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitationDate.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureTypeInfo.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeDimension.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeElementDescription.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDistribution.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultMedium.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultExtent.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywordClass.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationChainMetadata.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationMetadata.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultUsage.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessStep.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessStepReport.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultSource.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultDimension.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCPCollection.java
    sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTestCase.java
    sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeChildrenTest.java
    sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeTest.java
    sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableFormatTest.java
    sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableViewTest.java
    sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/AllMetadataTest.java
    sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentificationTest.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelope2D.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.properties
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.properties
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeodeticOperation.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Geographic2Dto3D.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Geographic3Dto2D.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicToGeocentric.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Providers.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/MissingFactoryResourceException.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/UnavailableFactoryException.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/CoordinateOperationSet.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/Geographic3Dto2DTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/CRSTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/integration/ConsistencyTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/logging/WarningListener.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/logging/WarningListeners.java
    sis/trunk/core/sis-utility/src/test/java/org/apache/sis/util/logging/EmptyWarningListeners.java
    sis/trunk/pom.xml
    sis/trunk/src/main/javadoc/stylesheet.css
    sis/trunk/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatReader.java
    sis/trunk/storage/sis-earth-observation/src/test/java/org/apache/sis/storage/earthobservation/LandsatReaderTest.java
    sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Decoder.java
    sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java
    sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/DecoderWrapper.java
    sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/LogAdapter.java
    sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java
    sis/trunk/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/TestCase.java
    sis/trunk/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/MetadataReaderTest.java
    sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/Store.java
    sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/Store.java
    sis/trunk/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/xml/stream/StaxDataStore.java

Propchange: sis/trunk/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Sat May  6 13:00:50 2017
@@ -1,5 +1,5 @@
 /sis/branches/Android:1430670-1480699
 /sis/branches/JDK6:1394364-1758914
-/sis/branches/JDK7:1394913-1792955
-/sis/branches/JDK8:1584960-1792953
+/sis/branches/JDK7:1394913-1794136
+/sis/branches/JDK8:1584960-1794135
 /sis/branches/JDK9:1773327-1789983

Modified: sis/trunk/core/sis-build-helper/src/main/java/org/apache/sis/internal/taglet/Preformat.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-build-helper/src/main/java/org/apache/sis/internal/taglet/Preformat.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-build-helper/src/main/java/org/apache/sis/internal/taglet/Preformat.java [UTF-8] (original)
+++ sis/trunk/core/sis-build-helper/src/main/java/org/apache/sis/internal/taglet/Preformat.java [UTF-8] Sat May  6 13:00:50 2017
@@ -148,7 +148,7 @@ all:    while (tk.hasMoreTokens()) {
         /*
          * Nows inserts each line.
          */
-        final StringBuilder buffer = new StringBuilder("<blockquote><pre>");
+        final StringBuilder buffer = new StringBuilder("<pre class=\"code-sample\">");
         tk = new StringTokenizer(text, "\r\n", true);
         while (tk.hasMoreTokens()) {
             String line = tk.nextToken();
@@ -166,7 +166,7 @@ all:    while (tk.hasMoreTokens()) {
             }
             buffer.append(line);
         }
-        return buffer.append("</pre></blockquote>").toString();
+        return buffer.append("</pre>").toString();
     }
 
     /**

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java [UTF-8] Sat May  6 13:00:50 2017
@@ -197,8 +197,8 @@ abstract class AbstractParser implements
     }
 
     /**
-     * Creates the object from a string. This method is for implementation of {@code createFromWKT(String)}
-     * method is SIS factories only.
+     * Creates the object from a string and log the warnings if any.
+     * This method is for implementation of {@code createFromWKT(String)} method is SIS factories only.
      *
      * @param  text  coordinate system encoded in Well-Known Text format (version 1 or 2).
      * @return the result of parsing the given text.

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Parser.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Parser.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Parser.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Parser.java [UTF-8] Sat May  6 13:00:50 2017
@@ -37,6 +37,12 @@ import org.opengis.util.FactoryException
  *   <li>{@link org.apache.sis.geometry.Envelopes#fromWKT(CharSequence)}</li>
  * </ul>
  *
+ * Non-fatal anomalies found in Well Known Texts are reported in a {@linkplain java.util.logging.Logger logger}
+ * named {@code "org.apache.sis.io.wkt"}. Warnings may be for unknown or unsupported WKT elements, inconsistent
+ * unit definitions (unit symbol, scale factor or EPSG code), unparsable axis abbreviations, <i>etc.</i>
+ * However this parser does not verify if the overall parsed object matches the EPSG (or other authority) definition.
+ * For such verification, see {@link org.apache.sis.referencing.CRS#fromWKT(String)}.
+ *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 0.6
  * @since   0.6
@@ -48,6 +54,12 @@ public interface Parser {
      * Objects returned by this method are typically (but not necessarily)
      * {@linkplain org.apache.sis.referencing.crs.AbstractCRS Coordinate Reference Systems} or
      * {@linkplain org.apache.sis.referencing.operation.transform.AbstractMathTransform Math Transforms}.
+     * If the given text contains non-fatal anomalies, warnings may be reported in a
+     * {@linkplain java.util.logging.Logger logger} named {@code "org.apache.sis.io.wkt"}.
+     *
+     * <div class="note"><b>Tip:</b>
+     * for processing warnings in a different way than logging them, one can use
+     * {@link WKTFormat#parseObject(String)} followed by a call to {@link WKTFormat#getWarnings()}.</div>
      *
      * @param  text  object encoded in Well-Known Text format (version 1 or 2).
      * @return the result of parsing the given text.

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/AbstractMetadata.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/AbstractMetadata.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/AbstractMetadata.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/AbstractMetadata.java [UTF-8] Sat May  6 13:00:50 2017
@@ -258,7 +258,7 @@ public abstract class AbstractMetadata i
      * adds a title to a citation:
      *
      * {@preformat java
-     *     TreeTable.Node node = ...; // The node for a DefaultCitation.
+     *     TreeTable.Node node = ...;                               // The node for a DefaultCitation.
      *     TreeTable.Node child = node.newChild();
      *     child.setValue(TableColumn.IDENTIFIER, "title");
      *     child.setValue(TableColumn.VALUE, "Le petit prince");
@@ -272,7 +272,7 @@ public abstract class AbstractMetadata i
      * The default implementation is equivalent to the following method call:
      *
      * {@preformat java
-     *   return getStandard().asTreeTable(this, null, ValueExistencePolicy.NON_EMPTY);
+     *   return getStandard().asTreeTable(this, null, ValueExistencePolicy.COMPACT);
      * }
      *
      * @return a tree table representation of the specified metadata.
@@ -280,7 +280,7 @@ public abstract class AbstractMetadata i
      * @see MetadataStandard#asTreeTable(Object, Class, ValueExistencePolicy)
      */
     public TreeTable asTreeTable() {
-        return getStandard().asTreeTable(this, null, ValueExistencePolicy.NON_EMPTY);
+        return getStandard().asTreeTable(this, null, ValueExistencePolicy.COMPACT);
     }
 
     /**

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java [UTF-8] Sat May  6 13:00:50 2017
@@ -868,7 +868,7 @@ public class MetadataStandard implements
      * adds a title to a citation:
      *
      * {@preformat java
-     *     TreeTable.Node node = ...; // The node for a DefaultCitation.
+     *     TreeTable.Node node = ...;                               // The node for a DefaultCitation.
      *     TreeTable.Node child = node.newChild();
      *     child.setValue(TableColumn.IDENTIFIER, "title");
      *     child.setValue(TableColumn.VALUE, "Le petit prince");

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeNode.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeNode.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeNode.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeNode.java [UTF-8] Sat May  6 13:00:50 2017
@@ -178,12 +178,20 @@ class TreeNode implements Node {
         this.parent   = parent;
         this.metadata = metadata;
         this.baseType = baseType;
-        if (!table.standard.isMetadata(baseType)) {
+        if (!isMetadata(baseType)) {
             children = LEAF;
         }
     }
 
     /**
+     * Returns {@code true} if nodes for values of the given type can be expanded with more children.
+     * A return value of {@code false} means that values of the given type are leaves.
+     */
+    final boolean isMetadata(final Class<?> type) {
+        return table.standard.isMetadata(type);
+    }
+
+    /**
      * Returns the key to use for calls to {@link MetadataStandard} methods.
      * This key is used only for some default method implementations in the root node;
      * children will use the class of their node value instead.
@@ -344,10 +352,63 @@ class TreeNode implements Node {
          * {@link KeyNamePolicy#UML_IDENTIFIER} instead than {@link KeyNamePolicy#JAVABEANS_PROPERTY}
          * in order to get the singular form instead of the plural one, because we will create one
          * node for each element in a collection.
+         *
+         * <p>If the property name is equals, ignoring case, to the simple type name, then this method
+         * returns the subtype name. For example instead of:</p>
+         *
+         * {@preformat text
+         *   Citation
+         *    └─Cited responsible party
+         *       └─Party
+         *          └─Name ……………………………… Jon Smith
+         * }
+         *
+         * we format:
+         *
+         * {@preformat
+         *   Citation
+         *    └─Cited responsible party
+         *       └─Individual
+         *          └─Name ……………………………… Jon Smith
+         * }
+         *
+         * @see <a href="https://issues.apache.org/jira/browse/SIS-298">SIS-298</a>
          */
         @Override
         CharSequence getName() {
-            return CharSequences.camelCaseToSentence(getIdentifier()).toString();
+            String identifier = getIdentifier();
+            if (identifier.equalsIgnoreCase(Classes.getShortName(baseType))) {
+                final Object value = getUserObject();
+                if (value != null) {
+                    Class<?> type = standardSubType(Classes.getLeafInterfaces(value.getClass(), baseType));
+                    if (type != null && type != Void.TYPE) {
+                        identifier = Classes.getShortName(type);
+                    }
+                }
+            }
+            return CharSequences.camelCaseToSentence(identifier).toString();
+        }
+
+        /**
+         * Returns the element of the given array which is both assignable to {@link #baseType} and a member
+         * of the standard represented by {@link TreeTableView#standard}. If no such type is found, returns
+         * {@code null}. If more than one type is found, returns the {@link Void#TYPE} sentinel value.
+         */
+        private Class<?> standardSubType(final Class<?>[] subtypes) {
+            Class<?> type = null;
+            for (Class<?> c : subtypes) {
+                if (baseType.isAssignableFrom(c)) {
+                    if (!isMetadata(c)) {
+                        c = standardSubType(c.getInterfaces());
+                    }
+                    if (type == null) {
+                        type = c;
+                    } else if (type != c) {
+                        return Void.TYPE;
+                    }
+                }
+            }
+            return type;
         }
 
         /**
@@ -592,19 +653,14 @@ class TreeNode implements Node {
             cachedValue = null;             // Use the cached value only once after iteration.
             /*
              * If there is a value, check if the cached collection is still applicable.
+             * We verify that the collection is a wrapper for the same metadata object.
+             * If we need to create a new collection, we know that the property accessor
+             * exists otherwise the call to 'isLeaf()' above would have returned 'true'.
              */
-            if (children instanceof TreeNodeChildren) {
-                final TreeNodeChildren candidate = (TreeNodeChildren) children;
-                if (candidate.metadata == value) {
-                    return candidate;
-                }
+            if (children == null || ((TreeNodeChildren) children).metadata != value) {
+                children = new TreeNodeChildren(this, value,
+                        table.standard.getAccessor(new CacheKey(value.getClass(), baseType), true));
             }
-            /*
-             * At this point, we need to create a new collection. The property accessor shall
-             * exist, otherwise the call to 'isLeaf()' above would have returned 'true'.
-             */
-            children = new TreeNodeChildren(this, value,
-                    table.standard.getAccessor(new CacheKey(value.getClass(), baseType), true));
         }
         return children;
     }
@@ -712,8 +768,10 @@ class TreeNode implements Node {
                         throw new IllegalArgumentException(Errors.format(Errors.Keys.ElementAlreadyPresent_1, value));
                     }
                     delegate = siblings.childAt(indexInData, indexInList);
-                    // Do not set 'delegate.cachedValue = value', since 'value' may
-                    // have been converted by the setter method to an other value.
+                    /*
+                     * Do not set 'delegate.cachedValue = value', since 'value' may
+                     * have been converted by the setter method to another value.
+                     */
                     return;
                 }
             }
@@ -736,36 +794,54 @@ class TreeNode implements Node {
     }
 
     /**
+     * Returns the children if the value policy is {@link ValueExistencePolicy#COMPACT}, or {@code null} otherwise.
+     */
+    private TreeNodeChildren getCompactChildren() {
+        if (table.valuePolicy == ValueExistencePolicy.COMPACT) {
+            final Collection<Node> children = getChildren();
+            if (children instanceof TreeNodeChildren) {
+                return (TreeNodeChildren) children;
+            }
+        }
+        return null;
+    }
+
+    /**
      * Returns the value of this node in the given column, or {@code null} if none. This method verifies
      * the {@code column} argument, then delegates to {@link #getName()}, {@link #getUserObject()} or
      * other properties.
      */
     @Override
     public final <V> V getValue(final TableColumn<V> column) {
-        ArgumentChecks.ensureNonNull("column", column);
         Object value = null;
-
-        // Check the columns in what we think may be the most frequently
-        // asked columns first, and less frequently asked columns last.
-        if (column == TableColumn.VALUE) {
+        ArgumentChecks.ensureNonNull("column", column);
+        if (column == TableColumn.IDENTIFIER) {
+            value = getIdentifier();
+        } else if (column == TableColumn.INDEX) {
+            value = getIndex();
+        } else if (column == TableColumn.NAME) {
+            if (name == null) {
+                name = getName();
+            }
+            value = name;
+        } else if (column == TableColumn.TYPE) {
+            final TreeNodeChildren children = getCompactChildren();
+            if (children == null || (value = children.getParentType()) == null) {
+                value = baseType;
+            }
+        } else if (column == TableColumn.VALUE) {
             if (isLeaf()) {
                 value = cachedValue;
                 cachedValue = null;                 // Use the cached value only once after iteration.
                 if (value == null) {
                     value = getUserObject();
                 }
+            } else {
+                final TreeNodeChildren children = getCompactChildren();
+                if (children != null) {
+                    value = children.getParentTitle();
+                }
             }
-        } else if (column == TableColumn.NAME) {
-            if (name == null) {
-                name = getName();
-            }
-            value = name;
-        } else if (column == TableColumn.IDENTIFIER) {
-            value = getIdentifier();
-        } else if (column == TableColumn.INDEX) {
-            value = getIndex();
-        } else if (column == TableColumn.TYPE) {
-            value = baseType;
         }
         return column.getElementType().cast(value);
     }
@@ -783,9 +859,12 @@ class TreeNode implements Node {
     public final <V> void setValue(final TableColumn<V> column, final V value) throws UnsupportedOperationException {
         ArgumentChecks.ensureNonNull("column", column);
         if (column == TableColumn.VALUE) {
-            ArgumentChecks.ensureNonNull("value", value);
+            ArgumentChecks.ensureNonNull("value", value);                       // See javadoc.
             cachedValue = null;
-            setUserObject(value);
+            final TreeNodeChildren children = getCompactChildren();
+            if (children == null || !(children.setParentTitle(value))) {
+                setUserObject(value);
+            }
         } else if (TreeTableView.COLUMNS.contains(column)) {
             throw new UnsupportedOperationException(unmodifiableCellValue(column));
         } else {

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeNodeChildren.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeNodeChildren.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeNodeChildren.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeNodeChildren.java [UTF-8] Sat May  6 13:00:50 2017
@@ -98,6 +98,30 @@ final class TreeNodeChildren extends Abs
     private final TreeNode[] children;
 
     /**
+     * Index of the property to write in the parent node instead than as a child.
+     * If a property has the same name than the parent property that contains it,
+     * we write its value in that parent property. For example instead of:
+     *
+     * {@preformat text
+     *   Citation
+     *    └─Date
+     *       ├─Date………………… 2012/01/01
+     *       └─Date type…… Creation
+     * }
+     *
+     * We simplify as:
+     *
+     * {@preformat text
+     *   Citation
+     *    └─Date………………………… 2012/01/01
+     *       └─Date type…… Creation
+     * }
+     *
+     * @see <a href="https://issues.apache.org/jira/browse/SIS-298">SIS-298</a>
+     */
+    final int titleProperty;
+
+    /**
      * Modification count, incremented when the content of this collection is modified. This check
      * is done on a <cite>best effort basis</cite> only, since we can't not track the changes which
      * are done independently in the {@linkplain #metadata} object.
@@ -116,6 +140,57 @@ final class TreeNodeChildren extends Abs
         this.metadata = metadata;
         this.accessor = accessor;
         this.children = new TreeNode[accessor.count()];
+        /*
+         * Search for something that looks like the main property, to be associated with the parent node
+         * instead than provided as a child. The intend is to have more compact and easy to read trees.
+         * That property shall be a singleton for a simple value (not another metadata object).
+         */
+        if (parent.table.valuePolicy == ValueExistencePolicy.COMPACT) {
+            TitleProperty an = accessor.implementation.getAnnotation(TitleProperty.class);
+            if (an == null) {
+                Class<?> implementation = parent.table.standard.getImplementation(accessor.type);
+                if (implementation != null) {
+                    an = implementation.getAnnotation(TitleProperty.class);
+                }
+            }
+            if (an != null) {
+                final int index = accessor.indexOf(an.name(), false);
+                final Class<?> type = accessor.type(index, TypeValuePolicy.ELEMENT_TYPE);
+                if (type != null && !parent.isMetadata(type) && type == accessor.type(index, TypeValuePolicy.PROPERTY_TYPE)) {
+                    titleProperty = index;
+                    return;
+                }
+            }
+        }
+        titleProperty = -1;
+    }
+
+    /**
+     * If a simple value should be associated to the parent node, returns the type of that value.
+     * Otherwise returns {@code null}.
+     */
+    final Class<?> getParentType() {
+        return (titleProperty >= 0) ? accessor.type(titleProperty, TypeValuePolicy.ELEMENT_TYPE) : null;
+    }
+
+    /**
+     * If a simple value should be associated to the parent node, returns that value.
+     * Otherwise returns {@code null}.
+     */
+    final Object getParentTitle() {
+        return (titleProperty >= 0) ? valueAt(titleProperty) : null;
+    }
+
+    /**
+     * Sets the value associated to the parent node, if possible.
+     * This returned boolean tells whether the value has been written.
+     */
+    final boolean setParentTitle(final Object value) {
+        if (titleProperty < 0) {
+            return false;
+        }
+        accessor.set(titleProperty, metadata, value, PropertyAccessor.RETURN_NULL);
+        return true;
     }
 
     /**
@@ -229,7 +304,9 @@ final class TreeNodeChildren extends Abs
      */
     @Override
     public int size() {
-        return accessor.count(metadata, parent.table.valuePolicy, PropertyAccessor.COUNT_DEEP);
+        int count = accessor.count(metadata, parent.table.valuePolicy, PropertyAccessor.COUNT_DEEP);
+        if (titleProperty >= 0 && !isSkipped(valueAt(titleProperty))) count--;
+        return count;
     }
 
     /**
@@ -310,11 +387,9 @@ final class TreeNodeChildren extends Abs
         private Object nextValue;
 
         /**
-         * If the call to {@link #next()} found a collection, the iterator over the elements
-         * in that collection. Otherwise {@code null}.
-         *
-         * <p>A non-null value (even if that sub-iterator has no next elements)
-         * means that {@link #nextValue} is an element of that sub-iteration.</p>
+         * If the call to {@link #next()} found a collection, the iterator over the elements in that collection.
+         * Otherwise {@code null}. A non-null value (even if that sub-iterator has no next elements) means that
+         * {@link #nextValue} is an element of that sub-iteration.
          */
         private Iterator<?> subIterator;
 
@@ -385,38 +460,40 @@ final class TreeNodeChildren extends Abs
              */
             final int count = childCount();
             while (nextInAccessor < count) {
-                nextValue = valueAt(nextInAccessor);
-                if (!isSkipped(nextValue)) {
-                    if (isCollection(nextInAccessor)) {
-                        /*
-                         * If the property is a collection, unconditionally get the first element
-                         * even if absent (null) in order to comply with the ValueExistencePolicy.
-                         * if we were expected to ignore empty collections, 'isSkipped(nextValue)'
-                         * would have returned 'true'.
-                         */
-                        if (nextValue != null) {
-                            subIterator = ((Iterable<?>) nextValue).iterator();
-                        } else {
-                            subIterator = Collections.emptyIterator();
+                if (nextInAccessor != titleProperty) {
+                    nextValue = valueAt(nextInAccessor);
+                    if (!isSkipped(nextValue)) {
+                        if (isCollection(nextInAccessor)) {
                             /*
-                             * Null collections are illegal (it shall be empty collections instead),
-                             * but we try to keep the iterator robut to ill-formed metadata, because
-                             * we want AbstractMetadata.toString() to work so we can spot problems.
-                             */
-                        }
-                        subIndex = 0;
-                        if (subIterator.hasNext()) {
-                            nextValue = subIterator.next();
-                        } else {
-                            nextValue = null;
-                            /*
-                             * Do not set 'childIterator' to null, since the above 'nextValue'
-                             * is considered as part of the child iteration.
+                             * If the property is a collection, unconditionally get the first element
+                             * even if absent (null) in order to comply with the ValueExistencePolicy.
+                             * if we were expected to ignore empty collections, 'isSkipped(nextValue)'
+                             * would have returned 'true'.
                              */
+                            if (nextValue != null) {
+                                subIterator = ((Iterable<?>) nextValue).iterator();
+                            } else {
+                                subIterator = Collections.emptyIterator();
+                                /*
+                                 * Null collections are illegal (it shall be empty collections instead),
+                                 * but we try to keep the iterator robut to ill-formed metadata, because
+                                 * we want AbstractMetadata.toString() to work so we can spot problems.
+                                 */
+                            }
+                            subIndex = 0;
+                            if (subIterator.hasNext()) {
+                                nextValue = subIterator.next();
+                            } else {
+                                nextValue = null;
+                                /*
+                                 * Do not set 'childIterator' to null, since the above 'nextValue'
+                                 * is considered as part of the child iteration.
+                                 */
+                            }
                         }
+                        isNextVerified = true;
+                        return true;
                     }
-                    isNextVerified = true;
-                    return true;
                 }
                 nextInAccessor++;
             }

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeTableView.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeTableView.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeTableView.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeTableView.java [UTF-8] Sat May  6 13:00:50 2017
@@ -104,7 +104,7 @@ final class TreeTableView implements Tre
     {
         this.standard    = standard;
         this.valuePolicy = valuePolicy;
-        this.root = new TreeNode(this, metadata, baseType);
+        this.root        = new TreeNode(this, metadata, baseType);
     }
 
     /**
@@ -113,7 +113,7 @@ final class TreeTableView implements Tre
     @Override
     @SuppressWarnings("ReturnOfCollectionOrArrayField")
     public List<TableColumn<?>> getColumns() {
-        return COLUMNS;     // Unmodifiable
+        return COLUMNS;                                 // Unmodifiable
     }
 
     /**

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/ValueExistencePolicy.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/ValueExistencePolicy.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/ValueExistencePolicy.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/ValueExistencePolicy.java [UTF-8] Sat May  6 13:00:50 2017
@@ -38,7 +38,7 @@ import org.apache.sis.xml.NilReason;
  * Those explanations can be obtained by calls to the {@link org.apache.sis.xml.NilReason#forObject(Object)} method.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.4
+ * @version 0.8
  *
  * @see MetadataStandard#asValueMap(Object, Class, KeyNamePolicy, ValueExistencePolicy)
  *
@@ -122,6 +122,59 @@ public enum ValueExistencePolicy {
         /** Skips all null or empty values. */
         @Override boolean isSkipped(final Object value) {
             return isNullOrEmpty(value);
+        }
+
+        /** Never substitute null or empty collections since they should be skipped. */
+        @Override boolean substituteByNullElement(final Collection<?> values) {
+            return false;
+        }
+    },
+
+    /**
+     * Includes non-empty properties but omits {@linkplain TitleProperty title properties}.
+     * Values associated to title properties are instead associated with the parent node.
+     * This policy is relevant for metadata classes annotated with {@link TitleProperty};
+     * for all other classes, this policy is identical to {@link #NON_EMPTY}.
+     *
+     * <div class="note"><b>Example:</b>
+     * the {@link org.apache.sis.metadata.iso.citation.DefaultCitation} and
+     * {@link org.apache.sis.metadata.iso.citation.DefaultCitationDate} classes are annotated with
+     * <code>&#64;TitleProperty(name="title")</code> and <code>&#64;TitleProperty(name="date")</code>
+     * respectively. The following table compares the trees produced by two policies:
+     *
+     * <table class="sis">
+     *   <caption>Comparison of "non-empty" and "compact" policy on the same metadata</caption>
+     *   <tr>
+     *     <th>{@code NON_EMPTY}</th>
+     *     <th class="sep">{@code COMPACT}</th>
+     *   </tr><tr><td>
+     *     {@preformat text
+     *       Citation
+     *        ├─Title……………………… My document
+     *        └─Date
+     *           ├─Date………………… 2012/01/01
+     *           └─Date type…… Creation
+     *     }
+     *   </td><td class="sep">
+     *     {@preformat text
+     *       Citation……………………… My document
+     *        └─Date………………………… 2012/01/01
+     *           └─Date type…… Creation
+     *     }
+     *   </td></tr>
+     * </table></div>
+     *
+     * This policy is the default behavior of {@link AbstractMetadata#asTreeTable()},
+     * and consequently defines the default rendering of {@link AbstractMetadata#toString()}.
+     *
+     * @see TitleProperty
+     *
+     * @since 0.8
+     */
+    COMPACT() {
+        /** Skips all null or empty values. */
+        @Override boolean isSkipped(final Object value) {
+            return isNullOrEmpty(value);
         }
 
         /** Never substitute null or empty collections since they should be skipped. */

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultExtendedElementInformation.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultExtendedElementInformation.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultExtendedElementInformation.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultExtendedElementInformation.java [UTF-8] Sat May  6 13:00:50 2017
@@ -26,6 +26,7 @@ import org.opengis.metadata.Obligation;
 import org.opengis.metadata.citation.ResponsibleParty;
 import org.opengis.metadata.ExtendedElementInformation;
 import org.opengis.util.InternationalString;
+import org.apache.sis.metadata.TitleProperty;
 import org.apache.sis.measure.ValueRange;
 import org.apache.sis.util.iso.Types;
 import org.apache.sis.internal.metadata.LegacyPropertyAdapter;
@@ -58,6 +59,7 @@ import static org.opengis.annotation.Spe
  * @module
  */
 @SuppressWarnings("CloneableClassWithoutClone")                 // ModifiableMetadata needs shallow clones.
+@TitleProperty(name = "name")
 @XmlType(name = "MD_ExtendedElementInformation_Type", propOrder = {
     "name",
     "shortName",

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultIdentifier.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultIdentifier.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultIdentifier.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultIdentifier.java [UTF-8] Sat May  6 13:00:50 2017
@@ -24,6 +24,7 @@ import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.util.InternationalString;
+import org.apache.sis.metadata.TitleProperty;
 import org.apache.sis.internal.util.Citations;
 
 import static org.opengis.annotation.Obligation.OPTIONAL;
@@ -90,6 +91,7 @@ import static org.opengis.annotation.Spe
  * @module
  */
 @SuppressWarnings("CloneableClassWithoutClone")                 // ModifiableMetadata needs shallow clones.
+@TitleProperty(name = "code")
 @XmlType(name = "MD_Identifier_Type", propOrder = {
     "authority",
     "code"

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java [UTF-8] Sat May  6 13:00:50 2017
@@ -29,6 +29,7 @@ import org.opengis.referencing.Reference
 import org.opengis.util.InternationalString;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.iso.Types;
+import org.apache.sis.metadata.TitleProperty;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.internal.metadata.NameMeaning;
 import org.apache.sis.internal.metadata.WKTKeywords;
@@ -127,6 +128,7 @@ import static org.apache.sis.util.collec
  * @since 0.3
  * @module
  */
+@TitleProperty(name = "code")
 @XmlType(name = "RS_Identifier_Type", propOrder = {
     "authority",
     "code",

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/AbstractParty.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/AbstractParty.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/AbstractParty.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/AbstractParty.java [UTF-8] Sat May  6 13:00:50 2017
@@ -24,6 +24,7 @@ import javax.xml.bind.annotation.XmlSeeA
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.citation.Contact;
 import org.apache.sis.metadata.iso.ISOMetadata;
+import org.apache.sis.metadata.TitleProperty;
 import org.apache.sis.util.iso.Types;
 
 // Branch-specific imports
@@ -60,6 +61,7 @@ import static org.opengis.annotation.Spe
  * @module
  */
 @SuppressWarnings("CloneableClassWithoutClone")                 // ModifiableMetadata needs shallow clones.
+@TitleProperty(name = "name")
 @XmlType(name = "AbstractCI_Party_Type", propOrder = {
     "name",
     "contactInfo"

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitation.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitation.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitation.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitation.java [UTF-8] Sat May  6 13:00:50 2017
@@ -33,6 +33,7 @@ import org.opengis.metadata.identificati
 import org.opengis.util.InternationalString;
 import org.apache.sis.util.iso.Types;
 import org.apache.sis.internal.jaxb.NonMarshalledAuthority;
+import org.apache.sis.metadata.TitleProperty;
 import org.apache.sis.metadata.iso.ISOMetadata;
 import org.apache.sis.xml.IdentifierSpace;
 import org.apache.sis.xml.IdentifierMap;
@@ -70,6 +71,7 @@ import static org.apache.sis.internal.me
  * @module
  */
 @SuppressWarnings("CloneableClassWithoutClone")                 // ModifiableMetadata needs shallow clones.
+@TitleProperty(name = "title")
 @XmlType(name = "CI_Citation_Type", propOrder = {
     "title",
     "alternateTitles",

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitationDate.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitationDate.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitationDate.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitationDate.java [UTF-8] Sat May  6 13:00:50 2017
@@ -23,6 +23,7 @@ import javax.xml.bind.annotation.XmlRoot
 import org.opengis.metadata.citation.CitationDate;
 import org.opengis.metadata.citation.DateType;
 import org.apache.sis.metadata.iso.ISOMetadata;
+import org.apache.sis.metadata.TitleProperty;
 
 import static org.apache.sis.internal.metadata.MetadataUtilities.toDate;
 import static org.apache.sis.internal.metadata.MetadataUtilities.toMilliseconds;
@@ -47,6 +48,7 @@ import static org.apache.sis.internal.me
  * @module
  */
 @SuppressWarnings("CloneableClassWithoutClone")                 // ModifiableMetadata needs shallow clones.
+@TitleProperty(name = "date")
 @XmlType(name = "CI_Date_Type", propOrder = {
     "date",
     "dateType"

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureTypeInfo.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureTypeInfo.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureTypeInfo.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureTypeInfo.java [UTF-8] Sat May  6 13:00:50 2017
@@ -21,6 +21,7 @@ import javax.xml.bind.annotation.XmlRoot
 import javax.xml.bind.annotation.XmlType;
 import org.opengis.util.GenericName;
 import org.apache.sis.measure.ValueRange;
+import org.apache.sis.metadata.TitleProperty;
 import org.apache.sis.metadata.iso.ISOMetadata;
 
 import static org.apache.sis.internal.metadata.MetadataUtilities.ensurePositive;
@@ -63,6 +64,7 @@ import static org.opengis.annotation.Spe
  * @module
  */
 @SuppressWarnings("CloneableClassWithoutClone")                 // ModifiableMetadata needs shallow clones.
+@TitleProperty(name = "featureTypeName")
 @XmlType(name = "MD_FeatureTypeInfo", propOrder = {
     "featureTypeName",
     "featureInstanceCount"

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeDimension.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeDimension.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeDimension.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeDimension.java [UTF-8] Sat May  6 13:00:50 2017
@@ -28,6 +28,7 @@ import org.opengis.metadata.Identifier;
 import org.opengis.metadata.content.RangeDimension;
 import org.opengis.metadata.content.Band;
 import org.apache.sis.metadata.iso.ISOMetadata;
+import org.apache.sis.metadata.TitleProperty;
 
 import static org.opengis.annotation.Obligation.OPTIONAL;
 import static org.opengis.annotation.Specification.ISO_19115;
@@ -54,6 +55,7 @@ import static org.opengis.annotation.Spe
  * @module
  */
 @SuppressWarnings("CloneableClassWithoutClone")                 // ModifiableMetadata needs shallow clones.
+@TitleProperty(name = "sequenceIdentifier")
 @XmlType(name = "MD_RangeDimension_Type", propOrder = {
     "sequenceIdentifier",
     "descriptor",

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeElementDescription.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeElementDescription.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeElementDescription.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeElementDescription.java [UTF-8] Sat May  6 13:00:50 2017
@@ -24,6 +24,7 @@ import org.opengis.util.Record;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.content.RangeElementDescription;
 import org.apache.sis.metadata.iso.ISOMetadata;
+import org.apache.sis.metadata.TitleProperty;
 import org.apache.sis.xml.Namespaces;
 
 
@@ -46,6 +47,7 @@ import org.apache.sis.xml.Namespaces;
  * @module
  */
 @SuppressWarnings("CloneableClassWithoutClone")                 // ModifiableMetadata needs shallow clones.
+@TitleProperty(name = "name")
 @XmlType(name = "MI_RangeElementDescription_Type", propOrder = {
     "name",
     "definition"/*,

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDistribution.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDistribution.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDistribution.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDistribution.java [UTF-8] Sat May  6 13:00:50 2017
@@ -27,6 +27,7 @@ import org.opengis.metadata.distribution
 import org.opengis.metadata.distribution.Distributor;
 import org.opengis.metadata.distribution.Format;
 import org.apache.sis.metadata.iso.ISOMetadata;
+import org.apache.sis.metadata.TitleProperty;
 
 import static org.opengis.annotation.Obligation.OPTIONAL;
 import static org.opengis.annotation.Specification.ISO_19115;
@@ -52,6 +53,7 @@ import static org.opengis.annotation.Spe
  * @module
  */
 @SuppressWarnings("CloneableClassWithoutClone")                 // ModifiableMetadata needs shallow clones.
+@TitleProperty(name = "description")
 @XmlType(name = "MD_Distribution_Type", propOrder = {
     "distributionFormats",
     "distributors",

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultMedium.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultMedium.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultMedium.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultMedium.java [UTF-8] Sat May  6 13:00:50 2017
@@ -28,6 +28,7 @@ import org.opengis.metadata.distribution
 import org.opengis.metadata.distribution.MediumName;
 import org.opengis.metadata.distribution.MediumFormat;
 import org.apache.sis.measure.ValueRange;
+import org.apache.sis.metadata.TitleProperty;
 import org.apache.sis.metadata.iso.ISOMetadata;
 import org.apache.sis.internal.jaxb.NonMarshalledAuthority;
 import org.apache.sis.internal.metadata.LegacyPropertyAdapter;
@@ -59,6 +60,7 @@ import static org.opengis.annotation.Spe
  * @module
  */
 @SuppressWarnings("CloneableClassWithoutClone")                 // ModifiableMetadata needs shallow clones.
+@TitleProperty(name = "name")
 @XmlType(name = "MD_Medium_Type", propOrder = {
     "name",
     "densities",

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultExtent.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultExtent.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultExtent.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultExtent.java [UTF-8] Sat May  6 13:00:50 2017
@@ -30,6 +30,7 @@ import org.opengis.referencing.operation
 import org.opengis.util.InternationalString;
 import org.apache.sis.util.iso.Types;
 import org.apache.sis.metadata.iso.ISOMetadata;
+import org.apache.sis.metadata.TitleProperty;
 import org.apache.sis.internal.metadata.ReferencingServices;
 
 
@@ -70,6 +71,7 @@ import org.apache.sis.internal.metadata.
  * @module
  */
 @SuppressWarnings("CloneableClassWithoutClone")                 // ModifiableMetadata needs shallow clones.
+@TitleProperty(name = "description")
 @XmlType(name = "EX_Extent_Type", propOrder = {
     "description",
     "geographicElements",

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywordClass.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywordClass.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywordClass.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywordClass.java [UTF-8] Sat May  6 13:00:50 2017
@@ -23,6 +23,7 @@ import javax.xml.bind.annotation.XmlRoot
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.citation.Citation;
 import org.apache.sis.metadata.iso.ISOMetadata;
+import org.apache.sis.metadata.TitleProperty;
 import org.apache.sis.util.iso.Types;
 
 
@@ -53,6 +54,7 @@ import org.apache.sis.util.iso.Types;
  * @module
  */
 @SuppressWarnings("CloneableClassWithoutClone")                 // ModifiableMetadata needs shallow clones.
+@TitleProperty(name = "className")
 @XmlType(name = "MD_KeywordClass_Type", propOrder = {
     "className",
     "conceptIdentifier",

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationChainMetadata.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationChainMetadata.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationChainMetadata.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationChainMetadata.java [UTF-8] Sat May  6 13:00:50 2017
@@ -22,6 +22,7 @@ import javax.xml.bind.annotation.XmlElem
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.util.InternationalString;
 import org.apache.sis.metadata.iso.ISOMetadata;
+import org.apache.sis.metadata.TitleProperty;
 import org.apache.sis.util.iso.Types;
 import org.apache.sis.xml.Namespaces;
 
@@ -59,6 +60,7 @@ import static org.opengis.annotation.Spe
  * @module
  */
 @SuppressWarnings("CloneableClassWithoutClone")                 // ModifiableMetadata needs shallow clones.
+@TitleProperty(name = "name")
 @XmlType(name = "SV_OperationChainMetadata_Type", namespace = Namespaces.SRV, propOrder = {
     "name",
     "description",

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationMetadata.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationMetadata.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationMetadata.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationMetadata.java [UTF-8] Sat May  6 13:00:50 2017
@@ -24,6 +24,7 @@ import javax.xml.bind.annotation.XmlRoot
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 import org.opengis.util.InternationalString;
 import org.apache.sis.metadata.iso.ISOMetadata;
+import org.apache.sis.metadata.TitleProperty;
 import org.opengis.metadata.citation.OnlineResource;
 import org.opengis.parameter.ParameterDescriptor;
 import org.apache.sis.xml.Namespaces;
@@ -64,6 +65,7 @@ import static org.opengis.annotation.Spe
  * @module
  */
 @SuppressWarnings("CloneableClassWithoutClone")                 // ModifiableMetadata needs shallow clones.
+@TitleProperty(name = "operationName")
 @XmlType(name = "SV_OperationMetadata_Type", namespace = Namespaces.SRV, propOrder = {
     "operationName",
     "distributedComputingPlatforms",

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultUsage.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultUsage.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultUsage.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultUsage.java [UTF-8] Sat May  6 13:00:50 2017
@@ -27,6 +27,7 @@ import org.opengis.metadata.citation.Cit
 import org.opengis.metadata.citation.ResponsibleParty;
 import org.opengis.metadata.identification.Usage;
 import org.apache.sis.metadata.iso.ISOMetadata;
+import org.apache.sis.metadata.TitleProperty;
 import org.apache.sis.util.iso.Types;
 
 import static org.opengis.annotation.Obligation.OPTIONAL;
@@ -56,6 +57,7 @@ import static org.apache.sis.internal.me
  * @module
  */
 @SuppressWarnings("CloneableClassWithoutClone")                 // ModifiableMetadata needs shallow clones.
+@TitleProperty(name = "specificUsage")
 @XmlType(name = "MD_Usage_Type", propOrder = {
     "specificUsage",
     "usageDate",

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessStep.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessStep.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessStep.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessStep.java [UTF-8] Sat May  6 13:00:50 2017
@@ -32,6 +32,7 @@ import org.opengis.metadata.lineage.Proc
 import org.opengis.metadata.lineage.ProcessStep;
 import org.opengis.metadata.lineage.ProcessStepReport;
 import org.apache.sis.metadata.iso.ISOMetadata;
+import org.apache.sis.metadata.TitleProperty;
 import org.apache.sis.util.iso.Types;
 import org.apache.sis.xml.Namespaces;
 
@@ -63,6 +64,7 @@ import static org.apache.sis.internal.me
  * @module
  */
 @SuppressWarnings("CloneableClassWithoutClone")                 // ModifiableMetadata needs shallow clones.
+@TitleProperty(name = "description")
 @XmlType(name = "LI_ProcessStep_Type", propOrder = {
     "description",
     "rationale",

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessStepReport.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessStepReport.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessStepReport.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessStepReport.java [UTF-8] Sat May  6 13:00:50 2017
@@ -22,6 +22,7 @@ import javax.xml.bind.annotation.XmlType
 import org.opengis.metadata.lineage.ProcessStepReport;
 import org.opengis.util.InternationalString;
 import org.apache.sis.metadata.iso.ISOMetadata;
+import org.apache.sis.metadata.TitleProperty;
 import org.apache.sis.xml.Namespaces;
 
 
@@ -45,6 +46,7 @@ import org.apache.sis.xml.Namespaces;
  * @module
  */
 @SuppressWarnings("CloneableClassWithoutClone")                 // ModifiableMetadata needs shallow clones.
+@TitleProperty(name = "name")
 @XmlType(name = "LE_ProcessStepReport_Type", propOrder = {
     "name",
     "description",

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultSource.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultSource.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultSource.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultSource.java [UTF-8] Sat May  6 13:00:50 2017
@@ -34,6 +34,7 @@ import org.opengis.metadata.identificati
 import org.opengis.metadata.identification.RepresentativeFraction;
 import org.opengis.metadata.quality.Scope;
 import org.opengis.referencing.ReferenceSystem;
+import org.apache.sis.metadata.TitleProperty;
 import org.apache.sis.metadata.iso.ISOMetadata;
 import org.apache.sis.metadata.iso.maintenance.DefaultScope;
 import org.apache.sis.metadata.iso.identification.DefaultResolution;
@@ -70,6 +71,7 @@ import static org.opengis.annotation.Spe
  * @module
  */
 @SuppressWarnings("CloneableClassWithoutClone")                 // ModifiableMetadata needs shallow clones.
+@TitleProperty(name = "description")
 @XmlType(name = "LI_Source_Type", propOrder = {
     "description",
     "scaleDenominator",

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultDimension.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultDimension.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultDimension.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultDimension.java [UTF-8] Sat May  6 13:00:50 2017
@@ -26,6 +26,7 @@ import org.opengis.metadata.spatial.Dime
 import org.opengis.metadata.spatial.DimensionNameType;
 import org.apache.sis.internal.jaxb.gco.GO_Measure;
 import org.apache.sis.metadata.iso.ISOMetadata;
+import org.apache.sis.metadata.TitleProperty;
 import org.apache.sis.measure.ValueRange;
 import org.apache.sis.util.ArgumentChecks;
 
@@ -57,6 +58,7 @@ import static org.opengis.annotation.Spe
  * @module
  */
 @SuppressWarnings("CloneableClassWithoutClone")                 // ModifiableMetadata needs shallow clones.
+@TitleProperty(name = "dimensionName")
 @XmlType(name = "MD_Dimension_Type", propOrder = {
     "dimensionName",
     "dimensionSize",

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCPCollection.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCPCollection.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCPCollection.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCPCollection.java [UTF-8] Sat May  6 13:00:50 2017
@@ -24,6 +24,7 @@ import org.opengis.metadata.spatial.GCP;
 import org.opengis.metadata.spatial.GCPCollection;
 import org.opengis.referencing.ReferenceSystem;
 import org.opengis.util.InternationalString;
+import org.apache.sis.metadata.TitleProperty;
 import org.apache.sis.xml.Namespaces;
 
 
@@ -46,6 +47,7 @@ import org.apache.sis.xml.Namespaces;
  * @module
  */
 @SuppressWarnings("CloneableClassWithoutClone")                 // ModifiableMetadata needs shallow clones.
+@TitleProperty(name = "collectionName")
 @XmlType(name = "MI_GCPCollection_Type", propOrder = {
     "collectionIdentification",
     "collectionName",

Modified: sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTestCase.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTestCase.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTestCase.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTestCase.java [UTF-8] Sat May  6 13:00:50 2017
@@ -45,7 +45,7 @@ import static org.opengis.test.Assert.*;
  * </ul>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.5
+ * @version 0.8
  * @since   0.3
  * @module
  */
@@ -314,4 +314,37 @@ public abstract strictfp class MetadataT
               (implementation == org.apache.sis.metadata.iso.citation.DefaultResponsibleParty.class &&
                method.equals("getParties"));
     }
+
+    /**
+     * Verifies the {@link TitleProperty} annotations. This method verifies that the property exist,
+     * is a singleton, and is not another metadata object. The property should also be mandatory,
+     * but this method does not verify that restriction since there is some exceptions.
+     *
+     * @since 0.8
+     */
+    @Test
+    public void testTitlePropertyAnnotation() {
+        for (final Class<?> type : types) {
+            final Class<?> impl = standard.getImplementation(type);
+            if (impl != null) {
+                final TitleProperty an = impl.getAnnotation(TitleProperty.class);
+                if (an != null) {
+                    final String name = an.name();
+                    final String message = impl.getSimpleName() + '.' + name;
+                    final PropertyAccessor accessor = new PropertyAccessor(standard.getCitation(), type, impl, impl);
+
+                    // Property shall exist.
+                    final int index = accessor.indexOf(name, false);
+                    assertTrue(message, index >= 0);
+
+                    // Property can not be a metadata.
+                    final Class<?> elementType = accessor.type(index, TypeValuePolicy.ELEMENT_TYPE);
+                    assertFalse(message, standard.isMetadata(elementType));
+
+                    // Property shall be a singleton.
+                    assertSame(message, elementType, accessor.type(index, TypeValuePolicy.PROPERTY_TYPE));
+                }
+            }
+        }
+    }
 }

Modified: sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeChildrenTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeChildrenTest.java?rev=1794138&r1=1794137&r2=1794138&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeChildrenTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeChildrenTest.java [UTF-8] Sat May  6 13:00:50 2017
@@ -16,24 +16,27 @@
  */
 package org.apache.sis.metadata;
 
+import java.util.Date;
 import java.util.Random;
 import java.util.Iterator;
 import java.util.List;
 import java.util.ArrayList;
-import org.opengis.metadata.Metadata;
+import org.opengis.metadata.citation.Citation;
+import org.opengis.metadata.citation.DateType;
 import org.opengis.metadata.citation.PresentationForm;
 import org.apache.sis.metadata.iso.citation.DefaultCitation;
+import org.apache.sis.metadata.iso.citation.DefaultCitationDate;
 import org.apache.sis.util.iso.SimpleInternationalString;
 import org.apache.sis.util.collection.DefaultTreeTable;
 import org.apache.sis.util.collection.TableColumn;
 import org.apache.sis.util.collection.TreeTable;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
+import org.apache.sis.test.TestUtilities;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
 import static org.junit.Assert.*;
-import static org.apache.sis.test.TestUtilities.createRandomNumberGenerator;
 
 
 /**
@@ -113,14 +116,42 @@ public final strictfp class TreeNodeChil
     }
 
     /**
+     * Creates a metadata object with a property than can be simplified.
+     * Strictly speaking, the metadata is:
+     *
+     * {@preformat text
+     *   DefaultCitation
+     *     └─Date
+     *        ├─Date………………… 2012-01-01
+     *        └─Date type…… Creation
+     * }
+     *
+     * However the tree view should simplify as:
+     *
+     * {@preformat text
+     *   DefaultCitation
+     *     └─Date………………………… 2012-01-01
+     *        └─Date type…… Creation
+     * }
+     *
+     * @see <a href="https://issues.apache.org/jira/browse/SIS-298">SIS-298</a>
+     */
+    static DefaultCitation metadataSimplifiable() {
+        final DefaultCitation citation = new DefaultCitation();
+        final DefaultCitationDate date = new DefaultCitationDate(TestUtilities.date("2012-01-01 00:00:00"), DateType.CREATION);
+        assertTrue(citation.getDates().add(date));
+        return citation;
+    }
+
+    /**
      * Creates a collection to be tested for the given metadata object and value policy.
      */
-    private static TreeNodeChildren create(final AbstractMetadata metadata, final ValueExistencePolicy valuePolicy) {
+    private static TreeNodeChildren create(final DefaultCitation citation, final ValueExistencePolicy valuePolicy) {
         final MetadataStandard standard = MetadataStandard.ISO_19115;
-        final TreeTableView    table    = new TreeTableView(standard, metadata, Metadata.class, valuePolicy);
+        final TreeTableView    table    = new TreeTableView(standard, citation, Citation.class, valuePolicy);
         final TreeNode         node     = (TreeNode) table.getRoot();
-        final PropertyAccessor accessor = standard.getAccessor(new CacheKey(metadata.getClass()), true);
-        return new TreeNodeChildren(node, metadata, accessor);
+        final PropertyAccessor accessor = standard.getAccessor(new CacheKey(citation.getClass()), true);
+        return new TreeNodeChildren(node, citation, accessor);
     }
 
     /**
@@ -135,6 +166,7 @@ public final strictfp class TreeNodeChil
             "Some edition",
             "Some other details"
         };
+        assertEquals("titleProperty", -1, children.titleProperty);
         assertFalse ("isEmpty()", children.isEmpty());
         assertEquals("size()", expected.length, children.size());
         assertAllNextEqual(expected, children.iterator());
@@ -156,6 +188,7 @@ public final strictfp class TreeNodeChil
             "PresentationForm[MAP_DIGITAL]",
             "Some other details"
         };
+        assertEquals("titleProperty", -1, children.titleProperty);
         assertFalse ("isEmpty()", children.isEmpty());
         assertEquals("size()", expected.length, children.size());
         assertAllNextEqual(expected, children.iterator());
@@ -179,6 +212,35 @@ public final strictfp class TreeNodeChil
             "PresentationForm[MAP_HARDCOPY]",
             "Some other details"
         };
+        assertEquals("titleProperty", -1, children.titleProperty);
+        assertFalse ("isEmpty()", children.isEmpty());
+        assertEquals("size()", expected.length, children.size());
+        assertAllNextEqual(expected, children.iterator());
+    }
+
+    /**
+     * Tests a metadata than can be simplified by displaying a child property value directly as the parent value.
+     */
+    @Test
+    @DependsOnMethod("testReadOnlyWithoutCollections")
+    public void testSimplifiable() {
+        final DefaultCitation  citation = metadataSimplifiable();
+        /*
+         *   DefaultCitation
+         *     └─Date
+         *        ├─Date………………… 2012-01-01
+         *        └─Date type…… Creation
+         *
+         * We need to perform the tests on the "Date" node, not on the "DefaultCitation" node.
+         */
+        final TreeTable.Node node = TestUtilities.getSingleton(create(citation, ValueExistencePolicy.COMPACT));
+        assertEquals("value", 1325376000000L, ((Date) node.getValue(TableColumn.VALUE)).getTime());
+        final TreeNodeChildren children = (TreeNodeChildren) node.getChildren();
+        final String[] expected = {
+            // The "Date" node should be omitted because merged with the parent "Date" node.
+            "DateType[CREATION]"
+        };
+        assertEquals("titleProperty", 0, children.titleProperty);
         assertFalse ("isEmpty()", children.isEmpty());
         assertEquals("size()", expected.length, children.size());
         assertAllNextEqual(expected, children.iterator());
@@ -192,6 +254,8 @@ public final strictfp class TreeNodeChil
     public void testAdd() {
         final DefaultCitation  citation = metadataWithMultiOccurrences();
         final TreeNodeChildren children = create(citation, ValueExistencePolicy.NON_EMPTY);
+        assertEquals("titleProperty", -1, children.titleProperty);
+
         final DefaultTreeTable.Node toAdd = new DefaultTreeTable.Node(new DefaultTreeTable(
                 TableColumn.IDENTIFIER,
                 TableColumn.VALUE));
@@ -241,7 +305,8 @@ public final strictfp class TreeNodeChil
     public void testRemoveWithoutCollections() {
         final DefaultCitation  citation = metadataWithoutCollections();
         final TreeNodeChildren children = create(citation, ValueExistencePolicy.NON_EMPTY);
-        testRemove(createRandomNumberGenerator(), children);
+        assertEquals("titleProperty", -1, children.titleProperty);
+        testRemove(TestUtilities.createRandomNumberGenerator(), children);
     }
 
     /**
@@ -256,7 +321,8 @@ public final strictfp class TreeNodeChil
     public void testRemoveWithSingletonInCollections() {
         final DefaultCitation  citation = metadataWithSingletonInCollections();
         final TreeNodeChildren children = create(citation, ValueExistencePolicy.NON_EMPTY);
-        testRemove(createRandomNumberGenerator(), children);
+        assertEquals("titleProperty", -1, children.titleProperty);
+        testRemove(TestUtilities.createRandomNumberGenerator(), children);
     }
 
     /**
@@ -271,7 +337,8 @@ public final strictfp class TreeNodeChil
     public void testRemoveWithMultiOccurrences() {
         final DefaultCitation  citation = metadataWithSingletonInCollections();
         final TreeNodeChildren children = create(citation, ValueExistencePolicy.NON_EMPTY);
-        testRemove(createRandomNumberGenerator(), children);
+        assertEquals("titleProperty", -1, children.titleProperty);
+        testRemove(TestUtilities.createRandomNumberGenerator(), children);
     }
 
     /**
@@ -281,9 +348,10 @@ public final strictfp class TreeNodeChil
     public void testClear() {
         final DefaultCitation  citation = metadataWithSingletonInCollections();
         final TreeNodeChildren children = create(citation, ValueExistencePolicy.NON_EMPTY);
-        assertFalse(children.isEmpty());
+        assertEquals("titleProperty", -1, children.titleProperty);
+        assertFalse("isEmpty()", children.isEmpty());
         children.clear();
-        assertTrue(children.isEmpty());
+        assertTrue("isEmpty()", children.isEmpty());
         assertNull(citation.getTitle());
         assertTrue(citation.getAlternateTitles().isEmpty());
     }
@@ -315,6 +383,7 @@ public final strictfp class TreeNodeChil
             null, // onlineResources (collection)
             null  // graphics (collection)
         };
+        assertEquals("titleProperty", -1, children.titleProperty);
         assertFalse ("isEmpty()", children.isEmpty());
         assertEquals("size()", expected.length, children.size());
         assertAllNextEqual(expected, children.iterator());



Mime
View raw message