Java API for generating .java source files programmatically with fluent builder interfaces.
—
Advanced type representations for complex generic scenarios including parameterized types, arrays, type variables, and wildcards. These types enable full support for Java's generic type system.
Represents parameterized types like List<String>, Map<String, Integer>, or Optional<? extends Number>. Handles generic type arguments and nested parameterization.
/**
* Represents parameterized types like List<String>, Map<K,V>
*/
public final class ParameterizedTypeName extends TypeName {
// Public fields
public final ClassName rawType;
public final List<TypeName> typeArguments;
// Static factory methods
public static ParameterizedTypeName get(ClassName rawType, TypeName... typeArguments);
public static ParameterizedTypeName get(Class<?> rawType, Type... typeArguments);
public static ParameterizedTypeName get(ParameterizedType type);
// Instance methods
public ParameterizedTypeName annotated(List<AnnotationSpec> annotations);
public TypeName withoutAnnotations();
public ParameterizedTypeName nestedClass(String name);
public ParameterizedTypeName nestedClass(String name, List<TypeName> typeArguments);
}Usage Examples:
// Simple parameterized types
ParameterizedTypeName listString = ParameterizedTypeName.get(List.class, String.class);
ParameterizedTypeName setInteger = ParameterizedTypeName.get(Set.class, Integer.class);
// Map with key-value types
ParameterizedTypeName mapStringInt = ParameterizedTypeName.get(
ClassName.get(Map.class),
ClassName.get(String.class),
ClassName.get(Integer.class)
);
// Nested parameterization
ParameterizedTypeName listOfMaps = ParameterizedTypeName.get(
List.class,
ParameterizedTypeName.get(Map.class, String.class, Object.class)
); // List<Map<String, Object>>
// Complex generic types
ParameterizedTypeName functionType = ParameterizedTypeName.get(
Function.class,
String.class,
ParameterizedTypeName.get(Optional.class, Integer.class)
); // Function<String, Optional<Integer>>
// Using with wildcards
ParameterizedTypeName wildcardList = ParameterizedTypeName.get(
List.class,
WildcardTypeName.subtypeOf(Number.class)
); // List<? extends Number>
// From reflection
ParameterizedType reflectionType = ...; // obtained from reflection
ParameterizedTypeName fromReflection = ParameterizedTypeName.get(reflectionType);Represents array types like String[], int[][], or List<String>[]. Supports multi-dimensional arrays and arrays of complex types.
/**
* Represents array types like String[], int[][], List<String>[]
*/
public final class ArrayTypeName extends TypeName {
// Public fields
public final TypeName componentType;
// Static factory methods
public static ArrayTypeName of(TypeName componentType);
public static ArrayTypeName of(Type componentType);
public static ArrayTypeName get(ArrayType mirror);
public static ArrayTypeName get(GenericArrayType type);
// Instance methods
public ArrayTypeName annotated(List<AnnotationSpec> annotations);
public TypeName withoutAnnotations();
}Usage Examples:
// Primitive arrays
ArrayTypeName intArray = ArrayTypeName.of(TypeName.INT); // int[]
ArrayTypeName byteArray = ArrayTypeName.of(TypeName.BYTE); // byte[]
// Object arrays
ArrayTypeName stringArray = ArrayTypeName.of(String.class); // String[]
ArrayTypeName objectArray = ArrayTypeName.of(Object.class); // Object[]
// Multi-dimensional arrays
ArrayTypeName intMatrix = ArrayTypeName.of(
ArrayTypeName.of(TypeName.INT)
); // int[][]
ArrayTypeName stringMatrix = ArrayTypeName.of(
ArrayTypeName.of(String.class)
); // String[][]
// Arrays of parameterized types
ArrayTypeName listArray = ArrayTypeName.of(
ParameterizedTypeName.get(List.class, String.class)
); // List<String>[]
// Arrays of custom types
ClassName customType = ClassName.get("com.example", "CustomClass");
ArrayTypeName customArray = ArrayTypeName.of(customType); // CustomClass[]
// Using in method signatures
MethodSpec method = MethodSpec.methodBuilder("processArrays")
.addParameter(ArrayTypeName.of(String.class), "names")
.addParameter(ArrayTypeName.of(ArrayTypeName.of(TypeName.INT)), "matrix")
.returns(ArrayTypeName.of(Object.class))
.addStatement("// Process arrays")
.build();
// From reflection
Method reflectionMethod = SomeClass.class.getMethod("arrayMethod", String[].class);
Type arrayType = reflectionMethod.getGenericParameterTypes()[0];
ArrayTypeName fromReflection = (ArrayTypeName) TypeName.get(arrayType);Represents type variables like T, E, K, V used in generic class and method declarations. Supports bounded type variables.
/**
* Represents type variables like T, E, K, V in generic declarations
*/
public final class TypeVariableName extends TypeName {
// Public fields
public final String name;
public final List<TypeName> bounds;
// Static factory methods
public static TypeVariableName get(String name);
public static TypeVariableName get(String name, TypeName... bounds);
public static TypeVariableName get(String name, Type... bounds);
public static TypeVariableName get(TypeVariable mirror);
public static TypeVariableName get(TypeParameterElement element);
public static TypeVariableName get(java.lang.reflect.TypeVariable<?> type);
// Instance methods
public TypeVariableName annotated(List<AnnotationSpec> annotations);
public TypeName withoutAnnotations();
public TypeVariableName withBounds(Type... bounds);
public TypeVariableName withBounds(TypeName... bounds);
public TypeVariableName withBounds(List<? extends TypeName> bounds);
}Usage Examples:
// Simple unbounded type variables
TypeVariableName T = TypeVariableName.get("T");
TypeVariableName E = TypeVariableName.get("E");
TypeVariableName K = TypeVariableName.get("K");
TypeVariableName V = TypeVariableName.get("V");
// Bounded type variables
TypeVariableName numberT = TypeVariableName.get("T", Number.class);
TypeVariableName comparableT = TypeVariableName.get("T", Comparable.class);
// Multiple bounds
TypeVariableName multibound = TypeVariableName.get("T",
ClassName.get(Serializable.class),
ClassName.get(Comparable.class)
); // T extends Serializable & Comparable
// Complex bounds with parameterized types
TypeVariableName complexBound = TypeVariableName.get("T",
ParameterizedTypeName.get(Comparable.class, TypeVariableName.get("T"))
); // T extends Comparable<T>
// Using in generic class
TypeSpec genericClass = TypeSpec.classBuilder("Container")
.addTypeVariable(TypeVariableName.get("T"))
.addField(TypeVariableName.get("T"), "value", Modifier.PRIVATE)
.addMethod(MethodSpec.methodBuilder("getValue")
.addModifiers(Modifier.PUBLIC)
.returns(TypeVariableName.get("T"))
.addStatement("return value")
.build())
.addMethod(MethodSpec.methodBuilder("setValue")
.addModifiers(Modifier.PUBLIC)
.addParameter(TypeVariableName.get("T"), "value")
.addStatement("this.value = value")
.build())
.build();
// Using in generic method
MethodSpec genericMethod = MethodSpec.methodBuilder("swap")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addTypeVariable(TypeVariableName.get("T"))
.addParameter(ArrayTypeName.of(TypeVariableName.get("T")), "array")
.addParameter(TypeName.INT, "i")
.addParameter(TypeName.INT, "j")
.addStatement("T temp = array[i]")
.addStatement("array[i] = array[j]")
.addStatement("array[j] = temp")
.build();
// Bounded generic method
MethodSpec boundedMethod = MethodSpec.methodBuilder("max")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addTypeVariable(TypeVariableName.get("T",
ParameterizedTypeName.get(Comparable.class, TypeVariableName.get("T"))))
.addParameter(TypeVariableName.get("T"), "a")
.addParameter(TypeVariableName.get("T"), "b")
.returns(TypeVariableName.get("T"))
.addStatement("return a.compareTo(b) > 0 ? a : b")
.build();Represents wildcard types like ? extends String, ? super Integer, or unbounded ?. Essential for flexible generic APIs.
/**
* Represents wildcard types like ? extends String, ? super Integer
*/
public final class WildcardTypeName extends TypeName {
// Public fields
public final List<TypeName> upperBounds;
public final List<TypeName> lowerBounds;
// Static factory methods
public static WildcardTypeName subtypeOf(TypeName upperBound);
public static WildcardTypeName subtypeOf(Type upperBound);
public static WildcardTypeName supertypeOf(TypeName lowerBound);
public static WildcardTypeName supertypeOf(Type lowerBound);
public static TypeName get(javax.lang.model.type.WildcardType mirror);
public static TypeName get(WildcardType wildcardName);
// Instance methods
public WildcardTypeName annotated(List<AnnotationSpec> annotations);
public TypeName withoutAnnotations();
}Usage Examples:
// Upper bounded wildcards (? extends Type)
WildcardTypeName extendsNumber = WildcardTypeName.subtypeOf(Number.class);
WildcardTypeName extendsString = WildcardTypeName.subtypeOf(String.class);
// Lower bounded wildcards (? super Type)
WildcardTypeName superInteger = WildcardTypeName.supertypeOf(Integer.class);
WildcardTypeName superString = WildcardTypeName.supertypeOf(String.class);
// Using with parameterized types
ParameterizedTypeName listExtendsNumber = ParameterizedTypeName.get(
List.class,
WildcardTypeName.subtypeOf(Number.class)
); // List<? extends Number>
ParameterizedTypeName listSuperInteger = ParameterizedTypeName.get(
List.class,
WildcardTypeName.supertypeOf(Integer.class)
); // List<? super Integer>
// Consumer/Producer patterns (PECS - Producer Extends, Consumer Super)
MethodSpec copyMethod = MethodSpec.methodBuilder("copy")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addTypeVariable(TypeVariableName.get("T"))
.addParameter(ParameterizedTypeName.get(List.class,
WildcardTypeName.subtypeOf(TypeVariableName.get("T"))), "src") // Producer
.addParameter(ParameterizedTypeName.get(List.class,
WildcardTypeName.supertypeOf(TypeVariableName.get("T"))), "dest") // Consumer
.addStatement("for (T item : src) dest.add(item)")
.build();
// Complex wildcard scenarios
ParameterizedTypeName complexWildcard = ParameterizedTypeName.get(
Map.class,
WildcardTypeName.subtypeOf(String.class),
WildcardTypeName.supertypeOf(
ParameterizedTypeName.get(List.class, Integer.class)
)
); // Map<? extends String, ? super List<Integer>>
// Unbounded wildcard (? - rarely used directly)
// Usually represented as WildcardTypeName.subtypeOf(Object.class)
WildcardTypeName unbounded = WildcardTypeName.subtypeOf(Object.class);
// Method accepting flexible collections
MethodSpec printAll = MethodSpec.methodBuilder("printAll")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addParameter(ParameterizedTypeName.get(Collection.class,
WildcardTypeName.subtypeOf(Object.class)), "items")
.addStatement("for (Object item : items) $T.out.println(item)", System.class)
.build();Combining multiple advanced types for complex generic scenarios:
// Repository pattern with complex generics
TypeVariableName entityT = TypeVariableName.get("T");
TypeVariableName idT = TypeVariableName.get("ID", Serializable.class);
TypeSpec repository = TypeSpec.interfaceBuilder("Repository")
.addModifiers(Modifier.PUBLIC)
.addTypeVariable(entityT)
.addTypeVariable(idT)
.addMethod(MethodSpec.methodBuilder("findById")
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.addParameter(idT, "id")
.returns(ParameterizedTypeName.get(Optional.class, entityT))
.build())
.addMethod(MethodSpec.methodBuilder("findAll")
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.returns(ParameterizedTypeName.get(List.class, entityT))
.build())
.addMethod(MethodSpec.methodBuilder("save")
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.addParameter(entityT, "entity")
.returns(entityT)
.build())
.build();
// Event handler with complex type relationships
TypeVariableName eventT = TypeVariableName.get("E",
ClassName.get("com.example", "Event"));
MethodSpec handleEvents = MethodSpec.methodBuilder("handleEvents")
.addModifiers(Modifier.PUBLIC)
.addTypeVariable(eventT)
.addParameter(ParameterizedTypeName.get(List.class,
WildcardTypeName.subtypeOf(eventT)), "events")
.addParameter(ParameterizedTypeName.get(Consumer.class,
WildcardTypeName.supertypeOf(eventT)), "handler")
.addStatement("events.forEach(handler)")
.build();
// Generic builder pattern
TypeVariableName builderT = TypeVariableName.get("T");
TypeVariableName builderB = TypeVariableName.get("B",
ParameterizedTypeName.get(ClassName.get("Builder"), builderT));
TypeSpec builder = TypeSpec.classBuilder("Builder")
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.addTypeVariable(builderT)
.addTypeVariable(builderB)
.addMethod(MethodSpec.methodBuilder("build")
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.returns(builderT)
.build())
.build();Advanced types support type annotations:
// Annotated type parameters
TypeVariableName annotatedT = TypeVariableName.get("T")
.annotated(AnnotationSpec.builder(NonNull.class).build());
// Annotated parameterized types
ParameterizedTypeName annotatedList = ParameterizedTypeName.get(List.class, String.class)
.annotated(AnnotationSpec.builder(Immutable.class).build());
// Annotated wildcards
WildcardTypeName annotatedWildcard = WildcardTypeName.subtypeOf(String.class)
.annotated(AnnotationSpec.builder(NonNull.class).build());
// Using annotated types in method signatures
MethodSpec annotatedMethod = MethodSpec.methodBuilder("processData")
.addParameter(annotatedList, "data")
.addParameter(ParameterizedTypeName.get(Optional.class, annotatedT), "context")
.returns(ArrayTypeName.of(annotatedT).annotated(
AnnotationSpec.builder(NonNull.class).build()))
.build();Install with Tessl CLI
npx tessl i tessl/maven-com-squareup--javapoet