JavaPoet is a Java API for generating .java source files programmatically with support for modern Java features including records and sealed types
WildcardTypeName represents wildcard types used in generic type arguments, such as ? extends Number (upper bounded) or ? super Integer (lower bounded). It extends TypeName and is commonly used in parameterized types to provide flexibility in generic type declarations.
Factory methods for creating wildcard type instances.
/**
* Creates an upper-bounded wildcard (? extends Type)
* @param upperBound - The upper bound type
* @return WildcardTypeName for "? extends upperBound"
*/
static WildcardTypeName subtypeOf(TypeName upperBound);
/**
* Creates an upper-bounded wildcard from reflection Type
* @param upperBound - The upper bound type
* @return WildcardTypeName for "? extends upperBound"
*/
static WildcardTypeName subtypeOf(Type upperBound);
/**
* Creates a lower-bounded wildcard (? super Type)
* @param lowerBound - The lower bound type
* @return WildcardTypeName for "? super lowerBound"
*/
static WildcardTypeName supertypeOf(TypeName lowerBound);
/**
* Creates a lower-bounded wildcard from reflection Type
* @param lowerBound - The lower bound type
* @return WildcardTypeName for "? super lowerBound"
*/
static WildcardTypeName supertypeOf(Type lowerBound);
/**
* Creates a WildcardTypeName from a WildcardType mirror
* @param mirror - The wildcard type from annotation processing
* @return WildcardTypeName from the mirror
*/
static WildcardTypeName get(javax.lang.model.type.WildcardType mirror);
/**
* Creates a WildcardTypeName from reflection WildcardType
* @param wildcardType - The wildcard type from reflection
* @return WildcardTypeName from the reflection type
*/
static WildcardTypeName get(java.lang.reflect.WildcardType wildcardType);Usage Examples:
// ? extends Number
WildcardTypeName extendsNumber = WildcardTypeName.subtypeOf(Number.class);
// ? extends Comparable
WildcardTypeName extendsComparable = WildcardTypeName.subtypeOf(Comparable.class);
// ? super Integer
WildcardTypeName superInteger = WildcardTypeName.supertypeOf(Integer.class);
// ? extends Object (unbounded wildcard)
WildcardTypeName unbounded = WildcardTypeName.subtypeOf(Object.class);
// ? extends User
ClassName user = ClassName.get("com.example", "User");
WildcardTypeName extendsUser = WildcardTypeName.subtypeOf(user);
// ? super String
WildcardTypeName superString = WildcardTypeName.supertypeOf(String.class);Get the upper and lower bounds of the wildcard.
/**
* Returns the upper bounds of this wildcard
* @return List of upper bound TypeName (always contains at least Object)
*/
List<TypeName> upperBounds();
/**
* Returns the lower bounds of this wildcard
* @return List of lower bound TypeName (empty for upper-bounded wildcards)
*/
List<TypeName> lowerBounds();Usage Examples:
// ? extends Number
WildcardTypeName extendsNumber = WildcardTypeName.subtypeOf(Number.class);
List<TypeName> upper = extendsNumber.upperBounds(); // [Number]
List<TypeName> lower = extendsNumber.lowerBounds(); // []
// ? super Integer
WildcardTypeName superInteger = WildcardTypeName.supertypeOf(Integer.class);
List<TypeName> upper2 = superInteger.upperBounds(); // [Object]
List<TypeName> lower2 = superInteger.lowerBounds(); // [Integer]Add or remove type annotations.
/**
* Returns a copy with additional annotations
* @param annotations - Annotations to add
* @return New WildcardTypeName with annotations
*/
WildcardTypeName annotated(AnnotationSpec... annotations);
/**
* Returns a copy with additional annotations from a list
* @param annotations - List of annotations to add
* @return New WildcardTypeName with annotations
*/
WildcardTypeName annotated(List<AnnotationSpec> annotations);
/**
* Returns a copy without any annotations
* @return New WildcardTypeName without annotations
*/
WildcardTypeName withoutAnnotations();// List<?>
WildcardTypeName unbounded = WildcardTypeName.subtypeOf(Object.class);
ParameterizedTypeName listOfAnything = ParameterizedTypeName.get(
ClassName.get(List.class),
unbounded
);
// Class<?>
ParameterizedTypeName anyClass = ParameterizedTypeName.get(
ClassName.get(Class.class),
unbounded
);// List<? extends Number>
WildcardTypeName extendsNumber = WildcardTypeName.subtypeOf(Number.class);
ParameterizedTypeName listOfNumbers = ParameterizedTypeName.get(
ClassName.get(List.class),
extendsNumber
);
// Collection<? extends String>
WildcardTypeName extendsString = WildcardTypeName.subtypeOf(String.class);
ParameterizedTypeName collectionOfStrings = ParameterizedTypeName.get(
ClassName.get(Collection.class),
extendsString
);
// Set<? extends Serializable>
WildcardTypeName extendsSerializable = WildcardTypeName.subtypeOf(Serializable.class);
ParameterizedTypeName setOfSerializable = ParameterizedTypeName.get(
ClassName.get(Set.class),
extendsSerializable
);// List<? super Integer>
WildcardTypeName superInteger = WildcardTypeName.supertypeOf(Integer.class);
ParameterizedTypeName listSuperInteger = ParameterizedTypeName.get(
ClassName.get(List.class),
superInteger
);
// Comparator<? super String>
WildcardTypeName superString = WildcardTypeName.supertypeOf(String.class);
ParameterizedTypeName comparatorSuperString = ParameterizedTypeName.get(
ClassName.get(Comparator.class),
superString
);
// Consumer<? super User>
ClassName user = ClassName.get("com.example", "User");
WildcardTypeName superUser = WildcardTypeName.supertypeOf(user);
ParameterizedTypeName consumerSuperUser = ParameterizedTypeName.get(
ClassName.get(Consumer.class),
superUser
);// Producer: ? extends T (provides values)
TypeVariableName t = TypeVariableName.get("T");
WildcardTypeName producer = WildcardTypeName.subtypeOf(t);
ParameterizedTypeName producerCollection = ParameterizedTypeName.get(
ClassName.get(Collection.class),
producer
);
MethodSpec addAll = MethodSpec.methodBuilder("addAll")
.addModifiers(Modifier.PUBLIC)
.addTypeVariable(t)
.addParameter(producerCollection, "source")
.returns(TypeName.VOID)
.addStatement("// add elements from source")
.build();
// Consumer: ? super T (accepts values)
WildcardTypeName consumer = WildcardTypeName.supertypeOf(t);
ParameterizedTypeName consumerCollection = ParameterizedTypeName.get(
ClassName.get(Collection.class),
consumer
);
MethodSpec copyTo = MethodSpec.methodBuilder("copyTo")
.addModifiers(Modifier.PUBLIC)
.addTypeVariable(t)
.addParameter(consumerCollection, "destination")
.returns(TypeName.VOID)
.addStatement("// copy elements to destination")
.build();// public void process(List<? extends Number> numbers)
WildcardTypeName extendsNumber = WildcardTypeName.subtypeOf(Number.class);
ParameterizedTypeName listOfNumbers = ParameterizedTypeName.get(
ClassName.get(List.class),
extendsNumber
);
MethodSpec process = MethodSpec.methodBuilder("process")
.addModifiers(Modifier.PUBLIC)
.addParameter(listOfNumbers, "numbers")
.returns(TypeName.VOID)
.build();
// public void add(Collection<? super String> collection)
WildcardTypeName superString = WildcardTypeName.supertypeOf(String.class);
ParameterizedTypeName collectionSuperString = ParameterizedTypeName.get(
ClassName.get(Collection.class),
superString
);
MethodSpec add = MethodSpec.methodBuilder("add")
.addModifiers(Modifier.PUBLIC)
.addParameter(collectionSuperString, "collection")
.returns(TypeName.VOID)
.build();// public List<?> getAll()
WildcardTypeName unbounded = WildcardTypeName.subtypeOf(Object.class);
ParameterizedTypeName listOfAnything = ParameterizedTypeName.get(
ClassName.get(List.class),
unbounded
);
MethodSpec getAll = MethodSpec.methodBuilder("getAll")
.addModifiers(Modifier.PUBLIC)
.returns(listOfAnything)
.addStatement("return items")
.build();
// public Class<?> getType()
ParameterizedTypeName anyClass = ParameterizedTypeName.get(
ClassName.get(Class.class),
unbounded
);
MethodSpec getType = MethodSpec.methodBuilder("getType")
.addModifiers(Modifier.PUBLIC)
.returns(anyClass)
.build();// private List<? extends Animal> animals;
ClassName animal = ClassName.get("com.example", "Animal");
WildcardTypeName extendsAnimal = WildcardTypeName.subtypeOf(animal);
ParameterizedTypeName listOfAnimals = ParameterizedTypeName.get(
ClassName.get(List.class),
extendsAnimal
);
FieldSpec animals = FieldSpec.builder(listOfAnimals, "animals")
.addModifiers(Modifier.PRIVATE)
.build();
// private Comparator<?> comparator;
WildcardTypeName unbounded = WildcardTypeName.subtypeOf(Object.class);
ParameterizedTypeName anyComparator = ParameterizedTypeName.get(
ClassName.get(Comparator.class),
unbounded
);
FieldSpec comparator = FieldSpec.builder(anyComparator, "comparator")
.addModifiers(Modifier.PRIVATE)
.build();// Map<String, List<? extends Number>>
WildcardTypeName extendsNumber = WildcardTypeName.subtypeOf(Number.class);
ParameterizedTypeName listOfNumbers = ParameterizedTypeName.get(
ClassName.get(List.class),
extendsNumber
);
ParameterizedTypeName mapType = ParameterizedTypeName.get(
ClassName.get(Map.class),
ClassName.get(String.class),
listOfNumbers
);
// Function<? super String, ? extends Integer>
WildcardTypeName superString = WildcardTypeName.supertypeOf(String.class);
WildcardTypeName extendsInteger = WildcardTypeName.subtypeOf(Integer.class);
ParameterizedTypeName functionType = ParameterizedTypeName.get(
ClassName.get(Function.class),
superString,
extendsInteger
);// Collector<String, ?, List<String>>
WildcardTypeName unbounded = WildcardTypeName.subtypeOf(Object.class);
ParameterizedTypeName listOfStrings = ParameterizedTypeName.get(
ClassName.get(List.class),
ClassName.get(String.class)
);
ParameterizedTypeName collector = ParameterizedTypeName.get(
ClassName.get(Collector.class),
ClassName.get(String.class),
unbounded,
listOfStrings
);
MethodSpec toList = MethodSpec.methodBuilder("toList")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(collector)
.addStatement("return $T.toList()", Collectors.class)
.build();// public <T> void copy(List<? extends T> source, List<? super T> dest)
TypeVariableName t = TypeVariableName.get("T");
WildcardTypeName extendsT = WildcardTypeName.subtypeOf(t);
WildcardTypeName superT = WildcardTypeName.supertypeOf(t);
ParameterizedTypeName sourceList = ParameterizedTypeName.get(
ClassName.get(List.class),
extendsT
);
ParameterizedTypeName destList = ParameterizedTypeName.get(
ClassName.get(List.class),
superT
);
MethodSpec copy = MethodSpec.methodBuilder("copy")
.addModifiers(Modifier.PUBLIC)
.addTypeVariable(t)
.addParameter(sourceList, "source")
.addParameter(destList, "dest")
.returns(TypeName.VOID)
.addStatement("dest.addAll(source)")
.build();// Comparable<? super T>
TypeVariableName t = TypeVariableName.get("T");
WildcardTypeName superT = WildcardTypeName.supertypeOf(t);
ParameterizedTypeName comparableSuperT = ParameterizedTypeName.get(
ClassName.get(Comparable.class),
superT
);
// Class<? extends Number>
WildcardTypeName extendsNumber = WildcardTypeName.subtypeOf(Number.class);
ParameterizedTypeName numberClass = ParameterizedTypeName.get(
ClassName.get(Class.class),
extendsNumber
);// class Box<T extends Comparable<? super T>>
TypeVariableName t = TypeVariableName.get("T");
WildcardTypeName superT = WildcardTypeName.supertypeOf(t);
ParameterizedTypeName comparableSuperT = ParameterizedTypeName.get(
ClassName.get(Comparable.class),
superT
);
TypeVariableName boundedT = TypeVariableName.get("T", comparableSuperT);
TypeSpec box = TypeSpec.classBuilder("Box")
.addTypeVariable(boundedT)
.build();Use when you want to read from a structure (producer):
// Can read Number or its subtypes from the list
void sum(List<? extends Number> numbers) {
double total = 0;
for (Number num : numbers) {
total += num.doubleValue(); // Safe to read
}
}Use when you want to write to a structure (consumer):
// Can add Integer or its subtypes to the list
void addIntegers(List<? super Integer> list) {
list.add(42); // Safe to write
list.add(Integer.valueOf(10)); // Safe to write
}class WildcardTypeName extends TypeName {
static WildcardTypeName subtypeOf(TypeName upperBound);
static WildcardTypeName subtypeOf(Type upperBound);
static WildcardTypeName supertypeOf(TypeName lowerBound);
static WildcardTypeName supertypeOf(Type lowerBound);
static WildcardTypeName get(javax.lang.model.type.WildcardType mirror);
static WildcardTypeName get(java.lang.reflect.WildcardType wildcardType);
List<TypeName> upperBounds();
List<TypeName> lowerBounds();
WildcardTypeName annotated(AnnotationSpec... annotations);
WildcardTypeName annotated(List<AnnotationSpec> annotations);
WildcardTypeName withoutAnnotations();
}Install with Tessl CLI
npx tessl i tessl/maven-com-palantir-javapoet--javapoetdocs