This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
commit 26a0f263d22459f766629a67e3c382a37dfe5868 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Mon May 1 13:38:39 2023 +0200 Implement the `getResourceClass()` method added in `Filter` and `Expression` interfaces. That method make possible to determine whether some optimizations are allowed or not. --- .../org/apache/sis/feature/FeatureOperations.java | 2 +- .../org/apache/sis/filter/AssociationValue.java | 10 +++++++++- .../java/org/apache/sis/filter/BinaryFunction.java | 11 +++++++++++ .../apache/sis/filter/BinaryGeometryFilter.java | 11 +++++++++++ .../org/apache/sis/filter/ComparisonFilter.java | 6 ++++++ .../apache/sis/filter/DefaultFilterFactory.java | 4 ++-- .../java/org/apache/sis/filter/FilterNode.java | 13 +++++++++++-- .../org/apache/sis/filter/IdentifierFilter.java | 19 ++++++++++++------- .../java/org/apache/sis/filter/LikeFilter.java | 8 ++++++++ .../java/org/apache/sis/filter/LogicalFilter.java | 17 +++++++++++++++++ .../java/org/apache/sis/filter/Optimization.java | 8 ++++---- .../java/org/apache/sis/filter/PropertyValue.java | 12 ++++++++++-- .../java/org/apache/sis/filter/UnaryFunction.java | 10 ++++++++++ .../sis/internal/coverage/j2d/ObservableImage.java | 2 +- .../sis/internal/filter/GeometryConverter.java | 8 ++++++++ .../java/org/apache/sis/internal/filter/Node.java | 22 +++++++++++++++++++++- .../internal/filter/sqlmm/FunctionWithSRID.java | 9 +++++++++ .../internal/filter/sqlmm/GeometryConstructor.java | 8 ++++++++ .../sis/internal/filter/sqlmm/OneGeometry.java | 18 +++++++++++++++++- .../apache/sis/internal/filter/sqlmm/ST_Point.java | 12 ++++++++++++ .../sis/internal/filter/sqlmm/ST_Transform.java | 8 ++++++++ .../sis/internal/filter/sqlmm/TwoGeometries.java | 16 ++++++++++++++++ .../apache/sis/filter/IdentifierFilterTest.java | 4 +++- .../org/apache/sis/filter/LeafExpressionTest.java | 3 ++- .../apache/sis/internal/filter/FunctionMock.java | 8 ++++++++ .../sis/internal/filter/FunctionNamesTest.java | 2 ++ .../sis/internal/filter/ValueReferenceMock.java | 8 ++++++++ 27 files changed, 235 insertions(+), 24 deletions(-) diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureOperations.java b/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureOperations.java index b9ab137a05..b4ab1692d0 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureOperations.java +++ b/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureOperations.java @@ -290,7 +290,7 @@ public final class FeatureOperations extends Static { /** * Creates an operation which delegates the computation to a given expression producing values of unknown type. * This method can be used as an alternative to {@link #expression expression(…)} when the constraint on the - * parameterized type {@code <V>} between {@code expression} and {@code result} can not be enforced at compile time. + * parameterized type {@code <V>} between {@code expression} and {@code result} cannot be enforced at compile time. * This method casts or converts the expression to the expected type by a call to * {@link Expression#toValueType(Class)}. * diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/AssociationValue.java b/core/sis-feature/src/main/java/org/apache/sis/filter/AssociationValue.java index 16d967535c..c8d714b8d5 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/filter/AssociationValue.java +++ b/core/sis-feature/src/main/java/org/apache/sis/filter/AssociationValue.java @@ -42,7 +42,7 @@ import org.opengis.filter.ValueReference; * (the tip) is evaluated by a {@link PropertyValue}. * * @author Martin Desruisseaux (Geomatys) - * @version 1.2 + * @version 1.4 * * @param <V> the type of value computed by the expression. * @@ -94,6 +94,14 @@ final class AssociationValue<V> extends LeafExpression<Feature, V> this.accessor = accessor; } + /** + * Returns the class of resources expected by this expression. + */ + @Override + public final Class<Feature> getResourceClass() { + return Feature.class; + } + /** * For {@link #toString()} implementation. */ diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/BinaryFunction.java b/core/sis-feature/src/main/java/org/apache/sis/filter/BinaryFunction.java index b7c33e33a2..a149e05cf9 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/filter/BinaryFunction.java +++ b/core/sis-feature/src/main/java/org/apache/sis/filter/BinaryFunction.java @@ -84,6 +84,17 @@ abstract class BinaryFunction<R,V1,V2> extends Node { this.expression2 = expression2; } + /** + * Returns the class of resources expected by this filter. + * Defined for {@link Filter#getResourceClass()} and {@link Expression#getResourceClass()} implementations. + * + * @return type of resources accepted by this filter, or {@code null} if inconsistent. + */ + public final Class<? super R> getResourceClass() { + return specializedClass(expression1.getResourceClass(), + expression2.getResourceClass()); + } + /** * Returns the expressions used as parameters by this function. * Defined for {@link Expression#getParameters()} implementations. diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/BinaryGeometryFilter.java b/core/sis-feature/src/main/java/org/apache/sis/filter/BinaryGeometryFilter.java index f668f78886..8b62b37a7f 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/filter/BinaryGeometryFilter.java +++ b/core/sis-feature/src/main/java/org/apache/sis/filter/BinaryGeometryFilter.java @@ -164,6 +164,17 @@ abstract class BinaryGeometryFilter<R,G> extends FilterNode<R> implements Spatia return unwrapped; } + /** + * Returns the class of resources expected by this filter. + * + * @return type of resources accepted by this filter, or {@code null} if inconsistent. + */ + @Override + public final Class<? super R> getResourceClass() { + return specializedClass(expression1.getResourceClass(), + expression2.getResourceClass()); + } + /** * Returns the two expressions used as parameters by this filter. */ diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/ComparisonFilter.java b/core/sis-feature/src/main/java/org/apache/sis/filter/ComparisonFilter.java index 1853662fe7..791e545b61 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/filter/ComparisonFilter.java +++ b/core/sis-feature/src/main/java/org/apache/sis/filter/ComparisonFilter.java @@ -812,6 +812,12 @@ abstract class ComparisonFilter<R> extends BinaryFunction<R,Object,Object> this.upper = new LessThanOrEqualTo<>(expression, upper, true, MatchAction.ANY); } + /** Returns the class of resources expected by this filter. */ + @Override public final Class<? super R> getResourceClass() { + return specializedClass(lower.getResourceClass(), + upper.getResourceClass()); + } + /** * Returns the 3 children of this node. Since {@code lower.expression2} * is the same as {@code upper.expression1}, that repetition is omitted. diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/DefaultFilterFactory.java b/core/sis-feature/src/main/java/org/apache/sis/filter/DefaultFilterFactory.java index 5f381105b0..7d56e36cc1 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/filter/DefaultFilterFactory.java +++ b/core/sis-feature/src/main/java/org/apache/sis/filter/DefaultFilterFactory.java @@ -186,7 +186,7 @@ public abstract class DefaultFilterFactory<R,G,T> extends AbstractFactory implem */ @Override public ResourceId<Feature> resourceId(final String identifier) { - return new IdentifierFilter<>(identifier); + return new IdentifierFilter(identifier); } /** @@ -207,7 +207,7 @@ public abstract class DefaultFilterFactory<R,G,T> extends AbstractFactory implem public ResourceId<Feature> resourceId(final String identifier, final Version version, final Instant startTime, final Instant endTime) { - return new IdentifierFilter<>(identifier); + return new IdentifierFilter(identifier); } /** diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/FilterNode.java b/core/sis-feature/src/main/java/org/apache/sis/filter/FilterNode.java index d5a8c25b85..d35ad68a46 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/filter/FilterNode.java +++ b/core/sis-feature/src/main/java/org/apache/sis/filter/FilterNode.java @@ -58,10 +58,19 @@ abstract class FilterNode<R> extends Node implements Filter<R> { * @param <R> desired parameterized type. * @param template the filter from which to get the runtime value of {@code <R>}. * @param other the predicate to cast to a filter compatible with the target. - * @return the casted predicate, or {@code null} if it can not be casted. + * @return the casted predicate, or {@code null} if it cannot be casted. */ + @SuppressWarnings("unchecked") static <R> Filter<R> castOrNull(final Filter<R> template, final Predicate<? super R> other) { - // TODO + if (other instanceof Filter<?>) { + final Class<?> type = template.getResourceClass(); + if (type != null) { + final Class<?> to = ((Filter<?>) other).getResourceClass(); + if (to != null && type.isAssignableFrom(to)) { + return (Filter<R>) other; + } + } + } return null; } diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/IdentifierFilter.java b/core/sis-feature/src/main/java/org/apache/sis/filter/IdentifierFilter.java index fbfe274224..3e2ec855a0 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/filter/IdentifierFilter.java +++ b/core/sis-feature/src/main/java/org/apache/sis/filter/IdentifierFilter.java @@ -34,12 +34,9 @@ import org.opengis.filter.ResourceId; * @author Johann Sorel (Geomatys) * @author Martin Desruisseaux (Geomatys) * @version 1.4 - * - * @param <R> the type of resources used as inputs. - * - * @since 1.1 + * @since 1.1 */ -final class IdentifierFilter<R extends Feature> extends FilterNode<R> implements ResourceId<R> { +final class IdentifierFilter extends FilterNode<Feature> implements ResourceId<Feature> { /** * For cross-version compatibility. */ @@ -58,6 +55,14 @@ final class IdentifierFilter<R extends Feature> extends FilterNode<R> implements this.identifier = identifier; } + /** + * Returns the class of resources expected by this expression. + */ + @Override + public Class<Feature> getResourceClass() { + return Feature.class; + } + /** * Returns the identifiers of feature instances to accept. */ @@ -70,7 +75,7 @@ final class IdentifierFilter<R extends Feature> extends FilterNode<R> implements * Returns the parameters of this filter. */ @Override - public List<Expression<R,?>> getExpressions() { + public List<Expression<Feature,?>> getExpressions() { return List.of(new LeafExpression.Literal<>(identifier)); } @@ -88,7 +93,7 @@ final class IdentifierFilter<R extends Feature> extends FilterNode<R> implements * is one of the identifier specified at {@code IdentifierFilter} construction time. */ @Override - public boolean test(R object) { + public boolean test(final Feature object) { if (object == null) { return false; } diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/LikeFilter.java b/core/sis-feature/src/main/java/org/apache/sis/filter/LikeFilter.java index f4cb6bbc7d..d2651378be 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/filter/LikeFilter.java +++ b/core/sis-feature/src/main/java/org/apache/sis/filter/LikeFilter.java @@ -161,6 +161,14 @@ final class LikeFilter<R> extends FilterNode<R> implements LikeOperator<R>, Opti return new LikeFilter<>(this, effective[0]); } + /** + * Returns the class of resources expected by this filter. + */ + @Override + public Class<? super R> getResourceClass() { + return expression.getResourceClass(); + } + /** * Returns the children of this node for displaying purposes. * This is used by {@link #toString()}, {@link #hashCode()} and {@link #equals(Object)} implementations. diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/LogicalFilter.java b/core/sis-feature/src/main/java/org/apache/sis/filter/LogicalFilter.java index 4dee42760d..0bdde0b4e6 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/filter/LogicalFilter.java +++ b/core/sis-feature/src/main/java/org/apache/sis/filter/LogicalFilter.java @@ -86,6 +86,18 @@ abstract class LogicalFilter<R> extends FilterNode<R> implements LogicalOperator */ protected abstract LogicalFilter<R> createSameType(Collection<? extends Filter<R>> op); + /** + * Returns the class of resources expected by this filter. + */ + @Override + public Class<? super R> getResourceClass() { + Class<? super R> type = Object.class; + for (final Filter<R> operand : operands) { + type = specializedClass(type, operand.getResourceClass()); + } + return type; + } + /** * Returns a list containing all of the child filters of this object. */ @@ -230,6 +242,11 @@ abstract class LogicalFilter<R> extends FilterNode<R> implements LogicalOperator return LogicalOperatorName.NOT; } + /** Returns the class of resources expected by this filter. */ + @Override public Class<? super R> getResourceClass() { + return operand.getResourceClass(); + } + /** Symbol of the operation. */ @Override protected char symbol() { return '¬'; diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/Optimization.java b/core/sis-feature/src/main/java/org/apache/sis/filter/Optimization.java index d13ef64099..2f1ca09039 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/filter/Optimization.java +++ b/core/sis-feature/src/main/java/org/apache/sis/filter/Optimization.java @@ -233,8 +233,8 @@ public class Optimization { /** * Returns the {@code AND} logical operation between this filter and the given predicate. - * If the given predicate is an instance of {@link Filter}, then the returned predicate - * is an instance of {@code Optimization.OnFilter}. + * If the given predicate is an instance of {@code Filter<R>}, then the returned predicate + * is an instance of {@code Optimization.OnFilter<R>}. * * @param other the other predicate. * @return the {@code AND} logical operation between this filter and the given predicate. @@ -253,8 +253,8 @@ public class Optimization { /** * Returns the {@code OR} logical operation between this filter and the given predicate. - * If the given predicate is an instance of {@link Filter}, then the returned predicate - * is an instance of {@code Optimization.OnFilter}. + * If the given predicate is an instance of {@code Filter<R>}, then the returned predicate + * is an instance of {@code Optimization.OnFilter<R>}. * * @param other the other predicate. * @return the {@code OR} logical operation between this filter and the given predicate. diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/PropertyValue.java b/core/sis-feature/src/main/java/org/apache/sis/filter/PropertyValue.java index 20d281e95e..cae63556d3 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/filter/PropertyValue.java +++ b/core/sis-feature/src/main/java/org/apache/sis/filter/PropertyValue.java @@ -46,7 +46,7 @@ import org.opengis.filter.ValueReference; * * @author Johann Sorel (Geomatys) * @author Martin Desruisseaux (Geomatys) - * @version 1.2 + * @version 1.4 * * @param <V> the type of value computed by the expression. * @@ -76,7 +76,7 @@ abstract class PropertyValue<V> extends LeafExpression<Feature,V> protected final boolean isVirtual; /** - * The prefix in a x-path for considering a property as virual. + * The prefix in a x-path for considering a property as virtual. */ static final String VIRTUAL_PREFIX = "/*/"; @@ -133,6 +133,14 @@ split: if (path != null) { return (path == null || path.isEmpty()) ? tip : new AssociationValue<>(path, tip); } + /** + * Returns the class of resources expected by this expression. + */ + @Override + public final Class<Feature> getResourceClass() { + return Feature.class; + } + /** * For {@link #toString()}, {@link #hashCode()} and {@link #equals(Object)} implementations. */ diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/UnaryFunction.java b/core/sis-feature/src/main/java/org/apache/sis/filter/UnaryFunction.java index 4cc5327b6c..cff832db14 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/filter/UnaryFunction.java +++ b/core/sis-feature/src/main/java/org/apache/sis/filter/UnaryFunction.java @@ -65,6 +65,16 @@ class UnaryFunction<R,V> extends Node { this.expression = expression; } + /** + * Returns the class of resources expected by this filter. + * Defined for {@link Filter#getResourceClass()} implementations. + * + * @return type of resources accepted by this filter, or {@code null} if inconsistent. + */ + public final Class<? super R> getResourceClass() { + return expression.getResourceClass(); + } + /** * Returns the expression used as parameter by this function. * Defined for {@link Expression#getParameters()} implementations. diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ObservableImage.java b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ObservableImage.java index 04942d510a..07279f0ef8 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ObservableImage.java +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ObservableImage.java @@ -36,7 +36,7 @@ import org.apache.sis.util.ArraysExt; * <p>This class should be used in preference to {@link BufferedImage} when the image may be the * source of {@link org.apache.sis.image.ImageProcessor} operations. It is the case In particular * when this image is given to {@link org.apache.sis.coverage.grid.GridCoverage2D} constructor. - * We can not prevent {@link BufferedImage} to implement {@link WritableRenderedImage}, but we + * We cannot prevent {@link BufferedImage} to implement {@link WritableRenderedImage}, but we * can give a change to Apache SIS to be notified about modifications to pixel data.</p> * * @author Martin Desruisseaux (Geomatys) diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/filter/GeometryConverter.java b/core/sis-feature/src/main/java/org/apache/sis/internal/filter/GeometryConverter.java index edb9f26946..a9bcf55dc4 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/internal/filter/GeometryConverter.java +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/filter/GeometryConverter.java @@ -106,6 +106,14 @@ final class GeometryConverter<R,G> extends Node implements Optimization.OnExpres return NAME; } + /** + * Returns the class of resources expected by this expression. + */ + @Override + public Class<? super R> getResourceClass() { + return expression.getResourceClass(); + } + /** * Returns the expression used as parameters for this function. * This is the value specified at construction time. diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/filter/Node.java b/core/sis-feature/src/main/java/org/apache/sis/internal/filter/Node.java index f48299a752..581588efb3 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/internal/filter/Node.java +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/filter/Node.java @@ -19,10 +19,10 @@ package org.apache.sis.internal.filter; import java.util.Map; import java.util.IdentityHashMap; import java.util.Collection; -import java.io.Serializable; import java.util.Collections; import java.util.function.Predicate; import java.util.logging.Logger; +import java.io.Serializable; import org.opengis.util.CodeList; import org.opengis.util.LocalName; import org.opengis.util.ScopedName; @@ -96,6 +96,26 @@ public abstract class Node implements Serializable { type, 1, 1, null, (AttributeType<?>[]) null); } + /** + * Returns the most specialized class of the given pair of class. A specialized class is guaranteed to exist + * if parametrized type safety has not been bypassed with unchecked casts, because {@code <R>} is always valid. + * However this method is not guaranteed to be able to find that specialized type, because it could be none of + * the given arguments if {@code t1}, {@code t2} and {@code <R>} are interfaces with {@code <R>} extending both + * {@code t1} and {@code t2}. + * + * @param <R> the compile-time type of resources expected by filters or expressions. + * @param t1 the runtime type of resources expected by the first filter or expression. May be null. + * @param t2 the runtime type of resources expected by the second filter or expression. May be null. + * @return the most specialized type of resources, or {@code null} if it cannot be determined. + */ + protected static <R> Class<? super R> specializedClass(final Class<? super R> t1, final Class<? super R> t2) { + if (t1 != null && t2 != null) { + if (t1.isAssignableFrom(t2)) return t2; + if (t2.isAssignableFrom(t1)) return t1; + } + return null; + } + /** * Returns the mathematical symbol for this binary function. * For comparison operators, the symbol should be one of {@literal < > ≤ ≥ = ≠}. diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/FunctionWithSRID.java b/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/FunctionWithSRID.java index daa6f702d8..b2640be641 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/FunctionWithSRID.java +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/FunctionWithSRID.java @@ -206,6 +206,15 @@ search: if (crs instanceof CoordinateReferenceSystem) { } } + /** + * Returns the class of resources expected by this expression. + * Subclasses should override this method. + */ + @Override + public Class<? super R> getResourceClass() { + return (srid != null) ? srid.getResourceClass() : Object.class; + } + /** * Provides the type of values produced by this expression when a feature of the given type is evaluated. * diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/GeometryConstructor.java b/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/GeometryConstructor.java index a687d91527..bebef3918e 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/GeometryConstructor.java +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/GeometryConstructor.java @@ -77,6 +77,14 @@ class GeometryConstructor<R,G> extends FunctionWithSRID<R> { return new GeometryConstructor<>(operation, effective, getGeometryLibrary()); } + /** + * Returns the class of resources expected by this expression. + */ + @Override + public Class<? super R> getResourceClass() { + return specializedClass(geometry.getResourceClass(), super.getResourceClass()); + } + /** * Returns the sub-expressions that will be evaluated to provide the parameters to the function. */ diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/OneGeometry.java b/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/OneGeometry.java index b1c7432548..2ce129b57d 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/OneGeometry.java +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/OneGeometry.java @@ -26,7 +26,7 @@ import org.opengis.filter.Expression; /** * SQLMM spatial functions taking a single geometry operand. - * This base class assume that the geometry is the only parameter. + * This base class assumes that the geometry is the only parameter. * Subclasses may add other kind of parameters. * * @author Johann Sorel (Geomatys) @@ -75,6 +75,14 @@ class OneGeometry<R,G> extends SpatialFunction<R> { return getGeometryLibrary(geometry); } + /** + * Returns the class of resources expected by this expression. + */ + @Override + public Class<? super R> getResourceClass() { + return geometry.getResourceClass(); + } + /** * Returns the sub-expressions that will be evaluated to provide the parameters to the function. */ @@ -127,6 +135,14 @@ class OneGeometry<R,G> extends SpatialFunction<R> { return new WithArgument<>(operation, effective, getGeometryLibrary()); } + /** + * Returns the class of resources expected by this expression. + */ + @Override + public Class<? super R> getResourceClass() { + return specializedClass(super.getResourceClass(), argument.getResourceClass()); + } + /** * Returns the sub-expressions that will be evaluated to provide the parameters to the function. */ diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/ST_Point.java b/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/ST_Point.java index 19d0e6ca91..eeb2809a65 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/ST_Point.java +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/ST_Point.java @@ -98,6 +98,18 @@ final class ST_Point<R,G> extends FunctionWithSRID<R> { return library; } + /** + * Returns the class of resources expected by this expression. + */ + @Override + public Class<? super R> getResourceClass() { + Class<? super R> type = super.getResourceClass(); + for (final Expression<R,?> p : parameters) { + type = specializedClass(type, p.getResourceClass()); + } + return type; + } + /** * Returns the sub-expressions that will be evaluated to provide the parameters to the function. */ diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/ST_Transform.java b/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/ST_Transform.java index 463b1e2660..887ae43dc4 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/ST_Transform.java +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/ST_Transform.java @@ -93,6 +93,14 @@ final class ST_Transform<R,G> extends FunctionWithSRID<R> { return new ST_Transform<>(effective, getGeometryLibrary()); } + /** + * Returns the class of resources expected by this expression. + */ + @Override + public Class<? super R> getResourceClass() { + return specializedClass(geometry.getResourceClass(), super.getResourceClass()); + } + /** * Returns a handler for the library of geometric objects used by this expression. */ diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/TwoGeometries.java b/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/TwoGeometries.java index e394a62f31..ad06f76fa8 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/TwoGeometries.java +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/TwoGeometries.java @@ -115,6 +115,14 @@ class TwoGeometries<R,G> extends SpatialFunction<R> { return getGeometryLibrary(geometry1); } + /** + * Returns the class of resources expected by this expression. + */ + @Override + public Class<? super R> getResourceClass() { + return specializedClass(geometry1.getResourceClass(), geometry2.getResourceClass()); + } + /** * Returns the sub-expressions that will be evaluated to provide the parameters to the function. */ @@ -172,6 +180,14 @@ class TwoGeometries<R,G> extends SpatialFunction<R> { return new WithArgument<>(operation, effective, getGeometryLibrary()); } + /** + * Returns the class of resources expected by this expression. + */ + @Override + public Class<? super R> getResourceClass() { + return specializedClass(super.getResourceClass(), argument.getResourceClass()); + } + /** * Returns the sub-expressions that will be evaluated to provide the parameters to the function. */ diff --git a/core/sis-feature/src/test/java/org/apache/sis/filter/IdentifierFilterTest.java b/core/sis-feature/src/test/java/org/apache/sis/filter/IdentifierFilterTest.java index 10d75b2326..d005888119 100644 --- a/core/sis-feature/src/test/java/org/apache/sis/filter/IdentifierFilterTest.java +++ b/core/sis-feature/src/test/java/org/apache/sis/filter/IdentifierFilterTest.java @@ -35,7 +35,7 @@ import org.opengis.filter.FilterFactory; * * @author Johann Sorel (Geomatys) * @author Martin Desruisseaux (Geomatys) - * @version 1.1 + * @version 1.4 * @since 1.1 */ public final class IdentifierFilterTest extends TestCase { @@ -81,6 +81,7 @@ public final class IdentifierFilterTest extends TestCase { final Feature f3 = ftb.clear().setName("Test 3").build().newInstance(); final Filter<Feature> id = factory.resourceId("123"); + assertEquals(Feature.class, id.getResourceClass()); assertTrue (id.test(f1)); assertTrue (id.test(f2)); assertFalse(id.test(f3)); @@ -103,6 +104,7 @@ public final class IdentifierFilterTest extends TestCase { factory.resourceId("abc"), factory.resourceId("123")); + assertEquals(Feature.class, id.getResourceClass()); assertTrue (id.test(f1)); assertTrue (id.test(f2)); assertFalse(id.test(f3)); diff --git a/core/sis-feature/src/test/java/org/apache/sis/filter/LeafExpressionTest.java b/core/sis-feature/src/test/java/org/apache/sis/filter/LeafExpressionTest.java index 1444efaf01..c1b80108a7 100644 --- a/core/sis-feature/src/test/java/org/apache/sis/filter/LeafExpressionTest.java +++ b/core/sis-feature/src/test/java/org/apache/sis/filter/LeafExpressionTest.java @@ -33,7 +33,7 @@ import org.opengis.filter.ValueReference; * Tests {@link LeafExpression}. * * @author Johann Sorel (Geomatys) - * @version 1.1 + * @version 1.4 * @since 1.1 */ public final class LeafExpressionTest extends TestCase { @@ -93,6 +93,7 @@ public final class LeafExpressionTest extends TestCase { final Feature f = ftb.setName("Test").build().newInstance(); ValueReference<Feature,?> ref = factory.property("some_property"); + assertEquals(Feature.class, ref.getResourceClass()); assertNull(ref.apply(f)); assertNull(ref.apply(null)); diff --git a/core/sis-feature/src/test/java/org/apache/sis/internal/filter/FunctionMock.java b/core/sis-feature/src/test/java/org/apache/sis/internal/filter/FunctionMock.java index dc25a40a7c..5faece4129 100644 --- a/core/sis-feature/src/test/java/org/apache/sis/internal/filter/FunctionMock.java +++ b/core/sis-feature/src/test/java/org/apache/sis/internal/filter/FunctionMock.java @@ -64,6 +64,14 @@ final class FunctionMock implements Expression<Map<String,?>, Object> { return Names.createScopedName(null, null, name); } + /** + * Returns the type of resources accepted by this mock. + */ + @Override + public Class<Map> getResourceClass() { + return Map.class; + } + /** * Returns the function parameters. */ diff --git a/core/sis-feature/src/test/java/org/apache/sis/internal/filter/FunctionNamesTest.java b/core/sis-feature/src/test/java/org/apache/sis/internal/filter/FunctionNamesTest.java index f3ee5e5c43..3ec880cfcd 100644 --- a/core/sis-feature/src/test/java/org/apache/sis/internal/filter/FunctionNamesTest.java +++ b/core/sis-feature/src/test/java/org/apache/sis/internal/filter/FunctionNamesTest.java @@ -60,6 +60,7 @@ public final class FunctionNamesTest extends TestCase { */ private static abstract class FilterBase implements ComparisonOperator<Object> { @Override public List<Expression<Object,?>> getExpressions() {return List.of();} + @Override public Class<Object> getResourceClass() {return Object.class;} @Override public boolean test(Object resource) {return false;} } @@ -121,6 +122,7 @@ public final class FunctionNamesTest extends TestCase { final var expression = new ValueReference<Object,Object>() { @Override public String getXPath() {return null;} @Override public Object apply(Object o) {return null;} + @Override public Class<Object> getResourceClass() {return Object.class;} @Override public <N> Expression<Object,N> toValueType(Class<N> target) { throw new UnsupportedOperationException(); } diff --git a/core/sis-feature/src/test/java/org/apache/sis/internal/filter/ValueReferenceMock.java b/core/sis-feature/src/test/java/org/apache/sis/internal/filter/ValueReferenceMock.java index 90eb9a1f75..0e56410095 100644 --- a/core/sis-feature/src/test/java/org/apache/sis/internal/filter/ValueReferenceMock.java +++ b/core/sis-feature/src/test/java/org/apache/sis/internal/filter/ValueReferenceMock.java @@ -56,6 +56,14 @@ final class ValueReferenceMock<V> implements ValueReference<Map<String,?>, V> { this.type = type; } + /** + * Returns the type of resources accepted by this mock. + */ + @Override + public Class<Map> getResourceClass() { + return Map.class; + } + /** * Returns the name of the property for which to get values. */