110 * |
110 * |
111 * @apiNote |
111 * @apiNote |
112 * |
112 * |
113 * A field type descriptor string for a non-array type is either |
113 * A field type descriptor string for a non-array type is either |
114 * a one-letter code corresponding to a primitive type |
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 |
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 ;}. |
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 [} |
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 |
118 * followed by the field descriptor for the component type. Examples of |
119 * valid type descriptor strings include {@code Ljava/lang/String;}, {@code I}, |
119 * valid type descriptor strings include {@code "Ljava/lang/String;"}, {@code "I"}, |
120 * {@code [I}, {@code V}, {@code [Ljava/lang/String;}, etc. |
120 * {@code "[I"}, {@code "V"}, {@code "[Ljava/lang/String;"}, etc. |
121 * for more detail. |
121 * See JVMS 4.3.2 ("Field Descriptors") for more detail. |
122 * |
122 * |
123 * @param descriptor a field descriptor string |
123 * @param descriptor a field descriptor string |
124 * @return a {@linkplain ClassDesc} describing the desired class |
124 * @return a {@linkplain ClassDesc} describing the desired class |
125 * @throws NullPointerException if any argument is {@code null} |
125 * @throws NullPointerException if any argument is {@code null} |
126 * @throws IllegalArgumentException if the name string is not in the |
126 * @throws IllegalArgumentException if the name string is not in the |
127 * correct format |
127 * correct format |
128 * @jvms 4.3.2 Field Descriptors |
128 * @jvms 4.3.2 Field Descriptors |
|
129 * @jvms 4.4.1 The CONSTANT_Class_info Structure |
129 */ |
130 */ |
130 static ClassDesc ofDescriptor(String descriptor) { |
131 static ClassDesc ofDescriptor(String descriptor) { |
131 requireNonNull(descriptor); |
132 requireNonNull(descriptor); |
|
133 int depth = ConstantUtils.arrayDepth(descriptor); |
|
134 if (depth > ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS) { |
|
135 throw new IllegalArgumentException(String.format("Cannot create an array type descriptor with more than %d dimensions", |
|
136 ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS)); |
|
137 } |
132 return (descriptor.length() == 1) |
138 return (descriptor.length() == 1) |
133 ? new PrimitiveClassDescImpl(descriptor) |
139 ? new PrimitiveClassDescImpl(descriptor) |
134 : new ReferenceClassDescImpl(descriptor); |
140 : new ReferenceClassDescImpl(descriptor); |
135 } |
141 } |
136 |
142 |
137 /** |
143 /** |
138 * Returns a {@linkplain ClassDesc} for an array type whose component type |
144 * Returns a {@linkplain ClassDesc} for an array type whose component type |
139 * is described by this {@linkplain ClassDesc}. |
145 * is described by this {@linkplain ClassDesc}. |
140 * |
146 * |
141 * @return a {@linkplain ClassDesc} describing the array type |
147 * @return a {@linkplain ClassDesc} describing the array type |
|
148 * @throws IllegalStateException if the resulting {@linkplain ClassDesc} would have an array rank of greater than 255 |
|
149 * @jvms 4.4.1 The CONSTANT_Class_info Structure |
142 */ |
150 */ |
143 default ClassDesc arrayType() { |
151 default ClassDesc arrayType() { |
|
152 int depth = ConstantUtils.arrayDepth(descriptorString()); |
|
153 if (depth >= ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS) { |
|
154 throw new IllegalStateException(String.format("Cannot create an array type descriptor with more than %d dimensions", |
|
155 ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS)); |
|
156 } |
144 return arrayType(1); |
157 return arrayType(1); |
145 } |
158 } |
146 |
159 |
147 /** |
160 /** |
148 * Returns a {@linkplain ClassDesc} for an array type of the specified rank, |
161 * Returns a {@linkplain ClassDesc} for an array type of the specified rank, |
149 * whose component type is described by this {@linkplain ClassDesc}. |
162 * whose component type is described by this {@linkplain ClassDesc}. |
150 * |
163 * |
151 * @param rank the rank of the array |
164 * @param rank the rank of the array |
152 * @return a {@linkplain ClassDesc} describing the array type |
165 * @return a {@linkplain ClassDesc} describing the array type |
153 * @throws IllegalArgumentException if the rank is zero or negative |
166 * @throws IllegalArgumentException if the rank is less than zero or if the rank of the resulting array type is |
|
167 * greater than 255 |
|
168 * @jvms 4.4.1 The CONSTANT_Class_info Structure |
154 */ |
169 */ |
155 default ClassDesc arrayType(int rank) { |
170 default ClassDesc arrayType(int rank) { |
156 if (rank <= 0) |
171 int currentDepth = ConstantUtils.arrayDepth(descriptorString()); |
157 throw new IllegalArgumentException("rank: " + rank); |
172 if (rank <= 0 || currentDepth + rank > ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS) |
|
173 throw new IllegalArgumentException("rank: " + currentDepth + rank); |
158 return ClassDesc.ofDescriptor("[".repeat(rank) + descriptorString()); |
174 return ClassDesc.ofDescriptor("[".repeat(rank) + descriptorString()); |
159 } |
175 } |
160 |
176 |
161 /** |
177 /** |
162 * Returns a {@linkplain ClassDesc} for a nested class of the class or |
178 * Returns a {@linkplain ClassDesc} for a nested class of the class or |
163 * interface type described by this {@linkplain ClassDesc}. |
179 * interface type described by this {@linkplain ClassDesc}. |
|
180 * |
|
181 * @apiNote |
|
182 * |
|
183 * Example: If descriptor {@code d} describes the class {@code java.util.Map}, a |
|
184 * descriptor for the class {@code java.util.Map.Entry} could be obtained |
|
185 * by {@code d.nested("Entry")}. |
164 * |
186 * |
165 * @param nestedName the unqualified name of the nested class |
187 * @param nestedName the unqualified name of the nested class |
166 * @return a {@linkplain ClassDesc} describing the nested class |
188 * @return a {@linkplain ClassDesc} describing the nested class |
167 * @throws NullPointerException if any argument is {@code null} |
189 * @throws NullPointerException if any argument is {@code null} |
168 * @throws IllegalStateException if this {@linkplain ClassDesc} does not |
190 * @throws IllegalStateException if this {@linkplain ClassDesc} does not |