CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-squareup--javapoet

Java API for generating .java source files programmatically with fluent builder interfaces.

Pending
Overview
Eval results
Files

advanced-types.mddocs/

Advanced Type System

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.

Capabilities

ParameterizedTypeName

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);

ArrayTypeName

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);

TypeVariableName

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();

WildcardTypeName

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();

Type Composition and Complex Scenarios

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();

Working with Annotations on Advanced Types

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

docs

advanced-types.md

code-generation.md

code-specifications.md

file-management.md

index.md

type-system.md

tile.json