001package Torello.JavaDoc; 002 003 004// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 005// Standard-Java Imports 006// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 007 008import java.io.IOException; 009import java.util.Optional; 010 011 012// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 013// Java-HTML Imports 014// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 015 016import Torello.Java.*; 017 018import static Torello.Java.C.*; 019import static Torello.JavaDoc.PF.*; 020 021import Torello.Java.Additional.Ret2; 022import Torello.Java.ReadOnly.ReadOnlyList; 023import Torello.Java.ReadOnly.ROArrayListBuilder; 024 025 026// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 027// JDUInternal 028// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 029 030import Torello.JDUInternal.Annotations.EntityAnnotations.EntityAnnotationData; 031import Torello.JDUInternal.Parse.HTML.Signature.D1_CallableSignature; 032 033 034// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 035// The new Source-Code Parser: com.sun.source.* 036// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 037 038import com.sun.source.tree.MethodTree; 039 040 041/** 042 *<B CLASS=JDDescLabel>Reflection Class:</B> 043 * 044 * <BR />Holds all information extracted from <CODE>'.java'</CODE> Source-Files about Method's 045 * identified in that file. 046 * 047 * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_GET_INST> 048 * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_METHOD> 049 */ 050@JDHeaderBackgroundImg(EmbedTagFileID={"REFLECTION_EXTENSION"}) 051public class Method 052 extends Callable 053 implements java.io.Serializable, Comparable<Method>, Cloneable 054{ 055 /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */ 056 public static final long serialVersionUID = 1; 057 058 /** 059 * The return type of the {@code method}, as a {@code String}. If this is a method with a 060 * {@code 'void'} return-type, this shall be "void". 061 */ 062 public final String returnType; 063 064 /** 065 * The return type of the {@code method}, as a {@code String}. 066 * <BR /><BR /> 067 * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_JOW_TITLE> 068 */ 069 public final String returnTypeJOW; 070 071 072 // ******************************************************************************************** 073 // ******************************************************************************************** 074 // Reference-Hook: com.sun.source.tree 075 // ******************************************************************************************** 076 // ******************************************************************************************** 077 078 079 /** 080 * <EMBED CLASS='external-html' DATA-FILE-ID=SSTB_HOOK_FIELD> 081 * 082 * If a user decides to make use of the native Oracle {@code MethodTree} instance that was 083 * used to build this {@code Method} instance, it may be retrieved from this {@code transient} 084 * field. 085 */ 086 public final transient MethodTree methodTree; 087 088 089 // ******************************************************************************************** 090 // ******************************************************************************************** 091 // Constructor - com.sun.source.tree 092 // ******************************************************************************************** 093 // ******************************************************************************************** 094 095 096 // Public, but internally-used-only Constructor for "Method" 097 public Method( 098 final MethodTree mt, 099 final EntityAnnotationData ead, 100 final TreeUtils util 101 ) 102 { 103 super(mt, mt.getName().toString(), Entity.METHOD, ead, util); 104 105 this.returnType = mt.getReturnType().toString(); 106 this.returnTypeJOW = StrSource.typeToJavaIdentifier(this.returnType); 107 this.methodTree = mt; 108 } 109 110 111 // ******************************************************************************************** 112 // ******************************************************************************************** 113 // Constructor: Used Internally by SignatureParse / SummaryHTMLFile 114 // ******************************************************************************************** 115 // ******************************************************************************************** 116 117 118 // Ensures that the Version with longer type-information strings is used. 119 // Java Doc often uses longer type strings than is available from the source-code parse 120 // Remember, JavaParser Symbol-Solver doesn't work well, and the Sun/Oracle Parser doesn't have 121 // a linker at all. 122 // 123 // Called from JDUInternal.ParseHTML.SignatureParse: 124 // This is used when the JavaDocHTMLFile is asking that a method be retrieved based on 125 // input from **BOTH** the HTML-File **AND** the Source-File 126 127 public Method(final D1_CallableSignature cSig, final Method mFromSourceParser) 128 { 129 // Does the same thing as the loop statement below, but for the "parameterTypes" 130 super(cSig, mFromSourceParser); 131 132 // Java Doc always produces "java.lang.String", while JP just gives "String" 133 // 134 // REMEMBER: JP is lazy when it comes to "Package Information" for types. 135 // Java-Doc includes it often - BUT NOT ALWAYS. (See above comment) 136 // 137 // Remember, though, the rest of the JavaParser fields are filled out, Java Doc 138 // leaves out all the other information that JP retrieves. 139 140 this.returnType = 141 (cSig.returnType.length() > mFromSourceParser.returnType.length()) 142 ? cSig.returnType 143 : mFromSourceParser.returnType; 144 145 // This should never matter. They must be identical. 146 this.returnTypeJOW = mFromSourceParser.returnTypeJOW; 147 148 // Save the reference hook 149 this.methodTree = mFromSourceParser.methodTree; 150 } 151 152 // Used for "Synthetic Methods ONLY!" Literally, this line is the only way this particular 153 // Constructor could ever be called: 154 // 155 // From JDUInternal.ParseHTML.SignatureParse: 156 // if (StrCmpr.equalsXOR(cSig.name, "valueOf", "values")) return new Method(cSig); 157 158 public Method(final D1_CallableSignature cSig) 159 { 160 // Does the same thing as the loop statement below, but for the "parameterTypes" 161 super(cSig, Entity.METHOD); 162 163 this.returnType = cSig.returnType; 164 this.returnTypeJOW = cSig.returnTypeJOW; 165 this.methodTree = null; 166 } 167 168 169 // ******************************************************************************************** 170 // ******************************************************************************************** 171 // toString() 172 // ******************************************************************************************** 173 // ******************************************************************************************** 174 175 176 /** 177 * Generates a string of this method, with most information included. 178 * 179 * <BR /><BR /><B CLASS=JDDescLabel>Reduced Information:</B> 180 * 181 * <BR />This {@code 'toString'} will not return every piece of information contained by this 182 * class. For example, both the method body, and any possible JavaDoc Comments are not 183 * included. For a more enhanced {@code toString()} method version, invoke the 184 * {@link #toString(int) toString(PrintFlags)} method which accepts {@link PF Print-Flags}. 185 * 186 * @return A printable {@code String} of this method. 187 * @see PF 188 * @see #toString(int) 189 */ 190 public String toString() 191 { 192 return 193 "Name: [" + name + "]\n" + 194 "Signature: [" + StrPrint.abbrevEndRDSF(signature, MAX_STR_LEN, true) + "]\n" + 195 "Modifiers: [" + StrCSV.toCSV(modifiers, true, true, null) + "]\n" + 196 printedParameterNamesTS() + 197 printedParameterTypesTS() + 198 "Return Type: [" + returnType + "]\n" + 199 printedExceptionsTS() + 200 201 // This will **NEVER** be null - unless 'this' instance was built from an HTML File, 202 // rather than a source-code file. Instances like that are only used temporarily, and 203 // are garbage collected instantly. Do this check anyway (just in case). 204 205 "Location: " + ((this.location == null) 206 ? "null" 207 : ('[' + this.location.quickSummary() + ']')); 208 } 209 210 /** 211 * <EMBED CLASS='external-html' DATA-FILE-ID=TO_STR_PF> 212 * @param flags These are defined in the {@link PF Print-Flags} class 213 * @return A printable {@code String} of this {@code Method}. 214 * @see #toString() 215 * @see PF 216 */ 217 public String toString(int flags) 218 { 219 boolean color = (flags & UNIX_COLORS) > 0; 220 Ret2<Boolean, Boolean> jow = jowFlags(flags); 221 222 return 223 printedName("Method", 20, color) + 224 printedSignature(20, color) + 225 printedModifiers(20) + 226 printedParamNames() + 227 printedParamTypes(jow) + 228 printedReturnType(jow, color) + 229 printedExceptions() + 230 printedLocation(20, color, (flags & BRIEF_LOCATION) > 0) + 231 232 // The previous method does not add a '\n' end to the end of the returned string 233 // These are both optional, they add a '\n' AT THE BEGINNING if one of them is included 234 235 printedComments(20, color, (flags & JAVADOC_COMMENTS) > 0) + 236 printedCallableBody(flags); 237 } 238 239 private String printedReturnType(Ret2<Boolean, Boolean> jow, boolean color) 240 { 241 String rt = null, rtJOW = null; 242 243 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 244 // Worry about the colors first 245 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 246 247 if (jow.a || jow.b) 248 rtJOW = color ? (BGREEN + returnTypeJOW + RESET) : returnTypeJOW; 249 250 if (! jow.b) 251 rt = color ? (BGREEN + returnType + RESET) : returnType; 252 253 254 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 255 // Now print the string 256 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 257 258 if (jow.b /*onlyJOW*/) return "Return Simple-Type: [" + rtJOW + "]\n"; 259 260 else if (jow.a /*addJOW*/) return 261 "Return Type: [" + rt + "]\n" + 262 "Return Simple-Type: [" + rtJOW + "]\n"; 263 264 else return "Return Type: [" + rt + "]\n"; 265 } 266 267 268 // ******************************************************************************************** 269 // ******************************************************************************************** 270 // CompareTo & Equals 271 // ******************************************************************************************** 272 // ******************************************************************************************** 273 274 275 /** 276 * Java's {@code interface Comparable<T>} requirements. This does a very simple comparison 277 * using the two method's {@link #name} field. If the name comparison will not 278 * suffice in making a decision, then the number of parameters, and parameter-types are used 279 * to making the sort-decision. 280 * 281 * @param m Any other {@code Method} to be compared to {@code 'this' Method} 282 * 283 * @return An integer that fulfills Java's {@code Comparable<Method>} interface 284 * requirements. 285 */ 286 public int compareTo(Method m) 287 { 288 // Identical References 289 if (this == m) return 0; 290 291 // Sorting by ignoring case is best - usually for the looks of a list 292 // NOTE: Returning '0' is bad, because a TreeSet will remove duplicate-elements. This 293 // means two different meethods with the same name would not "fit" into a treeset. 294 295 int ret = this.name.compareToIgnoreCase(m.name); 296 if (ret != 0) return ret; 297 298 // Try to identify a different without ignoring case. 299 ret = this.name.compareTo(m.name); 300 if (ret != 0) return ret; 301 302 ret = this.numParameters() - m.numParameters(); 303 if (ret != 0) return ret; 304 305 for (int i=0; i < this.parameterTypesJOW.size(); i++) 306 { 307 ret = this.parameterTypesJOW.get(i).compareTo(m.parameterTypesJOW.get(i)); 308 if (ret != 0) return ret; 309 } 310 311 return 0; 312 } 313 314 /** 315 * This <I>should be called an "atypical version" of </I>the usual {@code equals(Object other)} 316 * method. This version of equals merely compares the name and parameters-list of the method. 317 * The presumption here is that the definition of a 'method' only has 318 * meaning - <I>at all</I> - inside the context of a {@code class, interface, } or 319 * {@code enumerated-type} where that method is defined. Since inside any {@code '.java'} 320 * source-code file, there may only be one method with a given name and parameter-list, this 321 * shall return {@code TRUE} whenever the method being compared has the same name and parameter 322 * types as {@code 'this'} does. 323 * 324 * @param other This may be any other {@code method}. It is <I><B>strongly suggested</B></I> 325 * that this be a {@code method} defined in the same {@code '.java'} source-code file as 326 * {@code 'this' method}. 327 * 328 * @return This method returns {@code TRUE} when {@code 'this'} instance of {@code Method} has 329 * <B>both</B> the same {@code public final Sting name} <B>and</B> the same parameter-list as 330 * {@code 'other'}. 331 */ 332 public boolean equals(Method other) 333 { 334 // The method's must have the same name! 335 if (! this.name.equals(other.name)) return false; 336 337 // If the number of parameters in the 'other' instance of Method differ from the number 338 // of parameters in 'this' Method, then return FALSE immediately. It cannot be a match. 339 340 if (this.numParameters() != other.numParameters()) return false; 341 342 // If both of these have zero parameters, and their names have matched, return true 343 // immediately 344 345 if (this.numParameters() == 0) return true; 346 347 // If any of the parameter-names are different, break immediately and return false; 348 for (int i=0; i < this.parameterNames.size(); i++) 349 if (! this.parameterNames.get(i).equals(other.parameterNames.get(i))) return false; 350 351 // If the parameter-types listed by the javadoc '.html' file differ from the parameter 352 // types listed in the original '.java' source-code file, then break immediately. 353 // 354 // NOTE: The "package-information" for the FULL CLASS OR INTERFACE NAME is not always 355 // available. 356 357 for (int i=0; i < this.parameterTypesJOW.size(); i++) 358 if (! this.parameterTypesJOW.get(i).equals(other.parameterTypesJOW.get(i))) 359 return false; 360 361 // ALL TEST PASSED 362 return true; 363 } 364 365 366 // ******************************************************************************************** 367 // ******************************************************************************************** 368 // A.I. Token-Stream Generator-Method 369 // ******************************************************************************************** 370 // ******************************************************************************************** 371 372 373 public ReadOnlyList<ReadOnlyList<String>> getTokenStreams() 374 { 375 final ROArrayListBuilder<ReadOnlyList<String>> tokens = new ROArrayListBuilder<>(); 376 ROArrayListBuilder<String> b = new ROArrayListBuilder<>(); 377 378 tokens.add(ReadOnlyList.of("SECTION", "entity", "method")); 379 tokens.add(ReadOnlyList.of("SECTION", "name", this.name)); 380 tokens.add(ReadOnlyList.of("SECTION", "signature", this.signature)); 381 tokens.add(ReadOnlyList.of("SECTION", "return-type", this.returnTypeJOW)); 382 383 if ((this.parameterNames != null) && (this.parameterNames.size() > 0)) 384 { 385 b.add("SECTION"); 386 b.add("parameters"); 387 for (int i = 0; i < this.parameterNames.size(); i++) 388 b.add(this.parameterTypesJOW.get(i) + " " + this.parameterNames.get(i)); 389 tokens.add(b.build()); 390 } 391 392 if ((this.modifiers != null) && (modifiers.size() > 0)) 393 { 394 b = new ROArrayListBuilder<>(); 395 b.add("SECTION"); 396 b.add("modifiers"); 397 for (String m : this.modifiers) b.add(m); 398 tokens.add(b.build()); 399 } 400 401 if ((this.exceptions != null) && (this.exceptions.size() > 0)) 402 { 403 b = new ROArrayListBuilder<>(); 404 b.add("SECTION"); 405 b.add("throws"); 406 for (String exn : this.exceptions) b.add(exn); 407 tokens.add(b.build()); 408 } 409 410 if ((this.annotations != null) && (annotations.size() > 0)) 411 { 412 b = new ROArrayListBuilder<>(); 413 b.add("SECTION"); 414 b.add("annotations"); 415 for (String a : this.annotations) b.add(a); 416 tokens.add(b.build()); 417 } 418 419 return tokens.build(); 420 } 421 422}