You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@calcite.apache.org by "Vladimir Polukeev (Jira)" <ji...@apache.org> on 2021/07/29 09:59:00 UTC
[jira] [Created] (CALCITE-4708) Infer list generic type while Table
instance is created at ReflectiveSchema class
Vladimir Polukeev created CALCITE-4708:
------------------------------------------
Summary: Infer list generic type while Table instance is created at ReflectiveSchema class
Key: CALCITE-4708
URL: https://issues.apache.org/jira/browse/CALCITE-4708
Project: Calcite
Issue Type: Improvement
Components: core
Affects Versions: 1.27.0
Environment: Ubuntu 18.04
Java 11
Maven 3.6.0
Reporter: Vladimir Polukeev
I have such code:
{code:java}
// public class Main {
public static void main(String[] args) throws SQLException {
// 1. Create calcite connection
Properties info = new Properties();
info.setProperty("lex", "JAVA");
try(Connection connection = DriverManager.getConnection("jdbc:calcite:", info)) {
Employee employee1 = new Employee("first name 1", "last name 1");
Employee employee2 = new Employee("first name 2", "last name 2");
Employee employee3 = new Employee("first name 3", "last name 3"); List<Employee> employeeList = new LinkedList<>();
employeeList.add(employee1);
employeeList.add(employee2);
employeeList.add(employee3);
MyScheme myScheme = new MyScheme();
myScheme.employees = employeeList;
Schema schema = new ReflectiveSchema(myScheme);
// 2. add scheme with data to root scheme
CalciteConnection calciteConnection = connection.unwrap(CalciteConnection.class);
SchemaPlus rootSchema = calciteConnection.getRootSchema();
rootSchema.add("cache", schema);
// 3. execute sql query against scheme
String sql = "select e.* from cache.employees e";
ResultSet resultSet = calciteConnection.createStatement().executeQuery(sql);
// 4. read data from result set
while (resultSet.next()) {
printValues(resultSet);
}
}
}
public static class MyScheme {
public List<Employee> employees;
}
@AllArgsConstructor
public static class Employee {
public String firstName;
public String lastName;
}
public static void printValues(ResultSet resultSet) throws SQLException {
System.out.println("--------------- row " + resultSet.getRow() + " ---------------");
ResultSetMetaData metaData = resultSet.getMetaData();
for (int i = 1; i <= metaData.getColumnCount(); i++) {
String columnName = metaData.getColumnName(i);
System.out.println(columnName + " : " + resultSet.getObject(columnName));
}
}
}
{code}
Code execution output:
{noformat}
--------------- row 1 ---------------
--------------- row 2 ---------------
--------------- row 3 ---------------{noformat}
Calcite correctly gets 3 rows, but there is no information about columns at output due to item class at Iterable collection infer as Object.class. Here is code from ReflectiveSchema.class:
{code:java}
// private static @Nullable Type getElementType(Class clazz) {
if (clazz.isArray()) {
return clazz.getComponentType();
}
if (Iterable.class.isAssignableFrom(clazz)) {
return Object.class;
}
return null; // not a collection/array/iterable
}
{code}
Information about columns is retured If I change List<Employee> to Employee[] at MyScheme.class. But I have to use List due to my task requirement.
I manage this issue such way:
Java compiler erise information about generic type at compile time. Therefore I supply information about class using annotation org.apache.calcite.adapter.java.Array:
{code:java}
// public static class MyScheme {
+ @Array(component = Employee.class)
public List<Employee> employees;
}
{code}
Than I read element type from annotation at runtime. Here is code from improved ReflectiveSchema.class:
{code:java}
// private <T> @Nullable Table fieldRelation(final Field field) {
+ Array arrayAnnotation = field.getAnnotation(Array.class);
+ Class<?> elementListClass = arrayAnnotation != null ? arrayAnnotation.component() : null;
+ final Type elementType = getElementType(field.getType(), elementListClass);
... // redundant method code is omitted
}
{code}
Finanlly, I return type according to information retrieve from Array annotation:
{code:java}
//+ private static @Nullable Type getElementType(Class clazz, Class<?> elementListClass) {
if (clazz.isArray()) {
return clazz.getComponentType();
}
if (Iterable.class.isAssignableFrom(clazz)) {
+ return elementListClass != null ? elementListClass : Object.class;
}
return null; // not a collection/array/iterable
}
{code}
Now, code execution output:
{noformat}
--------------- row 1 ---------------
firstName : first name 1
lastName : last name 1
--------------- row 2 ---------------
firstName : first name 2
lastName : last name 2
--------------- row 3 ---------------
firstName : first name 3
lastName : last name 3{noformat}
Does such improvement fits to framework design? Can I create pull request in order to make such improvement?
--
This message was sent by Atlassian Jira
(v8.3.4#803005)