static String typeParametersString(List<? extends TypeParameterElement> typeParameters) {
    if (typeParameters.isEmpty()) {
      return "";
    } else {
      StringBuilder sb = new StringBuilder("<");
      String sep = "";
      for (TypeParameterElement typeParameter : typeParameters) {
        sb.append(sep);
        sep = ", ";
        appendTypeParameterWithBounds(typeParameter, sb);
      }
      return sb.append(">").toString();
    }
  }
Returns a string representing the given type parameters as they would appear in a class
declaration. For example, if we have {@code @AutoValue abstract class Foo<T extends SomeClass>}
then if we call {@link TypeElement#getTypeParameters()} on the representation of {@code Foo},
this method will return an encoding of {@code <T extends SomeClass>}. Likewise it will return
an encoding of the angle-bracket part of: <br>
{@code Foo<SomeClass>}<br>
{@code Foo<T extends Number>}<br>
{@code Foo<E extends Enum<E>>}<br>
{@code Foo<K, V extends Comparable<? extends K>>}.

<p>The encoding is simply that classes in the "extends" part are marked, so the examples will
actually look something like this:<br>
{@code <`bar.baz.SomeClass`>}<br>
{@code <T extends `java.lang.Number`>}<br>
{@code <E extends `java.lang.Enum`<E>>}<br>
{@code <K, V extends `java.lang.Comparable`<? extends K>>}.
value/src/main/java/com/google/auto/value/processor/TypeEncoder.java