This is an automated email from the ASF dual-hosted git repository.
github-actions[bot] pushed a commit to branch site
in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/site by this push:
new a2b9710b2c [CALCITE-7712] Enforce Input annotation on
ReflectiveSchema.Factory operands
a2b9710b2c is described below
commit a2b9710b2c0e8896fce7dc1612640b2d117988b9
Author: Stamatis Zampetakis <[email protected]>
AuthorDate: Thu Aug 13 16:02:13 2026 +0300
[CALCITE-7712] Enforce Input annotation on ReflectiveSchema.Factory operands
---
.../calcite/adapter/java/ReflectiveSchema.java | 23 ++++++++-
.../apache/calcite/test/ReflectiveSchemaTest.java | 58 ++++++++++++++++++++++
site/_docs/history.md | 15 ++++++
3 files changed, 94 insertions(+), 2 deletions(-)
diff --git
a/core/src/main/java/org/apache/calcite/adapter/java/ReflectiveSchema.java
b/core/src/main/java/org/apache/calcite/adapter/java/ReflectiveSchema.java
index 24dbe8a3d2..07e29b2b22 100644
--- a/core/src/main/java/org/apache/calcite/adapter/java/ReflectiveSchema.java
+++ b/core/src/main/java/org/apache/calcite/adapter/java/ReflectiveSchema.java
@@ -56,6 +56,10 @@
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
@@ -293,6 +297,15 @@ private static class ReflectiveTable
}
}
+ /**
+ * Designates a type that can be used as input in the {@link Factory}.
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.TYPE)
+ public @interface Input {
+
+ }
+
/** Factory that creates a schema by instantiating an object and looking at
* its public fields.
*
@@ -321,22 +334,28 @@ private static class ReflectiveTable
* Employee[] EMPS;
* Department[] DEPTS;
* }</pre></blockquote>
+ *
+ * <p>The class operand must be annotated as {@link Input} otherwise it
cannot
+ * be used in this factory.
*/
public static class Factory implements SchemaFactory {
@Override public Schema create(SchemaPlus parentSchema, String name,
Map<String, Object> operand) {
Class<?> clazz;
Object target;
- final Object className = operand.get("class");
+ final String className = (String) operand.get("class");
if (className != null) {
try {
- clazz = Class.forName((String) className);
+ clazz = Class.forName(className, false,
Factory.class.getClassLoader());
} catch (ClassNotFoundException e) {
throw new RuntimeException("Error loading class " + className, e);
}
} else {
throw new RuntimeException("Operand 'class' is required");
}
+ if (!clazz.isAnnotationPresent(Input.class)) {
+ throw new IllegalArgumentException(clazz + " is not annotated with
@Input");
+ }
final Object methodName = operand.get("staticMethod");
if (methodName != null) {
try {
diff --git
a/core/src/test/java/org/apache/calcite/test/ReflectiveSchemaTest.java
b/core/src/test/java/org/apache/calcite/test/ReflectiveSchemaTest.java
index 3c86c01255..e4979b95f3 100644
--- a/core/src/test/java/org/apache/calcite/test/ReflectiveSchemaTest.java
+++ b/core/src/test/java/org/apache/calcite/test/ReflectiveSchemaTest.java
@@ -20,6 +20,7 @@
import org.apache.calcite.avatica.util.DateTimeUtils;
import org.apache.calcite.config.Lex;
import org.apache.calcite.jdbc.CalciteConnection;
+import org.apache.calcite.jdbc.CalciteSchema;
import org.apache.calcite.jdbc.Driver;
import org.apache.calcite.linq4j.Enumerable;
import org.apache.calcite.linq4j.Linq4j;
@@ -44,6 +45,7 @@
import org.apache.calcite.util.Util;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -61,6 +63,7 @@
import java.util.Arrays;
import java.util.BitSet;
import java.util.List;
+import java.util.Map;
import java.util.Properties;
import static org.apache.calcite.test.Matchers.isListOf;
@@ -72,6 +75,7 @@
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.hasToString;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
@@ -1102,4 +1106,58 @@ public static class DateColumnSchema {
assertNotNull(statistic);
assertThat(statistic.getRowCount(), is(2D));
}
+
+ /** Test for <a
href="https://issues.apache.org/jira/browse/CALCITE-7712">[CALCITE-7712]
+ * Enforce Input annotation on ReflectiveSchema.Factory operands</a>. */
+ @Test void testFactoryCreateWithAnnotatedClassOperand() {
+ ReflectiveSchema.Factory factory = new ReflectiveSchema.Factory();
+ SchemaPlus root = CalciteSchema.createRootSchema(false).plus();
+ Map<String, Object> operand =
+ ImmutableMap.of("class",
"org.apache.calcite.test.ReflectiveSchemaTest$ValidClassOp");
+ assertNotNull(factory.create(root, "ignore", operand));
+ }
+
+ /** Test for <a
href="https://issues.apache.org/jira/browse/CALCITE-7712">[CALCITE-7712]
+ * Enforce Input annotation on ReflectiveSchema.Factory operands</a>. The
test ensures
+ * invalid classes are rejected with an informative exception.*/
+ @Test void testFactoryCreateWithInvalidClassOperandThrows() {
+ ReflectiveSchema.Factory factory = new ReflectiveSchema.Factory();
+ SchemaPlus root = CalciteSchema.createRootSchema(false).plus();
+ Map<String, Object> operand =
+ ImmutableMap.of("class",
"org.apache.calcite.test.ReflectiveSchemaTest$InvalidClassOp");
+ IllegalArgumentException e =
+ assertThrows(IllegalArgumentException.class, () ->
factory.create(root, "ignore", operand));
+ assertThat(e.getMessage(),
+ is("class org.apache.calcite.test.ReflectiveSchemaTest$InvalidClassOp
is not annotated "
+ + "with @Input"));
+ }
+
+ /** Test for <a
href="https://issues.apache.org/jira/browse/CALCITE-7712">[CALCITE-7712]
+ * Enforce Input annotation on ReflectiveSchema.Factory operands</a>. The
test ensures
+ * invalid classes are not initialized.*/
+ @Test void
testFactoryCreateWithInvalidClassOperandDoesNotTriggerInitializers() {
+ ReflectiveSchema.Factory factory = new ReflectiveSchema.Factory();
+ SchemaPlus root = CalciteSchema.createRootSchema(false).plus();
+ Map<String, Object> operand =
+ ImmutableMap.of("class",
"org.apache.calcite.InvalidStaticInitializer");
+ IllegalArgumentException e =
+ assertThrows(IllegalArgumentException.class, () ->
factory.create(root, "ignore", operand));
+ assertThat(e.getMessage(),
+ is("class org.apache.calcite.InvalidStaticInitializer is not annotated
with @Input"));
+ }
+
+ /**
+ * A valid class operand for {@link ReflectiveSchema.Factory} with proper
annotation.
+ */
+ @ReflectiveSchema.Input
+ public static class ValidClassOp {
+ public ValidClassOp() {}
+ }
+
+ /**
+ * An invalid class operand for {@link ReflectiveSchema.Factory} due to
missing annotation.
+ */
+ public static class InvalidClassOp {
+ public InvalidClassOp() {}
+ }
}
diff --git a/site/_docs/history.md b/site/_docs/history.md
index 15e2561d39..3aba1fd075 100644
--- a/site/_docs/history.md
+++ b/site/_docs/history.md
@@ -49,6 +49,21 @@ ## <a
href="https://github.com/apache/calcite/releases/tag/calcite-1.43.0">1.43.
#### Breaking Changes
{: #breaking-1-43-0}
+* [<a
href="https://issues.apache.org/jira/browse/CALCITE-7580">CALCITE-7580</a>]
+ Remove Gandiva dependency from Arrow adapter. Arrow adapter projection and
+ filter evaluation now run in Java, and the `arrow-gandiva` dependency is no
+ longer included in the Arrow module or BOM.
+
+* [<a
href="https://issues.apache.org/jira/browse/CALCITE-7712">CALCITE-7712</a>]
+`ReflectiveSchema.Factory` requires the class operand to explicitly use the new
+`ReflectiveSchema.Input` annotation. If the annotation is not present the
+creation will fail with `IllegalArgumentException: class X is not annotated
@Input`.
+
+* [<a
href="https://issues.apache.org/jira/browse/CALCITE-7713">CALCITE-7713</a>]
+Class loading from model files has been disabled by default. Any attempt to
load
+classes from model files will lead to `SecurityException` unless an appropriate
+pattern is set in `calcite.model.classes.allowed` system property.
+
#### New features
{: #new-features-1-43-0}