1*3c321d95SSadaf EbrahimiAnnotations 2*3c321d95SSadaf Ebrahimi=========== 3*3c321d95SSadaf Ebrahimi 4*3c321d95SSadaf EbrahimiSimple annotations are easy: 5*3c321d95SSadaf Ebrahimi 6*3c321d95SSadaf Ebrahimi```kotlin 7*3c321d95SSadaf Ebrahimival test = FunSpec.builder("test string equality") 8*3c321d95SSadaf Ebrahimi .addAnnotation(Test::class) 9*3c321d95SSadaf Ebrahimi .addStatement("assertThat(%1S).isEqualTo(%1S)", "foo") 10*3c321d95SSadaf Ebrahimi .build() 11*3c321d95SSadaf Ebrahimi``` 12*3c321d95SSadaf Ebrahimi 13*3c321d95SSadaf EbrahimiWhich generates this function with an `@Test` annotation: 14*3c321d95SSadaf Ebrahimi 15*3c321d95SSadaf Ebrahimi```kotlin 16*3c321d95SSadaf Ebrahimi@Test 17*3c321d95SSadaf Ebrahimifun `test string equality`() { 18*3c321d95SSadaf Ebrahimi assertThat("foo").isEqualTo("foo") 19*3c321d95SSadaf Ebrahimi} 20*3c321d95SSadaf Ebrahimi``` 21*3c321d95SSadaf Ebrahimi 22*3c321d95SSadaf EbrahimiUse `AnnotationSpec.builder()` to set properties on annotations: 23*3c321d95SSadaf Ebrahimi 24*3c321d95SSadaf Ebrahimi```kotlin 25*3c321d95SSadaf Ebrahimival logRecord = FunSpec.builder("recordEvent") 26*3c321d95SSadaf Ebrahimi .addModifiers(KModifier.ABSTRACT) 27*3c321d95SSadaf Ebrahimi .addAnnotation( 28*3c321d95SSadaf Ebrahimi AnnotationSpec.builder(Headers::class) 29*3c321d95SSadaf Ebrahimi .addMember("accept = %S", "application/json; charset=utf-8") 30*3c321d95SSadaf Ebrahimi .addMember("userAgent = %S", "Square Cash") 31*3c321d95SSadaf Ebrahimi .build() 32*3c321d95SSadaf Ebrahimi ) 33*3c321d95SSadaf Ebrahimi .addParameter("logRecord", LogRecord::class) 34*3c321d95SSadaf Ebrahimi .returns(LogReceipt::class) 35*3c321d95SSadaf Ebrahimi .build() 36*3c321d95SSadaf Ebrahimi``` 37*3c321d95SSadaf Ebrahimi 38*3c321d95SSadaf EbrahimiWhich generates this annotation with `accept` and `userAgent` properties: 39*3c321d95SSadaf Ebrahimi 40*3c321d95SSadaf Ebrahimi```kotlin 41*3c321d95SSadaf Ebrahimi@Headers( 42*3c321d95SSadaf Ebrahimi accept = "application/json; charset=utf-8", 43*3c321d95SSadaf Ebrahimi userAgent = "Square Cash" 44*3c321d95SSadaf Ebrahimi) 45*3c321d95SSadaf Ebrahimiabstract fun recordEvent(logRecord: LogRecord): LogReceipt 46*3c321d95SSadaf Ebrahimi``` 47*3c321d95SSadaf Ebrahimi 48*3c321d95SSadaf EbrahimiWhen you get fancy, annotation values can be annotations themselves. Use `%L` for embedded 49*3c321d95SSadaf Ebrahimiannotations: 50*3c321d95SSadaf Ebrahimi 51*3c321d95SSadaf Ebrahimi```kotlin 52*3c321d95SSadaf Ebrahimival headerList = ClassName("", "HeaderList") 53*3c321d95SSadaf Ebrahimival header = ClassName("", "Header") 54*3c321d95SSadaf Ebrahimival logRecord = FunSpec.builder("recordEvent") 55*3c321d95SSadaf Ebrahimi .addModifiers(KModifier.ABSTRACT) 56*3c321d95SSadaf Ebrahimi .addAnnotation( 57*3c321d95SSadaf Ebrahimi AnnotationSpec.builder(headerList) 58*3c321d95SSadaf Ebrahimi .addMember( 59*3c321d95SSadaf Ebrahimi "[\n⇥%L,\n%L⇤\n]", 60*3c321d95SSadaf Ebrahimi AnnotationSpec.builder(header) 61*3c321d95SSadaf Ebrahimi .addMember("name = %S", "Accept") 62*3c321d95SSadaf Ebrahimi .addMember("value = %S", "application/json; charset=utf-8") 63*3c321d95SSadaf Ebrahimi .build(), 64*3c321d95SSadaf Ebrahimi AnnotationSpec.builder(header) 65*3c321d95SSadaf Ebrahimi .addMember("name = %S", "User-Agent") 66*3c321d95SSadaf Ebrahimi .addMember("value = %S", "Square Cash") 67*3c321d95SSadaf Ebrahimi .build() 68*3c321d95SSadaf Ebrahimi ) 69*3c321d95SSadaf Ebrahimi .build() 70*3c321d95SSadaf Ebrahimi ) 71*3c321d95SSadaf Ebrahimi .addParameter("logRecord", logRecordName) 72*3c321d95SSadaf Ebrahimi .returns(logReceipt) 73*3c321d95SSadaf Ebrahimi .build() 74*3c321d95SSadaf Ebrahimi``` 75*3c321d95SSadaf Ebrahimi 76*3c321d95SSadaf EbrahimiWhich generates this: 77*3c321d95SSadaf Ebrahimi 78*3c321d95SSadaf Ebrahimi```kotlin 79*3c321d95SSadaf Ebrahimi@HeaderList( 80*3c321d95SSadaf Ebrahimi [ 81*3c321d95SSadaf Ebrahimi Header(name = "Accept", value = "application/json; charset=utf-8"), 82*3c321d95SSadaf Ebrahimi Header(name = "User-Agent", value = "Square Cash") 83*3c321d95SSadaf Ebrahimi ] 84*3c321d95SSadaf Ebrahimi) 85*3c321d95SSadaf Ebrahimiabstract fun recordEvent(logRecord: LogRecord): LogReceipt 86*3c321d95SSadaf Ebrahimi``` 87*3c321d95SSadaf Ebrahimi 88*3c321d95SSadaf EbrahimiKotlinPoet supports use-site targets for annotations: 89*3c321d95SSadaf Ebrahimi 90*3c321d95SSadaf Ebrahimi```kotlin 91*3c321d95SSadaf Ebrahimival utils = FileSpec.builder("com.example", "Utils") 92*3c321d95SSadaf Ebrahimi .addAnnotation( 93*3c321d95SSadaf Ebrahimi AnnotationSpec.builder(JvmName::class) 94*3c321d95SSadaf Ebrahimi .useSiteTarget(UseSiteTarget.FILE) 95*3c321d95SSadaf Ebrahimi .build() 96*3c321d95SSadaf Ebrahimi ) 97*3c321d95SSadaf Ebrahimi .addFunction( 98*3c321d95SSadaf Ebrahimi FunSpec.builder("abs") 99*3c321d95SSadaf Ebrahimi .receiver(Int::class) 100*3c321d95SSadaf Ebrahimi .returns(Int::class) 101*3c321d95SSadaf Ebrahimi .addStatement("return if (this < 0) -this else this") 102*3c321d95SSadaf Ebrahimi .build() 103*3c321d95SSadaf Ebrahimi ) 104*3c321d95SSadaf Ebrahimi .build() 105*3c321d95SSadaf Ebrahimi``` 106*3c321d95SSadaf Ebrahimi 107*3c321d95SSadaf EbrahimiWill output this: 108*3c321d95SSadaf Ebrahimi 109*3c321d95SSadaf Ebrahimi```kotlin 110*3c321d95SSadaf Ebrahimi@file:JvmName 111*3c321d95SSadaf Ebrahimi 112*3c321d95SSadaf Ebrahimipackage com.example 113*3c321d95SSadaf Ebrahimi 114*3c321d95SSadaf Ebrahimiimport kotlin.Int 115*3c321d95SSadaf Ebrahimiimport kotlin.jvm.JvmName 116*3c321d95SSadaf Ebrahimi 117*3c321d95SSadaf Ebrahimifun Int.abs(): Int = if (this < 0) -this else this 118*3c321d95SSadaf Ebrahimi``` 119