1 package java.lang.reflect.code; 2 3 import java.lang.reflect.code.type.TypeElementFactory; 4 import java.util.List; 5 import java.util.stream.Collectors; 6 7 /** 8 * A type, that defines a set of values. 9 * <p> 10 * A type can be assigned to a {@link Value value} in a code model, 11 * and implies the value is a member of the type's set. 12 * <p> 13 * The {@code equals} method should be used to check if two type elements 14 * are equal to each other. 15 * @apiNote 16 * Code model types enable reasoning statically about a code model, 17 * approximating run time behaviour. 18 */ 19 public non-sealed interface TypeElement extends CodeItem { 20 // @@@ Common useful methods generally associated with properties of a type 21 // e.g., arguments, is an array etc. (dimensions) 22 23 /** 24 * A type element's externalized content in structured symbolic form. 25 * <p> 26 * A {@link TypeElement type element} can be constructed from an externalized type element 27 * using a {@link TypeElementFactory}. 28 * 29 * @param identifier the externalized type's identifier 30 * @param arguments the externalized type's arguments 31 */ 32 record ExternalizedTypeElement(String identifier, List<ExternalizedTypeElement> arguments) { 33 34 /** 35 * {@inheritDoc} 36 */ 37 public ExternalizedTypeElement { 38 arguments = List.copyOf(arguments); 39 } 40 41 @Override 42 public String toString() { 43 return toString(this); 44 } 45 46 static String toString(ExternalizedTypeElement t) { 47 if (t.arguments.isEmpty()) { 48 return t.identifier; 49 } 50 51 // Unpack array-like identifier [+ 52 int dimensions = 0; 53 if (t.arguments.size() == 1) { 54 dimensions = dimensions(t.identifier); 55 if (dimensions > 0) { 56 t = t.arguments.getFirst(); 57 } 58 } 59 60 StringBuilder s = new StringBuilder(); 61 s.append(t.identifier); 62 if (!t.arguments.isEmpty()) { 63 String args = t.arguments.stream() 64 .map(Object::toString) 65 .collect(Collectors.joining(", ", "<", ">")); 66 s.append(args); 67 } 68 69 // Write out array-like syntax at end []+ 70 if (dimensions > 0) { 71 s.append("[]".repeat(dimensions)); 72 } 73 74 return s.toString(); 75 } 76 77 static int dimensions(String identifier) { 78 if (!identifier.isEmpty() && identifier.charAt(0) == '[') { 79 for (int i = 1; i < identifier.length(); i++) { 80 if (identifier.charAt(i) != '[') { 81 return 0; 82 } 83 } 84 return identifier.length(); 85 } else { 86 return 0; 87 } 88 } 89 90 // Factories 91 92 /** 93 * Parses a string as an externalized type element. 94 * <p> 95 * For any given externalized type element, {@code te}, the following 96 * expression returns {@code true}. 97 * {@snippet lang=java 98 * te.equals(ExternalizedTypeElement.ofString(te.toString())); 99 * } 100 * @param s the string 101 * @return the externalized code type. 102 */ 103 // Copied code in jdk.compiler module throws UOE 104 public static ExternalizedTypeElement ofString(String s) { 105 /*__throw new UnsupportedOperationException();__*/ return java.lang.reflect.code.parser.impl.DescParser.parseExTypeElem(s); 106 } 107 } 108 109 /** 110 * Externalizes this type element's content. 111 * 112 * @return the type element's content. 113 * @throws UnsupportedOperationException if the type element is not externalizable 114 */ 115 ExternalizedTypeElement externalize(); 116 117 @Override 118 String toString(); 119 120 @Override 121 boolean equals(Object o); 122 123 @Override 124 int hashCode(); 125 }