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
The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
new 16c01f5cdf Add a mechanism for letting `MetadataStandard` know that
the `Datum` interface implemented by `DefaultDatumEnsemble` should be ignored.
16c01f5cdf is described below
commit 16c01f5cdf40fe415196d5bd7d6d84db440c42fe
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Fri Jul 11 18:03:29 2025 +0200
Add a mechanism for letting `MetadataStandard` know that the `Datum`
interface implemented by `DefaultDatumEnsemble` should be ignored.
---
.../org/apache/sis/metadata/MetadataStandard.java | 67 +++++++++++-----------
.../org/apache/sis/metadata/PropertyAccessor.java | 4 +-
.../sis/metadata/StandardImplementation.java | 3 +-
.../main/org/apache/sis/metadata/TreeNode.java | 2 +-
.../org/apache/sis/metadata/TreeNodeChildren.java | 2 +-
.../apache/sis/metadata/internal/ExcludedSet.java | 6 +-
.../apache/sis/metadata/privy/SecondaryTrait.java | 45 +++++++++++++++
.../referencing/datum/DefaultDatumEnsemble.java | 2 +
.../sis/util/privy/UnmodifiableArrayList.java | 2 +-
9 files changed, 91 insertions(+), 42 deletions(-)
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 91eb62040e..6027ca5296 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
@@ -18,8 +18,7 @@ package org.apache.sis.metadata;
import java.util.Set;
import java.util.Map;
-import java.util.LinkedHashSet;
-import java.util.Collection;
+import java.util.LinkedHashMap;
import java.util.Iterator;
import java.util.Objects;
import java.util.concurrent.ConcurrentMap;
@@ -27,6 +26,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.io.IOException;
import java.io.Serializable;
import java.io.ObjectInputStream;
+import org.apache.sis.metadata.privy.SecondaryTrait;
import org.opengis.metadata.Identifier;
import org.opengis.metadata.ExtendedElementInformation;
import org.opengis.metadata.citation.Citation;
@@ -494,21 +494,29 @@ public class MetadataStandard implements Serializable {
}
} else {
/*
- * Gets every interfaces from the supplied class in declaration
order,
- * including the ones declared in the super-class.
+ * Get every interfaces from the supplied class in declaration
order,
+ * including the ones declared in the super-class. The Boolean
value
+ * tells whether the type is supported. Types associated to `FALSE`
+ * shall be ignored.
*/
- final Set<Class<?>> interfaces = new LinkedHashSet<>();
+ final var validities = new LinkedHashMap<Class<?>, Boolean>();
+ final SecondaryTrait ignore =
key.type.getAnnotation(SecondaryTrait.class);
+ if (ignore != null) {
+ validities.put(ignore.value(), Boolean.FALSE);
+ }
for (Class<?> t=key.type; t!=null; t=t.getSuperclass()) {
- getInterfaces(t, key.propertyType, interfaces);
+ getInterfaces(t, key.propertyType, validities);
}
/*
- * If we found more than one interface, removes the
- * ones that are sub-interfaces of the other.
+ * Remove all unsupported types. Then, if we found more than one
supported
+ * interface, remove the ones that are sub-interfaces of the other.
*/
+ validities.values().removeIf((isSupported) -> !isSupported);
+ final Set<Class<?>> interfaces = validities.keySet();
for (final Iterator<Class<?>> it=interfaces.iterator();
it.hasNext();) {
final Class<?> candidate = it.next();
- for (final Class<?> child : interfaces) {
- if (candidate != child &&
candidate.isAssignableFrom(child)) {
+ for (final Class<?> other : interfaces) {
+ if (candidate != other &&
candidate.isAssignableFrom(other)) {
it.remove();
break;
}
@@ -522,7 +530,7 @@ public class MetadataStandard implements Serializable {
}
/*
* Found more than one interface; we don't know which one to
pick.
- * Returns `null` for now; the caller will thrown an exception.
+ * Returns `null` for now; the caller will throw an exception.
*/
} else if (IMPLEMENTATION_CAN_ALTER_API) {
/*
@@ -543,8 +551,9 @@ public class MetadataStandard implements Serializable {
}
/**
- * Puts every interfaces for the given type in the specified collection.
+ * Puts every interfaces for the given type in the specified map.
* This method invokes itself recursively for scanning parent interfaces.
+ * The keys tell whether the interface is supported. validities
*
* <p>If the given class is the return value of a property, then the type
of that property should be specified
* in the {@code propertyType} argument. This information allows this
method to take in account only the types
@@ -554,14 +563,10 @@ public class MetadataStandard implements Serializable {
*
* @see Classes#getAllInterfaces(Class)
*/
- private void getInterfaces(final Class<?> type, final Class<?>
propertyType, final Collection<Class<?>> interfaces) {
+ private void getInterfaces(final Class<?> type, final Class<?>
propertyType, final Map<Class<?>, Boolean> validities) {
for (final Class<?> candidate : type.getInterfaces()) {
- if (propertyType.isAssignableFrom(candidate)) {
- if (isSupported(candidate.getName())) {
- interfaces.add(candidate);
- }
- getInterfaces(candidate, propertyType, interfaces);
- } else if (IMPLEMENTATION_CAN_ALTER_API) {
+ final boolean recursive = propertyType.isAssignableFrom(candidate);
+ if (recursive || (IMPLEMENTATION_CAN_ALTER_API &&
isPendingAPI(propertyType))) {
/*
* If a GeoAPI interface is not assignable to the property
type, maybe it is because the property type
* did not existed at the time current GeoAPI version was
published. In such case, the implementation
@@ -569,11 +574,8 @@ public class MetadataStandard implements Serializable {
* we skip the `isAssignableFrom` check, but without recursive
addition of parent interfaces since we
* would not know when to stop.
*/
- if (isPendingAPI(propertyType)) {
- if (isSupported(candidate.getName())) {
- interfaces.add(candidate);
- }
- // No recursive call here.
+ if (validities.putIfAbsent(candidate,
isSupported(candidate.getName())) == null && recursive) {
+ getInterfaces(candidate, propertyType, validities);
}
}
}
@@ -1062,14 +1064,15 @@ public class MetadataStandard implements Serializable {
return false;
}
final PropertyAccessor accessor = getAccessor(new CacheKey(type1),
true);
- if (type1 != type2 && (!accessor.type.isAssignableFrom(type2)
- || accessor.type != getAccessor(new CacheKey(type2),
false).type))
- {
- /*
- * Note: the check for (accessor.type != getAccessor(…).type)
would have been enough, but checking
- * for isAssignableFrom(…) first can avoid the (relatively costly)
creation of new PropertyAccessor.
- */
- return false;
+ if (type1 != type2) {
+ // Not strictly necessary, but can avoid the relatively costly
creation of new `PropertyAccessor`.
+ if (!accessor.type.isAssignableFrom(type2)) {
+ return false;
+ }
+ // The real condition.
+ if (accessor.type != getAccessor(new CacheKey(type2), false).type)
{
+ return false;
+ }
}
/*
* At this point, we have to perform the actual property-by-property
comparison.
diff --git
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/PropertyAccessor.java
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/PropertyAccessor.java
index 45382ab1a4..9b698f9533 100644
---
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/PropertyAccessor.java
+++
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/PropertyAccessor.java
@@ -287,7 +287,7 @@ class PropertyAccessor {
final int lo = name.codePointAt(base);
final int up = Character.toUpperCase(lo);
final int length = name.length();
- final StringBuilder buffer = new StringBuilder(length - base +
5).append(SET);
+ final var buffer = new StringBuilder(length - base +
5).append(SET);
if (lo != up) {
buffer.appendCodePoint(up).append(name, base +
Character.charCount(lo), length);
} else {
@@ -1319,7 +1319,7 @@ class PropertyAccessor {
*/
@Override
public String toString() {
- final StringBuilder buffer = new StringBuilder(60);
+ final var buffer = new StringBuilder(60);
buffer.append("PropertyAccessor[").append(standardCount).append("
getters");
final int extra = allCount - standardCount;
if (extra != 0) {
diff --git
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/StandardImplementation.java
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/StandardImplementation.java
index f60fd511ab..68acb877f5 100644
---
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/StandardImplementation.java
+++
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/StandardImplementation.java
@@ -20,7 +20,6 @@ import java.util.Map;
import java.util.IdentityHashMap;
import java.util.logging.Logger;
import java.io.ObjectStreamException;
-import java.util.concurrent.ConcurrentHashMap;
import org.opengis.annotation.UML;
import org.apache.sis.util.CharSequences;
import org.apache.sis.util.logging.Logging;
@@ -186,7 +185,7 @@ final class StandardImplementation extends MetadataStandard
{
* newer version of the Apache SIS library. The newer version could
contain constants
* not yet declared in this older SIS version, so we have to use this
instance.
*/
- implementations = new ConcurrentHashMap<>();
+ implementations = new IdentityHashMap<>();
return this;
}
}
diff --git
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/TreeNode.java
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/TreeNode.java
index 1f40818f3b..051be71fe1 100644
---
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/TreeNode.java
+++
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/TreeNode.java
@@ -1077,7 +1077,7 @@ class TreeNode implements Node {
*/
@Override
public final String toString() {
- final StringBuilder buffer = new StringBuilder(60);
+ final var buffer = new StringBuilder(60);
appendStringTo(buffer);
return buffer.toString();
}
diff --git
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/TreeNodeChildren.java
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/TreeNodeChildren.java
index 1be21c0771..d3b480119a 100644
---
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/TreeNodeChildren.java
+++
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/TreeNodeChildren.java
@@ -607,7 +607,7 @@ final class TreeNodeChildren extends
AbstractCollection<TreeTable.Node> {
return false;
}
// Conversion attempt happen in the PropertyAccessor.set(…) method.
- final Boolean changed = (Boolean) accessor.set(index, metadata, value,
PropertyAccessor.APPEND);
+ final var changed = (Boolean) accessor.set(index, metadata, value,
PropertyAccessor.APPEND);
if (changed == null) {
throw new
IllegalStateException(Errors.format(Errors.Keys.ValueAlreadyDefined_1,
accessor.name(index, KeyNamePolicy.UML_IDENTIFIER)));
diff --git
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/internal/ExcludedSet.java
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/internal/ExcludedSet.java
index c23df8037a..12b9eeafe1 100644
---
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/internal/ExcludedSet.java
+++
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/internal/ExcludedSet.java
@@ -24,9 +24,9 @@ import org.apache.sis.util.resources.Errors;
/**
- * A unmodifiable empty set with a customized exception message thrown by the
{@link #add(Object)}
- * method. This set is used only for mutually exclusive properties, when a
collection cannot have
- * elements because the other property is set.
+ * A unmodifiable empty set with a customized exception message thrown by the
{@link #add(Object)} method.
+ * This set is used only for mutually exclusive properties, when a collection
cannot have elements because
+ * the other property is set.
*
* @author Martin Desruisseaux (Geomatys)
*
diff --git
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/privy/SecondaryTrait.java
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/privy/SecondaryTrait.java
new file mode 100644
index 0000000000..8c267dd9e3
--- /dev/null
+++
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/privy/SecondaryTrait.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.metadata.privy;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+
+/**
+ * Indicates that an interface implemented by a class is considered less
significant compared to the primary interface.
+ * This annotation is used when a class implements two or more interfaces, but
some of those interfaces can be ignored.
+ * This information is needed for identifying the main interface in metadata.
+ *
+ * <h2>Design note</h2>
+ * {@link ElementType#TYPE_USE} would be more appropriate. However, in the way
that the metadata module currently uses
+ * this interface, an annotation on the class is more convenient (more
straightforward code).
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface SecondaryTrait {
+ /**
+ * The interface which is less significant compared to the primary
interface.
+ *
+ * @return the less significant interface.
+ */
+ Class<?> value();
+}
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DefaultDatumEnsemble.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DefaultDatumEnsemble.java
index 8920687048..1e831e468d 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DefaultDatumEnsemble.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DefaultDatumEnsemble.java
@@ -45,6 +45,7 @@ import org.apache.sis.referencing.GeodeticException;
import org.apache.sis.referencing.IdentifiedObjects;
import org.apache.sis.referencing.internal.Resources;
import org.apache.sis.referencing.privy.WKTKeywords;
+import org.apache.sis.metadata.privy.SecondaryTrait;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.ComparisonMode;
import org.apache.sis.util.Utilities;
@@ -82,6 +83,7 @@ import org.opengis.referencing.datum.RealizationMethod;
*
* @since 1.5
*/
+@SecondaryTrait(Datum.class)
public class DefaultDatumEnsemble<D extends Datum> extends
AbstractIdentifiedObject implements DatumEnsemble<D>, Datum {
/**
* Serial number for inter-operability with different versions.
diff --git
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/privy/UnmodifiableArrayList.java
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/privy/UnmodifiableArrayList.java
index be13369e4e..5bc007c279 100644
---
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/privy/UnmodifiableArrayList.java
+++
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/privy/UnmodifiableArrayList.java
@@ -398,7 +398,7 @@ public class UnmodifiableArrayList<E> extends
AbstractList<E> implements RandomA
/*
* We are cheating here since the array component may not be
assignable to T.
* But if this assumption is wrong, then the call to
System.arraycopy(…) later
- * will thrown an ArrayStoreException, which is the exception
type required by
+ * will throw an ArrayStoreException, which is the exception
type required by
* the Collection.toArray(T[]) javadoc.
*/
dest = (T[])
Array.newInstance(dest.getClass().getComponentType(), size);