|
13 | 13 | */ |
14 | 14 | package org.microbean.construct; |
15 | 15 |
|
| 16 | +import java.lang.reflect.Constructor; |
| 17 | +import java.lang.reflect.Executable; |
| 18 | +import java.lang.reflect.GenericArrayType; |
| 19 | +import java.lang.reflect.GenericDeclaration; |
| 20 | +import java.lang.reflect.Method; |
| 21 | +import java.lang.reflect.ParameterizedType; |
| 22 | +import java.lang.reflect.Type; |
| 23 | + |
16 | 24 | import java.util.List; |
17 | 25 | import java.util.Objects; |
18 | 26 |
|
@@ -407,6 +415,35 @@ public default TypeMirror elementType(final TypeMirror t) { |
407 | 415 | */ |
408 | 416 | public <T extends TypeMirror> T erasure(final T t); |
409 | 417 |
|
| 418 | + /** |
| 419 | + * Returns an {@link ExecutableElement} corresponding to the supplied {@link Executable}. |
| 420 | + * |
| 421 | + * @param e an {@link Executable}; must not be {@code null} |
| 422 | + * |
| 423 | + * @return an {@link ExecutableElement} corresponding to the supplied {@link Executable}; never {@code null} |
| 424 | + * |
| 425 | + * @exception NullPointerException if {@code e} is {@code null} |
| 426 | + * |
| 427 | + * @exception IllegalArgumentException if somehow {@code e} is neither a {@link Constructor} nor a {@link Method} |
| 428 | + */ |
| 429 | + public default ExecutableElement executableElement(final Executable e) { |
| 430 | + return switch (e) { |
| 431 | + case null -> throw new NullPointerException("e"); |
| 432 | + case Constructor<?> c -> |
| 433 | + this.executableElement(this.typeElement(c.getDeclaringClass().getCanonicalName()), |
| 434 | + this.noType(TypeKind.VOID), |
| 435 | + "<init>", |
| 436 | + this.types(c.getParameterTypes())); |
| 437 | + case Method m -> |
| 438 | + this.executableElement(this.typeElement(m.getDeclaringClass().getCanonicalName()), |
| 439 | + this.type(m.getReturnType()), |
| 440 | + m.getName(), |
| 441 | + this.types(m.getParameterTypes())); |
| 442 | + default -> throw new IllegalArgumentException("e: " + e); |
| 443 | + }; |
| 444 | + } |
| 445 | + |
| 446 | + |
410 | 447 | /** |
411 | 448 | * A convenience method that returns an {@link ExecutableElement} representing the static initializer, constructor or |
412 | 449 | * method described by the supplied arguments, <strong>or {@code null} if no such {@link ExecutableElement} |
@@ -763,6 +800,26 @@ public default TypeElement javaLangObject() { |
763 | 800 | */ |
764 | 801 | public PackageElement packageElement(final ModuleElement asSeenFrom, final CharSequence canonicalName); |
765 | 802 |
|
| 803 | + /** |
| 804 | + * Returns a {@link Parameterizable} corresponding to the supplied (reflective) {@link GenericDeclaration}. |
| 805 | + * |
| 806 | + * @param gd a {@link GenericDeclaration}; must not be {@code null} |
| 807 | + * |
| 808 | + * @return a {@link Parameterizable} corresponding to the supplied {@link GenericDeclaration}; never {@code null} |
| 809 | + * |
| 810 | + * @exception NullPointerException if {@code gd} is {@code null} |
| 811 | + * |
| 812 | + * @exception IllegalArgumentException if {@code gd} is neither a {@link Class} nor an {@link Executable} |
| 813 | + */ |
| 814 | + public default Parameterizable parameterizable(final GenericDeclaration gd) { |
| 815 | + return switch (gd) { |
| 816 | + case null -> throw new NullPointerException("gd"); |
| 817 | + case Class<?> c -> this.typeElement(c.getCanonicalName()); |
| 818 | + case Executable e -> this.executableElement(e); |
| 819 | + default -> throw new IllegalArgumentException("gd: " + gd); |
| 820 | + }; |
| 821 | + } |
| 822 | + |
766 | 823 | /** |
767 | 824 | * A convenience method that returns {@code true} if and only if {@code t} is a {@link DeclaredType}, {@linkplain |
768 | 825 | * TypeMirror#getKind() has a <code>TypeKind</code>} of {@link TypeKind#DECLARED DECLARED}, and {@linkplain |
@@ -1082,6 +1139,81 @@ public default String toString(final CharSequence name) { |
1082 | 1139 | }; |
1083 | 1140 | } |
1084 | 1141 |
|
| 1142 | + /** |
| 1143 | + * A convenience method that returns the {@link TypeMirror} corresponding to the supplied (reflective) {@link Type}. |
| 1144 | + * |
| 1145 | + * @param t a {@link Type}; must not be {@code null} |
| 1146 | + * |
| 1147 | + * @return the {@link TypeMirror} corresponding to the supplied {@link Type}; never {@code null} |
| 1148 | + * |
| 1149 | + * @exception NullPointerException if {@code t} is {@code null} |
| 1150 | + * |
| 1151 | + * @exception IllegalArgumentException if {@code t} is not a {@link Class}, {@link GenericArrayType}, {@link |
| 1152 | + * ParameterizedType}, {@link java.lang.reflect.TypeVariable} or {@link java.lang.reflect.WildcardType} |
| 1153 | + */ |
| 1154 | + public default TypeMirror type(final Type t) { |
| 1155 | + // TODO: anywhere there is domain.declaredType(), consider passing |
| 1156 | + // domain.moduleElement(this.getClass().getModule().getName()) as the first argument. Not sure how this works |
| 1157 | + // exactly but I think it might be necessary. |
| 1158 | + return switch (t) { |
| 1159 | + case null -> throw new NullPointerException("t"); |
| 1160 | + case Class<?> c when t == boolean.class -> this.primitiveType(TypeKind.BOOLEAN); |
| 1161 | + case Class<?> c when t == byte.class -> this.primitiveType(TypeKind.BYTE); |
| 1162 | + case Class<?> c when t == char.class -> this.primitiveType(TypeKind.CHAR); |
| 1163 | + case Class<?> c when t == double.class -> this.primitiveType(TypeKind.DOUBLE); |
| 1164 | + case Class<?> c when t == float.class -> this.primitiveType(TypeKind.FLOAT); |
| 1165 | + case Class<?> c when t == int.class -> this.primitiveType(TypeKind.INT); |
| 1166 | + case Class<?> c when t == long.class -> this.primitiveType(TypeKind.LONG); |
| 1167 | + case Class<?> c when t == short.class -> this.primitiveType(TypeKind.SHORT); |
| 1168 | + case Class<?> c when t == void.class -> this.noType(TypeKind.VOID); |
| 1169 | + case Class<?> c when t == Object.class -> this.javaLangObject().asType(); // cheap and easy optimization |
| 1170 | + case Class<?> c when c.isArray() -> this.arrayTypeOf(this.type(c.getComponentType())); |
| 1171 | + case Class<?> c -> this.declaredType(c.getCanonicalName()); |
| 1172 | + case GenericArrayType g -> this.arrayTypeOf(this.type(g.getGenericComponentType())); |
| 1173 | + case ParameterizedType pt when pt.getOwnerType() == null -> |
| 1174 | + this.declaredType(this.typeElement(((Class<?>)pt.getRawType()).getCanonicalName()), |
| 1175 | + this.types(pt.getActualTypeArguments())); |
| 1176 | + case ParameterizedType pt -> |
| 1177 | + this.declaredType((DeclaredType)this.type(pt.getOwnerType()), |
| 1178 | + this.typeElement(((Class<?>)pt.getRawType()).getCanonicalName()), |
| 1179 | + this.types(pt.getActualTypeArguments())); |
| 1180 | + case java.lang.reflect.TypeVariable<?> tv -> this.typeVariable(this.parameterizable(tv.getGenericDeclaration()), tv.getName()); |
| 1181 | + case java.lang.reflect.WildcardType w when w.getLowerBounds().length <= 0 -> this.wildcardType(this.type(w.getUpperBounds()[0]), null); |
| 1182 | + case java.lang.reflect.WildcardType w -> this.wildcardType(null, this.type(w.getLowerBounds()[0])); |
| 1183 | + default -> throw new IllegalArgumentException("t: " + t); |
| 1184 | + }; |
| 1185 | + } |
| 1186 | + |
| 1187 | + /** |
| 1188 | + * A convenience method that returns an array of {@link TypeMirror}s whose elements correspond, in order, to the |
| 1189 | + * elements in the supplied {@link Type} array. |
| 1190 | + * |
| 1191 | + * @param ts an array of {@link Type}s; must not be {@code null} |
| 1192 | + * |
| 1193 | + * @return an array of {@link TypeMirror}s whose elements correspond, in order, to the elements in the supplied {@link |
| 1194 | + * Type} array; never {@code null} |
| 1195 | + * |
| 1196 | + * @exception NullPointerException if {@code ts} is {@code null} or contains {@code null} elements |
| 1197 | + * |
| 1198 | + * @exception IllegalArgumentException if any element of {@code ts} is deemed illegal by the {@link #type(Type)} |
| 1199 | + * method |
| 1200 | + * |
| 1201 | + * @see #type(Type) |
| 1202 | + */ |
| 1203 | + public default TypeMirror[] types(final Type[] ts) { |
| 1204 | + return switch (ts.length) { |
| 1205 | + case 0 -> new TypeMirror[0]; |
| 1206 | + case 1 -> new TypeMirror[] { this.type(ts[0]) }; |
| 1207 | + default -> { |
| 1208 | + final TypeMirror[] rv = new TypeMirror[ts.length]; |
| 1209 | + for (int i = 0; i < ts.length; i++) { |
| 1210 | + rv[i] = this.type(ts[i]); |
| 1211 | + } |
| 1212 | + yield rv; |
| 1213 | + } |
| 1214 | + }; |
| 1215 | + } |
| 1216 | + |
1085 | 1217 | /** |
1086 | 1218 | * Returns a {@link TypeElement} representing the element bearing the supplied <dfn>canonical name</dfn>, <strong>or |
1087 | 1219 | * {@code null} if there is no such {@link TypeElement}</strong>. |
|
0 commit comments