0
# Annotations and Metadata
1
2
Complete support for Kotlin and Java annotations including annotation specifications, JVM-specific annotations, and metadata generation for annotation processors.
3
4
## Capabilities
5
6
### Annotation Specification
7
8
Creates annotation instances with support for all annotation parameter types and complex nested structures.
9
10
```kotlin { .api }
11
/**
12
* Specification for generating annotations
13
*/
14
class AnnotationSpec private constructor() {
15
/** The type name of this annotation */
16
val typeName: TypeName
17
18
/** The member values for this annotation */
19
val members: Map<String, List<CodeBlock>>
20
21
/** String representation for use in generated code */
22
val useSiteTarget: UseSiteTarget?
23
24
companion object {
25
/** Creates a builder for an annotation */
26
fun builder(type: ClassName): Builder
27
fun builder(type: Class<*>): Builder
28
fun builder(type: KClass<*>): Builder
29
30
/** Creates a simple annotation without parameters */
31
fun get(type: ClassName): AnnotationSpec
32
fun get(type: Class<*>): AnnotationSpec
33
fun get(type: KClass<*>): AnnotationSpec
34
}
35
36
/** Builder for constructing AnnotationSpec instances */
37
class Builder {
38
/** Adds a member value to the annotation */
39
fun addMember(name: String, format: String, vararg args: Any?): Builder
40
fun addMember(name: String, codeBlock: CodeBlock): Builder
41
42
/** Sets the use-site target for the annotation */
43
fun useSiteTarget(useSiteTarget: UseSiteTarget): Builder
44
45
/** Builds the AnnotationSpec */
46
fun build(): AnnotationSpec
47
}
48
49
/** Use-site targets for annotations */
50
enum class UseSiteTarget {
51
FILE, PROPERTY, FIELD, GET, SET, RECEIVER, PARAM, SETPARAM, DELEGATE
52
}
53
}
54
```
55
56
**Usage Examples:**
57
58
```kotlin
59
import com.squareup.kotlinpoet.*
60
61
// Simple annotation without parameters
62
val deprecatedAnnotation = AnnotationSpec.get(Deprecated::class)
63
64
// Annotation with string parameter
65
val deprecatedWithMessage = AnnotationSpec.builder(Deprecated::class)
66
.addMember("message = %S", "Use newMethod() instead")
67
.build()
68
69
// Annotation with multiple parameters
70
val suppressWarnings = AnnotationSpec.builder(Suppress::class)
71
.addMember("names = [%S, %S]", "UNCHECKED_CAST", "DEPRECATION")
72
.build()
73
74
// Custom annotation with complex parameters
75
val customAnnotation = AnnotationSpec.builder(ClassName.get("com.example", "Configuration"))
76
.addMember("name = %S", "database")
77
.addMember("timeout = %L", 30)
78
.addMember("enabled = %L", true)
79
.addMember("tags = [%S, %S]", "production", "critical")
80
.build()
81
82
// Annotation with enum parameter
83
val requestMapping = AnnotationSpec.builder(ClassName.get("", "RequestMapping"))
84
.addMember("method = %T.%L", ClassName.get("", "RequestMethod"), "GET")
85
.addMember("path = %S", "/users/{id}")
86
.build()
87
88
// Annotation with class parameter
89
val jsonDeserialize = AnnotationSpec.builder(ClassName.get("com.fasterxml.jackson.databind.annotation", "JsonDeserialize"))
90
.addMember("using = %T::class", ClassName.get("com.example", "CustomDeserializer"))
91
.build()
92
93
// Annotation with nested annotation
94
val validatedAnnotation = AnnotationSpec.builder(ClassName.get("", "Validated"))
95
.addMember("constraints = [%L]",
96
AnnotationSpec.builder(ClassName.get("", "NotNull")).build()
97
)
98
.build()
99
100
// Use-site targets for property annotations
101
val fieldAnnotation = AnnotationSpec.builder(ClassName.get("", "Inject"))
102
.useSiteTarget(AnnotationSpec.UseSiteTarget.FIELD)
103
.build()
104
105
val getterAnnotation = AnnotationSpec.builder(ClassName.get("", "JsonProperty"))
106
.useSiteTarget(AnnotationSpec.UseSiteTarget.GET)
107
.addMember("value = %S", "user_name")
108
.build()
109
```
110
111
### Type Alias Specification
112
113
Creates type aliases for improving code readability and providing semantic meaning to complex types.
114
115
```kotlin { .api }
116
/**
117
* Specification for generating type aliases
118
*/
119
class TypeAliasSpec private constructor() {
120
/** The name of the type alias */
121
val name: String
122
123
/** The type this alias refers to */
124
val type: TypeName
125
126
/** Modifiers applied to the type alias */
127
val modifiers: Set<KModifier>
128
129
/** Type parameters for generic type aliases */
130
val typeVariables: List<TypeVariableName>
131
132
companion object {
133
/** Creates a builder for a type alias */
134
fun builder(name: String, type: TypeName): Builder
135
fun builder(name: String, type: KClass<*>): Builder
136
}
137
138
/** Builder for constructing TypeAliasSpec instances */
139
class Builder {
140
/** Adds modifiers to the type alias */
141
fun addModifiers(vararg modifiers: KModifier): Builder
142
fun addModifiers(modifiers: Iterable<KModifier>): Builder
143
144
/** Adds type parameters */
145
fun addTypeVariable(typeVariable: TypeVariableName): Builder
146
fun addTypeVariables(typeVariables: Iterable<TypeVariableName>): Builder
147
148
/** Adds annotations */
149
fun addAnnotation(annotationSpec: AnnotationSpec): Builder
150
fun addAnnotation(annotation: ClassName): Builder
151
fun addAnnotation(annotation: Class<*>): Builder
152
fun addAnnotation(annotation: KClass<*>): Builder
153
154
/** Adds KDoc documentation */
155
fun addKdoc(format: String, vararg args: Any?): Builder
156
fun addKdoc(block: CodeBlock): Builder
157
158
/** Builds the TypeAliasSpec */
159
fun build(): TypeAliasSpec
160
}
161
}
162
```
163
164
**Usage Examples:**
165
166
```kotlin
167
// Simple type alias
168
val stringMap = TypeAliasSpec.builder(
169
"StringMap",
170
MAP.parameterizedBy(STRING, STRING)
171
).build()
172
173
// Generic type alias
174
val result = TypeAliasSpec.builder(
175
"Result",
176
ClassName.get("kotlin", "Result").parameterizedBy(TypeVariableName.get("T"))
177
)
178
.addTypeVariable(TypeVariableName.get("T"))
179
.build()
180
181
// Type alias for complex function type
182
val eventHandler = TypeAliasSpec.builder(
183
"EventHandler",
184
LambdaTypeName.get(
185
parameters = listOf(
186
ParameterSpec.builder("event", ClassName.get("", "Event")).build()
187
),
188
returnType = UNIT
189
)
190
).build()
191
192
// Type alias with annotations and documentation
193
val userId = TypeAliasSpec.builder("UserId", STRING)
194
.addKdoc("Represents a unique identifier for a user")
195
.addAnnotation(ClassName.get("", "JvmInline"))
196
.build()
197
198
// Internal type alias
199
val internalCache = TypeAliasSpec.builder(
200
"Cache",
201
MAP.parameterizedBy(STRING, ANY.copy(nullable = true))
202
)
203
.addModifiers(KModifier.INTERNAL)
204
.build()
205
206
// Complex generic type alias
207
val repository = TypeAliasSpec.builder("Repository", ClassName.get("", "BaseRepository"))
208
.addTypeVariable(TypeVariableName.get("T"))
209
.addTypeVariable(TypeVariableName.get("ID"))
210
.build()
211
```
212
213
### JVM-Specific Annotations
214
215
Support for JVM-specific annotations and interoperability features through the `com.squareup.kotlinpoet.jvm` package.
216
217
```kotlin { .api }
218
/**
219
* Utilities for JVM-specific annotations
220
*/
221
object JvmAnnotations {
222
/** Adds @JvmOverloads annotation to a function for Java interop */
223
fun overloads(funSpec: FunSpec): FunSpec
224
225
/** Creates @Throws annotation with specified exception classes */
226
fun throws(vararg exceptionClasses: ClassName): AnnotationSpec
227
fun throws(vararg exceptionClasses: Class<out Throwable>): AnnotationSpec
228
fun throws(vararg exceptionClasses: KClass<out Throwable>): AnnotationSpec
229
230
/** Creates @JvmStatic annotation */
231
fun jvmStatic(): AnnotationSpec
232
233
/** Creates @JvmField annotation */
234
fun jvmField(): AnnotationSpec
235
236
/** Creates @JvmName annotation */
237
fun jvmName(name: String): AnnotationSpec
238
239
/** Creates @JvmMultifileClass annotation */
240
fun jvmMultifileClass(): AnnotationSpec
241
}
242
```
243
244
**Usage Examples:**
245
246
```kotlin
247
import com.squareup.kotlinpoet.jvm.JvmAnnotations
248
import com.squareup.kotlinpoet.*
249
250
// Function with JVM overloads for Java interop
251
val functionWithDefaults = FunSpec.builder("processData")
252
.addParameter("data", STRING)
253
.addParameter(
254
ParameterSpec.builder("timeout", INT)
255
.defaultValue("%L", 5000)
256
.build()
257
)
258
.addParameter(
259
ParameterSpec.builder("retries", INT)
260
.defaultValue("%L", 3)
261
.build()
262
)
263
.returns(STRING)
264
.addStatement("return data.process()")
265
.build()
266
267
val jvmFunction = JvmAnnotations.overloads(functionWithDefaults)
268
269
// Function that throws exceptions for Java callers
270
val throwingFunction = FunSpec.builder("readFile")
271
.addParameter("filename", STRING)
272
.returns(STRING)
273
.addAnnotation(JvmAnnotations.throws(IOException::class, SecurityException::class))
274
.addStatement("return File(filename).readText()")
275
.build()
276
277
// Companion object function accessible as static from Java
278
val staticFunction = FunSpec.builder("getInstance")
279
.addAnnotation(JvmAnnotations.jvmStatic())
280
.returns(ClassName("", "Singleton"))
281
.addStatement("return instance")
282
.build()
283
284
// Property exposed as field to Java
285
val jvmFieldProperty = PropertySpec.builder("CONSTANT", STRING)
286
.addModifiers(KModifier.CONST)
287
.addAnnotation(JvmAnnotations.jvmField())
288
.initializer("%S", "constant_value")
289
.build()
290
291
// Function with custom JVM name
292
val kotlinFunction = FunSpec.builder("kotlinSpecificName")
293
.addAnnotation(JvmAnnotations.jvmName("javaFriendlyName"))
294
.returns(UNIT)
295
.addStatement("// Implementation")
296
.build()
297
298
// File-level annotation for multifile classes
299
val multifileClass = FileSpec.builder("com.example", "Utils")
300
.addAnnotation(JvmAnnotations.jvmMultifileClass())
301
.addFunction(staticFunction)
302
.build()
303
```
304
305
### Annotation Processing Support
306
307
Features specifically designed for annotation processors and code generation frameworks.
308
309
```kotlin { .api }
310
// Originating elements for annotation processors
311
interface OriginatingElementsHolder {
312
val originatingElements: List<Element>
313
}
314
315
// Context parameters for context receivers
316
class ContextParameter {
317
companion object {
318
fun get(name: String, type: TypeName): ContextParameter
319
}
320
}
321
```
322
323
**Usage Examples:**
324
325
```kotlin
326
// Annotation processor generated class
327
val generatedClass = TypeSpec.classBuilder("Generated_UserRepository")
328
.addOriginatingElement(userElement) // From annotation processor
329
.addFunction(
330
FunSpec.builder("save")
331
.addParameter("user", ClassName.get("", "User"))
332
.addStatement("database.save(user)")
333
.build()
334
)
335
.build()
336
337
// Generated annotation for tracking
338
val generatedAnnotation = AnnotationSpec.builder(ClassName.get("javax.annotation.processing", "Generated"))
339
.addMember("value = [%S]", "com.example.processor.UserProcessor")
340
.addMember("date = %S", Instant.now().toString())
341
.build()
342
343
val annotatedClass = TypeSpec.classBuilder("ProcessedUser")
344
.addAnnotation(generatedAnnotation)
345
.build()
346
```
347
348
### Metadata and Documentation Annotations
349
350
Support for documentation and metadata annotations that enhance code comprehension and tooling.
351
352
**Usage Examples:**
353
354
```kotlin
355
// Comprehensive documentation with multiple annotations
356
val documentedFunction = FunSpec.builder("complexOperation")
357
.addKdoc("""
358
Performs a complex operation on the input data.
359
360
This function processes the input through multiple stages:
361
1. Validation
362
2. Transformation
363
3. Persistence
364
365
@param data The input data to process
366
@param options Configuration options for processing
367
@return The processed result
368
@throws IllegalArgumentException if data is invalid
369
@throws ProcessingException if processing fails
370
@since 1.2.0
371
@see SimpleOperation for a simpler alternative
372
""".trimIndent())
373
.addAnnotation(
374
AnnotationSpec.builder(ClassName.get("", "ApiStatus"))
375
.addMember("value = %T.%L", ClassName.get("", "ApiStatus", "Stability"), "STABLE")
376
.build()
377
)
378
.addAnnotation(
379
AnnotationSpec.builder(ClassName.get("", "Contract"))
380
.addMember("pure = %L", true)
381
.build()
382
)
383
.addParameter("data", STRING)
384
.addParameter("options", ClassName.get("", "ProcessingOptions"))
385
.returns(ClassName.get("", "ProcessingResult"))
386
.addAnnotation(JvmAnnotations.throws(
387
ClassName.get("", "IllegalArgumentException"),
388
ClassName.get("", "ProcessingException")
389
))
390
.build()
391
392
// Experimental API annotation
393
val experimentalFunction = FunSpec.builder("experimentalFeature")
394
.addAnnotation(
395
AnnotationSpec.builder(ClassName.get("", "ExperimentalApi"))
396
.addMember("message = %S", "This API is experimental and may change")
397
.build()
398
)
399
.build()
400
```