ByteBuddy 有什么方法可以将TypeDescription.Generic 转换成合适的java.lang.reflect.Type 吗?

Is there any method in ByteBuddy to convert a TypeDescription.Generic into an appropriate java.lang.reflect.Type?

(ByteBuddy API 的表面积非常大,这就是我问这个问题的原因。)

我知道我可以使用 TypeDescription.Genericdetermine its "sort" 并从那里“手动”相当费力地进行,但我经常发现某处埋藏着一种方法会为我做这种繁琐的工作。

编辑:一位评论者要求提供“乏味”的食谱。在这里(退后一步;请注意各种 Type 的各种实现或多或少是您所期望的):

 public static final Type toType(final TypeDefinition type) throws ReflectiveOperationException {
    final Type returnValue;
    if (type == null) {
      returnValue = null;
    } else {
      final TypeDescription.Generic genericType = type.asGenericType();
      switch (type.getSort()) {
      case GENERIC_ARRAY:
        returnValue = new DefaultGenericArrayType(toType(type.getComponentType()));
        break;
      case NON_GENERIC:
        returnValue = Class.forName(type.getTypeName(), false, Thread.currentThread().getContextClassLoader());
        break;
      case PARAMETERIZED:
        final TypeDefinition ownerType = genericType.getOwnerType();
        final TypeDefinition rawType = type.asErasure();
        final List<? extends TypeDefinition> actualTypeArguments = genericType.getTypeArguments();
        if (actualTypeArguments == null || actualTypeArguments.isEmpty()) {
          returnValue = new DefaultParameterizedType(toType(ownerType), toType(rawType));
        } else {
          final Type[] actualJavaTypeArguments = new Type[actualTypeArguments.size()];
          for (int i = 0; i < actualTypeArguments.size(); i++) {
            actualJavaTypeArguments[i] = toType(actualTypeArguments.get(i));
          }
          returnValue = new DefaultParameterizedType(toType(ownerType), toType(rawType), actualJavaTypeArguments);
        }
        break;
      case VARIABLE:
        final TypeVariableSource typeVariableSource = genericType.getTypeVariableSource();
        final GenericDeclaration gd;
        if (typeVariableSource instanceof TypeDefinition typeDefinition) {
          gd = Class.forName(typeDefinition.asErasure().getTypeName(), false, Thread.currentThread().getContextClassLoader());
        } else if (typeVariableSource instanceof MethodDescription.InDefinedShape methodDescription) {
          // Reflection time
          final String name = methodDescription.getName();
          final Class<?> cls = Class.forName(methodDescription.getDeclaringType().asErasure().getTypeName(), false, Thread.currentThread().getContextClassLoader());
          final List<? extends TypeDefinition> parameterTypes = methodDescription.getParameters().asTypeList();
          final Class<?>[] parameterClasses = new Class<?>[parameterTypes.size()];
          for (int i = 0; i < parameterTypes.size(); i++) {
            parameterClasses[i] = Class.forName(parameterTypes.get(i).asErasure().getName(), false, Thread.currentThread().getContextClassLoader());
          }
          if (MethodDescription.CONSTRUCTOR_INTERNAL_NAME.equals(name)) {
            assert TypeDescription.VOID.equals(methodDescription.getReturnType());
            gd = cls.getDeclaredConstructor(parameterClasses);
          } else {
            assert !MethodDescription.TYPE_INITIALIZER_INTERNAL_NAME.equals(name);
            gd = cls.getDeclaredMethod(name, parameterClasses);            
          }
        } else {
          throw new IllegalArgumentException("Unexpected type variable source: " + typeVariableSource);
        }
        final TypeVariable<?>[] typeVariables = gd.getTypeParameters();
        TypeVariable<?> temp = null;
        for (final TypeVariable<?> typeVariable : typeVariables) {
          if (typeVariable.getName().equals(genericType.getSymbol())) {
            temp = typeVariable;
            break;
          }
        }
        assert temp != null;
        returnValue = temp;
        break;
      case VARIABLE_SYMBOLIC:
        throw new IllegalArgumentException("Unexpected type: " + type);
      case WILDCARD:
        final List<? extends TypeDefinition> upperBounds = genericType.getUpperBounds();
        final List<? extends TypeDefinition> lowerBounds = genericType.getLowerBounds();
        if (lowerBounds == null || lowerBounds.isEmpty()) {
          if (upperBounds == null || upperBounds.isEmpty() || (upperBounds.size() == 1 && TypeDescription.Generic.OBJECT.equals(upperBounds.get(0)))) {
            returnValue = UnboundedWildcardType.INSTANCE;
          } else {
            // Upper bounded.
            final Type[] upperJavaBounds = new Type[upperBounds.size()];
            for (int i = 0; i < upperBounds.size(); i++) {
              upperJavaBounds[i] = toType(upperBounds.get(i)); // XXX recursive
            }
            returnValue = new UpperBoundedWildcardType(upperJavaBounds);
          }
        } else {
          assert upperBounds == null || upperBounds.isEmpty() || (upperBounds.size() == 1 && TypeDescription.Generic.OBJECT.equals(upperBounds.get(0))) : "Unexpected upper bounds: " + upperBounds + "; lower bounds: " + lowerBounds;
          // Lower bounded.
          assert lowerBounds.size() == 1 : "Unexpected size in lower bounds: " + lowerBounds;
          returnValue = new LowerBoundedWildcardType(toType(lowerBounds.get(0))); // XXX recursive
        }
        break;        
      default:
        throw new IllegalArgumentException("Unexpected type: " + type);
      }
    }
    return returnValue;
  }

不,您只能将 Type 转换为 TypeDescription.Generic,但没有其他方法可以转换。模拟这个最简单的选择可能是定义一个 class 来定义给定 Type 的字段,加载这个 class 并使用 Java 读取字段类型反射。

Byte Buddy 无法将描述转换为 Type 的原因是 Byte Buddy 抽象出 class 加载器并且类型变量可能与其声明源分离。