sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] branch geoapi-4.0 updated: Clarify which exception may be thrown if result type of expressions can not be determined.
Date Mon, 19 Aug 2019 17:20:26 GMT
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 218845d  Clarify which exception may be thrown if result type of expressions can
not be determined.
218845d is described below

commit 218845d86fe2e4cdd09653b5a15527dfbba49879
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Mon Aug 19 19:19:17 2019 +0200

    Clarify which exception may be thrown if result type of expressions can not be determined.
---
 .../sis/filter/InvalidExpressionException.java     | 92 ++++++++++++++++++++++
 .../java/org/apache/sis/filter/NamedFunction.java  | 25 +++---
 .../sis/internal/feature/FeatureExpression.java    | 48 ++++++++++-
 .../org/apache/sis/internal/feature/Resources.java |  5 ++
 .../sis/internal/feature/Resources.properties      |  1 +
 .../sis/internal/feature/Resources_fr.properties   |  1 +
 .../sis/internal/storage/query/FeatureSubset.java  |  6 +-
 .../sis/internal/storage/query/SimpleQuery.java    | 41 ++++++----
 8 files changed, 190 insertions(+), 29 deletions(-)

diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/InvalidExpressionException.java
b/core/sis-feature/src/main/java/org/apache/sis/filter/InvalidExpressionException.java
new file mode 100644
index 0000000..46b761d
--- /dev/null
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/InvalidExpressionException.java
@@ -0,0 +1,92 @@
+/*
+ * 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.filter;
+
+import org.opengis.filter.expression.Expression;
+import org.apache.sis.internal.feature.Resources;
+import org.apache.sis.util.Classes;
+import org.apache.sis.util.Workaround;
+
+
+/**
+ * Thrown when an operation can not complete because an expression is illegal or unsupported.
+ * The invalid {@link Expression} may be a component of a larger object such as another expression
+ * or a query {@link org.apache.sis.storage.Query}.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ * @since   1.0
+ * @module
+ */
+public class InvalidExpressionException extends RuntimeException {
+    /**
+     * Serial number for inter-operability with different versions.
+     */
+    private static final long serialVersionUID = -2600709421042246855L;
+
+    /**
+     * Constructs an exception with no detail message.
+     */
+    public InvalidExpressionException() {
+    }
+
+    /**
+     * Constructs an exception with the specified detail message.
+     *
+     * @param  message  the detail message.
+     */
+    public InvalidExpressionException(final String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs an exception with the specified detail message and cause.
+     *
+     * @param  message  the detail message.
+     * @param  cause    the cause for this exception.
+     */
+    public InvalidExpressionException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs an exception with a message saying that the given expression is illegal
or unsupported.
+     * This constructor assumes that the expression was part of a larger object containing
many expressions
+     * identified by indices.
+     *
+     * @param  expression  the illegal expression, or {@code null} if unknown.
+     * @param  index       column number (or other kind of index) where the invalid expression
has been found.
+     */
+    public InvalidExpressionException(final Expression expression, final int index) {
+        super(message(expression, index));
+    }
+
+    /**
+     * Work around for RFE #4093999 in Sun's bug database
+     * ("Relax constraint on placement of this()/super() call in constructors").
+     */
+    @Workaround(library="JDK", version="1.8")
+    private static String message(final Expression expression, final int index) {
+        final String name;
+        if (expression instanceof Node) {
+            name = ((Node) expression).getName();
+        } else {
+            name = Classes.getShortClassName(expression);
+        }
+        return Resources.format(Resources.Keys.InvalidExpression_2, name, index);
+    }
+}
diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/NamedFunction.java b/core/sis-feature/src/main/java/org/apache/sis/filter/NamedFunction.java
index 8bc8bb1..c41923e 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/NamedFunction.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/NamedFunction.java
@@ -29,7 +29,6 @@ import org.apache.sis.util.ObjectConverters;
 import org.apache.sis.util.UnconvertibleObjectException;
 import org.apache.sis.internal.feature.FeatureExpression;
 import org.apache.sis.internal.util.UnmodifiableArrayList;
-import org.apache.sis.internal.util.CollectionsExt;
 
 
 /**
@@ -151,25 +150,29 @@ abstract class NamedFunction extends Node implements Function {
     }
 
     /**
-     * Returns the type of results computed by the parameters at given index, or {@code null}
if unknown.
-     * If the expression implements {@link FeatureExpression}, its {@code expectedType(valueType)}
method
-     * will be invoked. Otherwise this method returns the single property of the given feature
type if it
-     * contains exactly one property, or returns {@code null} otherwise.
+     * Returns the type of results computed by the parameters at given index.
+     * This method applies heuristic rules documented in {@link FeatureExpression}.
      *
      * @param  parameter  index of the expression for which to get the result type.
-     * @param  valueType  the type of features on which to apply the expression at given
index.
-     * @return expected expression result type, or {@code null} if unknown.
+     * @param  valueType  the type of features to be evaluated by the given expression.
+     * @return expected type resulting from expression evaluation (never null).
+     * @throws IllegalArgumentException if this method can operate only on some feature types
+     *         and the given type is not one of them.
+     * @throws InvalidExpressionException if this method can not determine the result type
of the expression
+     *         at given index. It may be because that expression is backed by an unsupported
implementation.
      */
     final PropertyType expectedType(final int parameter, final FeatureType valueType) {
-        final Expression exp = parameters.get(parameter);
-        if (exp instanceof FeatureExpression) {
-            return ((FeatureExpression) exp).expectedType(valueType);
+        final Expression expression = parameters.get(parameter);
+        final PropertyType pt = FeatureExpression.expectedType(expression, valueType);
+        if (pt == null) {
+            throw new InvalidExpressionException(expression, parameter);
         }
-        return CollectionsExt.singletonOrNull(valueType.getProperties(true));
+        return pt;
     }
 
     /**
      * Implementation of the visitor pattern.
+     * Not used in Apache SIS implementation.
      */
     @Override
     public Object accept(final ExpressionVisitor visitor, final Object extraData) {
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureExpression.java
b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureExpression.java
index 4667488..01d954f 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureExpression.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureExpression.java
@@ -19,6 +19,8 @@ package org.apache.sis.internal.feature;
 // Branch-dependent imports
 import org.opengis.feature.FeatureType;
 import org.opengis.feature.PropertyType;
+import org.opengis.filter.expression.Expression;
+import org.apache.sis.internal.util.CollectionsExt;
 
 
 /**
@@ -26,6 +28,8 @@ import org.opengis.feature.PropertyType;
  * This interface adds an additional method, {@link #expectedType(FeatureType)},
  * for fetching in advance the expected type of expression results.
  *
+ * <p>This is an experimental interface which may be removed in any future version.</p>
+ *
  * @author  Johann Sorel (Geomatys)
  * @version 1.0
  * @since   1.0
@@ -38,9 +42,47 @@ public interface FeatureExpression {
      * {@link org.opengis.feature.AttributeType} or a {@link org.opengis.feature.FeatureAssociationRole}
      * but not an {@link org.opengis.feature.Operation}.
      *
-     * @param  valueType  the type of features on which to apply this expression.
-     * @return expected expression result type.
-     * @throws IllegalArgumentException if this method can not determine the property type
for the given feature type.
+     * @param  valueType  the type of features to be evaluated by the given expression.
+     * @return expected type resulting from expression evaluation, or {@code null} if unknown.
+     * @throws IllegalArgumentException if this method can operate only on some feature types
+     *         and the given type is not one of them.
      */
     PropertyType expectedType(FeatureType valueType);
+
+    /**
+     * Returns the type of results computed by the given expression, or {@code null} if unknown.
+     * This method returns the first of the following choices that apply:
+     *
+     * <ol>
+     *   <li>If the expression implements {@link FeatureExpression}, delegate to {@link
#expectedType(FeatureType)}.
+     *       Note that the invoked method may throw an {@link IllegalArgumentException}.</li>
+     *   <li>Otherwise if {@link Expression#evaluate(Object, Class)} with a {@code
PropertyType.class} argument
+     *       returns a non-null value, returns that value.</li>
+     *   <li>Otherwise if the given feature type contains exactly one property (including
inherited properties),
+     *       returns that property.</li>
+     *   <li>Otherwise returns {@code null}.</li>
+     * </ol>
+     *
+     * It is caller's responsibility to verify if the returned value is {@code null} and
to throw an exception in such case.
+     * We leave that responsibility to the caller because (s)he may be able to provide better
error messages.
+     *
+     * @param  parameter  the expression for which to get the result type, or {@code null}.
+     * @param  valueType  the type of features to be evaluated by the given expression.
+     * @return expected type resulting from expression evaluation, or {@code null} if unknown.
+     * @throws IllegalArgumentException if this method can operate only on some feature types
+     *         and the given type is not one of them.
+     */
+    public static PropertyType expectedType(final Expression parameter, final FeatureType
valueType) {
+        if (parameter instanceof FeatureExpression) {
+            return ((FeatureExpression) parameter).expectedType(valueType);
+        }
+        if (parameter != null) {
+            // TODO: remove this hack if we can get more type-safe Expression.
+            PropertyType pt = parameter.evaluate(valueType, PropertyType.class);
+            if (pt != null) {
+                return pt;
+            }
+        }
+        return CollectionsExt.singletonOrNull(valueType.getProperties(true));
+    }
 }
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java
b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java
index 2181205..c15ee72 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java
@@ -184,6 +184,11 @@ public final class Resources extends IndexedResourceBundle {
         public static final short IncompatibleTile_2 = 35;
 
         /**
+         * Invalid or unsupported “{1}” expression at index {0}.
+         */
+        public static final short InvalidExpression_2 = 56;
+
+        /**
          * Iteration is finished.
          */
         public static final short IterationIsFinished = 36;
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties
b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties
index d0bcc90..8904f41 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties
@@ -43,6 +43,7 @@ IllegalPropertyType_2             = Type or result of \u201c{0}\u201d property
c
 IllegalPropertyValueClass_3       = Property \u201c{0}\u201d does not accept values of type
\u2018{2}\u2019. Expected an instance of \u2018{1}\u2019 or derived type.
 IllegalTransferFunction_1         = Illegal transfer function for \u201c{0}\u201d category.
 IncompatibleTile_2                = The ({0}, {1}) tile has an unexpected size, number of
bands or sample layout.
+InvalidExpression_2               = Invalid or unsupported \u201c{1}\u201d expression at
index {0}.
 IterationIsFinished               = Iteration is finished.
 IterationNotStarted               = Iteration did not started.
 MismatchedBandSize                = The bands have different number of sample values.
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties
b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties
index b6eccd1..2d2d051 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties
@@ -48,6 +48,7 @@ IllegalPropertyType_2             = Le type ou le r\u00e9sultat de la propri\u00
 IllegalPropertyValueClass_3       = La propri\u00e9t\u00e9 \u00ab\u202f{0}\u202f\u00bb n\u2019accepte
pas les valeurs de type \u2018{2}\u2019. Une instance de \u2018{1}\u2019 ou d\u2019un type
d\u00e9riv\u00e9 \u00e9tait attendue.
 IllegalTransferFunction_1         = Fonction de transfert ill\u00e9gale pour la cat\u00e9gorie
\u00ab\u202f{0}\u202f\u00bb.
 IncompatibleTile_2                = La tuile ({0}, {1}) a une taille, un nombre de bandes
ou une disposition des valeurs inattendu.
+InvalidExpression_2               = Expression \u00ab\u202f{1}\u202f\u00bb invalide ou non-support\u00e9e
\u00e0 l\u2019index {0}.
 IterationIsFinished               = L\u2019it\u00e9ration est termin\u00e9e.
 IterationNotStarted               = L\u2019it\u00e9ration n\u2019a pas commenc\u00e9e.
 MismatchedBandSize                = Les bandes ont un nombre diff\u00e9rent de valeurs.
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/FeatureSubset.java
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/FeatureSubset.java
index 6332215..bb714f5 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/FeatureSubset.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/FeatureSubset.java
@@ -22,6 +22,8 @@ import java.util.stream.Stream;
 import org.opengis.util.GenericName;
 import org.apache.sis.internal.feature.FeatureUtilities;
 import org.apache.sis.internal.storage.AbstractFeatureSet;
+import org.apache.sis.filter.InvalidExpressionException;
+import org.apache.sis.storage.DataStoreContentException;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.FeatureSet;
 
@@ -84,8 +86,10 @@ final class FeatureSubset extends AbstractFeatureSet {
      */
     @Override
     public synchronized FeatureType getType() throws DataStoreException {
-        if (resultType == null) {
+        if (resultType == null) try {
             resultType = query.expectedType(source.getType());
+        } catch (IllegalArgumentException | InvalidExpressionException e) {
+            throw new DataStoreContentException(e);
         }
         return resultType;
     }
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/SimpleQuery.java
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/SimpleQuery.java
index ef716db..3b675f7 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/SimpleQuery.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/SimpleQuery.java
@@ -22,6 +22,7 @@ import java.util.List;
 import java.util.LinkedHashMap;
 import java.util.Objects;
 import org.opengis.util.GenericName;
+import org.apache.sis.filter.InvalidExpressionException;
 import org.apache.sis.feature.builder.FeatureTypeBuilder;
 import org.apache.sis.internal.feature.FeatureExpression;
 import org.apache.sis.internal.util.UnmodifiableArrayList;
@@ -305,17 +306,22 @@ public class SimpleQuery extends Query {
         }
 
         /**
-         * Returns the expected property type for this column.
+         * Returns the type of results computed by this column.
+         *
+         * @param  valueType  the type of features to be evaluated by the expression in this
column.
+         * @param  column     index of this column. Used for error message only.
+         * @return expected type resulting from expression evaluation (never null).
+         * @throws IllegalArgumentException if this method can operate only on some feature
types
+         *         and the given type is not one of them.
+         * @throws InvalidExpressionException if this method can not determine the result
type of the expression
+         *         in this column. It may be because that expression is backed by an unsupported
implementation.
          *
          * @see SimpleQuery#expectedType(FeatureType)
          */
-        final PropertyType expectedType(final FeatureType type) {
-            PropertyType resultType;
-            if (expression instanceof FeatureExpression) {
-                resultType = ((FeatureExpression) expression).expectedType(type);
-            } else {
-                // TODO: remove this hack if we can get more type-safe Expression.
-                resultType = expression.evaluate(type, PropertyType.class);
+        final PropertyType expectedType(final FeatureType valueType, final int column) {
+            PropertyType resultType = FeatureExpression.expectedType(expression, valueType);
+            if (resultType == null) {
+                throw new InvalidExpressionException(expression, column);
             }
             /*
              * If a name has been explicitly given, rename the result type.
@@ -401,15 +407,22 @@ public class SimpleQuery extends Query {
     }
 
     /**
-     * Returns the expected property type for this query executed on features of the given
type.
+     * Returns the type or values evaluated by this query when executed on features of the
given type.
+     *
+     * @param  valueType  the type of features to be evaluated by the expressions in this
query.
+     * @return type resulting from expressions evaluation (never null).
+     * @throws IllegalArgumentException if this method can operate only on some feature types
+     *         and the given type is not one of them.
+     * @throws InvalidExpressionException if this method can not determine the result type
of an expression
+     *         in this query. It may be because that expression is backed by an unsupported
implementation.
      */
-    final FeatureType expectedType(final FeatureType source) {
+    final FeatureType expectedType(final FeatureType valueType) {
         if (columns == null) {
-            return source;          // All columns included: result is of the same type.
+            return valueType;           // All columns included: result is of the same type.
         }
-        final FeatureTypeBuilder ftb = new FeatureTypeBuilder().setName(source.getName());
-        for (final Column col : columns) {
-            ftb.addProperty(col.expectedType(source));
+        final FeatureTypeBuilder ftb = new FeatureTypeBuilder().setName(valueType.getName());
+        for (int i=0; i<columns.length; i++) {
+            ftb.addProperty(columns[i].expectedType(valueType, i));
         }
         return ftb.build();
     }


Mime
View raw message