95 * @throws IllegalArgumentException if the package name or class name are
96 * not in the correct format
97 */
98 static ClassDesc of(String packageName, String className) {
99 ConstantUtils.validateBinaryClassName(requireNonNull(packageName));
100 validateMemberName(requireNonNull(className));
101 return ofDescriptor(String.format("L%s%s%s;",
102 binaryToInternal(packageName),
103 (packageName.length() > 0 ? "/" : ""),
104 className));
105 }
106
107 /**
108 * Returns a {@linkplain ClassDesc} given a descriptor string for a class,
109 * interface, array, or primitive type.
110 *
111 * @apiNote
112 *
113 * A field type descriptor string for a non-array type is either
114 * a one-letter code corresponding to a primitive type
115 * ({@code J,I,C,S,B,D,F,Z,V}), or the letter {@code L}, followed
116 * by the fully qualified binary name of a class, followed by {@code ;}.
117 * A field type descriptor for an array type is the character {@code [}
118 * followed by the field descriptor for the component type. Examples of
119 * valid type descriptor strings include {@code Ljava/lang/String;}, {@code I},
120 * {@code [I}, {@code V}, {@code [Ljava/lang/String;}, etc.
121 * for more detail.
122 *
123 * @param descriptor a field descriptor string
124 * @return a {@linkplain ClassDesc} describing the desired class
125 * @throws NullPointerException if any argument is {@code null}
126 * @throws IllegalArgumentException if the name string is not in the
127 * correct format
128 * @jvms 4.3.2 Field Descriptors
129 */
130 static ClassDesc ofDescriptor(String descriptor) {
131 requireNonNull(descriptor);
132 return (descriptor.length() == 1)
133 ? new PrimitiveClassDescImpl(descriptor)
134 : new ReferenceClassDescImpl(descriptor);
135 }
136
137 /**
138 * Returns a {@linkplain ClassDesc} for an array type whose component type
139 * is described by this {@linkplain ClassDesc}.
140 *
141 * @return a {@linkplain ClassDesc} describing the array type
144 return arrayType(1);
145 }
146
147 /**
148 * Returns a {@linkplain ClassDesc} for an array type of the specified rank,
149 * whose component type is described by this {@linkplain ClassDesc}.
150 *
151 * @param rank the rank of the array
152 * @return a {@linkplain ClassDesc} describing the array type
153 * @throws IllegalArgumentException if the rank is zero or negative
154 */
155 default ClassDesc arrayType(int rank) {
156 if (rank <= 0)
157 throw new IllegalArgumentException("rank: " + rank);
158 return ClassDesc.ofDescriptor("[".repeat(rank) + descriptorString());
159 }
160
161 /**
162 * Returns a {@linkplain ClassDesc} for a nested class of the class or
163 * interface type described by this {@linkplain ClassDesc}.
164 *
165 * @param nestedName the unqualified name of the nested class
166 * @return a {@linkplain ClassDesc} describing the nested class
167 * @throws NullPointerException if any argument is {@code null}
168 * @throws IllegalStateException if this {@linkplain ClassDesc} does not
169 * describe a class or interface type
170 * @throws IllegalArgumentException if the nested class name is invalid
171 */
172 default ClassDesc nested(String nestedName) {
173 validateMemberName(nestedName);
174 if (!isClassOrInterface())
175 throw new IllegalStateException("Outer class is not a class or interface type");
176 return ClassDesc.ofDescriptor(String.format("%s$%s;", dropLastChar(descriptorString()), nestedName));
177 }
178
179 /**
180 * Returns a {@linkplain ClassDesc} for a nested class of the class or
181 * interface type described by this {@linkplain ClassDesc}.
182 *
183 * @param firstNestedName the unqualified name of the first level of nested class
|
95 * @throws IllegalArgumentException if the package name or class name are
96 * not in the correct format
97 */
98 static ClassDesc of(String packageName, String className) {
99 ConstantUtils.validateBinaryClassName(requireNonNull(packageName));
100 validateMemberName(requireNonNull(className));
101 return ofDescriptor(String.format("L%s%s%s;",
102 binaryToInternal(packageName),
103 (packageName.length() > 0 ? "/" : ""),
104 className));
105 }
106
107 /**
108 * Returns a {@linkplain ClassDesc} given a descriptor string for a class,
109 * interface, array, or primitive type.
110 *
111 * @apiNote
112 *
113 * A field type descriptor string for a non-array type is either
114 * a one-letter code corresponding to a primitive type
115 * ({@code "J", "I", "C", "S", "B", "D", "F", "Z", "V"}), or the letter {@code "L"}, followed
116 * by the fully qualified binary name of a class, followed by {@code ";"}.
117 * A field type descriptor for an array type is the character {@code "["}
118 * followed by the field descriptor for the component type. Examples of
119 * valid type descriptor strings include {@code "Ljava/lang/String;"}, {@code "I"},
120 * {@code "[I"}, {@code "V"}, {@code "[Ljava/lang/String;"}, etc.
121 * See JVMS 4.3.2 ("Field Descriptors") for more detail.
122 *
123 * @param descriptor a field descriptor string
124 * @return a {@linkplain ClassDesc} describing the desired class
125 * @throws NullPointerException if any argument is {@code null}
126 * @throws IllegalArgumentException if the name string is not in the
127 * correct format
128 * @jvms 4.3.2 Field Descriptors
129 */
130 static ClassDesc ofDescriptor(String descriptor) {
131 requireNonNull(descriptor);
132 return (descriptor.length() == 1)
133 ? new PrimitiveClassDescImpl(descriptor)
134 : new ReferenceClassDescImpl(descriptor);
135 }
136
137 /**
138 * Returns a {@linkplain ClassDesc} for an array type whose component type
139 * is described by this {@linkplain ClassDesc}.
140 *
141 * @return a {@linkplain ClassDesc} describing the array type
144 return arrayType(1);
145 }
146
147 /**
148 * Returns a {@linkplain ClassDesc} for an array type of the specified rank,
149 * whose component type is described by this {@linkplain ClassDesc}.
150 *
151 * @param rank the rank of the array
152 * @return a {@linkplain ClassDesc} describing the array type
153 * @throws IllegalArgumentException if the rank is zero or negative
154 */
155 default ClassDesc arrayType(int rank) {
156 if (rank <= 0)
157 throw new IllegalArgumentException("rank: " + rank);
158 return ClassDesc.ofDescriptor("[".repeat(rank) + descriptorString());
159 }
160
161 /**
162 * Returns a {@linkplain ClassDesc} for a nested class of the class or
163 * interface type described by this {@linkplain ClassDesc}.
164 *
165 * @apiNote
166 *
167 * Example: If descriptor {@code d} describes the class {@code java.util.Map}, a
168 * descriptor for the class {@code java.util.Map.Entry} could be obtained
169 * by {@code d.nested("Entry")}.
170 *
171 * @param nestedName the unqualified name of the nested class
172 * @return a {@linkplain ClassDesc} describing the nested class
173 * @throws NullPointerException if any argument is {@code null}
174 * @throws IllegalStateException if this {@linkplain ClassDesc} does not
175 * describe a class or interface type
176 * @throws IllegalArgumentException if the nested class name is invalid
177 */
178 default ClassDesc nested(String nestedName) {
179 validateMemberName(nestedName);
180 if (!isClassOrInterface())
181 throw new IllegalStateException("Outer class is not a class or interface type");
182 return ClassDesc.ofDescriptor(String.format("%s$%s;", dropLastChar(descriptorString()), nestedName));
183 }
184
185 /**
186 * Returns a {@linkplain ClassDesc} for a nested class of the class or
187 * interface type described by this {@linkplain ClassDesc}.
188 *
189 * @param firstNestedName the unqualified name of the first level of nested class
|