chaokunyang commented on code in PR #1553:
URL: https://github.com/apache/incubator-fury/pull/1553#discussion_r1579722048


##########
java/fury-core/src/main/java/org/apache/fury/reflect/TypeRef.java:
##########
@@ -0,0 +1,828 @@
+/*
+ * 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.fury.reflect;
+
+import static org.apache.fury.reflect.Types.asTypeVariableKeyOrNull;
+import static org.apache.fury.reflect.Types.newArrayType;
+import static org.apache.fury.reflect.Types.typeVariablesEquals;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+import org.apache.fury.type.TypeUtils;
+
+public class TypeRef<T> {
+
+  private final Type type;
+
+  /**
+   * Constructs a new type token of {@code T}.
+   *
+   * <p>Clients create an empty anonymous subclass. This embeds the type 
parameter in the anonymous
+   * class's type hierarchy, so we can reconstitute it at runtime despite 
erasure.
+   *
+   * <p>For example:
+   *
+   * <pre>{@code
+   * TypeToken<List<String>> t = new TypeToken<List<String>>() {};
+   * }</pre>
+   */
+  protected TypeRef() {
+    this.type = capture();
+  }
+
+  private TypeRef(Class<T> declaringClass) {
+    this.type = declaringClass;
+  }
+
+  private TypeRef(Type type) {
+    this.type = type;
+  }
+
+  /** Returns an instance of type token that wraps {@code type}. */
+  public static <T> TypeRef<T> of(Class<T> clazz) {
+    return new TypeRef<>(clazz);
+  }
+
+  /** Returns an instance of type token that wraps {@code type}. */
+  public static <T> TypeRef<T> of(Type type) {
+    return new TypeRef<>(type);
+  }
+
+  /** Returns the captured type. */
+  private Type capture() {
+    final Type superclass = getClass().getGenericSuperclass();
+    if (!(superclass instanceof ParameterizedType)) {
+      throw new IllegalArgumentException(superclass + " isn't parameterized");
+    }
+    return ((ParameterizedType) superclass).getActualTypeArguments()[0];
+  }
+
+  /** Returns the represented type. */
+  public Type getType() {
+    return type;
+  }
+
+  /**
+   * Returns the raw type of {@code T}. Formally speaking, if {@code T} is 
returned by {@link
+   * java.lang.reflect.Method#getGenericReturnType}, the raw type is what's 
returned by {@link
+   * java.lang.reflect.Method#getReturnType} of the same method object. 
Specifically:
+   *
+   * <ul>
+   *   <li>If {@code T} is a {@code Class} itself, {@code T} itself is 
returned.
+   *   <li>If {@code T} is a {@link ParameterizedType}, the raw type of the 
parameterized type is
+   *       returned.
+   *   <li>If {@code T} is a {@link GenericArrayType}, the returned type is 
the corresponding array
+   *       class. For example: {@code List<Integer>[] => List[]}.
+   *   <li>If {@code T} is a type variable or a wildcard type, the raw type of 
the first upper bound
+   *       is returned. For example: {@code <X extends Foo> => Foo}.
+   * </ul>
+   */
+  public Class<? super T> getRawType() {
+    @SuppressWarnings("unchecked")
+    Class<? super T> result = (Class<? super T>) TypeUtils.getRawType(type);
+    return result;
+  }
+
+  private static Stream<Class<?>> getRawTypes(Type... types) {
+    return Arrays.stream(types)
+        .flatMap(
+            type -> {
+              if (type instanceof TypeVariable) {
+                return getRawTypes(((TypeVariable<?>) type).getBounds());
+              } else if (type instanceof WildcardType) {
+                return getRawTypes(((WildcardType) type).getUpperBounds());
+              } else if (type instanceof ParameterizedType) {
+                return Stream.of((Class<?>) ((ParameterizedType) 
type).getRawType());
+              } else if (type instanceof Class) {
+                return Stream.of((Class<?>) type);
+              } else if (type instanceof GenericArrayType) {
+                Class<?> rawType =
+                    getArrayClass(
+                        of(((GenericArrayType) 
type).getGenericComponentType()).getRawType());
+                return Stream.of(rawType);
+              } else {
+                throw new AssertionError("Unknown type: " + type);
+              }
+            });
+  }
+
+  /** Returns true if this type is one of the primitive types (including 
{@code void}). */
+  public boolean isPrimitive() {
+    return type instanceof Class && ((Class<?>) type).isPrimitive();
+  }
+
+  /**
+   * Returns true if this type is known to be an array type, such as {@code 
int[]}, {@code T[]},
+   * {@code <? extends Map<String, Integer>[]>} etc.
+   */
+  public boolean isArray() {
+    return getComponentType(type) != null;
+  }
+
+  /**
+   * Returns the array component type if this type represents an array ({@code 
int[]}, {@code T[]},
+   * {@code <? extends Map<String, Integer>[]>} etc.), or else {@code null} is 
returned.
+   */
+  public TypeRef<?> getComponentType() {
+    return of(getComponentType(type));
+  }
+
+  /**
+   * Returns the array component type if this type represents an array ({@code 
int[]}, {@code T[]},
+   * {@code <? extends Map<String, Integer>[]>} etc.), or else {@code null} is 
returned.
+   */
+  private static Type getComponentType(Type type) {
+    if (type == null) {
+      return null;
+    }
+    if (type instanceof TypeVariable) {
+      return subtypeOfComponentType(((TypeVariable<?>) type).getBounds());
+    } else if (type instanceof WildcardType) {
+      return subtypeOfComponentType(((WildcardType) type).getUpperBounds());
+    } else if (type instanceof Class) {
+      return ((Class<?>) type).getComponentType();
+    } else if (type instanceof GenericArrayType) {
+      return ((GenericArrayType) type).getGenericComponentType();
+    }
+    return null;
+  }
+
+  /**
+   * Returns {@code ? extends X} if any of {@code bounds} is a subtype of 
{@code X[]}; or null
+   * otherwise.
+   */
+  private static Type subtypeOfComponentType(Type[] bounds) {
+    for (Type bound : bounds) {
+      final Type componentType = getComponentType(bound);
+      if (componentType != null) {
+        // Only the first bound can be a class or array.
+        // Bounds after the first can only be interfaces.
+        if (componentType instanceof Class) {
+          final Class<?> componentClass = (Class<?>) componentType;
+          if (componentClass.isPrimitive()) {
+            return componentClass;
+          }
+        }
+        return componentType;
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Resolves the given {@code type} against the type context represented by 
this type. For example:
+   *
+   * <pre>{@code
+   * new TypeToken<List<String>>() {}.resolveType(
+   *     List.class.getMethod("get", int.class).getGenericReturnType())
+   * => String.class
+   * }</pre>
+   */
+  public TypeRef<?> resolveType(Type iteratorReturnType) {
+    if (iteratorReturnType instanceof WildcardType) { // fast path
+      return of(iteratorReturnType);
+    }
+    Type invariantContext = WildcardCapturer.capture(type);
+    Map<Types.TypeVariableKey, Type> mappings = 
resolveTypeMappings(invariantContext);
+    return resolveType0(iteratorReturnType, mappings);
+  }
+
+  private TypeRef<?> resolveType0(
+      Type iteratorReturnType, Map<Types.TypeVariableKey, Type> mappings) {
+    if (iteratorReturnType instanceof TypeVariable) {
+      TypeVariable<?> typeVariable = (TypeVariable<?>) iteratorReturnType;
+      Type type = mappings.get(new Types.TypeVariableKey(typeVariable));
+      if (type == null) {
+        return of(typeVariable);
+      }
+      return resolveType0(type, mappings);
+    } else if (iteratorReturnType instanceof ParameterizedType) {
+      ParameterizedType parameterizedType = (ParameterizedType) 
iteratorReturnType;
+      Type owner = parameterizedType.getOwnerType();
+      Type resolvedOwner = owner == null ? null : resolveType0(owner, 
mappings).type;
+      Type resolvedRawType = resolveType0(parameterizedType.getRawType(), 
mappings).type;
+
+      Type[] args = parameterizedType.getActualTypeArguments();
+
+      Type[] resolvedArgs = new Type[args.length];
+      for (int i = 0; i < args.length; i++) {
+        resolvedArgs[i] = resolveType0(args[i], mappings).type;
+      }
+
+      return of(new Types.ParameterizedTypeImpl(resolvedOwner, 
resolvedRawType, resolvedArgs));
+    } else if (iteratorReturnType instanceof GenericArrayType) {
+      Type componentType = ((GenericArrayType) 
iteratorReturnType).getGenericComponentType();
+      Type resolvedComponentType = resolveType0(componentType, mappings).type;
+      return of(newArrayType(resolvedComponentType));
+    }
+    return of(iteratorReturnType);
+  }
+
+  private static Map<Types.TypeVariableKey, Type> resolveTypeMappings(Type 
contextType) {
+    Map<Types.TypeVariableKey, Type> result = new HashMap<>();
+    populateTypeMapping(result, contextType);
+    return result;
+  }

Review Comment:
   Yep, creating map is costly, cache is better. But be careful do not hold 
strong reference, otherwise the class is nog eligible for GC



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscr...@fury.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@fury.apache.org
For additional commands, e-mail: commits-h...@fury.apache.org

Reply via email to