|
| 1 | +--- |
| 2 | +title: Annotations |
| 3 | +id: annotations |
| 4 | +menuTitle: Annotations |
| 5 | +categories: |
| 6 | +- server |
| 7 | +related: |
| 8 | +- tag-component |
| 9 | +- tag-interface |
| 10 | +- tag-function |
| 11 | +- tag-property |
| 12 | +- language-syntax-differences |
| 13 | +- function-getmetadata |
| 14 | +--- |
| 15 | + |
| 16 | +Annotations in Lucee allow you to add metadata to components, interfaces, functions, and properties using JavaDoc-style documentation blocks (docblocks). |
| 17 | + |
| 18 | +This metadata is available at runtime via [[function-getmetadata]] but does not affect code execution. |
| 19 | + |
| 20 | +## Docblock Syntax |
| 21 | + |
| 22 | +Annotations are written in docblock comments (`/** ... */`) placed immediately before the element they describe: |
| 23 | + |
| 24 | +```luceescript |
| 25 | +/** |
| 26 | + * A user service component |
| 27 | + * @author John Smith |
| 28 | + * @version 1.0 |
| 29 | + */ |
| 30 | +component { |
| 31 | +
|
| 32 | + /** |
| 33 | + * Retrieves a user by ID |
| 34 | + * @id The unique user identifier |
| 35 | + * @return A user struct or null if not found |
| 36 | + * @deprecated Use getUserById() instead |
| 37 | + */ |
| 38 | + function getUser( required numeric id ) { |
| 39 | + // implementation |
| 40 | + } |
| 41 | +
|
| 42 | +} |
| 43 | +``` |
| 44 | + |
| 45 | +## Annotation Format |
| 46 | + |
| 47 | +Annotations use the `@name value` format within docblocks: |
| 48 | + |
| 49 | +- **Description**: Text before any `@` tags becomes the description |
| 50 | +- **@tags**: Lines starting with `@` followed by a name and optional value |
| 51 | + |
| 52 | +```luceescript |
| 53 | +/** |
| 54 | + * This is the description. |
| 55 | + * It can span multiple lines. |
| 56 | + * @param.name The user's name |
| 57 | + * @param.age The user's age |
| 58 | + * @return A greeting string |
| 59 | + * @custom.anything You can use any tag name |
| 60 | + */ |
| 61 | +function greet( string name, numeric age ) { |
| 62 | + return "Hello #name#!"; |
| 63 | +} |
| 64 | +``` |
| 65 | + |
| 66 | +## Supported Elements |
| 67 | + |
| 68 | +Docblock annotations can be applied to: |
| 69 | + |
| 70 | +- [[tag-component]] (`component {}`) |
| 71 | +- [[tag-interface]] (`interface {}`) |
| 72 | +- [[tag-function]] (both script and tag style) |
| 73 | +- [[tag-property]] (`property name="..."`) |
| 74 | + |
| 75 | +## Accessing Annotations |
| 76 | + |
| 77 | +Use [[function-getmetadata]] to retrieve annotations at runtime: |
| 78 | + |
| 79 | +```luceescript |
| 80 | +component { |
| 81 | + /** |
| 82 | + * Component description |
| 83 | + * @author Test Author |
| 84 | + */ |
| 85 | +} |
| 86 | +
|
| 87 | +meta = getMetadata( new MyComponent() ); |
| 88 | +dump( meta.hint ); // "Component description" |
| 89 | +dump( meta.author ); // "Test Author" |
| 90 | +``` |
| 91 | + |
| 92 | +For functions: |
| 93 | + |
| 94 | +```luceescript |
| 95 | +/** |
| 96 | + * Function description |
| 97 | + * @return The result |
| 98 | + */ |
| 99 | +function myFunc() {} |
| 100 | +
|
| 101 | +meta = getMetadata( myFunc ); |
| 102 | +dump( meta.hint ); // "Function description" |
| 103 | +dump( meta.return ); // "The result" |
| 104 | +``` |
| 105 | + |
| 106 | +## Annotations vs Inline Attributes |
| 107 | + |
| 108 | +Lucee distinguishes between: |
| 109 | + |
| 110 | +- **Annotations**: Metadata from docblocks (accessed via [[function-getmetadata]]) |
| 111 | +- **Inline attributes**: Attributes in the declaration itself (affect behaviour) |
| 112 | + |
| 113 | +```luceescript |
| 114 | +/** |
| 115 | + * @mixin controller |
| 116 | + */ |
| 117 | +function handler() mixin="model" output="false" { |
| 118 | + // The docblock @mixin is annotation metadata |
| 119 | + // The inline mixin="model" is the actual attribute |
| 120 | +} |
| 121 | +``` |
| 122 | + |
| 123 | +**Important**: When there's a conflict, inline attributes take precedence. Docblock annotations that would affect runtime behaviour (`@returntype`, `@output`, etc.) are ignored if they conflict with the actual declaration. |
| 124 | + |
| 125 | +## Annotations Do Not Affect Runtime |
| 126 | + |
| 127 | +Unlike some other CFML engines, Lucee treats docblock annotations as pure metadata. |
| 128 | + |
| 129 | +They populate [[function-getmetadata]] results but do not change how code executes: |
| 130 | + |
| 131 | +```luceescript |
| 132 | +/** |
| 133 | + * @returntype string |
| 134 | + */ |
| 135 | +public numeric function calculate() { |
| 136 | + return 42; |
| 137 | +} |
| 138 | +// Return type is numeric (from declaration), not string (from annotation) |
| 139 | +``` |
| 140 | + |
| 141 | +This design ensures that comments never cause compiler errors or unexpected behaviour changes. |
| 142 | + |
| 143 | +## Common Annotation Tags |
| 144 | + |
| 145 | +While you can use any tag name, these are commonly used: |
| 146 | + |
| 147 | +| Tag | Purpose | |
| 148 | +|-----|---------| |
| 149 | +| `@param` | Document function parameters | |
| 150 | +| `@return` | Document return value | |
| 151 | +| `@author` | Author information | |
| 152 | +| `@version` | Version number | |
| 153 | +| `@deprecated` | Mark as deprecated with reason | |
| 154 | +| `@see` | Reference to related documentation | |
| 155 | +| `@throws` | Document exceptions that may be thrown | |
| 156 | +| `@hint` | Short description (alternative to first line) | |
| 157 | + |
| 158 | +## Parameter Hints |
| 159 | + |
| 160 | +Document function parameters using `@param.paramname` or just the parameter name: |
| 161 | + |
| 162 | +```luceescript |
| 163 | +/** |
| 164 | + * Greets a user |
| 165 | + * @name The user's name |
| 166 | + * @age The user's age in years |
| 167 | + */ |
| 168 | +function greet( string name, numeric age ) { |
| 169 | + return "Hello #name#, you are #age# years old!"; |
| 170 | +} |
| 171 | +``` |
| 172 | + |
| 173 | +The parameter hints become available in `getMetadata( greet ).parameters[n].hint`. |
| 174 | + |
| 175 | +## Property Annotations |
| 176 | + |
| 177 | +[[tag-property]] supports docblock annotations: |
| 178 | + |
| 179 | +```luceescript |
| 180 | +component accessors="true" { |
| 181 | +
|
| 182 | + /** The user's unique identifier */ |
| 183 | + property name="id" type="numeric"; |
| 184 | +
|
| 185 | + /** |
| 186 | + * The user's display name |
| 187 | + * @validate required |
| 188 | + */ |
| 189 | + property name="displayName" type="string"; |
| 190 | +
|
| 191 | +} |
| 192 | +``` |
| 193 | + |
| 194 | +## Best Practices |
| 195 | + |
| 196 | +1. **Use docblocks for documentation** - descriptions, author info, deprecation notices |
| 197 | +2. **Use inline attributes for behaviour** - output, returntype, access modifiers |
| 198 | +3. **Keep descriptions concise** - first line should be a summary |
| 199 | +4. **Document parameters** - helps IDE tooling and API consumers |
| 200 | +5. **Mark deprecated code** - use `@deprecated` with migration guidance |
0 commit comments