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; 008 009/** 010 * Compiler feature flags that are subject to change. Use at your own risk! 011 * <p> 012 * <strong>Flags maybe added without a major version change unlike the rest of the 013 * API.</strong> If a flag becomes popular enough it will eventually make its way to 014 * {@link JStacheConfig} so please file an issue if you depend on flag and would like it 015 * to remain in the library. 016 * <p> 017 * Order of flag lookup and precedence is as follows: 018 * <ol> 019 * <li>type annotated with JStache and this annotation. 020 * <li>enclosing class (of type annotated with JStache) with this annotation with inner to 021 * outer order. 022 * <li>package annotated with this annotation. 023 * <li>module annotated with this annotation. 024 * <li>annotation processor compiler arg options (<code>-A</code>). The flags are 025 * lowercased and prefixed with "<code>jstache.</code>"</li> 026 * </ol> 027 * <em>The flags are NOT combined but rather the first found dictates the flags set or not 028 * (including empty)</em> 029 * 030 * @author agentgt 031 * @apiNote the retention policy is purposely {@link RetentionPolicy#SOURCE} as these 032 * flags only impact compiling of the template. 033 */ 034@Retention(RetentionPolicy.SOURCE) 035@Target({ ElementType.MODULE, ElementType.PACKAGE, ElementType.TYPE }) 036@Documented 037public @interface JStacheFlags { 038 039 /** 040 * Compiler flags that will be used on for this model. 041 * @return flags 042 * @see JStacheFlags 043 */ 044 Flag[] flags(); 045 046 /** 047 * Compiler flags. Besides setting with {@link JStacheFlags} the flags are also 048 * available as annotation processor options but are prefixed with 049 * "<code>jstache.</code>" and lowercased 050 * <p> 051 * For example {@link Flag#DEBUG} would be: <code>-Ajstache.debug=true/false</code> 052 * 053 * @apiNote SUBJECT TO CHANGE! 054 * @author agentgt 055 * 056 */ 057 public enum Flag { 058 059 /** 060 * This will produce additional logging that is sent to standard out while the 061 * annotation processor runs (not during runtime). 062 */ 063 DEBUG, 064 /** 065 * Per mustache spec dotted names can actually not exist at all for inverted 066 * sections. This flag disables that so that a compiler failure will happen if the 067 * fields are missing. 068 * 069 * For example assume "missing" is not present on "data" as in data has no field 070 * or method called "missing". 071 * 072 * <pre> 073 * {{^data.missing}} 074 * {{/data.missing}} 075 * </pre> 076 * 077 * Normally the above will compile just fine per the spec but this can lead to 078 * bugs. To not allow what the spec calls "dotted broken chains" you can use this 079 * flag. 080 */ 081 NO_INVERTED_BROKEN_CHAIN, 082 083 /** 084 * <strong>EXPERIMENTAL:</strong> Normally falsey is either empty list, boolean 085 * false, or <code>null</code>. This flag disables <code>null</code> as a falsey 086 * check. 087 * 088 * For example when opening a section like: <pre><code class="language-hbs"> 089 * {{#myNonNull}} 090 * Hi! 091 * {{/myNonNull}} 092 * </code> </pre> 093 * 094 * JStachio would produce code that checks if <code>myNonNull</code> is null as 095 * well as iterate if it is a list or check if true if it is a boolean. 096 * 097 * <p> 098 * However null checking will still be done if JStachio can find a 099 * {@link ElementType#TYPE_USE} annotation with the {@link Class#getSimpleName()} 100 * of <code>Nullable</code> on the type that is being accessed as a section. This 101 * follows <a href="https://github.com/jspecify/jspecify">JSpecify rules</a> but 102 * not other nullable annotations like 103 * <a href="https://spotbugs.github.io/">SpotBugs</a> that are not 104 * {@link ElementType#TYPE_USE}. 105 * 106 * <h4>Benefits</h4> 107 * 108 * The advantages of disabling null checking are: 109 * <ul> 110 * <li>Failing fast instead of just not rendering something which may make finding 111 * bugs easier.</li> 112 * <li>Less generated code which maybe easier to read</li> 113 * <li>Avoid warnings of superfluous null checking by static analysis tools</li> 114 * <li>Possible slight improvement of performance</li> 115 * </ul> 116 * 117 * <h4>Caveats</h4> 118 * 119 * <h5>JDK Bug</h5> Because of JDK bug: 120 * <a href="https://bugs.openjdk.org/browse/JDK-8225377">JDK-8225377</a> this 121 * <em>nullable detection will only work if the type that is being checked is 122 * currently within the same compile boundary as the JStache model being 123 * analyzed!</em> 124 * 125 * <h5>Manually checking for null</h5> If JStachio cannot detect that the type is 126 * nullable because it is not annotated or because of the aforementioned JDK bug 127 * then it will conclude that it can never be null and thus you will be unable to 128 * use section like conditions to check if is null. One workaround is to use a 129 * custom {@link JStacheLambda} to check for null. 130 * 131 * @apiNote This is currently experimental and a flag because of the JDK bug. In 132 * the future more comprehensive support will be put in {@link JStacheConfig}. 133 */ 134 NO_NULL_CHECKING, 135 136 /** 137 * If set the templates will <strong>NOT</strong> have pre-encoded bytes of the 138 * static parts of the template and the generated {@link JStacheType#JSTACHIO} 139 * code will not implement 140 * <code>io.jstach.jstachio.Template.EncodedTemplate</code>. 141 */ 142 PRE_ENCODE_DISABLE; 143 144 } 145 146}