You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by da...@apache.org on 2019/10/23 06:37:18 UTC

[calcite] branch master updated: [CALCITE-3414] In calcite-core, use RexToLixTranslator.convert for type conversion code generation uniformly (DonnyZone)

This is an automated email from the ASF dual-hosted git repository.

danny0405 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/master by this push:
     new 429c0d0  [CALCITE-3414] In calcite-core, use RexToLixTranslator.convert for type conversion code generation uniformly (DonnyZone)
429c0d0 is described below

commit 429c0d0e4cacc76933ae6cc651e5e4164f868383
Author: wellfengzhu <we...@gmail.com>
AuthorDate: Mon Oct 14 20:44:01 2019 +0800

    [CALCITE-3414] In calcite-core, use RexToLixTranslator.convert for type conversion code generation uniformly (DonnyZone)
    
    close apache/calcite#1507
---
 .../adapter/enumerable/EnumerableMatch.java        | 10 +++---
 .../adapter/enumerable/EnumerableMergeJoin.java    |  9 +++--
 .../calcite/adapter/enumerable/PhysTypeImpl.java   | 20 +++++------
 .../calcite/adapter/enumerable/RexImpTable.java    | 23 +++++++------
 .../adapter/enumerable/RexToLixTranslator.java     | 39 ++++++++++++++++------
 .../adapter/enumerable/StrictAggImplementor.java   |  3 +-
 .../calcite/adapter/java/ReflectiveSchema.java     |  8 ++---
 .../java/org/apache/calcite/schema/Schemas.java    |  4 +--
 .../java/org/apache/calcite/test/JdbcTest.java     | 10 ++++--
 .../apache/calcite/test/ReflectiveSchemaTest.java  |  4 +--
 .../java/org/apache/calcite/linq4j/tree/Types.java | 28 +++++++++++++---
 11 files changed, 99 insertions(+), 59 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMatch.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMatch.java
index e56e0bd..5cc63df 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMatch.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMatch.java
@@ -176,8 +176,9 @@ public class EnumerableMatch extends Match implements EnumerableRel {
     // Add loop variable initialization
     builder2.add(
         Expressions.declare(0, row_,
-            Types.castIfNecessary(inputPhysType.getJavaRowType(),
-                Expressions.call(rows_, BuiltInMethod.LIST_GET.method, i_))));
+            RexToLixTranslator.convert(
+                Expressions.call(rows_, BuiltInMethod.LIST_GET.method, i_),
+                inputPhysType.getJavaRowType())));
 
     RexBuilder rexBuilder = new RexBuilder(implementor.getTypeFactory());
     RexProgramBuilder rexProgramBuilder =
@@ -475,9 +476,10 @@ public class EnumerableMatch extends Match implements EnumerableRel {
       return Expressions.condition(
           Expressions.greaterThanOrEqual(this.index, Expressions.constant(0)),
           generator.apply(
-              Types.castIfNecessary(physType.getJavaRowType(),
+              RexToLixTranslator.convert(
                   Expressions.call(this.passedRows,
-                      BuiltInMethod.LIST_GET.method, this.index)))
+                      BuiltInMethod.LIST_GET.method, this.index),
+                  physType.getJavaRowType()))
               .field(list, index, storageType),
           Expressions.constant(null));
     }
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoin.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoin.java
index d17184b..aa86c61 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoin.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoin.java
@@ -21,7 +21,6 @@ import org.apache.calcite.linq4j.tree.BlockBuilder;
 import org.apache.calcite.linq4j.tree.Expression;
 import org.apache.calcite.linq4j.tree.Expressions;
 import org.apache.calcite.linq4j.tree.ParameterExpression;
-import org.apache.calcite.linq4j.tree.Types;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptCost;
 import org.apache.calcite.plan.RelOptPlanner;
@@ -146,11 +145,11 @@ public class EnumerableMergeJoin extends Join implements EnumerableRel {
                   right.getRowType().getFieldList().get(pair.right).getType()));
       final Type keyClass = typeFactory.getJavaClass(keyType);
       leftExpressions.add(
-          Types.castIfNecessary(keyClass,
-              leftResult.physType.fieldReference(left_, pair.left)));
+          RexToLixTranslator.convert(
+              leftResult.physType.fieldReference(left_, pair.left), keyClass));
       rightExpressions.add(
-          Types.castIfNecessary(keyClass,
-              rightResult.physType.fieldReference(right_, pair.right)));
+          RexToLixTranslator.convert(
+              rightResult.physType.fieldReference(right_, pair.right), keyClass));
     }
     final PhysType leftKeyPhysType =
         leftResult.physType.project(joinInfo.leftKeys, JavaRowFormat.LIST);
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysTypeImpl.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysTypeImpl.java
index 402f4ac..a48d0eb 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysTypeImpl.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysTypeImpl.java
@@ -219,9 +219,9 @@ public class PhysTypeImpl implements PhysType {
     final List<Expression> expressions = new ArrayList<>();
     for (int field : argList) {
       expressions.add(
-          Types.castIfNecessary(
-              fieldClass(field),
-              fieldReference(v1, field)));
+          RexToLixTranslator.convert(
+              fieldReference(v1, field),
+              fieldClass(field)));
     }
     return expressions;
   }
@@ -308,8 +308,8 @@ public class PhysTypeImpl implements PhysType {
       Expression arg1 = fieldReference(parameterV1, index);
       switch (Primitive.flavor(fieldClass(index))) {
       case OBJECT:
-        arg0 = Types.castIfNecessary(Comparable.class, arg0);
-        arg1 = Types.castIfNecessary(Comparable.class, arg1);
+        arg0 = RexToLixTranslator.convert(arg0, Comparable.class);
+        arg1 = RexToLixTranslator.convert(arg1, Comparable.class);
       }
       final boolean nullsFirst =
           collation.nullDirection
@@ -407,8 +407,8 @@ public class PhysTypeImpl implements PhysType {
       Expression arg1 = fieldReference(parameterV1, index);
       switch (Primitive.flavor(fieldClass(index))) {
       case OBJECT:
-        arg0 = Types.castIfNecessary(Comparable.class, arg0);
-        arg1 = Types.castIfNecessary(Comparable.class, arg1);
+        arg0 = RexToLixTranslator.convert(arg0, Comparable.class);
+        arg1 = RexToLixTranslator.convert(arg1, Comparable.class);
       }
       final boolean nullsFirst =
           fieldCollation.nullDirection
@@ -566,9 +566,9 @@ public class PhysTypeImpl implements PhysType {
       // }
       Class returnType = fieldClasses.get(field0);
       Expression fieldReference =
-          Types.castIfNecessary(
-              returnType,
-              fieldReference(v1, field0));
+          RexToLixTranslator.convert(
+              fieldReference(v1, field0),
+              returnType);
       return Expressions.lambda(
           Function1.class,
           fieldReference,
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
index 1737967..95bfac6 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
@@ -32,7 +32,6 @@ import org.apache.calcite.linq4j.tree.MethodCallExpression;
 import org.apache.calcite.linq4j.tree.OptimizeShuttle;
 import org.apache.calcite.linq4j.tree.ParameterExpression;
 import org.apache.calcite.linq4j.tree.Primitive;
-import org.apache.calcite.linq4j.tree.Types;
 import org.apache.calcite.linq4j.tree.UnaryExpression;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
@@ -1097,7 +1096,7 @@ public class RexImpTable {
       final Expression ifTrue;
       switch (nullAs) {
       case NULL:
-        ifTrue = Types.castIfNecessary(box.getType(), NULL_EXPR);
+        ifTrue = RexToLixTranslator.convert(NULL_EXPR, box.getType());
         break;
       case IS_NULL:
         ifTrue = TRUE_EXPR;
@@ -1380,7 +1379,7 @@ public class RexImpTable {
         next = Expressions.call(acc, "add", add.arguments().get(0));
       } else {
         next = Expressions.add(acc,
-            Types.castIfNecessary(acc.type, add.arguments().get(0)));
+            RexToLixTranslator.convert(add.arguments().get(0), acc.type));
       }
       accAdvance(add, acc, next);
     }
@@ -2200,9 +2199,9 @@ public class RexImpTable {
     private Expression call(Expression operand, Type type,
         TimeUnit timeUnit) {
       return Expressions.call(SqlFunctions.class, methodName,
-          Types.castIfNecessary(type, operand),
-          Types.castIfNecessary(type,
-              Expressions.constant(timeUnit.multiplier)));
+          RexToLixTranslator.convert(operand, type),
+          RexToLixTranslator.convert(
+              Expressions.constant(timeUnit.multiplier), type));
     }
   }
 
@@ -2228,7 +2227,7 @@ public class RexImpTable {
 
       final Type returnType =
           translator.typeFactory.getJavaClass(call.getType());
-      return Types.castIfNecessary(returnType, expression);
+      return RexToLixTranslator.convert(expression, returnType);
     }
   }
 
@@ -2324,9 +2323,10 @@ public class RexImpTable {
 
       final Type returnType =
           translator.typeFactory.getJavaClass(call.getType());
-      return Types.castIfNecessary(returnType,
+      return RexToLixTranslator.convert(
           Expressions.makeBinary(expressionType, expressions.get(0),
-              expressions.get(1)));
+              expressions.get(1)),
+          returnType);
     }
 
     /** Returns whether any of a call's operands have ANY type. */
@@ -2940,8 +2940,9 @@ public class RexImpTable {
     @Override public Expression implement(RexToLixTranslator translator, RexCall call,
         ParameterExpression row, ParameterExpression rows,
         ParameterExpression symbols, ParameterExpression i) {
-      return Types.castIfNecessary(String.class,
-          Expressions.call(symbols, BuiltInMethod.LIST_GET.method, i));
+      return RexToLixTranslator.convert(
+          Expressions.call(symbols, BuiltInMethod.LIST_GET.method, i),
+          String.class);
     }
   }
 
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
index 200f552..a791157 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
@@ -30,6 +30,7 @@ import org.apache.calcite.linq4j.tree.Expressions;
 import org.apache.calcite.linq4j.tree.ParameterExpression;
 import org.apache.calcite.linq4j.tree.Primitive;
 import org.apache.calcite.linq4j.tree.Statement;
+import org.apache.calcite.linq4j.tree.Types;
 import org.apache.calcite.linq4j.tree.UnaryExpression;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactoryImpl;
@@ -963,7 +964,7 @@ public class RexToLixTranslator {
 
   public static Expression convert(Expression operand, Type fromType,
       Type toType) {
-    if (fromType.equals(toType)) {
+    if (!Types.needTypeCast(fromType, toType)) {
       return operand;
     }
     // E.g. from "Short" to "int".
@@ -1050,7 +1051,15 @@ public class RexToLixTranslator {
           return Expressions.box(una.expression, toBox);
         }
       }
-      return Expressions.box(operand, toBox);
+      if (fromType == toBox.primitiveClass) {
+        return Expressions.box(operand, toBox);
+      }
+      // E.g., from "int" to "Byte".
+      // Convert it first and generate "Byte.valueOf((byte)x)"
+      // Because there is no method "Byte.valueOf(int)" in Byte
+      return Expressions.box(
+          Expressions.convert_(operand, toBox.primitiveClass),
+          toBox);
     } else if (fromType == java.sql.Date.class) {
       if (toBox == Primitive.INT) {
         return Expressions.call(BuiltInMethod.DATE_TO_INT.method, operand);
@@ -1134,7 +1143,7 @@ public class RexToLixTranslator {
         }
       } else if (fromType == BigDecimal.class) {
         // E.g. from "BigDecimal" to "String"
-        // Generate "x.toString()"
+        // Generate "SqlFunctions.toString(x)"
         return Expressions.condition(
             Expressions.equal(operand, RexImpTable.NULL_EXPR),
             RexImpTable.NULL_EXPR,
@@ -1143,14 +1152,22 @@ public class RexToLixTranslator {
                 "toString",
                 operand));
       } else {
-        // E.g. from "BigDecimal" to "String"
-        // Generate "x == null ? null : x.toString()"
-        return Expressions.condition(
-            Expressions.equal(operand, RexImpTable.NULL_EXPR),
-            RexImpTable.NULL_EXPR,
-            Expressions.call(
-                operand,
-                "toString"));
+        Expression result;
+        try {
+          // Try to call "toString()" method
+          // E.g. from "Integer" to "String"
+          // Generate "x == null ? null : x.toString()"
+          result = Expressions.condition(
+              Expressions.equal(operand, RexImpTable.NULL_EXPR),
+              RexImpTable.NULL_EXPR,
+              Expressions.call(operand, "toString"));
+        } catch (RuntimeException e) {
+          // For some special cases, e.g., "BuiltInMethod.LESSER",
+          // its return type is generic ("Comparable"), which contains
+          // no "toString()" method. We fall through to "(String)x".
+          return Expressions.convert_(operand, toType);
+        }
+        return result;
       }
     }
     return Expressions.convert_(operand, toType);
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/StrictAggImplementor.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/StrictAggImplementor.java
index a34813c..3c85ddf 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/StrictAggImplementor.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/StrictAggImplementor.java
@@ -22,7 +22,6 @@ import org.apache.calcite.linq4j.tree.Expression;
 import org.apache.calcite.linq4j.tree.Expressions;
 import org.apache.calcite.linq4j.tree.ParameterExpression;
 import org.apache.calcite.linq4j.tree.Primitive;
-import org.apache.calcite.linq4j.tree.Types;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rex.RexNode;
 
@@ -55,7 +54,7 @@ public abstract class StrictAggImplementor implements AggImplementor {
       Expression next) {
     add.currentBlock().add(
         Expressions.statement(
-            Expressions.assign(acc, Types.castIfNecessary(acc.type, next))));
+            Expressions.assign(acc, RexToLixTranslator.convert(next, acc.type))));
   }
 
   public final List<Type> getStateType(AggContext info) {
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 89cb2ff..60a6ea2 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
@@ -17,6 +17,7 @@
 package org.apache.calcite.adapter.java;
 
 import org.apache.calcite.DataContext;
+import org.apache.calcite.adapter.enumerable.RexToLixTranslator;
 import org.apache.calcite.linq4j.Enumerable;
 import org.apache.calcite.linq4j.Enumerator;
 import org.apache.calcite.linq4j.Linq4j;
@@ -26,7 +27,6 @@ import org.apache.calcite.linq4j.function.Function1;
 import org.apache.calcite.linq4j.tree.Expression;
 import org.apache.calcite.linq4j.tree.Expressions;
 import org.apache.calcite.linq4j.tree.Primitive;
-import org.apache.calcite.linq4j.tree.Types;
 import org.apache.calcite.rel.RelReferentialConstraint;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
@@ -167,13 +167,13 @@ public class ReflectiveSchema
   /** Returns an expression for the object wrapped by this schema (not the
    * schema itself). */
   Expression getTargetExpression(SchemaPlus parentSchema, String name) {
-    return Types.castIfNecessary(
-        target.getClass(),
+    return RexToLixTranslator.convert(
         Expressions.call(
             Schemas.unwrap(
                 getExpression(parentSchema, name),
                 ReflectiveSchema.class),
-            BuiltInMethod.REFLECTIVE_SCHEMA_GET_TARGET.method));
+            BuiltInMethod.REFLECTIVE_SCHEMA_GET_TARGET.method),
+        target.getClass());
   }
 
   /** Returns a table based on a particular field of this schema. If the
diff --git a/core/src/main/java/org/apache/calcite/schema/Schemas.java b/core/src/main/java/org/apache/calcite/schema/Schemas.java
index b303358..aa1b425 100644
--- a/core/src/main/java/org/apache/calcite/schema/Schemas.java
+++ b/core/src/main/java/org/apache/calcite/schema/Schemas.java
@@ -17,6 +17,7 @@
 package org.apache.calcite.schema;
 
 import org.apache.calcite.DataContext;
+import org.apache.calcite.adapter.enumerable.RexToLixTranslator;
 import org.apache.calcite.adapter.java.JavaTypeFactory;
 import org.apache.calcite.config.CalciteConnectionConfig;
 import org.apache.calcite.config.CalciteConnectionConfigImpl;
@@ -30,7 +31,6 @@ import org.apache.calcite.linq4j.Queryable;
 import org.apache.calcite.linq4j.tree.Expression;
 import org.apache.calcite.linq4j.tree.Expressions;
 import org.apache.calcite.linq4j.tree.MethodCallExpression;
-import org.apache.calcite.linq4j.tree.Types;
 import org.apache.calcite.materialize.Lattice;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
@@ -176,7 +176,7 @@ public final class Schemas {
           Expressions.constant(elementType),
           Expressions.constant(tableName));
     }
-    return Types.castIfNecessary(clazz, expression);
+    return RexToLixTranslator.convert(expression, clazz);
   }
 
   public static DataContext createDataContext(
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index 8cca9ed..5fb8f71 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -2408,7 +2408,7 @@ public class JdbcTest {
         .planContains("return inp2_ == null "
             + "|| $L4J$C$_org_apache_calcite_runtime_SqlFunctions_ne_ ? (String) null"
             + " : org.apache.calcite.runtime.SqlFunctions.substring(inp2_, "
-            + "current.deptno + 1);");
+            + "Integer.valueOf(current.deptno + 1).intValue());");
   }
 
   @Test public void testReuseExpressionWhenNullChecking4() {
@@ -2439,7 +2439,7 @@ public class JdbcTest {
             + ": org.apache.calcite.runtime.SqlFunctions.substring("
             + "org.apache.calcite.runtime.SqlFunctions.trim(true, true, \" \", "
             + "org.apache.calcite.runtime.SqlFunctions.substring(inp2_, "
-            + "inp1_ * 0 + 1), true), (v5 ? 4 : 5) - 2);")
+            + "Integer.valueOf(inp1_ * 0 + 1).intValue()), true), Integer.valueOf((v5 ? 4 : 5) - 2).intValue());")
         .returns("T=ill\n"
             + "T=ric\n"
             + "T=ebastian\n"
@@ -2463,6 +2463,10 @@ public class JdbcTest {
             "final int inp1_ = current.deptno;")
         .planContains(
             "static final int $L4J$C$5_2 = 5 - 2;")
+        .planContains(
+            "static final Integer $L4J$C$Integer_valueOf_5_2_ = Integer.valueOf($L4J$C$5_2);")
+        .planContains(
+            "static final int $L4J$C$Integer_valueOf_5_2_intValue_ = $L4J$C$Integer_valueOf_5_2_.intValue();")
         .planContains("static final boolean "
             + "$L4J$C$org_apache_calcite_runtime_SqlFunctions_eq_ = "
             + "org.apache.calcite.runtime.SqlFunctions.eq(\"\", \"\");")
@@ -2476,7 +2480,7 @@ public class JdbcTest {
             + ": org.apache.calcite.runtime.SqlFunctions.substring("
             + "org.apache.calcite.runtime.SqlFunctions.trim(true, true, \" \", "
             + "org.apache.calcite.runtime.SqlFunctions.substring(inp2_, "
-            + "inp1_ * 0 + 1), true), $L4J$C$5_2);")
+            + "Integer.valueOf(inp1_ * 0 + 1).intValue()), true), $L4J$C$Integer_valueOf_5_2_intValue_);")
         .returns("T=ll\n"
             + "T=ic\n"
             + "T=bastian\n"
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 0c9b328..95f30c3 100644
--- a/core/src/test/java/org/apache/calcite/test/ReflectiveSchemaTest.java
+++ b/core/src/test/java/org/apache/calcite/test/ReflectiveSchemaTest.java
@@ -612,8 +612,8 @@ public class ReflectiveSchemaTest {
             "final Long inp13_ = ((org.apache.calcite.test.ReflectiveSchemaTest.EveryType) inputEnumerator.current()).wrapperLong;")
         .planContains(
             "return inp13_ == null ? (Long) null "
-                + ": Long.valueOf(inp13_.longValue() / inp13_.longValue() "
-                + "+ inp13_.longValue() / inp13_.longValue());")
+                + ": Long.valueOf(Long.valueOf(inp13_.longValue() / inp13_.longValue()).longValue() "
+                + "+ Long.valueOf(inp13_.longValue() / inp13_.longValue()).longValue());")
         .returns("C=null\n");
   }
 
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Types.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Types.java
index 65a2726..1297c23 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Types.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Types.java
@@ -427,11 +427,7 @@ public abstract class Types {
   public static Expression castIfNecessary(Type returnType,
       Expression expression) {
     final Type type = expression.getType();
-    if (returnType instanceof RecordType) {
-      // We can't extract Class from RecordType since mapping Java Class might not generated yet.
-      return expression;
-    }
-    if (Types.isAssignableFrom(returnType, type)) {
+    if (!needTypeCast(type, returnType)) {
       return expression;
     }
     if (returnType instanceof Class
@@ -464,6 +460,28 @@ public abstract class Types {
     return Expressions.convert_(expression, returnType);
   }
 
+  /**
+   * When trying to cast/convert a {@code Type} to another {@code Type},
+   * it is necessary to pre-check whether the cast operation is needed.
+   * We summarize general exceptions, including:
+   *
+   * <ol>
+   *   <li>target Type {@code toType} equals with original Type {@code fromType}</li>
+   *   <li>target Type can be assignable from original Type</li>
+   *   <li>target Type is an instance of {@code RecordType},
+   *   since the mapping Java Class might not generated yet</li>
+   * </ol>
+   *
+   * @param fromType original type
+   * @param toType   target type
+   * @return Whether a cast operation is needed
+   */
+  public static boolean needTypeCast(Type fromType, Type toType) {
+    return !(fromType.equals(toType)
+        || toType instanceof RecordType
+        || isAssignableFrom(toType, fromType));
+  }
+
   public static PseudoField field(final Field field) {
     return new ReflectedPseudoField(field);
   }