public static void appendTypeParameters(
    TextBuffer buffer,
    List<String> parameters,
    List<? extends List<GenericType>> bounds,
    final List<TypeAnnotation> typeAnnotations
  ) {
    buffer.append('<');
    for (int i = 0; i < parameters.size(); i++) {
      if (i > 0) {
        buffer.append(", ");
      }
      TargetInfo.TypeParameterTarget.extract(typeAnnotations, i).forEach(typeAnnotation -> typeAnnotation.writeTo(buffer));
      buffer.append(parameters.get(i));
      List<GenericType> parameterBounds = bounds.get(i);
      if (parameterBounds.size() > 1 || !"java/lang/Object".equals(parameterBounds.get(0).getValue())) {
        buffer.append(" extends ");
        TargetInfo.TypeParameterBoundTarget.extract(typeAnnotations, i, 0).forEach(typeAnnotation -> typeAnnotation.writeTo(buffer));
        buffer.append(GenericMain.getGenericCastTypeName(parameterBounds.get(0), Collections.emptyList()));
        for (int j = 1; j < parameterBounds.size(); j++) {
          buffer.append(" & ");
          TargetInfo.TypeParameterBoundTarget.extract(typeAnnotations, i, j).forEach(typeAnnotation -> typeAnnotation.writeTo(buffer));
          buffer.append(GenericMain.getGenericCastTypeName(parameterBounds.get(j), Collections.emptyList()));
        }
      }
    }

    buffer.append('>');
  }
public static void appendTypeParameters(
    TextBuffer buffer,
    List<String> parameters,
    List<? extends List<GenericType>> bounds,
    final List<TypeAnnotation> typeAnnotations
  )