Kotlin and Java API for generating Kotlin source files (.kt) with type-safe, fluent builder patterns
—
Complete support for Kotlin and Java annotations including annotation specifications, JVM-specific annotations, and metadata generation for annotation processors.
Creates annotation instances with support for all annotation parameter types and complex nested structures.
/**
* Specification for generating annotations
*/
class AnnotationSpec private constructor() {
/** The type name of this annotation */
val typeName: TypeName
/** The member values for this annotation */
val members: Map<String, List<CodeBlock>>
/** String representation for use in generated code */
val useSiteTarget: UseSiteTarget?
companion object {
/** Creates a builder for an annotation */
fun builder(type: ClassName): Builder
fun builder(type: Class<*>): Builder
fun builder(type: KClass<*>): Builder
/** Creates a simple annotation without parameters */
fun get(type: ClassName): AnnotationSpec
fun get(type: Class<*>): AnnotationSpec
fun get(type: KClass<*>): AnnotationSpec
}
/** Builder for constructing AnnotationSpec instances */
class Builder {
/** Adds a member value to the annotation */
fun addMember(name: String, format: String, vararg args: Any?): Builder
fun addMember(name: String, codeBlock: CodeBlock): Builder
/** Sets the use-site target for the annotation */
fun useSiteTarget(useSiteTarget: UseSiteTarget): Builder
/** Builds the AnnotationSpec */
fun build(): AnnotationSpec
}
/** Use-site targets for annotations */
enum class UseSiteTarget {
FILE, PROPERTY, FIELD, GET, SET, RECEIVER, PARAM, SETPARAM, DELEGATE
}
}Usage Examples:
import com.squareup.kotlinpoet.*
// Simple annotation without parameters
val deprecatedAnnotation = AnnotationSpec.get(Deprecated::class)
// Annotation with string parameter
val deprecatedWithMessage = AnnotationSpec.builder(Deprecated::class)
.addMember("message = %S", "Use newMethod() instead")
.build()
// Annotation with multiple parameters
val suppressWarnings = AnnotationSpec.builder(Suppress::class)
.addMember("names = [%S, %S]", "UNCHECKED_CAST", "DEPRECATION")
.build()
// Custom annotation with complex parameters
val customAnnotation = AnnotationSpec.builder(ClassName.get("com.example", "Configuration"))
.addMember("name = %S", "database")
.addMember("timeout = %L", 30)
.addMember("enabled = %L", true)
.addMember("tags = [%S, %S]", "production", "critical")
.build()
// Annotation with enum parameter
val requestMapping = AnnotationSpec.builder(ClassName.get("", "RequestMapping"))
.addMember("method = %T.%L", ClassName.get("", "RequestMethod"), "GET")
.addMember("path = %S", "/users/{id}")
.build()
// Annotation with class parameter
val jsonDeserialize = AnnotationSpec.builder(ClassName.get("com.fasterxml.jackson.databind.annotation", "JsonDeserialize"))
.addMember("using = %T::class", ClassName.get("com.example", "CustomDeserializer"))
.build()
// Annotation with nested annotation
val validatedAnnotation = AnnotationSpec.builder(ClassName.get("", "Validated"))
.addMember("constraints = [%L]",
AnnotationSpec.builder(ClassName.get("", "NotNull")).build()
)
.build()
// Use-site targets for property annotations
val fieldAnnotation = AnnotationSpec.builder(ClassName.get("", "Inject"))
.useSiteTarget(AnnotationSpec.UseSiteTarget.FIELD)
.build()
val getterAnnotation = AnnotationSpec.builder(ClassName.get("", "JsonProperty"))
.useSiteTarget(AnnotationSpec.UseSiteTarget.GET)
.addMember("value = %S", "user_name")
.build()Creates type aliases for improving code readability and providing semantic meaning to complex types.
/**
* Specification for generating type aliases
*/
class TypeAliasSpec private constructor() {
/** The name of the type alias */
val name: String
/** The type this alias refers to */
val type: TypeName
/** Modifiers applied to the type alias */
val modifiers: Set<KModifier>
/** Type parameters for generic type aliases */
val typeVariables: List<TypeVariableName>
companion object {
/** Creates a builder for a type alias */
fun builder(name: String, type: TypeName): Builder
fun builder(name: String, type: KClass<*>): Builder
}
/** Builder for constructing TypeAliasSpec instances */
class Builder {
/** Adds modifiers to the type alias */
fun addModifiers(vararg modifiers: KModifier): Builder
fun addModifiers(modifiers: Iterable<KModifier>): Builder
/** Adds type parameters */
fun addTypeVariable(typeVariable: TypeVariableName): Builder
fun addTypeVariables(typeVariables: Iterable<TypeVariableName>): Builder
/** Adds annotations */
fun addAnnotation(annotationSpec: AnnotationSpec): Builder
fun addAnnotation(annotation: ClassName): Builder
fun addAnnotation(annotation: Class<*>): Builder
fun addAnnotation(annotation: KClass<*>): Builder
/** Adds KDoc documentation */
fun addKdoc(format: String, vararg args: Any?): Builder
fun addKdoc(block: CodeBlock): Builder
/** Builds the TypeAliasSpec */
fun build(): TypeAliasSpec
}
}Usage Examples:
// Simple type alias
val stringMap = TypeAliasSpec.builder(
"StringMap",
MAP.parameterizedBy(STRING, STRING)
).build()
// Generic type alias
val result = TypeAliasSpec.builder(
"Result",
ClassName.get("kotlin", "Result").parameterizedBy(TypeVariableName.get("T"))
)
.addTypeVariable(TypeVariableName.get("T"))
.build()
// Type alias for complex function type
val eventHandler = TypeAliasSpec.builder(
"EventHandler",
LambdaTypeName.get(
parameters = listOf(
ParameterSpec.builder("event", ClassName.get("", "Event")).build()
),
returnType = UNIT
)
).build()
// Type alias with annotations and documentation
val userId = TypeAliasSpec.builder("UserId", STRING)
.addKdoc("Represents a unique identifier for a user")
.addAnnotation(ClassName.get("", "JvmInline"))
.build()
// Internal type alias
val internalCache = TypeAliasSpec.builder(
"Cache",
MAP.parameterizedBy(STRING, ANY.copy(nullable = true))
)
.addModifiers(KModifier.INTERNAL)
.build()
// Complex generic type alias
val repository = TypeAliasSpec.builder("Repository", ClassName.get("", "BaseRepository"))
.addTypeVariable(TypeVariableName.get("T"))
.addTypeVariable(TypeVariableName.get("ID"))
.build()Support for JVM-specific annotations and interoperability features through the com.squareup.kotlinpoet.jvm package.
/**
* Utilities for JVM-specific annotations
*/
object JvmAnnotations {
/** Adds @JvmOverloads annotation to a function for Java interop */
fun overloads(funSpec: FunSpec): FunSpec
/** Creates @Throws annotation with specified exception classes */
fun throws(vararg exceptionClasses: ClassName): AnnotationSpec
fun throws(vararg exceptionClasses: Class<out Throwable>): AnnotationSpec
fun throws(vararg exceptionClasses: KClass<out Throwable>): AnnotationSpec
/** Creates @JvmStatic annotation */
fun jvmStatic(): AnnotationSpec
/** Creates @JvmField annotation */
fun jvmField(): AnnotationSpec
/** Creates @JvmName annotation */
fun jvmName(name: String): AnnotationSpec
/** Creates @JvmMultifileClass annotation */
fun jvmMultifileClass(): AnnotationSpec
}Usage Examples:
import com.squareup.kotlinpoet.jvm.JvmAnnotations
import com.squareup.kotlinpoet.*
// Function with JVM overloads for Java interop
val functionWithDefaults = FunSpec.builder("processData")
.addParameter("data", STRING)
.addParameter(
ParameterSpec.builder("timeout", INT)
.defaultValue("%L", 5000)
.build()
)
.addParameter(
ParameterSpec.builder("retries", INT)
.defaultValue("%L", 3)
.build()
)
.returns(STRING)
.addStatement("return data.process()")
.build()
val jvmFunction = JvmAnnotations.overloads(functionWithDefaults)
// Function that throws exceptions for Java callers
val throwingFunction = FunSpec.builder("readFile")
.addParameter("filename", STRING)
.returns(STRING)
.addAnnotation(JvmAnnotations.throws(IOException::class, SecurityException::class))
.addStatement("return File(filename).readText()")
.build()
// Companion object function accessible as static from Java
val staticFunction = FunSpec.builder("getInstance")
.addAnnotation(JvmAnnotations.jvmStatic())
.returns(ClassName("", "Singleton"))
.addStatement("return instance")
.build()
// Property exposed as field to Java
val jvmFieldProperty = PropertySpec.builder("CONSTANT", STRING)
.addModifiers(KModifier.CONST)
.addAnnotation(JvmAnnotations.jvmField())
.initializer("%S", "constant_value")
.build()
// Function with custom JVM name
val kotlinFunction = FunSpec.builder("kotlinSpecificName")
.addAnnotation(JvmAnnotations.jvmName("javaFriendlyName"))
.returns(UNIT)
.addStatement("// Implementation")
.build()
// File-level annotation for multifile classes
val multifileClass = FileSpec.builder("com.example", "Utils")
.addAnnotation(JvmAnnotations.jvmMultifileClass())
.addFunction(staticFunction)
.build()Features specifically designed for annotation processors and code generation frameworks.
// Originating elements for annotation processors
interface OriginatingElementsHolder {
val originatingElements: List<Element>
}
// Context parameters for context receivers
class ContextParameter {
companion object {
fun get(name: String, type: TypeName): ContextParameter
}
}Usage Examples:
// Annotation processor generated class
val generatedClass = TypeSpec.classBuilder("Generated_UserRepository")
.addOriginatingElement(userElement) // From annotation processor
.addFunction(
FunSpec.builder("save")
.addParameter("user", ClassName.get("", "User"))
.addStatement("database.save(user)")
.build()
)
.build()
// Generated annotation for tracking
val generatedAnnotation = AnnotationSpec.builder(ClassName.get("javax.annotation.processing", "Generated"))
.addMember("value = [%S]", "com.example.processor.UserProcessor")
.addMember("date = %S", Instant.now().toString())
.build()
val annotatedClass = TypeSpec.classBuilder("ProcessedUser")
.addAnnotation(generatedAnnotation)
.build()Support for documentation and metadata annotations that enhance code comprehension and tooling.
Usage Examples:
// Comprehensive documentation with multiple annotations
val documentedFunction = FunSpec.builder("complexOperation")
.addKdoc("""
Performs a complex operation on the input data.
This function processes the input through multiple stages:
1. Validation
2. Transformation
3. Persistence
@param data The input data to process
@param options Configuration options for processing
@return The processed result
@throws IllegalArgumentException if data is invalid
@throws ProcessingException if processing fails
@since 1.2.0
@see SimpleOperation for a simpler alternative
""".trimIndent())
.addAnnotation(
AnnotationSpec.builder(ClassName.get("", "ApiStatus"))
.addMember("value = %T.%L", ClassName.get("", "ApiStatus", "Stability"), "STABLE")
.build()
)
.addAnnotation(
AnnotationSpec.builder(ClassName.get("", "Contract"))
.addMember("pure = %L", true)
.build()
)
.addParameter("data", STRING)
.addParameter("options", ClassName.get("", "ProcessingOptions"))
.returns(ClassName.get("", "ProcessingResult"))
.addAnnotation(JvmAnnotations.throws(
ClassName.get("", "IllegalArgumentException"),
ClassName.get("", "ProcessingException")
))
.build()
// Experimental API annotation
val experimentalFunction = FunSpec.builder("experimentalFeature")
.addAnnotation(
AnnotationSpec.builder(ClassName.get("", "ExperimentalApi"))
.addMember("message = %S", "This API is experimental and may change")
.build()
)
.build()Install with Tessl CLI
npx tessl i tessl/maven-com-squareup--kotlinpoet