001package io.jstach.jstache; 002 003import java.lang.annotation.Documented; 004import java.lang.annotation.ElementType; 005import java.lang.annotation.Retention; 006import java.lang.annotation.RetentionPolicy; 007import java.lang.annotation.Target; 008import java.util.Map; 009import java.util.Optional; 010 011/** 012 * Generates a JStachio Renderer from a template and a model (the annotated class). 013 * <p> 014 * Classes annotated are typically called "models" as they will be the root context for 015 * the template. 016 * 017 * <h2 class="toc-title">Contents</h2> <div class="js-toc"></div> 018 * <div class="js-toc-content"> 019 * <h2 id="_example">Example Usage</h2> 020 * 021 * <pre class="code"> 022 * <code class="language-java"> 023 * @JStache(template = """ 024 * {{#people}} 025 * {{message}} {{name}}! You are {{#ageInfo}}{{age}}{{/ageInfo}} years old! 026 * {{#-last}} 027 * That is all for now! 028 * {{/-last}} 029 * {{/people}} 030 * """) 031 * public record HelloWorld(String message, List<Person> people) implements AgeLambdaSupport {} 032 * 033 * public record Person(String name, LocalDate birthday) {} 034 * 035 * public record AgeInfo(long age, String date) {} 036 * 037 * public interface AgeLambdaSupport { 038 * @JStacheLambda 039 * default AgeInfo ageInfo( 040 * Person person) { 041 * long age = ChronoUnit.YEARS.between(person.birthday(), LocalDate.now()); 042 * String date = person.birthday().format(DateTimeFormatter.ISO_DATE); 043 * return new AgeInfo(age, date); 044 * } 045 * } 046 * </code> </pre> 047 * 048 * <h2 id="_model_and_templates">Models and Templates</h2> 049 * 050 * Because JStachio checks types its best to think of the model and template as married. 051 * With the exception of partials JStachio cannot have a template without a model and vice 052 * versa. The way to create Renderer (what we call the model and template combined) is to 053 * annotate your model with {@link io.jstach.jstache.JStache}. 054 * 055 * <h3 id="_models">Models</h3> <strong>@{@link io.jstach.jstache.JStache}</strong> 056 * <p> 057 * A JStachio model can be any class type including Records and Enums so long as you can 058 * you annotate the type with {@link io.jstach.jstache.JStache}. 059 * <p> 060 * When the compiler runs the annotation processor will create readable java classes that 061 * are suffixed with "Renderer" which will have methods to write the model to an 062 * {@link java.lang.Appendable}. The generated instance methods are named 063 * <code>execute</code> and the corresponding static methods are named 064 * <code>render</code>. 065 * <p> 066 * <em>TIP: If you like to see the generated classes from the annotation processor they 067 * usually get put in <code>target/generated-sources/annotations</code> for Maven 068 * projects.</em> 069 * 070 * <h4 id="_decorating_models">Adding interfaces to models and renderers</h4> 071 * <strong>@{@link io.jstach.jstache.JStacheInterfaces}</strong> 072 * <p> 073 * Java has a huge advantage over JSON and Javascript. <em>You can use interfaces to add 074 * additional variables as well as lambda methods 075 * ({@link io.jstach.jstache.JStacheLambda})!</em> To enforce that certain interfaces are 076 * added to models (the ones annotated) and renderers (the generated classes) you can use 077 * {@link io.jstach.jstache.JStacheInterfaces} on packages or the classes themselves. 078 * <p> 079 * You can also make generated classes have {@link ElementType#TYPE} annotations (see 080 * {@link JStacheInterfaces#templateAnnotations()}) and extend a class 081 * {@link JStacheInterfaces#templateExtends()}) as well which maybe useful for integration 082 * with other frameworks particularly DI frameworks. 083 * 084 * <h3 id="_templates">Templates</h3> 085 * 086 * The format of the templates should by default be Mustache. The syntax is informally 087 * explained by the 088 * <a href="https://jgonggrijp.gitlab.io/wontache/mustache.5.html">mustache manual</a> and 089 * formally explained by the <a href="https://github.com/mustache/spec">spec</a>. There 090 * are some subtle differences in JStachio version of Mustache due to the static nature 091 * that are discussed in <a href="#_context_lookup">context lookup</a>. <strong>Template 092 * finding is as follows:</strong> 093 * <ol> 094 * <li><code>path</code> which is a classpath with slashes following the same format as 095 * the ClassLoader resources. The path maybe augmented with {@link JStachePath}. 096 * <li><code>template</code> which if not empty is used as the template contents 097 * <li>if the above is not set then the name of the class suffixed with ".mustache" is 098 * used as the resource. 099 * </ol> 100 * 101 * <h4 id="_inline_templates">Inline Templates</h4> 102 * <strong>{@link io.jstach.jstache.JStache#template()}</strong> 103 * <p> 104 * Inline templates are pretty straight forward. Just set 105 * {@link io.jstach.jstache.JStache#template()} to a literal string. If you go this route 106 * it is <em>highly recommend you use the new triple quote string literal for inline 107 * templates</em> 108 * 109 * <h4 id="_resource_templates">Resource Templates</h4> 110 * <strong>{@link io.jstach.jstache.JStache#path()} and 111 * @{@link io.jstach.jstache.JStachePath} </strong> 112 * <p> 113 * Resource templates are files that are in the classpath and are more complicated because 114 * of lookup resolution. 115 * <p> 116 * When the annotation processor runs these files usually are in: 117 * <code>javax.tools.StandardLocation#CLASS_OUTPUT</code> and in a Maven or Gradle project 118 * they normally would reside in <code>src/main/resources</code> or 119 * <code>src/test/resources</code> which get copied on build to 120 * <code>target/classes</code> or similar. <em>N.B. becareful not to have resource 121 * filtering turned on for mustache templates.</em> 122 * <p> 123 * Ideally JStachio would use <code>javax.tools.StandardLocation#SOURCE_PATH</code> to 124 * find resource templates but that is currently <a href= 125 * "https://stackoverflow.com/questions/22494596/eclipse-annotation-processor-get-project-path"> 126 * problematic with incremental compilers such as Eclipse</a>. 127 * <p> 128 * Another issue with incremental compiling is that template files are not always copied 129 * after being edited to <code>target/classes</code> and thus are not found by the 130 * annotation processor. To deal with this issue JStachio during compilation fallsback to 131 * direct filesystem access and assumes that your templates are located: 132 * <code>CWD/src/main/resources</code>. That location is configurable via the annotation 133 * processor option {@link #RESOURCES_PATH_OPTION} 134 * (<strong>{@value #RESOURCES_PATH_OPTION}</strong>). 135 * 136 * <p> 137 * Normally you need to specify the full path in {@link #path()} which is a resource path 138 * (and not a file path) as specified by {@link ClassLoader#getResource(String)} however 139 * you can make path expansion happen with {@link io.jstach.jstache.JStachePath} which 140 * allows you to prefix and suffix the path. 141 * 142 * <h4 id="_partials">Partials</h4> 143 * <strong><code>{{> partial }} and {{< parent }}{{/parent}} </code></strong> 144 * <p> 145 * JStachio supports Mustache partials (and parents) and by default works just like 146 * template resources such that {@link io.jstach.jstache.JStachePath} is used for 147 * resolution if specified. 148 * <p> 149 * You may also remap partial names via {@link io.jstach.jstache.JStachePartial} to a 150 * different location as well as to an inline template (string literal). 151 * 152 * <h4 id="_fragments">Fragments</h4> 153 * 154 * JStachio allows referencing a <a href="https://htmx.org/essays/template-fragments/"> 155 * subset of a template called "fragments"</a>. The subset of a template can be any type 156 * of section block and the <em>first one found from top to bottom reading with the 157 * matching name</em> is picked. The subset of a resource template is referenced with the 158 * URI fragment notation. 159 * 160 * <p> 161 * For example let us say we have a template like <code>/contacts/details.mustache</code>: 162 * <pre><code class="language-hbs"> 163 * <html> 164 * <body> 165 * <div hx-target="this"> 166 * {{#archive-ui}} 167 * {{#contact.archived}} 168 * <button hx-patch="/contacts/${contact.id}/unarchive">Unarchive</button> 169 * {{/contact.archived}} 170 * {{^contact.archived}} 171 * <button hx-delete="/contacts/${contact.id}">Archive</button> 172 * {{/contact.archived}} 173 * {{/archive-ui}} 174 * </div> 175 * <h3>Contact</h3> 176 * <p>${contact.email}</p> 177 * </body> 178 * </html> 179 * </code> </pre> 180 * 181 * <pre><code class="language-java"> 182 * @JStache("/contacts/details.mustache#archive-ui") 183 * public record ContactDetails(Contact contact){} 184 * </code> </pre> 185 * 186 * The effective template for <code>ContactDetails</code> would be: 187 * 188 * <pre><code class="language-hbs"> 189 * {{#contact.archived}} 190 * <button hx-patch="/contacts/${contact.id}/unarchive">Unarchive</button> 191 * {{/contact.archived}} 192 * {{^contact.archived}} 193 * <button hx-delete="/contacts/${contact.id}">Archive</button> 194 * {{/contact.archived}} 195 * </code> </pre> 196 * 197 * <strong> If the fragment start tag is "standalone" and all the content inside the 198 * fragment start tag starts with the same whitespace (or more) as the fragment start tag 199 * starting whitespace will be stripped from each line of the content. </strong> This is 200 * to allow a partial references to dictate the indentation based on spec whitespace 201 * handling. 202 * <p> 203 * Fragment section blocks can be of these type: 204 * <ul> 205 * <li><code>{{#fragment}}</code></li> 206 * <li><code>{{$fragment}}</code></li> 207 * <li><code>{{<fragment}}</code></li> 208 * <li><code>{{^fragment}}</code></li> 209 * </ul> 210 * 211 * The semantics of the section block are ignored as well as the rest of the template. 212 * 213 * <h4 id="_optional_spec">Optional Spec Support</h4> JStachio implements some optional 214 * parts of the specification. Below shows what is and is not supported. 215 * <table border="1"> 216 * <caption><strong>Optional Spec Features Table</strong></caption> 217 * <tr> 218 * <th>Name</th> 219 * <th>Supported</th> 220 * <th>Manual Description</th> 221 * </tr> 222 * <tr> 223 * <td>Lambda variables (arity 0)</td> 224 * <td style="color:red;">NO</td> 225 * <td>An optional part of the specification states that if the final key in the name is a 226 * lambda that returns a string, then that string should be rendered as a Mustache 227 * template before interpolation. It will be rendered using the default delimiters (see 228 * Set Delimiter below) against the current context.</td> 229 * </tr> 230 * <tr> 231 * <td>Lambda sections (arity 1)</td> 232 * <td style="color:blue;">YES</td> 233 * <td>An optional part of the specification states that if the final key in the name is a 234 * lambda that returns a string, then that string replaces the content of the section. It 235 * will be rendered using the same delimiters (see Set Delimiter below) as the original 236 * section content. In this way you can implement filters or caching.</td> 237 * </tr> 238 * <tr> 239 * <td>Delimiters</td> 240 * <td style="color:blue;">YES</td> 241 * <td>Set Delimiter tags are used to change the tag delimiters for all content following 242 * the tag in the current compilation unit. The tag's content MUST be any two 243 * non-whitespace sequences (separated by whitespace) EXCEPT an equals sign ('=') followed 244 * by the current closing delimiter. Set Delimiter tags SHOULD be treated as standalone 245 * when appropriate. <em>(this feature is non-optional in current mustache but some 246 * mustaches implemenations treat it as optional)</em></td> 247 * </tr> 248 * <tr> 249 * <td>Dynamic Names</td> 250 * <td style="color:red;">NO</td> 251 * <td>Partials can be loaded dynamically at runtime using Dynamic Names; an optional part 252 * of the Mustache specification which allows to dynamically determine a tag's content at 253 * runtime.</td> 254 * </tr> 255 * <tr> 256 * <td>Blocks</td> 257 * <td style="color:blue;">YES</td> 258 * <td>A block begins with a dollar and ends with a slash. That is, {{$title}} begins a 259 * "title" block and {{/title}} ends it.</td> 260 * </tr> 261 * <tr> 262 * <td>Parents</td> 263 * <td style="color:blue;">YES</td> 264 * <td>A parent begins with a less than sign and ends with a slash. That is, 265 * {{<article}} begins an "article" parent and {{/article}} ends it.</td> 266 * </tr> 267 * </table> 268 * 269 * <h3 id="_context_lookup">Context Lookup</h3> 270 * 271 * JStachio unlike almost all other Mustache implementations does its context lookup 272 * statically during compile time. Consequently JStachio pedantically is early bound where 273 * as Mustache is traditionally late bound. Most of the time this difference will not 274 * manifest itself so long as you avoid using {@link Map} in your models. 275 * <p> 276 * The other notable difference is JStachio does not like missing variables (a compiler 277 * error will happen) where as many Mustache implementations sometimes allow this and will 278 * just not output anything. 279 * 280 * <em> n.b. This doc and various other docs often appears to use the term "variable" and 281 * "binding" interchangeable. "variable" however is generally a subset of "binding" and is 282 * the leaf nodes of the model tree that are to be outputted like String 283 * interpolation.</em> In mustache spec parlance it is the last key (all the way to the 284 * right) of a dotted name. Also in some cases this doc calls dotted names "path". 285 * 286 * 287 * <h4 id="_context_java_types">Interpretation of Java-types and values</h4> When some 288 * value is null nothing is rendered if it is used as a section. If some value is null and 289 * it is used as a variable a null pointer exception will be thrown by default. This is 290 * configurable via {@link JStacheFormatterTypes} and custom {@link JStacheFormatter}. 291 * <p> 292 * Boxed and unboxed <code>boolean</code> can be used for mustache-sections. Section is 293 * only rendered if value is true. 294 * <p> 295 * {@link Optional} empty is treated like an empty list or a boolean false. Optional 296 * values are always assumed to be non null. 297 * <p> 298 * {@code Map<String,?>} follow different nesting rules than other types. If you are in a 299 * {@link Map} nested section the rest of the context is checked before the 300 * <code>Map</code>. Once that is done the Map is then checked using 301 * {@link Map#get(Object)}' where the key is the <em>last part of the dotted name</em>. 302 * <p> 303 * Data-binding contexts are nested. Names are looked up in innermost context first. If 304 * name is not found in current context, parent context is inspected. This process 305 * continues up to root context. 306 * 307 * In each rendering context name lookup is performed as follows: 308 * 309 * <ol> 310 * <li>Method with requested name is looked up. Method should have no arguments and should 311 * throw no checked exceptions. If there is such method it is used to fetch actual data to 312 * render. Compile-time error is raised if there is method with given name, but it is not 313 * accessible, has parameters or throws checked exceptions.</li> 314 * <li>Method with requested name and annotated correctly with {@link JStacheLambda} and 315 * the lookup is for a section than the method lambda method will be used.</li> 316 * <li>Method with getter-name for requested name is looked up. (For example, if 'age' is 317 * requested, 'getAge' method is looked up.) Method should have no arguments and should 318 * throw no checked exceptions. If there is such method it is used to fetch actual data to 319 * render. Compile-time error is raised if there is method with such name, but it is not 320 * accessible, has parameters or throws checked exceptions</li> 321 * 322 * <li>Field with requested name is looked up. Compile-time error is raised if there is 323 * field with such name but it's not accessible.</li> 324 * </ol> 325 * 326 * <h4 id="_inheritance">Inheritance and enclosed access of fields and methods</h4> 327 * 328 * Currently JStachio will only allow access to <code>public</code> methods and fields 329 * that are <strong>inherited</strong>. However enclosed fields and methods 330 * <strong>directly</strong> on the type annotated can be package protected (the default 331 * no modifier). <code>private</code> fields and methods regardless of inheritance are not 332 * allowed as the only way to access them would be through MethodHandles and would greatly 333 * complicate code generation. 334 * <p> 335 * <em> The above behavior is to simplify portability and usage of reflective engines such 336 * as JMustache and Handlebars.java in modular applications and libraries. However the use 337 * of these engines unlike JStachio may still require <code>open</code>ing up the module 338 * containing the annotated models. If you would like different rules for access please 339 * file an issue. </em> 340 * 341 * <h4 id="_enums">Enum Matching Extension</h4> Basically enums have boolean keys that are 342 * the enums name ({@code Enum.name()}) that can be used as conditional sections. Assume 343 * {@code light} is an enum like: 344 * 345 * <pre> 346 * <code class="language-java"> 347 * public enum Light { 348 * RED, 349 * GREEN, 350 * YELLOW 351 * } 352 * </code> </pre> 353 * 354 * You can conditinally select on the enum like a pattern match: 355 * 356 * <pre> 357 * <code class="language-hbs"> 358 * {{#light.RED}} 359 * STOP 360 * {{/light.RED}} 361 * {{#light.GREEN}} 362 * GO 363 * {{/light.GREEN}} 364 * {{#light.YELLOW}} 365 * Proceeed with caution 366 * {{/light.YELLOW}} 367 * </code> </pre> 368 * 369 * <h4 id="_index_support">Index Extension</h4> 370 * 371 * JStachio is compatible with both handlebars.js (handlebars.java as well) and JMustache 372 * index keys for iterable sections. 373 * <ol> 374 * <li><code>{@value #FIRST_JMUSTACHE_BINDING_NAME}</code> and 375 * <code>{@value #FIRST_BINDING_NAME}</code> is boolean that is true when you are on the 376 * first item.</li> 377 * <li><code>{@value #LAST_JMUSTACHE_BINDING_NAME}</code> and 378 * <code>{@value #LAST_JMUSTACHE_BINDING_NAME}</code> is a boolean that is true when you 379 * are on the last item in the iterable</li> 380 * <li><code>{@value #INDEX_JMUSTACHE_BINDING_NAME}</code> is a one based index. The first 381 * item would be {@code 1} and not {@code 0}</li> 382 * <li><code>{@value #INDEX_BINDING_NAME}</code> is zero based index (handlebars). The 383 * first item would be {@code 0}. 384 * </ol> 385 * 386 * <h3 id="_lambdas">Lambda Support</h3> 387 * 388 * <strong>@{@link JStacheLambda}</strong> 389 * <p> 390 * JStachio supports lambda section calls in a similar manner to 391 * <a href="https://github.com/samskivert/jmustache">JMustache</a>. Just tag your methods 392 * with {@link JStacheLambda} and the returned models will be used to render the contents 393 * of the lambda section. The top of the context stack can be passed to the lambda. 394 * 395 * 396 * <h2 id="_code_generation">Code Generation</h2> 397 * 398 * <strong>@{@link io.jstach.jstache.JStacheConfig#type()}</strong> 399 * <p> 400 * JStachio by default reads mustache syntax and generates code that needs the jstachio 401 * runtime (io.jstache.jstachio). However it is possible to generate code that does not 402 * need the runtime and possibly in the future other syntaxs like Handlebars might be 403 * supported. 404 * 405 * <h3 id="_methods_generated">Generated Renderer Classes</h3> JStachio generates a single 406 * class from a mustache template and model (class annotated with JStache) pair. The 407 * generated classes are generally called "Renderers" or sometimes "Templates". Depending 408 * on which JStache type is picked different methods are generated. The guaranteed 409 * generated methods <em>not to change on minor version or less</em> on the renderer 410 * classes are discussed in <strong>{@link JStacheType}</strong>. 411 * 412 * <h3 id="_zero_dep">Zero dependency code generation</h3> 413 * 414 * <strong>@{@link io.jstach.jstache.JStacheConfig#type()} == 415 * {@link JStacheType#STACHE}</strong> 416 * <p> 417 * Zero dependency code generation is useful if you want to avoid coupling your runtime 418 * and downstream dependencies with JStachio (including the annotations themselves) as 419 * well as minimize the overall footprint and or classes loaded. A common use case would 420 * be using jstachio for code generation in an annotation processing library where you 421 * want as minimal class path issues as possible. 422 * <p> 423 * If this configuration is selected generated code will <strong>ONLY have references to 424 * stock base JDK module ({@link java.base/}) classes</strong>. However one major caveat 425 * is that generated classes will not be reflectively accessible to the JStachio runtime 426 * and thus fallback and filtering will not work. Thus in a web framework environment this 427 * configuration choice is less desirable. 428 * <p> 429 * <em>n.b. as long as the jstachio annotations are not accessed reflectively you do not 430 * need the annotation jar in the classpath during runtime thus the annotations jar is 431 * effectively an optional compile time dependency.</em> 432 * 433 * 434 * <h2 id="_formatting">Formatting variables</h2> 435 * 436 * JStachio has strict control on what happens when you output a variable (a binding that 437 * is not an iterable) like <code>{{variable}}</code> or <code>{{{variable}}}</code>. 438 * 439 * <h3 id="_allowed_types">Allowed formatting types</h3> <strong> 440 * @{@link io.jstach.jstache.JStacheFormatterTypes}</strong> 441 * <p> 442 * Only a certain set of types are allowed to be formatted and if they are not a compiler 443 * error will happen (as in the annotation processor will fail). To understand more about 444 * that see {@link io.jstach.jstache.JStacheFormatterTypes}. 445 * 446 * <h3 id="_runtime_formatting">Runtime formatting</h3> 447 * <strong>@{@link io.jstach.jstache.JStacheFormatter} and 448 * @{@link JStacheConfig#formatter()}</strong> 449 * <p> 450 * Assuming the compiler allowed the variable to be formatted you can control the output 451 * via {@link io.jstach.jstache.JStacheFormatter} and setting 452 * {@link io.jstach.jstache.JStacheConfig#formatter()}. 453 * <p> 454 * If you are using the JStachio runtime (io.jstach.jstachio) and have 455 * {@link JStacheConfig#type()} set to {@link JStacheType#JSTACHIO} (or UNSPECIFIED aka 456 * default) the default formatter will be used (see <code class= 457 * "externalLink">io.jstach.jstachio.formatters.DefaultFormatter</code>). The default 458 * formatter is slightly different than the mustache spec in that it does not allow 459 * formatting nulls. If you would like to follow the spec rules where <code>null</code> 460 * should be an empty string use <code class= 461 * "externalLink">io.jstach.jstachio.formatters.SpecFormatter</code>. 462 * 463 * <h2 id="_escaping">Escaping and Content Type</h2> 464 * <strong>@{@link io.jstach.jstache.JStacheContentType}, and 465 * @{@link JStacheConfig#contentType()} </strong> 466 * <p> 467 * If you are using the JStachio runtime (io.jstach.jstachio) and have 468 * {@link JStacheConfig#type()} set to {@link JStacheType#JSTACHIO} (or UNSPECIFIED aka 469 * default) you will get out of the box escaping for HTML (see 470 * <code class="externalLink">io.jstach.jstachio.escapers.Html</code>) per the mustache 471 * spec. 472 * <p> 473 * <strong>To disable escaping</strong> set {@link JStacheConfig#contentType()} to 474 * <code class="externalLink">io.jstach.jstachio.escapers.PlainText</code>. 475 * 476 * <h2 id="_config">Configuration</h2> <strong>@{@link JStacheConfig}</strong> 477 * <p> 478 * You can set global configuration on class, packages and module elements. See 479 * {@link JStacheConfig} for more details on config resolution. Some configuration is set 480 * through compiler flags and annotation processor options. However {@link JStacheConfig} 481 * unlike compiler flags and annotation processor options are available during runtime 482 * through reflective access. 483 * 484 * <h3 id="_config_flags">Compiler flags</h3> 485 * 486 * The compiler has some boolean flags that can be set statically via {@link JStacheFlags} 487 * as well as through annotation processor options. 488 * 489 * <h3 id="_config_compiler">Annotation processor options</h3> 490 * 491 * Some configuration is available as an annotation processor option. Current available 492 * options are: 493 * 494 * <ul> 495 * <li>{@link #RESOURCES_PATH_OPTION}</li> 496 * <li>{@link #INCREMENTAL_OPTION}</li> 497 * </ul> 498 * 499 * The previously mentioned {@linkplain JStacheFlags compiler flags} are also available as 500 * annotation options. The flags are prefixed with "<code>jstache.</code>". For example 501 * {@link JStacheFlags.Flag#DEBUG} would be: 502 * <p> 503 * <code>jstache.debug=true/false</code>. 504 * 505 * <h4 id="_config_compiler_maven">Configuring options with Maven</h4> 506 * 507 * Example configuration with Maven: 508 * 509 * <pre class="language-xml">{@code 510 * <plugin> 511 * <groupId>org.apache.maven.plugins</groupId> 512 * <artifactId>maven-compiler-plugin</artifactId> 513 * <version>3.8.1</version> 514 * <configuration> 515 * <source>17</source> 516 * <target>17</target> 517 * <annotationProcessorPaths> 518 * <path> 519 * <groupId>io.jstach</groupId> 520 * <artifactId>jstachio-apt</artifactId> 521 * <version>${io.jstache.version}</version> 522 * </path> 523 * </annotationProcessorPaths> 524 * <compilerArgs> 525 * <arg> 526 * -Ajstache.resourcesPath=src/main/resources 527 * </arg> 528 * <arg> 529 * -Ajstache.debug=false 530 * </arg> 531 * </compilerArgs> 532 * </configuration> 533 * </plugin> 534 * }</pre> 535 * 536 * <h4 id="_config_compiler_gradle">Configuring options with Gradle</h4> 537 * 538 * Example configuration with Gradle: 539 * 540 * <pre> 541 * <code class="language-kotlin"> 542 * compileJava { 543 * options.compilerArgs += [ 544 * '-Ajstache.resourcesPath=src/main/resources' 545 * ] 546 * } 547 * </code> </pre> 548 * 549 * 550 * </div> 551 * 552 * @author agentgt 553 * @see JStachePath 554 * @see JStacheFormatterTypes 555 * @see JStacheConfig 556 * @see JStacheFormatter 557 * @see JStacheContentType 558 * @see JStacheConfig 559 * 560 * @jstachioVersion 561 */ 562@Retention(RetentionPolicy.RUNTIME) 563@Target(ElementType.TYPE) 564@Documented 565public @interface JStache { 566 567 /** 568 * Resource path to template 569 * @return Path to mustache template 570 * @see JStachePath 571 */ 572 String path() default ""; 573 574 /** 575 * Inline the template as a Java string instead of a file. Use the new triple quote 576 * string literal for complex templates. 577 * @return An inline template 578 */ 579 String template() default ""; 580 581 /** 582 * Name of generated class. 583 * <p> 584 * name can be omitted. <code>model.getClass().getName()</code> + 585 * {@link JStacheName#DEFAULT_SUFFIX} name is used by default. 586 * @return Name of generated class 587 */ 588 String name() default ""; 589 590 /** 591 * An annotation processor compiler flag 592 * (<strong>{@value #RESOURCES_PATH_OPTION}</strong>) that says where the templates 593 * files are located. 594 * <p> 595 * When the annotation processor runs these files usually are in: 596 * <code>javax.tools.StandardLocation#CLASS_OUTPUT</code> and in a Maven or Gradle 597 * project they normally would reside in <code>src/main/resources</code> or 598 * <code>src/test/resources</code> which get copied on build to 599 * <code>target/classes</code> or similar. However due to incremental compiling 600 * template files are not always copied to <code>target/classes</code> and thus are 601 * not found by the annotation processor. To deal with this issue JStachio during 602 * compilation fallsback to direct filesystem access of the <em>source</em> directory 603 * instead of the output (<code>javax.tools.StandardLocation#CLASS_OUTPUT</code>) if 604 * the files cannot be found. 605 * <p> 606 * JStachio tries to resolve your project layout and project directory (current 607 * project being compiled if in a multi-module project) automatically based on variety 608 * of heuristics so that you do not need to use this flag. JStachio may not find the 609 * correct source folder for your templates but it usually can find the correct 610 * "<em>project directory</em>" (which will be called "<em>PD</em>" for the rest of 611 * this passage). 612 * </p> 613 * <strong>Multiple paths can be passed by comma separating them.</strong> The paths 614 * are tried in order. If a path does not start with a path separator then it will be 615 * appended to the <strong>resolved</strong> PD otherwise it is assumed to be a fully 616 * qualified path. <strong> NOTE the PD may not be correct! </strong> 617 * <p> 618 * The default location is <code>PD/src/main/resources</code>. Again the PD may not be 619 * resolved correctly so the only guarantee is to give the absolute path if nothing 620 * else is working. Please file an issue with info on your build system and IDE if 621 * your project is mostly canonical in layout if you are experiencing issues. 622 * </p> 623 * 624 * <strong>If the option is blank or empty then NO fallback will happen and 625 * effectively disables the above behavior. </strong> 626 * 627 * You can change it by passing to the annotation processor a setting for 628 * <strong>{@value #RESOURCES_PATH_OPTION}</strong> like: 629 * <pre><code>jstache.resourcesPath=some/path</code></pre> 630 * 631 * For build annotation processor configuration examples see: 632 * <ol> 633 * <li><a href="#_config_compiler_maven">Configuring options with Maven</a></li> 634 * <li><a href="#_config_compiler_gradle">Configuring options with Gradle</a></li> 635 * </ol> 636 * 637 */ 638 public static final String RESOURCES_PATH_OPTION = "jstache.resourcesPath"; 639 640 /** 641 * <strong>EXPERIMENTAL:</strong> annotation processor compiler flag 642 * (<strong>{@value #INCREMENTAL_OPTION}</strong>) that turns on incremental compiling 643 * of supported platforms (currently only Gradle). <em>This option may turn off other 644 * settings and if it does it will warn you!</em> 645 * <p> 646 * Incremental compiling does not support generating {@linkplain JStacheCatalog 647 * catalogs} or Service Provider files (<code>META-INF/services</code>). 648 */ 649 public static final String INCREMENTAL_OPTION = "jstache.incremental"; 650 651 /** 652 * A virtual variable that is direct analog to 653 * <a href="https://handlebarsjs.com/api-reference/data-variables.html#root"> 654 * handlebars <code>@root</code></a>. The root model instance is accessible to 655 * mustache templates with this global binding name. This allows easier access to the 656 * model if deeply nested in a context stack. 657 */ 658 public static final String ROOT_BINDING_NAME = "@root"; 659 660 /** 661 * A handlebars inspired virtual variable that is bound while in list contexts. If on 662 * the first element then it is <code>true</code>. 663 */ 664 public static final String FIRST_BINDING_NAME = "@first"; 665 666 /** 667 * A JMustache inspired virtual variable that is bound while in list contexts. If on 668 * the first element then it is <code>true</code>. 669 */ 670 public static final String FIRST_JMUSTACHE_BINDING_NAME = "-first"; 671 672 /** 673 * A handlebars inspired virtual variable that is bound while in list contexts. If on 674 * the last element then it is <code>true</code>. 675 */ 676 public static final String LAST_BINDING_NAME = "@last"; 677 678 /** 679 * A JMustache inspired virtual variable that is bound while in list contexts. If on 680 * the last element then it is <code>true</code>. 681 */ 682 public static final String LAST_JMUSTACHE_BINDING_NAME = "-last"; 683 684 /** 685 * A handlebars inspired virtual variable that is bound while in list contexts. A zero 686 * based index that is an integer. 687 */ 688 public static final String INDEX_BINDING_NAME = "@index"; 689 690 /** 691 * A JMustache inspired virtual variable that is bound while in list contexts. A one 692 * based index that is an integer. 693 */ 694 public static final String INDEX_JMUSTACHE_BINDING_NAME = "-index"; 695 696}