[ 
https://issues.apache.org/jira/browse/CALCITE-4708?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17935314#comment-17935314
 ] 

Artem Simeshin commented on CALCITE-4708:
-----------------------------------------

[~DarrMirr] you are totally right about reflected access question.

field.getGenericType() could be called without reflected access problems, 
tested on jdk17, jdk21 without any additional flags.

Also Calcite call field.getType() without any another problems either on code 
line - 
[https://github.com/apache/calcite/blob/main/core/src/main/java/org/apache/calcite/adapter/java/ReflectiveSchema.java#L197]
 
{code:java}
  private <T> @Nullable Table fieldRelation(final Field field) {
    final Type elementType = getElementType(field.getType());
    //... so on
  } {code}
Attaching for you javadoc for getGenericType() with throws list without any 
IllegalAccessException.

 
{code:java}
/**
 * Returns a {@code Type} object that represents the declared type for
 * the field represented by this {@code Field} object.
 *
 * <p>If the declared type of the field is a parameterized type,
 * the {@code Type} object returned must accurately reflect the
 * actual type arguments used in the source code.
 *
 * <p>If the type of the underlying field is a type variable or a
 * parameterized type, it is created. Otherwise, it is resolved.
 *
 * @return a {@code Type} object that represents the declared type for
 *     the field represented by this {@code Field} object
 * @throws GenericSignatureFormatError if the generic field
 *     signature does not conform to the format specified in
 *     <cite>The Java Virtual Machine Specification</cite>
 * @throws TypeNotPresentException if the generic type
 *     signature of the underlying field refers to a non-existent
 *     class or interface declaration
 * @throws MalformedParameterizedTypeException if the generic
 *     signature of the underlying field refers to a parameterized type
 *     that cannot be instantiated for any reason
 * @since 1.5
 */ {code}
 

>And finally, there is some issue with this proposal. PR at Github still open 
>and there is no comments or decision regarding this issue from framework 
>development team.

Should I create another issue with my solution? What do you think?

 

> 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
>            Priority: Major
>              Labels: pull-request-available
>          Time Spent: 10m
>  Remaining Estimate: 0h
>
> 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}
> Finally, I return type according to information retrieved 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 fit to framework design? Can I create pull request in 
> order to make such improvement?



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to