001package Torello.JavaDoc.Annotations; 002 003import Torello.JDUInternal.Miscellaneous.EntityAnnotationData; 004 005import Torello.JavaDoc.Messager.Messager; 006import Torello.JavaDoc.Messager.MsgPrintTools; 007 008import Torello.JDUInternal.Miscellaneous.Where.JDUAnnotations; 009 010import Torello.Java.ReadOnly.ReadOnlyList; 011import Torello.Java.ReadOnly.ROArrayListBuilder; 012import Torello.Java.ReadOnly.ReadOnlyArrayList; 013 014import static Torello.Java.C.BRED; 015import static Torello.Java.C.RESET; 016 017import java.util.List; 018 019import com.sun.source.tree.Tree; 020import com.sun.source.tree.AnnotationTree; 021import com.sun.source.tree.IdentifierTree; 022import com.sun.source.tree.MemberSelectTree; 023 024 025/** 026 * This class is intended to contain / hold a single mirror instance for each 027 * <B STYLE='color:red;'>Entity-Level Annotation</B> that has been placed on a single entity. 028 * 029 * <BR /><BR /> 030 * See: {@link Torello.JavaDoc.Entity Entity} - Methods, Fields, Constructors, 031 * Enumeration-Constants & Annotation-Elements are referred to as "Entities" in JDU. 032 * 033 * @see Torello.JavaDoc.Annotations.LinkJavaSource 034 * @see Torello.JavaDoc.Annotations.IntoHTMLTable 035 */ 036public class EntityAnnotationMirrors 037{ 038 // ******************************************************************************************** 039 // ******************************************************************************************** 040 // An Empty-Mirror Reference 041 // ******************************************************************************************** 042 // ******************************************************************************************** 043 044 045 /** 046 * If there are ZERO annotations that have been placed on a particular "Entity" (Method, Field, 047 * Constructor, etc...), then there is no chance whatsoever that there are any JDU Annotations! 048 * In such cases, the entire constructor is skipeed, and this "EMPTY_MIRROR" is assigned, 049 * instead. 050 */ 051 public static final EntityAnnotationMirrors EMPTY_MIRROR = new EntityAnnotationMirrors(); 052 053 @SuppressWarnings("unchecked") 054 private EntityAnnotationMirrors() 055 { 056 this.ljsMirrors = ReadOnlyArrayList.emptyROAL(); 057 this.ihtMirror = null; 058 } 059 060 061 // ******************************************************************************************** 062 // ******************************************************************************************** 063 // The Actual Mirrors - as Fields of this class 064 // ******************************************************************************************** 065 // ******************************************************************************************** 066 067 068 /** 069 * {@code 'LinkJavaSource'} Data. 070 * 071 * <BR /><BR /> 072 * This is a "Repeatable Annotation", and thus this is not a single reference, but rather a 073 * "Read Only List" of references. This pointer will never be null, instead if a particular 074 * {@link Torello.JavaDoc.Entity Entity} has not been adorned with any 075 * {@code '@LinkJavaSource'} annotations, then {@code 'ljsMirrors'} will be an empty list. 076 * 077 * @see Torello.JavaDoc.Annotations.LinkJavaSource 078 */ 079 public final ReadOnlyList<LJSMirror> ljsMirrors; 080 081 /** 082 * {@code 'IntoHTMLTable'} Data 083 * @see Torello.JavaDoc.Annotations.IntoHTMLTable 084 */ 085 public final IHTMirror ihtMirror; 086 087 088 // ******************************************************************************************** 089 // ******************************************************************************************** 090 // Constructor: This is used (ONLY !) in class Torello.JavaDoc.Declaration 091 // ******************************************************************************************** 092 // ******************************************************************************************** 093 094 095 @SuppressWarnings("unchecked") 096 public EntityAnnotationMirrors( 097 final List<AnnotationTree> annotList, 098 final String signature, 099 final EntityAnnotationData ead 100 ) 101 { 102 // @LinkJavaSource is a @Repeatable Annotation ==> Keep Track of all of them 103 ROArrayListBuilder<LJSMirror> ljsROALB = new ROArrayListBuilder<>(); 104 105 106 // @IntoHTMLTable is not *NOT* @Repeatable ==> it's an error to have more than one 107 // This is declared as non-final, because it is also "Optional", and because it needs to 108 // be assigned to the actual final Instance-Field "ihtMirror". 109 // 110 // NOTE: If you try to change this a third time, you are just goig to revert it back to the 111 // way it is right now... 112 113 IHTMirror ihtMirror = null; 114 115 TOP: 116 for (AnnotationTree at : annotList) 117 { 118 Tree annotationType = at.getAnnotationType(); 119 120 // Say: "Thank-You ChatGPT" 121 // That thing saved me a lot of time AND stress levels today. 122 123 final String annotationClassName; 124 125 if (annotationType instanceof IdentifierTree) 126 { 127 // This handles simple annotations, for instance: @SuppressWarnings and @Override 128 // NOTE: Chat-GPT explained this whole thing - where there are 2 kinds of 129 // "AnnotatinTypes" that are used by the Sun-Oracle Parser... 130 // 131 // Unfortunately I forgot to write down what it said. It was very right though ! 132 133 annotationClassName = ((IdentifierTree) annotationType).getName().toString(); 134 135 // System.out.println("\nIdentifierTree => annotationClassName: " + annotationClassName); 136 } 137 138 else if (annotationType instanceof MemberSelectTree) 139 { 140 // This handles fully qualified annotations like @java.lang.SuppressWarnings 141 annotationClassName = ((MemberSelectTree) annotationType).getIdentifier().toString(); 142 143 // System.out.println("\nMemberSelectTree => annotationClassName: " + annotationClassName); 144 } 145 146 else 147 { 148 annotationClassName = null; 149 150 throw Messager.assertFail( 151 BRED + "My Annotation Parser just bit the dust" + RESET + '\n' + 152 "Extracted instance of 'com.sun.source.tree.AnnotationTree' was neither an " + 153 "instance of 'IdentifierTree' nor 'MemberSelectTree'.\n" + 154 "This is not supposed to be possible / This is unreachable code.\n" + 155 "The returned Type / Class-Name was:\n" + 156 BRED + annotationType.getClass().getCanonicalName() + RESET, 157 JDUAnnotations.EntityAnnotationMirrors 158 ); 159 } 160 161 switch (annotationClassName) 162 { 163 case "LinkJavaSource" : 164 165 final LJSMirror ljsm = new LJSMirror( 166 at.toString(), 167 at.getArguments(), 168 signature, 169 ead.unParsedLJSFilesList, 170 ead.allPkgLJSHandlesList 171 ); 172 173 // Skip the Annotation completely if there were errors 174 if (Messager.hadErrors()) break TOP; 175 176 // System.out.println(at.toString() + '\n' + m.toString()); 177 ljsROALB.add(ljsm); 178 179 break; 180 181 182 case "IntoHTMLTable" : 183 184 if (ihtMirror != null) throw Messager.assertFail( 185 "There appears to be a second instance of the @IntoHTMLTable " + 186 "Annotation. However, this is not a @Repeatable Annotation." + 187 MsgPrintTools.annotationProcessingError(), 188 JDUAnnotations.EntityAnnotationMirrors 189 ); 190 191 192 // The parsed arguments to to the Annotation 193 // final List<? extends ExpressionTree> arguments, 194 // 195 // This is the Annotation, as a simple Java-String. This is very useful for 196 // Error-Printing with the Messager. That's the only purpose of it 197 // final String annotationAsStr, 198 // 199 // The Signature of the Detail-Entity onto which this "@LinkJavaSource" 200 // Annotation was placed. Very important for error messages 201 // final String signature 202 203 ihtMirror = new IHTMirror(at.getArguments(), at.toString(), signature); 204 205 // Skip the Annotation completely if there were errors 206 if (Messager.hadErrors()) break TOP; 207 208 break; 209 210 default: continue TOP; 211 } 212 } 213 214 this.ljsMirrors = (Messager.hadErrors() || (ljsROALB.size() == 0)) 215 ? ReadOnlyArrayList.emptyROAL() 216 : ljsROALB.build(); 217 218 this.ihtMirror = ihtMirror; 219 } 220};