This is an automated email from the ASF dual-hosted git repository.
zabetak pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite-avatica.git
The following commit(s) were added to refs/heads/main by this push:
new 9e13fa95d [CALCITE-7610] Improve type checking when instantiating
plugins
9e13fa95d is described below
commit 9e13fa95d6b86f669dfaa8801c5faea6911870c0
Author: Stamatis Zampetakis <[email protected]>
AuthorDate: Thu Jun 18 16:55:15 2026 +0200
[CALCITE-7610] Improve type checking when instantiating plugins
---
.../org/apache/calcite/avatica/AvaticaUtils.java | 43 +++++++++++++++----
.../main/java/org/apache/calcite/avatica/Meta.java | 2 +-
.../remote/AvaticaHttpClientFactoryImpl.java | 3 +-
.../avatica/remote/BearerTokenProviderFactory.java | 3 +-
.../apache/calcite/avatica/AuthorNoInitPojo.java | 26 ++++++++++++
.../org/apache/calcite/avatica/AuthorPojo.java | 24 +++++++++++
.../calcite/avatica/CursorFactoryProtoTest.java | 45 ++++++++++++++++++++
.../calcite/avatica/InvalidStaticInitializer.java | 34 +++++++++++++++
.../InvalidStaticInitializerWithInstanceField.java | 30 ++++++++++++++
.../InvalidStaticInitializerWithStaticField.java | 30 ++++++++++++++
.../remote/AvaticaHttpClientFactoryTest.java | 8 ++--
.../remote/BearerTokenProviderFactoryTest.java | 12 +++---
.../calcite/avatica/test/AvaticaUtilsTest.java | 48 ++++++++++++++++------
13 files changed, 276 insertions(+), 32 deletions(-)
diff --git a/core/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
b/core/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
index ef27e8269..820fb1613 100644
--- a/core/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
+++ b/core/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
@@ -25,6 +25,8 @@
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.sql.PreparedStatement;
@@ -229,10 +231,13 @@ public static <T> T instantiatePlugin(Class<T>
pluginClass,
int i = className.indexOf('#');
left = className.substring(0, i);
right = className.substring(i + 1);
- //noinspection unchecked
- final Class<T> clazz = (Class) Class.forName(left);
+ final Class<?> clazz = Class.forName(left, false,
AvaticaUtils.class.getClassLoader());
final Field field;
field = clazz.getField(right);
+ if (!isValidPluginField(field, pluginClass)) {
+ throw new RuntimeException(
+ "Property '" + className + "' not valid for plugin type " +
pluginClass.getName());
+ }
final Object fieldValue = field.get(null);
if (fieldValue instanceof ThreadLocal) {
value = ((ThreadLocal<?>) fieldValue).get();
@@ -241,12 +246,13 @@ public static <T> T instantiatePlugin(Class<T>
pluginClass,
}
return pluginClass.cast(value);
}
- //noinspection unchecked
- final Class<T> clazz = (Class) Class.forName(className);
+ final Class<?> clazz = Class.forName(className, false,
AvaticaUtils.class.getClassLoader());
try {
- // We assume that if there is an INSTANCE field it is static and
- // has the right type.
final Field field = clazz.getField("INSTANCE");
+ if (!isValidPluginField(field, pluginClass)) {
+ throw new RuntimeException(
+ "Property '" + className + "' not valid for plugin type " +
pluginClass.getName());
+ }
value = field.get(null);
return pluginClass.cast(value);
} catch (NoSuchFieldException e) {
@@ -256,7 +262,7 @@ public static <T> T instantiatePlugin(Class<T> pluginClass,
throw new RuntimeException("Property '" + className
+ "' not valid for plugin type " + pluginClass.getName());
}
- return clazz.getConstructor().newInstance();
+ return pluginClass.cast(clazz.getConstructor().newInstance());
} catch (ClassNotFoundException e) {
throw new RuntimeException("Property '" + className
+ "' not valid as '" + className + "' not found in the classpath",
e);
@@ -280,6 +286,29 @@ public static <T> T instantiatePlugin(Class<T> pluginClass,
}
}
+ /**
+ * Returns whether the specified field is valid for the instantiation of a
plugin.
+ * <p> The field is valid if it can be assigned directly to the expected
{@code clazz} type or,
+ * it is a {@link ThreadLocal} with a parameterized type that can be
assigned {@code clazz}.
+ * @param field the field to check for validity
+ * @param clazz the expected type after the instantiation of the plugin
+ * @return whether the specified field is valid for the instantiation of a
plugin.
+ */
+ private static boolean isValidPluginField(Field field, Class<?> clazz) {
+ if (clazz.isAssignableFrom(field.getType())) {
+ return true;
+ }
+ if (ThreadLocal.class.isAssignableFrom(field.getType())) {
+ Type genericType = field.getGenericType();
+ if (genericType instanceof ParameterizedType) {
+ Type[] types = ((ParameterizedType)
genericType).getActualTypeArguments();
+ return types.length == 1 && types[0] instanceof Class &&
clazz.isAssignableFrom(
+ (Class<?>) types[0]);
+ }
+ }
+ return false;
+ }
+
/** Reads the contents of an input stream and returns as a string. */
public static String readFully(InputStream inputStream) throws IOException {
return readFully(inputStream, new UnsynchronizedBuffer(1024));
diff --git a/core/src/main/java/org/apache/calcite/avatica/Meta.java
b/core/src/main/java/org/apache/calcite/avatica/Meta.java
index a4f45c6bc..92dec1f18 100644
--- a/core/src/main/java/org/apache/calcite/avatica/Meta.java
+++ b/core/src/main/java/org/apache/calcite/avatica/Meta.java
@@ -722,7 +722,7 @@ public static CursorFactory fromProto(Common.CursorFactory
proto) {
if (proto.hasField(CLASS_NAME_DESCRIPTOR)) {
try {
- clz = Class.forName(proto.getClassName());
+ clz = Class.forName(proto.getClassName(), false,
CursorFactory.class.getClassLoader());
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
diff --git
a/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClientFactoryImpl.java
b/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClientFactoryImpl.java
index 445848979..a4ee4a231 100644
---
a/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClientFactoryImpl.java
+++
b/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClientFactoryImpl.java
@@ -162,7 +162,8 @@ private AvaticaHttpClient instantiateClient(String
className, URL url) {
try {
// Ensure that the given class is actually a subclass of
AvaticaHttpClient
Class<? extends AvaticaHttpClient> clz =
- Class.forName(className).asSubclass(AvaticaHttpClient.class);
+ Class.forName(className, false,
AvaticaHttpClientFactoryImpl.class.getClassLoader())
+ .asSubclass(AvaticaHttpClient.class);
Constructor<? extends AvaticaHttpClient> constructor =
clz.getConstructor(URL.class);
client = constructor.newInstance(Objects.requireNonNull(url));
} catch (Exception e) {
diff --git
a/core/src/main/java/org/apache/calcite/avatica/remote/BearerTokenProviderFactory.java
b/core/src/main/java/org/apache/calcite/avatica/remote/BearerTokenProviderFactory.java
index f6dda63b7..c639b1a12 100644
---
a/core/src/main/java/org/apache/calcite/avatica/remote/BearerTokenProviderFactory.java
+++
b/core/src/main/java/org/apache/calcite/avatica/remote/BearerTokenProviderFactory.java
@@ -44,7 +44,8 @@ private static BearerTokenProvider
instantiateTokenProvider(String className) {
try {
Class<? extends BearerTokenProvider> clz =
- Class.forName(className).asSubclass(BearerTokenProvider.class);
+ Class.forName(className, false,
BearerTokenProviderFactory.class.getClassLoader())
+ .asSubclass(BearerTokenProvider.class);
Constructor<? extends BearerTokenProvider> constructor =
clz.getConstructor();
tokenProvider = constructor.newInstance();
} catch (Exception e) {
diff --git
a/core/src/test/java/org/apache/calcite/avatica/AuthorNoInitPojo.java
b/core/src/test/java/org/apache/calcite/avatica/AuthorNoInitPojo.java
new file mode 100644
index 000000000..8fdeebda4
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/avatica/AuthorNoInitPojo.java
@@ -0,0 +1,26 @@
+/*
+ * 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.calcite.avatica;
+
+@SuppressWarnings("unused")
+public class AuthorNoInitPojo extends InvalidStaticInitializer {
+
+ public long id;
+ public String fname;
+ public String lname;
+ public int age;
+}
diff --git a/core/src/test/java/org/apache/calcite/avatica/AuthorPojo.java
b/core/src/test/java/org/apache/calcite/avatica/AuthorPojo.java
new file mode 100644
index 000000000..c7ced7c78
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/avatica/AuthorPojo.java
@@ -0,0 +1,24 @@
+/*
+ * 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.calcite.avatica;
+
+public class AuthorPojo {
+ public long id;
+ public String fname;
+ public String lname;
+ public int age;
+}
diff --git
a/core/src/test/java/org/apache/calcite/avatica/CursorFactoryProtoTest.java
b/core/src/test/java/org/apache/calcite/avatica/CursorFactoryProtoTest.java
new file mode 100644
index 000000000..8c3d82cbc
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/avatica/CursorFactoryProtoTest.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.calcite.avatica;
+
+import org.apache.calcite.avatica.proto.Common;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Unit tests for {@link org.apache.calcite.avatica.Meta.CursorFactory} proto
conversions.
+ */
+public class CursorFactoryProtoTest {
+
+ @Test
+ public void testFromProtoAvoidsClassInitialization() {
+ Meta.CursorFactory baseFactory =
Meta.CursorFactory.create(Meta.Style.RECORD, AuthorPojo.class,
+ Arrays.asList("id", "fname", "lname", "age"));
+ Common.CursorFactory.Builder builder = Common.CursorFactory.newBuilder();
+ builder.mergeFrom(baseFactory.toProto());
+ builder.setClassName("org.apache.calcite.avatica.AuthorNoInitPojo");
+ Common.CursorFactory newProto = builder.build();
+ Meta.CursorFactory newFactory = Meta.CursorFactory.fromProto(newProto);
+ assertNotNull(newFactory);
+ assertEquals(baseFactory.fieldNames, newFactory.fieldNames);
+ }
+}
diff --git
a/core/src/test/java/org/apache/calcite/avatica/InvalidStaticInitializer.java
b/core/src/test/java/org/apache/calcite/avatica/InvalidStaticInitializer.java
new file mode 100644
index 000000000..787f2ef8d
--- /dev/null
+++
b/core/src/test/java/org/apache/calcite/avatica/InvalidStaticInitializer.java
@@ -0,0 +1,34 @@
+/*
+ * 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.calcite.avatica;
+
+/**
+ * An invalid class that always fail if initialized. The class may be
sub-classed to cover
+ * test cases where a static initializer is not allowed to be triggered. All
the classes in the
+ * hierarchy are called by reflection thus appear as unused.
+ */
+@SuppressWarnings("unused")
+public class InvalidStaticInitializer {
+
+ static {
+ throwError();
+ }
+
+ private static void throwError() {
+ throw new AssertionError("Static initializer must not be triggered");
+ }
+}
diff --git
a/core/src/test/java/org/apache/calcite/avatica/InvalidStaticInitializerWithInstanceField.java
b/core/src/test/java/org/apache/calcite/avatica/InvalidStaticInitializerWithInstanceField.java
new file mode 100644
index 000000000..6350dce75
--- /dev/null
+++
b/core/src/test/java/org/apache/calcite/avatica/InvalidStaticInitializerWithInstanceField.java
@@ -0,0 +1,30 @@
+/*
+ * 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.calcite.avatica;
+
+/**
+ * A class with an invalid initializer and a static INSTANCE field. Certain
reflection utils,
+ * rely on the presence of a static INSTANCE field to create an instance of a
class.
+ */
+@SuppressWarnings("unused")
+public class InvalidStaticInitializerWithInstanceField extends
InvalidStaticInitializer {
+ public static final String INSTANCE = "INSTANCE_VALUE";
+
+ private InvalidStaticInitializerWithInstanceField() {
+ throw new AssertionError("Must not be instantiated");
+ }
+}
diff --git
a/core/src/test/java/org/apache/calcite/avatica/InvalidStaticInitializerWithStaticField.java
b/core/src/test/java/org/apache/calcite/avatica/InvalidStaticInitializerWithStaticField.java
new file mode 100644
index 000000000..60f5f7ec6
--- /dev/null
+++
b/core/src/test/java/org/apache/calcite/avatica/InvalidStaticInitializerWithStaticField.java
@@ -0,0 +1,30 @@
+/*
+ * 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.calcite.avatica;
+
+/**
+ * A class with an invalid initializer and static field. Certain reflection
utils,
+ * can create instances by accessing fields with a specified name.
+ */
+@SuppressWarnings("unused")
+public class InvalidStaticInitializerWithStaticField extends
InvalidStaticInitializer {
+ public static final String FIELD_A = "FIELD_A";
+
+ private InvalidStaticInitializerWithStaticField() {
+ throw new AssertionError("Must not be instantiated");
+ }
+}
diff --git
a/core/src/test/java/org/apache/calcite/avatica/remote/AvaticaHttpClientFactoryTest.java
b/core/src/test/java/org/apache/calcite/avatica/remote/AvaticaHttpClientFactoryTest.java
index 7dae31401..17b31532f 100644
---
a/core/src/test/java/org/apache/calcite/avatica/remote/AvaticaHttpClientFactoryTest.java
+++
b/core/src/test/java/org/apache/calcite/avatica/remote/AvaticaHttpClientFactoryTest.java
@@ -26,6 +26,7 @@
import java.net.URL;
import java.util.Properties;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
/**
@@ -57,16 +58,15 @@ public class AvaticaHttpClientFactoryTest {
client instanceof AvaticaHttpClientImpl);
}
- @Test(expected = RuntimeException.class) public void testInvalidHttpClient()
throws Exception {
+ @Test public void testInvalidHttpClient() throws Exception {
Properties props = new Properties();
props.setProperty(BuiltInConnectionProperty.HTTP_CLIENT_IMPL.name(),
- Properties.class.getName()); // Properties is intentionally *not* a
valid class
+ "org.apache.calcite.avatica.InvalidStaticInitializer");
URL url = new URI("http://localhost:8765").toURL();
ConnectionConfig config = new ConnectionConfigImpl(props);
AvaticaHttpClientFactory httpClientFactory = new
AvaticaHttpClientFactoryImpl();
- // This should throw since the Properties class is invalid
- httpClientFactory.getClient(url, config, null);
+ assertThrows(RuntimeException.class, () ->
httpClientFactory.getClient(url, config, null));
}
}
diff --git
a/core/src/test/java/org/apache/calcite/avatica/remote/BearerTokenProviderFactoryTest.java
b/core/src/test/java/org/apache/calcite/avatica/remote/BearerTokenProviderFactoryTest.java
index 601181a71..270be4d87 100644
---
a/core/src/test/java/org/apache/calcite/avatica/remote/BearerTokenProviderFactoryTest.java
+++
b/core/src/test/java/org/apache/calcite/avatica/remote/BearerTokenProviderFactoryTest.java
@@ -39,6 +39,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
public class BearerTokenProviderFactoryTest {
@@ -123,13 +124,14 @@ public void testCustomBearerTokenInvalid() throws
Exception {
}
- @Test(expected = RuntimeException.class)
- public void testInvalidBearerToken() throws Exception {
+ @Test
+ public void testInvalidBearerToken() {
Properties props = new Properties();
- props.setProperty(BuiltInConnectionProperty.HTTP_CLIENT_IMPL.name(),
- Properties.class.getName()); // Properties is intentionally *not*
a valid class
+ props.setProperty(BuiltInConnectionProperty.TOKEN_PROVIDER_CLASS.name(),
+ "org.apache.calcite.avatica.InvalidStaticInitializer");
ConnectionConfig config = new ConnectionConfigImpl(props);
- BearerTokenProviderFactory.getBearerTokenProvider(config);
+ assertThrows(RuntimeException.class,
+ () -> BearerTokenProviderFactory.getBearerTokenProvider(config));
}
public static class TestTokenProvider implements BearerTokenProvider {
diff --git
a/core/src/test/java/org/apache/calcite/avatica/test/AvaticaUtilsTest.java
b/core/src/test/java/org/apache/calcite/avatica/test/AvaticaUtilsTest.java
index 355702256..39f0f0bad 100644
--- a/core/src/test/java/org/apache/calcite/avatica/test/AvaticaUtilsTest.java
+++ b/core/src/test/java/org/apache/calcite/avatica/test/AvaticaUtilsTest.java
@@ -44,6 +44,7 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.fail;
/**
@@ -95,8 +96,8 @@ public class AvaticaUtilsTest {
fail("expected error, got " + s2);
} catch (Throwable e) {
assertThat(e.getMessage(),
- is("Property 'java.math.BigInteger#ONE' not valid as "
- + "cannot convert java.math.BigInteger to java.lang.String"));
+ is("Property 'java.math.BigInteger#ONE' not valid "
+ + "for plugin type java.lang.String"));
}
// No default constructor or INSTANCE member
@@ -141,8 +142,7 @@ public class AvaticaUtilsTest {
} catch (Throwable e) {
assertThat(e.getMessage(),
is("Property 'org.apache.calcite.avatica.test.AvaticaUtilsTest"
- + "#STRING_THREAD_LOCAL' not valid as cannot convert
java.lang.String "
- + "to java.lang.Integer"));
+ + "#STRING_THREAD_LOCAL' not valid for plugin type
java.lang.Integer"));
} finally {
STRING_THREAD_LOCAL.remove();
}
@@ -158,8 +158,7 @@ public class AvaticaUtilsTest {
} catch (Throwable e) {
assertThat(e.getMessage(),
is("Property 'org.apache.calcite.avatica.test.AvaticaUtilsTest"
- + "#STRING_THREAD_LOCAL' not valid as cannot convert "
- + "java.lang.String to java.math.BigDecimal[]"));
+ + "#STRING_THREAD_LOCAL' not valid for plugin type
[Ljava.math.BigDecimal;"));
} finally {
STRING_THREAD_LOCAL.remove();
}
@@ -175,9 +174,8 @@ public class AvaticaUtilsTest {
} catch (Throwable e) {
assertThat(e.getMessage(),
is("Property 'org.apache.calcite.avatica.test.AvaticaUtilsTest"
- + "#STRING_THREAD_LOCAL' not valid as cannot convert "
- + "java.lang.String to "
- + "org.apache.calcite.avatica.test.AvaticaUtilsTest.Weight"));
+ + "#STRING_THREAD_LOCAL' not valid for plugin type "
+ + "org.apache.calcite.avatica.test.AvaticaUtilsTest$Weight"));
} finally {
STRING_THREAD_LOCAL.remove();
}
@@ -192,8 +190,7 @@ public class AvaticaUtilsTest {
} catch (Throwable e) {
assertThat(e.getMessage(),
is("Property 'org.apache.calcite.avatica.test.AvaticaUtilsTest"
- + "#STRING_THREAD_LOCAL' not valid as cannot convert "
- + "java.lang.String to float"));
+ + "#STRING_THREAD_LOCAL' not valid for plugin type float"));
} finally {
STRING_THREAD_LOCAL.remove();
}
@@ -208,13 +205,38 @@ public class AvaticaUtilsTest {
} catch (Throwable e) {
assertThat(e.getMessage(),
is("Property 'org.apache.calcite.avatica.test.AvaticaUtilsTest"
- + "#FLOAT_THREAD_LOCAL' not valid as cannot convert "
- + "java.lang.Float to float"));
+ + "#FLOAT_THREAD_LOCAL' not valid for plugin type float"));
} finally {
FLOAT_THREAD_LOCAL.remove();
}
}
+ @Test public void testInstantiatePluginViaConstructorWithUnloadedClass() {
+ RuntimeException e = assertThrows(RuntimeException.class,
+ () -> AvaticaUtils.instantiatePlugin(Integer.class,
+ "org.apache.calcite.avatica.InvalidStaticInitializer"));
+ assertThat(e.getMessage(), is("Property
'org.apache.calcite.avatica.InvalidStaticInitializer' "
+ + "not valid for plugin type java.lang.Integer"));
+ }
+
+ @Test public void testInstantiatePluginViaNamedFieldWithUnloadedClass() {
+ RuntimeException e = assertThrows(RuntimeException.class,
+ () -> AvaticaUtils.instantiatePlugin(Integer.class,
+
"org.apache.calcite.avatica.InvalidStaticInitializerWithStaticField#FIELD_A"));
+ assertThat(e.getMessage(),
+ is("Property
'org.apache.calcite.avatica.InvalidStaticInitializerWithStaticField#FIELD_A' "
+ + "not valid for plugin type java.lang.Integer"));
+ }
+
+ @Test public void testInstantiatePluginViaINSTANCEFieldWithUnloadedClass() {
+ RuntimeException e = assertThrows(RuntimeException.class,
+ () -> AvaticaUtils.instantiatePlugin(Integer.class,
+
"org.apache.calcite.avatica.InvalidStaticInitializerWithInstanceField"));
+ assertThat(e.getMessage(),
+ is("Property
'org.apache.calcite.avatica.InvalidStaticInitializerWithInstanceField' "
+ + "not valid for plugin type java.lang.Integer"));
+ }
+
/** Unit test for
* {@link org.apache.calcite.avatica.AvaticaUtils#unique(java.lang.String)}.
*/
@Test public void testUnique() {