--- /dev/null 2013-05-13 18:24:09.635812635 -0700 +++ new/src/share/sample/language/model/CoreReflectionFactory.java 2013-05-14 23:59:43.000000000 -0700 @@ -0,0 +1,3771 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.lang.annotation.Annotation; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.element.*; +import javax.lang.model.element.Modifier; +import javax.lang.model.type.*; +import javax.lang.model.util.*; +import java.lang.reflect.*; +import java.io.Writer; +import java.util.*; + +import static javax.lang.model.SourceVersion.RELEASE_8; +import static java.util.Objects.*; + +/** + * This class provides a proof-of-concept implementation of the {@code + * javax.lang.model.*} API backed by core reflection. That is, rather + * than having a source file or compile-time class file as the + * originator of the information about an element or type, as done + * during standard annotation processing, runtime core reflection + * objects serve that purpose instead. + * + * With this kind of implementation, the same logic can be used for + * both compile-time and runtime processing of annotations. + * + * The nested types in this class define a specialization of {@code + * javax.lang.model.*} to provide some additional functionality and + * type information. The original {@code javax.lang.model.*} API was + * designed to accommodate such a specialization by using wildcards in + * the return types of methods. + * + * It would be technically possible for further specializations of the + * API implemented in this class to define alternative semantics of + * annotation look-up. For example to allow one annotation to have the + * effect of macro-expanding into a set of other annotations. + * + * Some aspects of the implementation are left as "exercises for the + * reader" to complete if interested. + * + * When passed null pointers, the methods defined in this type will + * generally throw null pointer exceptions. + * + * To get started, first compile this file with a command line like: + * + *
+ * $JDK/bin/javac -parameters -Xdoclint:all/public -Xlint:all -d $OUTPUT_DIR CoreReflectionFactory.java
+ * 
+ * + * and then run the main method of {@code CoreReflectionFactory}, + * which will print out a representation of {@code + * CoreReflectionFactory}. To use the printing logic defined in {@code + * javac}, put {@code tools.jar} on the classpath as in: + * + *
+ * $JDK/bin/java -cp $OUTPUT_DIR:$JDK_ROOT/lib/tools.jar CoreReflectionFactory
+ * 
+ * + * @author Joseph D. Darcy (darcy) + * @author Joel Borggren-Franck (jfranck) + */ +public class CoreReflectionFactory { + private CoreReflectionFactory() { + throw new AssertionError("No instances of CoreReflectionFactory for you!"); + } + + /** + * Returns a reflection type element mirroring a {@code Class} object. + * @return a reflection type element mirroring a {@code Class} object + * @param clazz the {@code Class} to mirror + */ + public static ReflectionTypeElement createMirror(Class clazz) { + return new CoreReflTypeElement(Objects.requireNonNull(clazz)); + } + + /** + * Returns a reflection package element mirroring a {@code Package} object. + * @return a reflection package element mirroring a {@code Package} object + * @param pkg the {@code Package} to mirror + */ + public static ReflectionPackageElement createMirror(Package pkg) { + // Treat a null pkg to mean an unnamed package. + return new CoreReflPackageElement(pkg); + } + + /** + * Returns a reflection variable element mirroring a {@code Field} object. + * @return a reflection variable element mirroring a {@code Field} object + * @param field the {@code Field} to mirror + */ + public static ReflectionVariableElement createMirror(Field field) { + return new CoreReflFieldVariableElement(Objects.requireNonNull(field)); + } + + /** + * Returns a reflection executable element mirroring a {@code Method} object. + * @return a reflection executable element mirroring a {@code Method} object + * @param method the {@code Method} to mirror + */ + public static ReflectionExecutableElement createMirror(Method method) { + return new CoreReflMethodExecutableElement(Objects.requireNonNull(method)); + } + + /** + * Returns a reflection executable element mirroring a {@code Constructor} object. + * @return a reflection executable element mirroring a {@code Constructor} object + * @param constructor the {@code Constructor} to mirror + */ + public static ReflectionExecutableElement createMirror(Constructor constructor) { + return new CoreReflConstructorExecutableElement(Objects.requireNonNull(constructor)); + } + + /** + * Returns a type parameter element mirroring a {@code TypeVariable} object. + * @return a type parameter element mirroring a {@code TypeVariable} object + * @param tv the {@code TypeVariable} to mirror + */ + public static TypeParameterElement createMirror(java.lang.reflect.TypeVariable tv) { + return new CoreReflTypeParameterElement(Objects.requireNonNull(tv)); + } + + /** + * Returns a variable element mirroring a {@code Parameter} object. + * @return a variable element mirroring a {@code Parameter} object + * @param p the {Parameter} to mirror + */ + public static VariableElement createMirror(java.lang.reflect.Parameter p) { + return new CoreReflParameterVariableElement(Objects.requireNonNull(p)); + } + + /** + * Returns an annotation mirror mirroring an annotation object. + * @return an annotation mirror mirroring an annotation object + * @param annotation the annotation to mirror + */ + public static AnnotationMirror createMirror(Annotation annotation) { + return new CoreReflAnnotationMirror(Objects.requireNonNull(annotation)); + } + + /** + * Returns a {@code Types} utility object for type objects backed by core reflection. + * @return a {@code Types} utility object for type objects backed by core reflection + */ + public static Types getTypes() { + return CoreReflTypes.instance(); + } + + /** + * Returns an {@code Elements} utility object for type objects backed by core reflection. + * @return an {@code Elements} utility object for type objects backed by core reflection + */ + public static Elements getElements() { + return CoreReflElements.instance(); + } + + // Helper + private static TypeMirror createTypeMirror(Class c) { + return TypeFactory.instance(Objects.requireNonNull(c)); + } + + /** + * Main method; prints out a representation of this class. + * @param args command-line arguments, currently ignored + */ + public static void main(String... args) { + getElements().printElements(new java.io.PrintWriter(System.out), + createMirror(CoreReflectionFactory.class)); + } + + /** + * A specialization of {@code javax.lang.model.element.Element} that is + * backed by core reflection. + */ + public static interface ReflectionElement + extends Element, AnnotatedElement { + + /** + * {@inheritDoc} + */ + @Override + ReflectionElement getEnclosingElement(); + + /** + * {@inheritDoc} + */ + @Override + List getEnclosedElements(); + + /** + * Applies a visitor to this element. + * + * @param v the visitor operating on this element + * @param p additional parameter to the visitor + * @param the return type of the visitor's methods + * @param

the type of the additional parameter to the visitor's methods + * @return a visitor-specified result + */ + R accept(ReflectionElementVisitor v, P p); + + // Functionality specific to the specialization + /** + * Returns the underlying core reflection source object, if applicable. + * @return the underlying core reflection source object, if applicable + */ + AnnotatedElement getSource(); + + // Functionality from javax.lang.model.util.Elements + /** + * Returns the package of an element. The package of a package + * is itself. + * @return the package of an element + */ + ReflectionPackageElement getPackage(); + + } + + /** + * A logical specialization of {@code + * javax.lang.model.element.ElementVisitor} being backed by core + * reflection. + * + * @param the return type of this visitor's methods. + * @param

the type of the additional parameter to this visitor's + * methods. + */ + public static interface ReflectionElementVisitor { + /** + * Visits an element. + * @param e the element to visit + * @param p a visitor-specified parameter + * @return a visitor-specified result + */ + R visit(ReflectionElement e, P p); + + /** + * A convenience method equivalent to {@code v.visit(e, null)}. + * @param e the element to visit + * @return a visitor-specified result + */ + R visit(ReflectionElement e); + + /** + * Visits a package element. + * @param e the element to visit + * @param p a visitor-specified parameter + * @return a visitor-specified result + */ + R visitPackage(ReflectionPackageElement e, P p); + + /** + * Visits a type element. + * @param e the element to visit + * @param p a visitor-specified parameter + * @return a visitor-specified result + */ + R visitType(ReflectionTypeElement e, P p); + + /** + * Visits a variable element. + * @param e the element to visit + * @param p a visitor-specified parameter + * @return a visitor-specified result + */ + R visitVariable(ReflectionVariableElement e, P p); + + /** + * Visits an executable element. + * @param e the element to visit + * @param p a visitor-specified parameter + * @return a visitor-specified result + */ + R visitExecutable(ReflectionExecutableElement e, P p); + + /** + * Visits a type parameter element. + * @param e the element to visit + * @param p a visitor-specified parameter + * @return a visitor-specified result + */ + R visitTypeParameter(ReflectionTypeParameterElement e, P p); + + /** + * Visits an unknown kind of element. + * This can occur if the language evolves and new kinds + * of elements are added to the {@code Element} hierarchy. + * + * @param e the element to visit + * @param p a visitor-specified parameter + * @return a visitor-specified result + * @throws UnknownElementException + * a visitor implementation may optionally throw this exception + */ + R visitUnknown(ReflectionElement e, P p); + } + + /** + * A specialization of {@code javax.lang.model.element.ExecutableElement} that is + * backed by core reflection. + */ + public static interface ReflectionExecutableElement + extends ReflectionElement, ExecutableElement, ReflectionParameterizable { + + /** + * {@inheritDoc} + */ + @Override + List getTypeParameters(); + + /** + * {@inheritDoc} + */ + @Override + List getParameters(); + + // Functionality specific to the specialization + /** + * Returns all parameters, including synthetic ones. + * @return all parameters, including synthetic ones + */ + List getAllParameters(); + + /** + * {@inheritDoc} + */ + @Override + Executable getSource(); + + /** + * Returns true if this executable is a synthetic construct; returns false otherwise. + * @return true if this executable is a synthetic construct; returns false otherwise + */ + boolean isSynthetic(); + + /** + * Returns true if this executable is a bridge method; returns false otherwise. + * @return true if this executable is a bridge method; returns false otherwise + */ + boolean isBridge(); + } + + /** + * A specialization of {@code javax.lang.model.element.PackageElement} being + * backed by core reflection. + */ + public static interface ReflectionPackageElement + extends ReflectionElement, PackageElement { + + // Functionality specific to the specialization + /** + * {@inheritDoc} + */ + @Override + Package getSource(); + } + + /** + * A specialization of {@code javax.lang.model.element.TypeElement} that is + * backed by core reflection. + */ + public static interface ReflectionTypeElement + extends ReflectionElement, TypeElement, ReflectionParameterizable { + + /** + * {@inheritDoc} + */ + @Override + List getTypeParameters(); + + /** + * {@inheritDoc} + */ + @Override + List getEnclosedElements(); + + // Methods specific to the specialization, but functionality + // also present in javax.lang.model.util.Elements. + /** + * Returns all members of a type element, whether inherited or + * declared directly. For a class the result also includes its + * constructors, but not local or anonymous classes. + * @return all members of the type + */ + List getAllMembers(); + + /** + * Returns the binary name of a type element. + * @return the binary name of a type element + */ + Name getBinaryName(); + + // Functionality specific to the specialization + /** + * {@inheritDoc} + */ + @Override + Class getSource(); + } + + /** + * A specialization of {@code javax.lang.model.element.TypeParameterElement} being + * backed by core reflection. + */ + public static interface ReflectionTypeParameterElement + extends ReflectionElement, TypeParameterElement { + + /** + * {@inheritDoc} + */ + @Override + ReflectionElement getGenericElement(); + + // Functionality specific to the specialization + + // Conceptually should have an override for getSource + // returning GenericDeclaration, but GenericDeclaration + // doesn't currently implement AnnotatedElement. +// /** +// * {@inheritDoc} +// */ +// @Override +// java.lang.reflect.GenericDeclaration getSource(); + } + + /** + * A specialization of {@code javax.lang.model.element.VariableElement} that is + * backed by core reflection. + */ + public static interface ReflectionVariableElement + extends ReflectionElement, VariableElement { + + // Functionality specific to the specialization + /** + * Returns true if this variable is a synthetic construct; returns false otherwise. + * @return true if this variable is a synthetic construct; returns false otherwise + */ + boolean isSynthetic(); + + /** + * Returns true if this variable is implicitly declared in source code; returns false otherwise. + * @return true if this variable is implicitly declared in source code; returns false otherwise + */ + boolean isImplicit(); + + // The VariableElement concept covers fields, variables, and + // method and constructor parameters. Therefore, this + // interface cannot define a more precise override of + // getSource since those three concept have different core + // reflection types with no supertype more precise than + // AnnotatedElement. + } + + /** + * A specialization of {@code javax.lang.model.element.Parameterizable} being + * backed by core reflection. + */ + public static interface ReflectionParameterizable + extends ReflectionElement, Parameterizable { + @Override + List getTypeParameters(); + } + + /** + * Base class for concrete visitors of elements backed by core reflection. + */ + public static abstract class AbstractReflectionElementVisitor8 + extends AbstractElementVisitor8 + implements ReflectionElementVisitor { + protected AbstractReflectionElementVisitor8() { + super(); + } + } + + /** + * Base class for simple visitors of elements that are backed by core reflection. + */ + @SupportedSourceVersion(value=RELEASE_8) + public static abstract class SimpleReflectionElementVisitor8 + extends SimpleElementVisitor8 + implements ReflectionElementVisitor { + + protected SimpleReflectionElementVisitor8(){ + super(); + } + + protected SimpleReflectionElementVisitor8(R defaultValue) { + super(defaultValue); + } + + // Create manual "bridge methods" for now. + + @Override + public final R visitPackage(PackageElement e, P p) { + return visitPackage((ReflectionPackageElement) e , p); + } + + @Override + public final R visitType(TypeElement e, P p) { + return visitType((ReflectionTypeElement) e , p); + } + + @Override + public final R visitVariable(VariableElement e, P p) { + return visitVariable((ReflectionVariableElement) e , p); + } + + @Override + public final R visitExecutable(ExecutableElement e, P p) { + return visitExecutable((ReflectionExecutableElement) e , p); + } + + @Override + public final R visitTypeParameter(TypeParameterElement e, P p) { + return visitTypeParameter((ReflectionTypeParameterElement) e , p); + } + } + + /** + * {@inheritDoc} + */ + public static interface ReflectionElements extends Elements { + /** + * Returns the innermost enclosing {@link ReflectionTypeElement} + * of the {@link ReflectionElement} or {@code null} if the + * supplied ReflectionElement is toplevel or represents a + * Package. + * + * @param e the {@link ReflectionElement} whose innermost + * enclosing {@link ReflectionTypeElement} is sought + * @return the innermost enclosing {@link + * ReflectionTypeElement} or @{code null} if the parameter + * {@code e} is a toplevel element or a package + */ + ReflectionTypeElement getEnclosingTypeElement(ReflectionElement e); + + /** + * {@inheritDoc} + */ + @Override + List getAllMembers(TypeElement type); + + /** + * {@inheritDoc} + */ + @Override + ReflectionPackageElement getPackageElement(CharSequence name); + + /** + * {@inheritDoc} + */ + @Override + ReflectionPackageElement getPackageOf(Element type); + + /** + * {@inheritDoc} + */ + @Override + ReflectionTypeElement getTypeElement(CharSequence name); + } + + // ------------------------- Implementation classes ------------------------ + + // Exercise for the reader: review the CoreReflElement class + // hierarchy below with an eye toward exposing it as an extensible + // API that could be subclassed to provide customized behavior, + // such as alternate annotation lookup semantics. + + private static abstract class CoreReflElement + implements ReflectionElement, AnnotatedElement { + public abstract AnnotatedElement getSource(); + + protected CoreReflElement() { + super(); + } + + // ReflectionElement methods + @Override + public ReflectionPackageElement getPackage() { + throw new UnsupportedOperationException(); + } + + @Override + public TypeMirror asType() { + throw new UnsupportedOperationException(getClass().toString()); + } + + @Override + public List getAnnotationMirrors() { + Annotation[] annotations = getSource().getDeclaredAnnotations(); + int len = annotations.length; + + if (len > 0) { + List res = new ArrayList<>(len); + for (Annotation a : annotations) { + res.add(createMirror(a)); + } + return Collections.unmodifiableList(res); + } else { + return Collections.emptyList(); + } + } + + @Override + public Set getModifiers() { + return ModifierUtil.instance(0, false); + } + + @Override + public abstract Name getSimpleName(); + + @Override + public abstract ReflectionElement getEnclosingElement(); + + @Override + public abstract List getEnclosedElements(); + + //AnnotatedElement methods + @Override + public T getAnnotation(Class annotationClass) { + return getSource().getAnnotation(annotationClass); + } + + @Override + public T[] getAnnotationsByType(Class annotationClass) { + return getSource().getAnnotationsByType(annotationClass); + } + + @Override + public Annotation[] getAnnotations() { + return getSource().getAnnotations(); + } + + @Override + public T getDeclaredAnnotation(Class annotationClass) { + return getSource().getDeclaredAnnotation(annotationClass); + } + + @Override + public T[] getDeclaredAnnotationsByType(Class annotationClass) { + return getSource().getDeclaredAnnotationsByType(annotationClass); + } + + @Override + public Annotation[] getDeclaredAnnotations() { + return getSource().getDeclaredAnnotations(); + } + + // java.lang.Object methods + @Override + public boolean equals(Object obj) { + if (obj instanceof CoreReflElement) { + CoreReflElement other = (CoreReflElement)obj; + return Objects.equals(other.getSource(), this.getSource()); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(getSource()); + } + + @Override + public String toString() { + return getKind().toString() + " " + getSimpleName().toString(); + } + } + + // Type + private static class CoreReflTypeElement extends CoreReflElement + implements ReflectionTypeElement { + private final Class source; + + protected CoreReflTypeElement(Class source) { + Objects.requireNonNull(source); + if (source.isPrimitive() || + source.isArray()) { + throw new IllegalArgumentException("Cannot create a ReflectionTypeElement based on class: " + source); + } + + this.source = source; + } + + @Override + public TypeMirror asType() { + return createTypeMirror(source); + } + + @Override + public Class getSource() { + return source; + } + + @Override + public boolean equals(Object o) { + if (o instanceof CoreReflTypeElement) { + return source.equals(((CoreReflTypeElement)o).getSource()); + } else { + return false; + } + } + + @Override + public R accept(ElementVisitor v, P p) { + return v.visitType(this, p); + } + + @Override + public R accept(ReflectionElementVisitor v, P p) { + return v.visitType(this, p); + } + + @Override + public Set getModifiers() { + return ModifierUtil.instance(source.getModifiers() & + (source.isInterface() ? + java.lang.reflect.Modifier.interfaceModifiers() : + java.lang.reflect.Modifier.classModifiers()), + false); + } + + @Override + public List getEnclosedElements() { + List enclosedElements = new ArrayList<>(); + + for (Class declaredClass : source.getDeclaredClasses()) { + enclosedElements.add(createMirror(declaredClass)); + } + + // Add elements in the conventional ordering: fields, then + // constructors, then methods. + for (Field f : source.getDeclaredFields()) { + enclosedElements.add(createMirror(f)); + } + + for (Constructor c : source.getDeclaredConstructors()) { + enclosedElements.add(createMirror(c)); + } + + for (Method m : source.getDeclaredMethods()) { + enclosedElements.add(createMirror(m)); + } + + return (enclosedElements.isEmpty() ? + Collections.emptyList(): + Collections.unmodifiableList(enclosedElements)); + } + + // Review for default method handling. + @Override + public List getAllMembers() { + List allMembers = new ArrayList<>(); + + // If I only had a MultiMap ... + List fields = new ArrayList<>(); + List methods = new ArrayList<>(); + List classes = new ArrayList<>(); + + // Add all fields for this class + for (Field f : source.getDeclaredFields()) { + fields.add(createMirror(f)); + } + + // Add all methods for this class + for (Method m : source.getDeclaredMethods()) { + methods.add(createMirror(m)); + } + + // Add all classes for this class, except anonymous/local as per Elements.getAllMembers doc + for (Class c : source.getDeclaredClasses()) { + if (c.isLocalClass() || c.isAnonymousClass()) + continue; + classes.add(createMirror(c)); + } + + Class cls = source; + if (cls.isInterface()) { + cls = null; + } + do { + // Walk up superclasses adding non-private elements. + // If source is an interface, just add Object's + // elements. + + if (cls == null) { + cls = java.lang.Object.class; + } else { + cls = cls.getSuperclass(); + } + + addMembers(cls, fields, methods, classes); + + } while (cls != java.lang.Object.class); + + // add members on (super)interface(s) + Set> seenInterfaces = new HashSet<>(); + Queue> interfaces = new LinkedList<>(); + if (source.isInterface()) { + seenInterfaces.add(source); + interfaces.add(source); + } else { + Class[] ifaces = source.getInterfaces(); + for (Class iface : ifaces) { + seenInterfaces.add(iface); + interfaces.add(iface); + } + } + + while (interfaces.peek() != null) { + Class head = interfaces.remove(); + addMembers(head, fields, methods, classes); + + Class[] ifaces = head.getInterfaces(); + for (Class iface : ifaces) { + if (!seenInterfaces.contains(iface)) { + seenInterfaces.add(iface); + interfaces.add(iface); + } + } + } + + // Add constructors + for (Constructor c : source.getDeclaredConstructors()) { + allMembers.add(createMirror(c)); + } + + // Add all unique methods + allMembers.addAll(methods); + + // Add all unique fields + allMembers.addAll(fields); + + // Add all unique classes + allMembers.addAll(classes); + + return Collections.unmodifiableList(allMembers); + } + + private void addMembers(Class cls, + List fields, + List methods, + List classes) { + Elements elements = getElements(); + + for (Field f : cls.getDeclaredFields()) { + if (java.lang.reflect.Modifier.isPrivate(f.getModifiers())) { continue; } + ReflectionElement tmp = createMirror(f); + boolean add = true; + for (ReflectionElement e : fields) { + if (elements.hides(e, tmp)) { + add = false; + break; + } + } + if (add) { + fields.add(tmp); + } + } + + for (Method m : cls.getDeclaredMethods()) { + if (java.lang.reflect.Modifier.isPrivate(m.getModifiers())) + continue; + + ReflectionExecutableElement tmp = createMirror(m); + boolean add = true; + for (ReflectionExecutableElement e : methods) { + if (elements.hides(e, tmp)) { + add = false; + break; + } else if (elements.overrides(e, tmp, this)) { + add = false; + break; + } + } + if (add) { + methods.add(tmp); + } + } + + for (Class c : cls.getDeclaredClasses()) { + if (java.lang.reflect.Modifier.isPrivate(c.getModifiers()) || + c.isLocalClass() || + c.isAnonymousClass()) + continue; + + ReflectionElement tmp = createMirror(c); + boolean add = true; + for (ReflectionElement e : classes) { + if (elements.hides(e, tmp)) { + add = false; + break; + } + } + if (add) { + classes.add(tmp); + } + } + } + + @Override + public ElementKind getKind() { + if (source.isInterface()) { + if (source.isAnnotation()) + return ElementKind.ANNOTATION_TYPE; + else + return ElementKind.INTERFACE; + } else if (source.isEnum()) { + return ElementKind.ENUM; + } else + return ElementKind.CLASS; + } + + @Override + public NestingKind getNestingKind() { + if (source.isAnonymousClass()) + return NestingKind.ANONYMOUS; + else if (source.isLocalClass()) + return NestingKind.LOCAL; + else if (source.isMemberClass()) + return NestingKind.MEMBER; + else return + NestingKind.TOP_LEVEL; + } + + @Override + public Name getQualifiedName() { + String name = source.getCanonicalName(); // TODO, this should be a FQN for + // the current element + if (name == null) + name = ""; + return StringName.instance(name); + } + + @Override + public Name getSimpleName() { + return StringName.instance(source.getSimpleName()); + } + + @Override + public TypeMirror getSuperclass() { + if (source.equals(java.lang.Object.class)) { + return NoType.getNoneInstance(); + } else { + return createTypeMirror(source.getSuperclass()); + } + } + + @Override + public List getInterfaces() { + Class[] interfaces = source.getInterfaces(); + int len = interfaces.length; + List res = new ArrayList<>(len); + + if (len > 0) { + for (Class c : interfaces) { + res.add(createTypeMirror(c)); + } + } else { + return Collections.emptyList(); + } + return Collections.unmodifiableList(res); + } + + @Override + public List getTypeParameters() { + return createTypeParameterList(source); + } + + @Override + public ReflectionElement getEnclosingElement() { + // Returns the package of a top-level type and returns the + // immediately lexically enclosing element for a nested type. + + switch(getNestingKind()) { + case TOP_LEVEL: + return createMirror(source.getPackage()); + case MEMBER: + return createMirror(source.getEnclosingClass()); + default: + if (source.getEnclosingConstructor() != null) { + return createMirror(source.getEnclosingConstructor()); + } else if (source.getEnclosingMethod() != null) { + return createMirror(source.getEnclosingMethod()); + } else { + return createMirror(source.getEnclosingClass()); + } + } + } + + @Override + public Name getBinaryName() { + return StringName.instance(getSource().getName()); + } + } + + private static abstract class CoreReflExecutableElement extends CoreReflElement + implements ReflectionExecutableElement { + + protected Executable source = null; + protected final List parameters; + + protected CoreReflExecutableElement(Executable source, + List parameters) { + this.source = Objects.requireNonNull(source); + this.parameters = Objects.requireNonNull(parameters); + } + + @Override + public R accept(ElementVisitor v, P p) { + return v.visitExecutable(this, p); + } + + @Override + public R accept(ReflectionElementVisitor v, P p) { + return v.visitExecutable(this, p); + } + + @Override + public abstract ExecutableType asType(); + + // Only Types and Packages enclose elements; see Element.getEnclosedElements() + @Override + public List getEnclosedElements() { + return Collections.emptyList(); + } + + @Override + public List getParameters() { + List tmp = new ArrayList<>(); + for (ReflectionVariableElement parameter : parameters) { + if (!parameter.isSynthetic()) + tmp.add(parameter); + } + return tmp; + } + + @Override + public List getAllParameters() { + // Could "fix" this if the return type included wildcards + @SuppressWarnings("unchecked") + List tmp = (List)(List)parameters; + return tmp; + } + + @Override + public List getThrownTypes() { + Class[] thrown = source.getExceptionTypes(); + int len = thrown.length; + List res = new ArrayList<>(len); + + if (len > 0) { + for (Class c : thrown) { + res.add(createTypeMirror(c)); + } + } else { + return Collections.emptyList(); + } + return Collections.unmodifiableList(res); + } + + @Override + public boolean isVarArgs() { + return source.isVarArgs(); + } + + @Override + public boolean isSynthetic() { + return source.isSynthetic(); + } + + @Override + public boolean isBridge() { + return false; + } + + @Override + public List getTypeParameters() { + return createTypeParameterList(source); + } + + public abstract AnnotationValue getDefaultValue(); + + @Override + public TypeMirror getReceiverType() { + // New in JDK 8 + throw new UnsupportedOperationException(this.toString()); + } + } + + private static class CoreReflConstructorExecutableElement + extends CoreReflExecutableElement { + + protected CoreReflConstructorExecutableElement(Constructor source) { + super(Objects.requireNonNull(source), + createParameterList(source)); + } + + @Override + public Constructor getSource() { + return (Constructor)source; + } + + @Override + public TypeMirror getReturnType() { + return NoType.getVoidInstance(); + } + + @Override + public ExecutableType asType() { + throw new UnsupportedOperationException(getClass().toString()); + } + + @Override + public boolean equals(Object o) { + if (o instanceof CoreReflConstructorExecutableElement) { + return source.equals(((CoreReflConstructorExecutableElement)o).getSource()); + } else { + return false; + } + } + + @Override + public ElementKind getKind() { + return ElementKind.CONSTRUCTOR; + } + + @Override + public Set getModifiers() { + return ModifierUtil.instance(source.getModifiers() & + java.lang.reflect.Modifier.constructorModifiers(), false); + } + + @Override + public ReflectionElement getEnclosingElement() { + return createMirror(source.getDeclaringClass()); + } + + @Override + public Name getSimpleName() { + return StringName.instance(""); + } + + @Override + public AnnotationValue getDefaultValue() { + // a constructor is never an annotation element + return null; + } + + @Override + public boolean isDefault() { + return false; // A constructor cannot be a default method + } + } + + private static class CoreReflMethodExecutableElement + extends CoreReflExecutableElement { + + protected CoreReflMethodExecutableElement(Method source) { + super(Objects.requireNonNull(source), + createParameterList(source)); + this.source = source; + } + + @Override + public Method getSource() { + return (Method)source; + } + + @Override + public TypeMirror getReturnType() { + return TypeFactory.instance(getSource().getReturnType()); + } + + @Override + public boolean equals(Object o) { + if (o instanceof CoreReflMethodExecutableElement) { + return source.equals( ((CoreReflMethodExecutableElement)o).getSource()); + } else { + return false; + } + } + + @Override + public ElementKind getKind() { + return ElementKind.METHOD; + } + + @Override + public Set getModifiers() { + return ModifierUtil.instance(source.getModifiers() & + java.lang.reflect.Modifier.methodModifiers(), + isDefault()); + } + + @Override + public ReflectionElement getEnclosingElement() { + return createMirror(source.getDeclaringClass()); + } + + @Override + public Name getSimpleName() { + return StringName.instance(source.getName()); + } + + @Override + public AnnotationValue getDefaultValue() { + Object value = getSource().getDefaultValue(); + if (null == value) { + return null; + } else { + return new CoreReflAnnotationValue(value); + } + } + + @Override + public boolean isDefault() { + return getSource().isDefault(); + } + + @Override + public boolean isBridge() { + return getSource().isBridge(); + } + + @Override + public ExecutableType asType() { + return TypeFactory.instance(getSource()); + } + } + + private static List createParameterList(Executable source) { + Parameter[] parameters = source.getParameters(); + int length = parameters.length; + if (length == 0) + return Collections.emptyList(); + else { + List tmp = new ArrayList<>(length); + for (Parameter parameter : parameters) { + tmp.add(new CoreReflParameterVariableElement(parameter)); + } + return Collections.unmodifiableList(tmp); + } + } + + private static List createTypeParameterList(GenericDeclaration source) { + java.lang.reflect.TypeVariable[] typeParams = source.getTypeParameters(); + int length = typeParams.length; + if (length == 0) + return Collections.emptyList(); + else { + List tmp = new ArrayList<>(length); + for (java.lang.reflect.TypeVariable typeVar : typeParams) + tmp.add(new CoreReflTypeParameterElement(typeVar)); + return Collections.unmodifiableList(tmp); + } + } + + private static class CoreReflTypeParameterElement + extends CoreReflElement + implements ReflectionTypeParameterElement { + + private final GenericDeclaration source; + private final java.lang.reflect.TypeVariable sourceTypeVar; + + protected CoreReflTypeParameterElement(java.lang.reflect.TypeVariable sourceTypeVar) { + this.sourceTypeVar = Objects.requireNonNull(sourceTypeVar); + this.source = Objects.requireNonNull(sourceTypeVar.getGenericDeclaration()); + } + + @Override + public AnnotatedElement getSource() { + return (AnnotatedElement)source; + } + + protected java.lang.reflect.TypeVariable getSourceTypeVar() { + return sourceTypeVar; + } + + @Override + public boolean equals(Object o) { + if (o instanceof CoreReflTypeParameterElement) { + return sourceTypeVar.equals(((CoreReflTypeParameterElement)o).sourceTypeVar); + } else { + return false; + } + } + + @Override + public R accept(ElementVisitor v, P p) { + return v.visitTypeParameter(this, p); + } + + @Override + public R accept(ReflectionElementVisitor v, P p) { + return v.visitTypeParameter(this, p); + } + + @Override + public List getEnclosedElements() { + return Collections.emptyList(); + } + + @Override + public ReflectionElement getEnclosingElement() { + if (source instanceof Class) + return createMirror((Class)source); + else if (source instanceof Method) + return createMirror((Method)source); + else if (source instanceof Constructor) + return createMirror((Constructor)source); + else + throw new AssertionError("Unexpected enclosing element: " + source); + } + + @Override + public ElementKind getKind() { + return ElementKind.TYPE_PARAMETER; + } + + @Override + public Name getSimpleName() { + return StringName.instance(sourceTypeVar.getName()); + } + + // TypeParameterElement methods + @Override + public ReflectionElement getGenericElement() { + return getEnclosingElement(); // As per the doc, + // getEnclosingElement and + // getGenericElement return + // the same information. + } + + @Override + public List getBounds() { + Type[] types = getSourceTypeVar().getBounds(); + int len = types.length; + + if (len > 0) { + List res = new ArrayList<>(len); + for (Type t : types) { + res.add(TypeFactory.instance(t)); + } + return Collections.unmodifiableList(res); + } else { + return Collections.emptyList(); + } + } + } + + private abstract static class CoreReflVariableElement extends CoreReflElement + implements ReflectionVariableElement { + + protected CoreReflVariableElement() {} + + // Element visitor + @Override + public R accept(ElementVisitorv, P p) { + return v.visitVariable(this, p); + } + + // ReflectElement visitor + @Override + public R accept(ReflectionElementVisitor v, P p) { + return v.visitVariable(this, p); + } + + @Override + public List getEnclosedElements() { + return Collections.emptyList(); + } + + @Override + public ReflectionElement getEnclosingElement() { + return null; + } + + @Override + public boolean isSynthetic() { + return false; + } + + @Override + public boolean isImplicit() { + return false; + } + } + + private static class CoreReflFieldVariableElement extends CoreReflVariableElement { + private final Field source; + + protected CoreReflFieldVariableElement(Field source) { + this.source = Objects.requireNonNull(source); + } + + @Override + public Field getSource() { + return source; + } + + @Override + public TypeMirror asType() { + return createTypeMirror(getSource().getType()); + } + + @Override + public ElementKind getKind() { + if (source.isEnumConstant()) + return ElementKind.ENUM_CONSTANT; + else + return ElementKind.FIELD; + } + + @Override + public Set getModifiers() { + return ModifierUtil.instance(source.getModifiers() & + java.lang.reflect.Modifier.fieldModifiers(), false); + } + + @Override + public Name getSimpleName() { + return StringName.instance(source.getName()); + } + + @Override + public ReflectionElement getEnclosingElement() { + return createMirror(source.getDeclaringClass()); + } + + @Override + public boolean equals(Object o) { + if (o instanceof CoreReflFieldVariableElement) { + return Objects.equals(source, + ((CoreReflFieldVariableElement)o).getSource()); + } else { + return false; + } + } + + @Override + public Object getConstantValue() { + Field target = source; + + // The api says only Strings and primitives may be compile time constants. + // Ensure field is that, and final. + // + // Also, we don't have an instance so restrict to static Fields + // + if (!(source.getType().equals(java.lang.String.class) + || source.getType().isPrimitive())) { + return null; + } + final int modifiers = target.getModifiers(); + if (!( java.lang.reflect.Modifier.isFinal(modifiers) && + java.lang.reflect.Modifier.isStatic(modifiers))) { + return null; + } + + try { + return target.get(null); + } catch (IllegalAccessException e) { + try { + target.setAccessible(true); + return target.get(null); + } catch (IllegalAccessException i) { + throw new SecurityException(i); + } + } + } + } + + private static class CoreReflParameterVariableElement + extends CoreReflVariableElement { + private final Parameter source; + + protected CoreReflParameterVariableElement(Parameter source) { + this.source = Objects.requireNonNull(source); + } + + @Override + public Parameter getSource() { + return source; + } + + @Override + public Set getModifiers() { + return ModifierUtil.instance(source.getModifiers() & + java.lang.reflect.Modifier.parameterModifiers(), false); + } + + @Override + public TypeMirror asType() { + // TODO : switch to parameterized type + return createTypeMirror(source.getType()); + } + + @Override + public ElementKind getKind() { + return ElementKind.PARAMETER; + } + + @Override + public Name getSimpleName() { + return StringName.instance(source.getName()); + } + + @Override + public ReflectionElement getEnclosingElement() { + Executable enclosing = source.getDeclaringExecutable(); + if (enclosing instanceof Method) + return createMirror((Method)enclosing); + else if (enclosing instanceof Constructor) + return createMirror((Constructor)enclosing); + else + throw new AssertionError("Bad enclosing value."); + } + + @Override + public boolean equals(Object o) { + if (o instanceof CoreReflParameterVariableElement) { + return source.equals(((CoreReflParameterVariableElement) o).getSource()); + } else + return false; + } + + // VariableElement methods + @Override + public Object getConstantValue() { + return null; + } + + @Override + public boolean isSynthetic() { + return source.isSynthetic(); + } + + @Override + public boolean isImplicit() { + return source.isImplicit(); + } + } + + private static class CoreReflPackageElement extends CoreReflElement + implements ReflectionPackageElement { + + private final Package source; + + protected CoreReflPackageElement(Package source) { + this.source = source; + } + + @Override + public Package getSource() { + return source; + } + + @Override + public R accept(ElementVisitor v, P p) { + return v.visitPackage(this, p); + } + + @Override + public R accept(ReflectionElementVisitor v, P p) { + return v.visitPackage(this, p); + } + + @Override + public boolean equals(Object o) { + if (o instanceof CoreReflPackageElement) { + return Objects.equals(source, + ((CoreReflPackageElement)o).getSource()); + } else { + return false; + } + } + + @Override + public ElementKind getKind() { + return ElementKind.PACKAGE; + } + + @Override + public ReflectionElement getEnclosingElement() { + return null; + } + + @Override + public List getEnclosedElements() { + throw new UnsupportedOperationException(); + } + + @Override + public Name getQualifiedName() { + return StringName.instance((source != null) ? + source.getName() : + "" ); + } + + @Override + public Name getSimpleName() { + String n = ((source != null) ? + source.getName() : + ""); + int index = n.lastIndexOf('.'); + if (index > 0) { + return StringName.instance(n.substring(index + 1, n.length())); + } else { + return StringName.instance(n); + } + } + + @Override + public boolean isUnnamed() { + if (source != null) { + String name = source.getName(); + return(name == null || name.isEmpty()); + } else + return true; + } + } + + private static class CoreReflAnnotationMirror + implements javax.lang.model.element.AnnotationMirror { + private final Annotation annotation; + + protected CoreReflAnnotationMirror(Annotation annotation) { + this.annotation = Objects.requireNonNull(annotation); + } + + @Override + public DeclaredType getAnnotationType() { + return (DeclaredType)TypeFactory.instance(annotation.annotationType()); + } + + @Override + public Map getElementValues() { + // This differs from the javac implementation in that it returns default values + + Method[] elems = annotation.annotationType().getDeclaredMethods(); + int len = elems.length; + + if (len > 0) { + Map res = new HashMap<>(); + for (Method m : elems) { + AnnotationValue v; + try { + v = new CoreReflAnnotationValue(m.invoke(annotation)); + } catch (IllegalAccessException e) { + try { + m.setAccessible(true); + v = new CoreReflAnnotationValue(m.invoke(annotation)); + } catch (IllegalAccessException i) { + throw new SecurityException(i); + } catch (InvocationTargetException ee) { + throw new RuntimeException(ee); + } + } catch (InvocationTargetException ee) { + throw new RuntimeException(ee); + } + ReflectionExecutableElement e = createMirror(m); + res.put(e, v); + } + + return Collections.unmodifiableMap(res); + } else { + return Collections.emptyMap(); + } + } + + @Override + public boolean equals(Object other) { + if (other instanceof CoreReflAnnotationMirror) { + return annotation.equals(((CoreReflAnnotationMirror)other).annotation); + } else { + return false; + } + } + + @Override + public int hashCode() { + return Objects.hashCode(annotation); + } + + @Override + public String toString() { + return annotation.toString(); + } + } + + private static class CoreReflAnnotationValue + implements javax.lang.model.element.AnnotationValue { + private Object value = null; + + protected CoreReflAnnotationValue(Object value) { + // Is this constraint really necessary? + Objects.requireNonNull(value); + this.value = value; + } + + @Override + public Object getValue() { + return value; + } + + @Override + public String toString() { + return value.toString(); + } + + @Override + public R accept(AnnotationValueVisitor v, P p) { + return v.visit(this, p); + } + } + + // Helper utility classes + + private static class StringName implements Name { + private String name; + + private StringName(String name) { + this.name = Objects.requireNonNull(name); + } + + public static StringName instance(String name) { + return new StringName(name); + } + + @Override + public int length() { + return name.length(); + } + + @Override + public char charAt(int index) { + return name.charAt(index); + } + + @Override + public CharSequence subSequence(int start, int end) { + return name.subSequence(start, end); + } + + @Override + public String toString() { + return name; + } + + @Override + public boolean equals(Object other) { + if (other instanceof StringName) { + return name.equals(((StringName) other).name); + } else { + return false; + } + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public boolean contentEquals(CharSequence cs) { + return name.contentEquals(cs); + } + } + + /* + * Given an {@code int} value of modifiers, return a proper immutable set + * of {@code Modifier}s as a result. + */ + private static class ModifierUtil { + private ModifierUtil() { + throw new AssertionError("No instances for you."); + } + + // Exercise for the reader: explore if caching of sets of + // Modifiers would be helpful. + + public static Set instance(int modifiers, boolean isDefault) { + Set modSet = EnumSet.noneOf(Modifier.class); + + if (java.lang.reflect.Modifier.isAbstract(modifiers)) + modSet.add(Modifier.ABSTRACT); + + if (java.lang.reflect.Modifier.isFinal(modifiers)) + modSet.add(Modifier.FINAL); + + if (java.lang.reflect.Modifier.isNative(modifiers)) + modSet.add(Modifier.NATIVE); + + if (java.lang.reflect.Modifier.isPrivate(modifiers)) + modSet.add(Modifier.PRIVATE); + + if (java.lang.reflect.Modifier.isProtected(modifiers)) + modSet.add(Modifier.PROTECTED); + + if (java.lang.reflect.Modifier.isPublic(modifiers)) + modSet.add(Modifier.PUBLIC); + + if (java.lang.reflect.Modifier.isStatic(modifiers)) + modSet.add(Modifier.STATIC); + + if (java.lang.reflect.Modifier.isStrict(modifiers)) + modSet.add(Modifier.STRICTFP); + + if (java.lang.reflect.Modifier.isSynchronized(modifiers)) + modSet.add(Modifier.SYNCHRONIZED); + + if (java.lang.reflect.Modifier.isTransient(modifiers)) + modSet.add(Modifier.TRANSIENT); + + if (java.lang.reflect.Modifier.isVolatile(modifiers)) + modSet.add(Modifier.VOLATILE); + + if (isDefault) + modSet.add(Modifier.DEFAULT); + + return Collections.unmodifiableSet(modSet); + } + } + + private abstract static class AbstractTypeMirror implements TypeMirror { + private final TypeKind kind; + + protected AbstractTypeMirror(TypeKind kind) { + this.kind = Objects.requireNonNull(kind); + } + + @Override + public TypeKind getKind() { + return kind; + } + + @Override + public R accept(TypeVisitor v, P p) { + return v.visit(this, p); + } + + //Types methods + abstract List directSuperTypes(); + + TypeMirror capture() { + // Exercise for the reader: make this abstract and implement in subtypes + throw new UnsupportedOperationException(); + } + + TypeMirror erasure() { + // Exercise for the reader: make this abstract and implement in subtypes + throw new UnsupportedOperationException(); + } + + // Exercise for the reader: implement the AnnotatedConstruct methods + @Override + public List getAnnotationMirrors() { + throw new UnsupportedOperationException(); + } + + @Override + public T getAnnotation(Class annotationClass) { + throw new UnsupportedOperationException(); + } + + @Override + public T[] getAnnotationsByType(Class annotationClass) { + throw new UnsupportedOperationException(); + } + } + + private static class CoreReflArrayType extends AbstractTypeMirror + implements javax.lang.model.type.ArrayType, + Reifiable { + private Class source = null; + private Class component = null; + private TypeMirror eagerComponent = null; + + protected CoreReflArrayType(Class source) { + super(TypeKind.ARRAY); + this.source = source; + this.component = source.getComponentType(); + this.eagerComponent = TypeFactory.instance(component); + } + + public TypeMirror getComponentType() { + return eagerComponent; + } + + @Override + public Class getSource() { + return source; + } + + @Override + List directSuperTypes() { + final TypeMirror componentType = getComponentType(); + final TypeMirror[] directSupers; + + // JLS v4 4.10.3 + if (componentType.getKind().isPrimitive() || + component.equals(java.lang.Object.class)) { + directSupers = new TypeMirror[3]; + directSupers[0] = TypeFactory.instance(java.lang.Object.class); + directSupers[1] = TypeFactory.instance(java.lang.Cloneable.class); + directSupers[2] = TypeFactory.instance(java.io.Serializable.class); + } else if (componentType.getKind() == TypeKind.ARRAY) { + List componentDirectSupertypes = CoreReflTypes.instance().directSupertypes(componentType); + directSupers = new TypeMirror[componentDirectSupertypes.size()]; + for (int i = 0; i < directSupers.length; i++) { + directSupers[i] = new CoreReflArrayType(Array.newInstance(((Reifiable)componentDirectSupertypes.get(i)).getSource(), 0).getClass()); + } + } else { + Class superClass = component.getSuperclass(); + Class[] interfaces = component.getInterfaces(); + directSupers = new TypeMirror[1 + interfaces.length]; + + directSupers[0] = TypeFactory.instance(Array.newInstance(superClass, 0).getClass()); + + for (int i = 0; i < interfaces.length; i++) { + directSupers[i + 1] = TypeFactory.instance(Array.newInstance(interfaces[i],0).getClass()); + } + } + + return Collections.unmodifiableList(Arrays.asList(directSupers)); + } + + @Override + public String toString() { + return getKind() + " of " + getComponentType().toString(); + } + } + + private static class CaptureTypeVariable extends AbstractTypeMirror implements javax.lang.model.type.TypeVariable { + private TypeMirror source = null; + private TypeMirror upperBound = null; + private TypeMirror lowerBound = null; + + CaptureTypeVariable(TypeMirror source, + TypeMirror upperBound, + TypeMirror lowerBound) { + super(TypeKind.TYPEVAR); + + this.source = Objects.requireNonNull(source); + this.upperBound = (upperBound == null ? CoreReflTypes.instance().getNullType() : upperBound); + this.lowerBound = (lowerBound == null ? CoreReflTypes.instance().getNullType() : lowerBound); + } + + protected Class getSource() { + if (source instanceof CoreReflDeclaredType) { + return ((CoreReflDeclaredType)source).getSource(); + } else { + return null; + } + } + + @Override + public TypeMirror getUpperBound() { + return upperBound; + } + + @Override + public TypeMirror getLowerBound() { + return lowerBound; + } + + @Override + public Element asElement() { + if (null == getSource()) { + return null; + } + return CoreReflectionFactory.createMirror(getSource()); + } + + @Override + List directSuperTypes() { + throw new UnsupportedOperationException(); + + } + + @Override + public String toString() { + return getKind() + " CAPTURE of: " + source.toString(); + } + } + + private static class CoreReflElements implements ReflectionElements { + private CoreReflElements() {} // mostly one instance for you + + private static CoreReflElements instance = new CoreReflElements(); + + static CoreReflElements instance() { + return instance; + } + + /** + * {@inheritDoc} + */ + @Override + public ReflectionPackageElement getPackageElement(CharSequence name) { + return createMirror(Package.getPackage(name.toString())); + } + + /** + * {@inheritDoc} + */ + @Override + public ReflectionTypeElement getTypeElement(CharSequence name) { + // where name is a Canonical Name jls 6.7 + // but this method will probably accept an equivalent FQN + // depending on Class.forName(String) + + ReflectionTypeElement tmp = null; + + // Filter out arrays + String n = name.toString(); + if (n.contains("[")) return null; + if (n.equals("")) return null; + + // The intention of this loop is to handle nested + // elements. If finding the element using Class.forName + // fails, an attempt is made to find the element as an + // enclosed element by trying fo find a prefix of the name + // (dropping a trailing ".xyz") and looking for "xyz" as + // an enclosed element. + + Deque parts = new ArrayDeque<>(); + boolean again; + do { + again = false; + try { + tmp = createMirror(Class.forName(n)); + } catch (ClassNotFoundException e) { + tmp = null; + } + + if (tmp != null) { + if (parts.isEmpty()) { + return tmp; + } + + tmp = findInner(tmp, parts); + if (tmp != null) { + return tmp; + } + } + + int indx = n.lastIndexOf('.'); + if (indx > -1) { + parts.addFirst(n.substring(indx + 1)); + n = n.substring(0, indx); + again = true; + } + } while (again); + + return null; + } + + // Recursively finds enclosed type elements named as part.top() popping part and repeating + private ReflectionTypeElement findInner(ReflectionTypeElement e, Deque parts) { + if (parts.isEmpty()) { + return e; + } + + String part = parts.removeFirst(); + List enclosed = e.getEnclosedElements(); + for (ReflectionElement elm : enclosed) { + if ((elm.getKind() == ElementKind.CLASS || + elm.getKind() == ElementKind.INTERFACE || + elm.getKind() == ElementKind.ENUM || + elm.getKind() == ElementKind.ANNOTATION_TYPE) + && elm.getSimpleName().toString().equals(part)) { + ReflectionTypeElement t = findInner((ReflectionTypeElement)elm, parts); + if (t != null) { + return t; + } + } + } + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public Map + getElementValuesWithDefaults(AnnotationMirror a) { + if (a instanceof CoreReflAnnotationMirror) { + return ((CoreReflAnnotationMirror)a).getElementValues(); + } else { + throw new IllegalArgumentException(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public String getDocComment(Element e) { + checkElement(e); + return null; // As per the doc + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isDeprecated(Element e) { + checkElement(e); + return ((CoreReflElement)e).getSource().isAnnotationPresent(java.lang.Deprecated.class); + } + + /** + * {@inheritDoc} + */ + @Override + public Name getBinaryName(TypeElement type) { + checkElement(type); + return StringName.instance(((CoreReflTypeElement)type) + .getSource() + .getName()); + } + + /** + * {@inheritDoc} + */ + @Override + public ReflectionPackageElement getPackageOf(Element type) { + checkElement(type); + if (type instanceof ReflectionPackageElement) { + return (ReflectionPackageElement)type; + } + + Package p; + if (type instanceof CoreReflTypeElement) { + p = ((CoreReflTypeElement)type).getSource().getPackage(); + } else { + CoreReflTypeElement enclosingTypeElement = (CoreReflTypeElement)getEnclosingTypeElement((ReflectionElement)type); + p = enclosingTypeElement.getSource().getPackage(); + } + + return createMirror(p); + } + + /** + * {@inheritDoc} + */ + @Override + public List getAllMembers(TypeElement type) { + checkElement(type); + return getAllMembers((ReflectionTypeElement)type); + } + + // Exercise for the reader: should this method, and similar + // ones that specialize on the more specific argument types, + // be addd to the public ReflectionElements API? + public List getAllMembers(ReflectionTypeElement type) { + return type.getAllMembers(); + } + + /** + * {@inheritDoc} + */ + @Override + public List getAllAnnotationMirrors(Element e) { + checkElement(e); + AnnotatedElement ae = CoreReflElement.class.cast(e).getSource(); + Annotation[] annotations = ae.getAnnotations(); + int len = annotations.length; + + if (len > 0) { + List res = new ArrayList<>(len); + for (Annotation a : annotations) { + res.add(createMirror(a)); + } + return Collections.unmodifiableList(res); + } else { + List ret = Collections.emptyList(); + return ret; + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean hides(Element hider, Element hidden) { + checkElement(hider); + checkElement(hidden); + + // Names must be equal + if (!hider.getSimpleName().equals(hidden.getSimpleName())) { + return false; + } + + // Hides isn't reflexive + if (hider.equals(hidden)) { + return false; + } + + // Hider and hidden needs to be field, method or type + // and fields hide fields, types hide types, methods hide methods + // IE a Field doesn't hide a Methods etc + ElementKind hiderKind = hider.getKind(); + ElementKind hiddenKind = hidden.getKind(); + if (hiderKind.isField() && !hiddenKind.isField()) { + return false; + } else if (hiderKind.isClass() && + !(hiddenKind.isClass() || hiddenKind.isInterface())) { + return false; + } else if (hiderKind.isInterface() && + !(hiddenKind.isClass() || hiddenKind.isInterface())) { + return false; + } else if (hiderKind == ElementKind.METHOD && hiddenKind != ElementKind.METHOD) { + return false; + } else if (!(hiderKind.isClass() || + hiderKind.isInterface() || + hiderKind.isField() || + hiderKind == ElementKind.METHOD)) { + return false; + } + + Set hm = hidden.getModifiers(); + // jls 8.4.8.2 only static methods can hide methods + if (hider.getKind() == ElementKind.METHOD) { + if (!hider.getModifiers().contains(Modifier.STATIC)) { + return false; // hider not static + } else if (!hm.contains(Modifier.STATIC)) { // we know it's a method + return false; // hidden not static + } + + // For methods we also need to check parameter types + Class[] h1 = ((CoreReflMethodExecutableElement)hider).getSource().getParameterTypes(); + Class[] h2 = ((CoreReflMethodExecutableElement)hidden).getSource().getParameterTypes(); + if (h1.length != h2.length) { + return false; + } + for (int i = 0; i < h1.length; i++) { + if (h1[i] != h2[i]) { + return false; + } + } + } + + // You can only hide visible elements + if (hm.contains(Modifier.PRIVATE)) { + return false; // hidden private, can't be hidden + } else if ((!(hm.contains(Modifier.PUBLIC) || hm.contains(Modifier.PROTECTED))) && // not private, not (public or protected) IE package private + (!getPackageOf(hider).equals(getPackageOf(hidden)))) { + return false; // hidden package private, and different packages, IE not visible + } + + // Ok so now hider actually hides hidden if hider is + // declared on a subtype of hidden. + // + // TODO: should this be a proper subtype or is that taken + // care of by the reflexive check in the beginning? + // + TypeMirror hiderType = getEnclosingTypeElement((ReflectionElement)hider).asType(); + TypeMirror hiddenType = getEnclosingTypeElement((ReflectionElement)hidden).asType(); + + return getTypes().isSubtype(hiderType, hiddenType); + } + + /** + * {@inheritDoc} + */ + @Override + public ReflectionTypeElement getEnclosingTypeElement(ReflectionElement e) { + if (e.getKind() == ElementKind.PACKAGE) { + return null; + } + + if(e instanceof CoreReflTypeParameterElement) { + ReflectionElement encElem = ((CoreReflTypeParameterElement)e).getEnclosingElement(); + if (encElem instanceof ReflectionTypeElement) { + return (ReflectionTypeElement)encElem; + } else { + return getEnclosingTypeElement(encElem); + } + } + + Class encl = null; + if (e instanceof CoreReflTypeElement) { + encl = ((CoreReflTypeElement)e).getSource().getDeclaringClass(); + } else if (e instanceof CoreReflExecutableElement) { + encl = (((CoreReflExecutableElement)e).getSource()).getDeclaringClass(); + } else if (e instanceof CoreReflFieldVariableElement) { + encl = ((CoreReflFieldVariableElement)e).getSource().getDeclaringClass(); + } else if (e instanceof CoreReflParameterVariableElement) { + encl = ((CoreReflParameterVariableElement)e).getSource().getDeclaringExecutable().getDeclaringClass(); + } + + return encl == null ? null : createMirror(encl); + } + + /** + *{@inheritDoc} + * + * Note that this implementation does not handle the situation + * where A overrides B and B overrides C but A does not + * directly override C. In this case, this implementation will + * erroneously return false. + */ + @Override + public boolean overrides(ExecutableElement overrider, ExecutableElement overridden, + TypeElement type) { + checkElement(overrider); + checkElement(overridden); + checkElement(type); + + // TODO handle transitive overrides + return overridesDirect(overrider, overridden, type); + } + + private boolean overridesDirect(ExecutableElement overrider, ExecutableElement overridden, + TypeElement type) { + // Should we check that at least one of the types + // overrider has is in fact a supertype of the TypeElement + // 'type' supplied? + + CoreReflExecutableElement rider = (CoreReflExecutableElement)overrider; + CoreReflExecutableElement ridden = (CoreReflExecutableElement)overridden; + CoreReflTypeElement riderType = (CoreReflTypeElement)type; + + // Names must match, redundant - see subsignature below + if (!rider.getSimpleName().equals(ridden.getSimpleName())) { + return false; + } + + // Constructors don't override + // TODO: verify this fact + if (rider.getKind() == ElementKind.CONSTRUCTOR || + ridden.getKind() == ElementKind.CONSTRUCTOR) { + return false; + } + + // Overridden must be visible to be overridden + // TODO Fix transitive visibility/override + Set rm = ridden.getModifiers(); + if (rm.contains(Modifier.PRIVATE)) { + return false; // overridden private, can't be overridden + } else if ((!(rm.contains(Modifier.PUBLIC) || rm.contains(Modifier.PROTECTED))) && // not private, not (public or protected) IE package private + (!getPackageOf(rider).equals(getPackageOf(ridden)))) { + return false; // ridden package private, and different packages, IE not visible + } + + // Static methods doesn't override + if (rm.contains(Modifier.STATIC) || + rider.getModifiers().contains(Modifier.STATIC)) { + return false; + } + + // Declaring class of overrider must be a subclass of declaring class of overridden + // except we use the parameter type as declaring class of overrider + if (!getTypes().isSubtype(riderType.asType(), getEnclosingTypeElement(ridden).asType())) { + return false; + } + + // Now overrider overrides overridden if the signature of rider is a subsignature of ridden + return getTypes().isSubsignature(rider.asType(), ridden.asType()); + } + + /** + *{@inheritDoc} + */ + @Override + public String getConstantExpression(Object value) { + return Constants.format(value); + } + + // If CoreReflectionFactory were a proper part of the JDK, the + // analogous functionality in javac could be reused. + private static class Constants { + /** + * Returns a string representation of a constant value (given in + * standard wrapped representation), quoted and formatted as in + * Java source. + */ + public static String format(Object value) { + if (value instanceof Byte) return formatByte((Byte) value); + if (value instanceof Short) return formatShort((Short) value); + if (value instanceof Long) return formatLong((Long) value); + if (value instanceof Float) return formatFloat((Float) value); + if (value instanceof Double) return formatDouble((Double) value); + if (value instanceof Character) return formatChar((Character) value); + if (value instanceof String) return formatString((String) value); + if (value instanceof Integer || + value instanceof Boolean) return value.toString(); + else + throw new IllegalArgumentException("Argument is not a primitive type or a string; it " + + ((value == null) ? + "is a null value." : + "has class " + + value.getClass().getName()) + "." ); + } + + private static String formatByte(byte b) { + return String.format("(byte)0x%02x", b); + } + + private static String formatShort(short s) { + return String.format("(short)%d", s); + } + + private static String formatLong(long lng) { + return lng + "L"; + } + + private static String formatFloat(float f) { + if (Float.isNaN(f)) + return "0.0f/0.0f"; + else if (Float.isInfinite(f)) + return (f < 0) ? "-1.0f/0.0f" : "1.0f/0.0f"; + else + return f + "f"; + } + + private static String formatDouble(double d) { + if (Double.isNaN(d)) + return "0.0/0.0"; + else if (Double.isInfinite(d)) + return (d < 0) ? "-1.0/0.0" : "1.0/0.0"; + else + return d + ""; + } + + private static String formatChar(char c) { + return '\'' + quote(c) + '\''; + } + + private static String formatString(String s) { + return '"' + quote(s) + '"'; + } + + /** + * Escapes each character in a string that has an escape sequence or + * is non-printable ASCII. Leaves non-ASCII characters alone. + */ + private static String quote(String s) { + StringBuilder buf = new StringBuilder(); + for (int i = 0; i < s.length(); i++) { + buf.append(quote(s.charAt(i))); + } + return buf.toString(); + } + + /** + * Escapes a character if it has an escape sequence or is + * non-printable ASCII. Leaves ASCII characters alone. + */ + private static String quote(char ch) { + switch (ch) { + case '\b': return "\\b"; + case '\f': return "\\f"; + case '\n': return "\\n"; + case '\r': return "\\r"; + case '\t': return "\\t"; + case '\'': return "\\'"; + case '\"': return "\\\""; + case '\\': return "\\\\"; + default: + return (isPrintableAscii(ch)) + ? String.valueOf(ch) + : String.format("\\u%04x", (int) ch); + } + } + + /** + * Is a character printable ASCII? + */ + private static boolean isPrintableAscii(char ch) { + return ch >= ' ' && ch <= '~'; + } + } + + /** + * {@inheritDoc} + */ + @Override + public void printElements(Writer w, Element... elements) { + ElementVisitor printer = getPrinter(w); + try { + for (Element e : elements) { + checkElement(e); + printer.visit(e); + } + } finally { + try { + w.flush(); + } catch (java.io.IOException e) { /* Ignore */;} + } + } + + private ElementVisitor getPrinter(Writer w) { + // First try a reflective call into javac and if that + // fails, fallback to a very simple toString-based + // scanner. + try { + //reflective form of + // return new com.sun.tools.javac.processing.PrintingProcessor.PrintingElementVisitor(w, getElements()); + Class printProcClass = + ClassLoader.getSystemClassLoader().loadClass("com.sun.tools.javac.processing.PrintingProcessor$PrintingElementVisitor"); + Constructor printProcCtor = printProcClass.getConstructor(Writer.class, Elements.class); + return (ElementVisitor) printProcCtor.newInstance(w, getElements()); + } catch (ReflectiveOperationException | SecurityException e) { + return new ElementScanner8(w){ + @Override + public Writer scan(Element e, Void v) { + try { + DEFAULT_VALUE.append(e.toString()); + DEFAULT_VALUE.append("\n"); + } catch (java.io.IOException ioe) { + throw new RuntimeException(ioe); + } + return DEFAULT_VALUE; + } + }; + } + } + + /** + * {@inheritDoc} + */ + @Override + public Name getName(CharSequence cs) { + return StringName.instance(cs.toString()); + } + + private void checkElement(Element e) { + if(!(e instanceof CoreReflElement)) { + throw new IllegalArgumentException(); + } + } + + @Override + public boolean isFunctionalInterface(TypeElement e) { + throw new UnsupportedOperationException(); + // Update once this functionality is in core reflection + } + } + + private static class CoreReflTypes implements javax.lang.model.util.Types { + private static Types instance = new CoreReflTypes(); + + public static Types instance() { + return instance; + } + + // Private to suppress instantiation + private CoreReflTypes() {} + + // Types methods + @Override + public Element asElement(TypeMirror t) { + checkType(t); + if (t instanceof javax.lang.model.type.TypeVariable) { + ((javax.lang.model.type.TypeVariable)t).asElement(); + } else if (t instanceof DeclaredType) { + return ((DeclaredType)t).asElement(); + } + return null; + } + + @Override + public boolean isSameType(TypeMirror t1, TypeMirror t2) { + if (t1.getKind() != t2.getKind()) { + return false; + } + + if (t1.getKind() == TypeKind.WILDCARD || + t2.getKind() == TypeKind.WILDCARD) { + // Wildcards are not equal to any type + return false; + } + + if (t1 instanceof CoreReflDeclaredType && + t2 instanceof CoreReflDeclaredType) { + return ((CoreReflDeclaredType)t1).isSameType((CoreReflDeclaredType)t2); + } else if (t1 instanceof PrimitiveType && + t2 instanceof PrimitiveType) { + return t1.getKind() == t2.getKind(); + } else if (t1 instanceof NoType && + t2 instanceof NoType) { + return true; + } else if (t1 instanceof NullType && + t2 instanceof NullType) { + return true; + } else if (t1 instanceof ArrayType && + t2 instanceof ArrayType) { + return isSameType(((ArrayType)t1).getComponentType(), ((ArrayType)t2).getComponentType()); + } + + return false; + } + + @Override + public boolean isSubtype(TypeMirror t1, TypeMirror t2) { + checkType(t1); + checkType(t2); + + if (isSameType(t1, t2)) { + return true; + } else if(t1.getKind() == TypeKind.NULL) { + return true; + } + + // This depth first traversal should terminate due to the ban on circular inheritance + List directSupertypes = directSupertypes(t1); + if (directSupertypes.isEmpty()) { + return false; + } + for (TypeMirror ti : directSupertypes) { + if (isSameType(ti, t2) || isSubtype(ti, t2)) { + return true; + } + } + return false; + } + + @Override + public boolean isAssignable(TypeMirror t1, TypeMirror t2) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean contains(TypeMirror t1, TypeMirror t2) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isSubsignature(ExecutableType m1, ExecutableType m2) { + checkType(m1); + checkType(m2); + + ExecutableMethodType m0 = (ExecutableMethodType)m1; + + return m0.sameSignature((ExecutableMethodType)m2) || m0.sameSignature((ExecutableMethodType)erasure(m2)); + } + + @Override + public List directSupertypes(TypeMirror t) { + checkType(t); + if (t instanceof ExecutableType || + t.getKind() == TypeKind.PACKAGE) { + throw new IllegalArgumentException("You can't ask for direct supertypes for type: " + t); + } + return ((AbstractTypeMirror)t).directSuperTypes(); + } + + @Override + public TypeMirror erasure(TypeMirror t) { + checkType(t); + return ((AbstractTypeMirror)t).erasure(); + } + + @Override + public TypeElement boxedClass(javax.lang.model.type.PrimitiveType p) { + throw new UnsupportedOperationException(); + } + + @Override + public PrimitiveType unboxedType(TypeMirror t) { + throw new UnsupportedOperationException(); + } + + @Override + public TypeMirror capture(TypeMirror t) { + checkType(t); + return ((AbstractTypeMirror)t).capture(); + } + + @Override + public PrimitiveType getPrimitiveType(TypeKind kind) { + return PrimitiveType.instance(kind); + } + + @Override + public NullType getNullType() { + return CoreReflNullType.getInstance(); + } + + @Override + public javax.lang.model.type.NoType getNoType(TypeKind kind) { + if (kind == TypeKind.NONE) { + return NoType.getNoneInstance(); + } else if (kind == TypeKind.VOID) { + return NoType.getVoidInstance(); + } else { + throw new IllegalArgumentException("No NoType of kind: " + kind); + } + } + + @Override + public ArrayType getArrayType(TypeMirror componentType) { + throw new UnsupportedOperationException(); + } + + @Override + public javax.lang.model.type.WildcardType getWildcardType(TypeMirror extendsBound, + TypeMirror superBound) { + throw new UnsupportedOperationException(); + } + + @Override + public DeclaredType getDeclaredType(TypeElement typeElem, TypeMirror... typeArgs) { + throw new UnsupportedOperationException(); + } + + @Override + public javax.lang.model.type.DeclaredType getDeclaredType(javax.lang.model.type.DeclaredType containing, + TypeElement typeElem, + TypeMirror... typeArgs) { + throw new UnsupportedOperationException(); + } + + @Override + public TypeMirror asMemberOf(javax.lang.model.type.DeclaredType containing, Element element) { + throw new UnsupportedOperationException(); + } + + private void checkType(TypeMirror t) { + if (!(t instanceof AbstractTypeMirror)) { + throw new IllegalArgumentException("This Types implementation can only operate on CoreReflectionFactory type classes"); + } + } + } + + private abstract static class CoreReflDeclaredType extends AbstractTypeMirror + implements javax.lang.model.type.DeclaredType { + private Class source = null; + + private CoreReflDeclaredType(Class source) { + super(TypeKind.DECLARED); + this.source = source; + } + + static DeclaredType instance(Class source, Type genericSource) { + if (genericSource instanceof ParameterizedType) { + return new ParameterizedDeclaredType(source, (ParameterizedType)genericSource); + } else if (genericSource instanceof Class) { // This happens when a field has a raw type + if (!source.equals(genericSource)) { + throw new IllegalArgumentException("Don't know how to handle this"); + } + return instance(source); + } + throw new IllegalArgumentException("Don't know how to create a declared type from: " + + source + + " and genericSource " + + genericSource); + } + + static DeclaredType instance(Class source) { + return new RawDeclaredType(source); + } + + protected Class getSource() { + return source; + } + + @Override + public Element asElement() { + return CoreReflectionFactory.createMirror(getSource()); + } + + abstract boolean isSameType(DeclaredType other); + + @Override + TypeMirror capture() { + return new CaptureDeclaredType(this); + } + + private static class CaptureDeclaredType extends CoreReflDeclaredType { + CoreReflDeclaredType cap; + CaptureDeclaredType(CoreReflDeclaredType t) { + super(t.source); + this.cap = t; + } + + @Override + public List getTypeArguments() { + List wrapped = cap.getTypeArguments(); + ArrayList res = new ArrayList<>(wrapped.size()); + res.ensureCapacity(wrapped.size()); + + for (int i = 0; i < wrapped.size(); i++) { + TypeMirror t = wrapped.get(i); + + if (t instanceof javax.lang.model.type.WildcardType) { + res.add(i, convert(t)); + } else { + res.add(i, t); + } + } + return Collections.unmodifiableList(res); + } + + private TypeMirror convert(TypeMirror t) { + if (!(t instanceof javax.lang.model.type.WildcardType)) { + throw new IllegalArgumentException(); + } else { + javax.lang.model.type.WildcardType w = (javax.lang.model.type.WildcardType)t; + return TypeFactory.typeVariableInstance(w, w.getExtendsBound(), w.getSuperBound()); + } + } + + @Override + public TypeMirror getEnclosingType() { + return cap.getEnclosingType(); + } + + @Override + List directSuperTypes() { + return cap.directSuperTypes(); + } + + @Override + boolean isSameType(DeclaredType other) { + return other == this; + } + + @Override + public String toString() { + return " CAPTURE of: " + cap.toString(); + } + } + + private static class RawDeclaredType extends CoreReflDeclaredType + implements Reifiable { + private RawDeclaredType(Class source) { + super(source); + } + + @Override + public Class getSource() { + return super.getSource(); + } + + @Override + public TypeMirror getEnclosingType() { + Class enclosing = getSource().getEnclosingClass(); + if (null == enclosing) { + return NoType.getNoneInstance(); + } else { + return TypeFactory.instance(enclosing); + } + } + + @Override + public List getTypeArguments() { + return Collections.emptyList(); + } + + @Override + List directSuperTypes() { + if (getSource().isEnum()) { + return enumSuper(); + } + + if (getSource() == java.lang.Object.class) { + return Collections.emptyList(); + } + List res = new ArrayList<>(); + Type[] superInterfaces = getSource().getInterfaces(); + if (!getSource().isInterface()) { + res.add(TypeFactory.instance(getSource().getSuperclass())); + } else if (superInterfaces.length == 0) { + // Interfaces that don't extend another interface + // have java.lang.Object as a direct supertype. + return Collections.unmodifiableList(Arrays.asList(TypeFactory.instance(java.lang.Object.class))); + } + + for (Type t : superInterfaces) { + res.add(TypeFactory.instance(t)); + } + return Collections.unmodifiableList(res); + } + + private List enumSuper() { + Class rawSuper = getSource().getSuperclass(); + Type[] actualArgs = ((ParameterizedTypeImpl)getSource().getGenericSuperclass()).getActualTypeArguments(); + + // Reconsider this : assume the problem is making + // Enum rather than just a raw enum. + return Collections.unmodifiableList(Arrays.asList(TypeFactory.instance(ParameterizedTypeImpl.make(rawSuper, + Arrays.copyOf(actualArgs, + actualArgs.length), + null)))); + } + + @Override + boolean isSameType(DeclaredType other) { + if (other instanceof RawDeclaredType) { + return Objects.equals(getSource(), ((RawDeclaredType)other).getSource()); + } else { + return false; + } + } + + @Override + public String toString() { + return getSource().toString(); + } + } + + private static class ParameterizedDeclaredType extends CoreReflDeclaredType { + private ParameterizedType genericSource = null; + private ParameterizedDeclaredType(Class source, ParameterizedType genericSource) { + super(source); + this.genericSource = genericSource; + } + + @Override + public TypeMirror getEnclosingType() { + Type me = genericSource; + Type owner = GenericTypes.getEnclosingType(me); + if (owner == null) { + return NoType.getNoneInstance(); + } + return TypeFactory.instance(owner); + } + + @Override + public List getTypeArguments() { + Type[] typeArgs = genericSource.getActualTypeArguments(); + + int length = typeArgs.length; + if (length == 0) + return Collections.emptyList(); + else { + List tmp = new ArrayList<>(length); + for (Type t : typeArgs) { + tmp.add(TypeFactory.instance(t)); + } + return Collections.unmodifiableList(tmp); + } + } + + @Override + List directSuperTypes() { + if (getSource() == java.lang.Object.class) { + return Collections.emptyList(); + } + + List res = new ArrayList<>(); + Type[] superInterfaces = getSource().getGenericInterfaces(); + if (!getSource().isInterface()) { + // Replace actual type arguments with our type arguments + res.add(TypeFactory.instance(substituteTypeArgs(getSource().getGenericSuperclass()))); + } else if (superInterfaces.length == 0) { + // Interfaces that don't extend another interface + // have java.lang.Object as a direct supertype, plus + // possibly the interface's raw type + res.add(TypeFactory.instance(java.lang.Object.class)); + } + + for (Type t : superInterfaces) { + res.add(TypeFactory.instance(substituteTypeArgs(t))); + } + + res.add(TypeFactory.instance(getSource())); // Add raw type + return Collections.unmodifiableList(res); + } + + private Type substituteTypeArgs(Type type) { + if (!(type instanceof ParameterizedType)) { + return type; + } + + ParameterizedType target = (ParameterizedType)type; + // Cast to get a Class instead of a plain type. + Class raw = ((ParameterizedTypeImpl)target).getRawType(); + Type[] actualArgs = genericSource.getActualTypeArguments(); + + return ParameterizedTypeImpl.make(raw, Arrays.copyOf(actualArgs, actualArgs.length), null); + } + + @Override + boolean isSameType(DeclaredType other) { + if (other instanceof ParameterizedDeclaredType) { + return GenericTypes.isSameGenericType(genericSource, + ((ParameterizedDeclaredType)other).genericSource); + } else { + return false; + } + } + + @Override + public String toString() { + return getKind().toString() + " " + genericSource.toString(); + } + } + + /** + * Implementing class for ParameterizedType interface. + * Derived from sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl + */ + + private static class ParameterizedTypeImpl implements ParameterizedType { + private Type[] actualTypeArguments; + private Class rawType; + private Type ownerType; + + private ParameterizedTypeImpl(Class rawType, + Type[] actualTypeArguments, + Type ownerType) { + this.actualTypeArguments = actualTypeArguments; + this.rawType = rawType; + if (ownerType != null) { + this.ownerType = ownerType; + } else { + this.ownerType = rawType.getDeclaringClass(); + } + validateConstructorArguments(); + } + + private void validateConstructorArguments() { + java.lang.reflect.TypeVariable/**/[] formals = rawType.getTypeParameters(); + // check correct arity of actual type args + if (formals.length != actualTypeArguments.length){ + throw new MalformedParameterizedTypeException(); + } + } + + /** + * Static factory. Given a (generic) class, actual type arguments + * and an owner type, creates a parameterized type. + * This class can be instantiated with a a raw type that does not + * represent a generic type, provided the list of actual type + * arguments is empty. + * If the ownerType argument is null, the declaring class of the + * raw type is used as the owner type. + *

This method throws a MalformedParameterizedTypeException + * under the following circumstances: + * If the number of actual type arguments (i.e., the size of the + * array {@code typeArgs}) does not correspond to the number of + * formal type arguments. + * If any of the actual type arguments is not an instance of the + * bounds on the corresponding formal. + * @param rawType the Class representing the generic type declaration being + * instantiated + * @param actualTypeArguments - a (possibly empty) array of types + * representing the actual type arguments to the parameterized type + * @param ownerType - the enclosing type, if known. + * @return An instance of {@code ParameterizedType} + * @throws MalformedParameterizedTypeException - if the instantiation + * is invalid + */ + public static ParameterizedTypeImpl make(Class rawType, + Type[] actualTypeArguments, + Type ownerType) { + return new ParameterizedTypeImpl(rawType, actualTypeArguments, + ownerType); + } + + + /** + * Returns an array of {@code Type} objects representing the actual type + * arguments to this type. + * + *

Note that in some cases, the returned array be empty. This can occur + * if this type represents a non-parameterized type nested within + * a parameterized type. + * + * @return an array of {@code Type} objects representing the actual type + * arguments to this type + * @throws {@code TypeNotPresentException} if any of the + * actual type arguments refers to a non-existent type declaration + * @throws {@code MalformedParameterizedTypeException} if any of the + * actual type parameters refer to a parameterized type that cannot + * be instantiated for any reason + * @since 1.5 + */ + public Type[] getActualTypeArguments() { + return actualTypeArguments.clone(); + } + + /** + * Returns the {@code Type} object representing the class or interface + * that declared this type. + * + * @return the {@code Type} object representing the class or interface + * that declared this type + */ + public Class getRawType() { + return rawType; + } + + + /** + * Returns a {@code Type} object representing the type that this type + * is a member of. For example, if this type is {@code O.I}, + * return a representation of {@code O}. + * + *

If this type is a top-level type, {@code null} is returned. + * + * @return a {@code Type} object representing the type that + * this type is a member of. If this type is a top-level type, + * {@code null} is returned + */ + public Type getOwnerType() { + return ownerType; + } + + /* + * From the JavaDoc for java.lang.reflect.ParameterizedType + * "Instances of classes that implement this interface must + * implement an equals() method that equates any two instances + * that share the same generic type declaration and have equal + * type parameters." + */ + @Override + public boolean equals(Object o) { + if (o instanceof ParameterizedType) { + // Check that information is equivalent + ParameterizedType that = (ParameterizedType) o; + + if (this == that) + return true; + + Type thatOwner = that.getOwnerType(); + Type thatRawType = that.getRawType(); + + return Objects.equals(ownerType, thatOwner) && + Objects.equals(rawType, thatRawType) && + Arrays.equals(actualTypeArguments, // avoid clone + that.getActualTypeArguments()); + } else + return false; + } + + @Override + public int hashCode() { + return + Arrays.hashCode(actualTypeArguments) ^ + Objects.hashCode(ownerType) ^ + Objects.hashCode(rawType); + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + + if (ownerType != null) { + if (ownerType instanceof Class) + sb.append(((Class)ownerType).getName()); + else + sb.append(ownerType.toString()); + + sb.append("."); + + if (ownerType instanceof ParameterizedTypeImpl) { + // Find simple name of nested type by removing the + // shared prefix with owner. + sb.append(rawType.getName().replace( ((ParameterizedTypeImpl)ownerType).rawType.getName() + "$", + "")); + } else + sb.append(rawType.getName()); + } else + sb.append(rawType.getName()); + + if (actualTypeArguments != null && + actualTypeArguments.length > 0) { + sb.append("<"); + boolean first = true; + for (Type t: actualTypeArguments) { + if (!first) + sb.append(", "); + if (t instanceof Class) + sb.append(((Class)t).getName()); + else + sb.append(t.toString()); + first = false; + } + sb.append(">"); + } + + return sb.toString(); + } + } + + } + + private static class ErasedMethodType extends ExecutableMethodType implements javax.lang.model.type.ExecutableType { + private final Method m; + + ErasedMethodType(Method m) { + super(m); + this.m = Objects.requireNonNull(m); + } + + @Override + public List getTypeVariables() { + return Collections.emptyList(); + } + + @Override + public List getThrownTypes() { + Class[] exceptions = m.getExceptionTypes(); + int len = exceptions.length; + + if (len > 0) { + List res = new ArrayList(len); + for (Class t : exceptions) { + res.add(TypeFactory.instance(t)); + } + return Collections.unmodifiableList(res); + } else { + List ret = Collections.emptyList(); + return ret; + } + } + + @Override + public List getParameterTypes() { + Class[] params = m.getParameterTypes(); + int len = params.length; + + if (len > 0) { + List res = new ArrayList(len); + for (Class t : params) { + res.add(TypeFactory.instance(t)); + } + return Collections.unmodifiableList(res); + } else { + List ret = Collections.emptyList(); + return ret; + } + } + + @Override + public TypeMirror getReturnType() { + return TypeFactory.instance(m.getReturnType()); + } + + @Override + TypeMirror erasure() { + return this; + } + } + + private static class ErrorType extends AbstractTypeMirror implements javax.lang.model.type.ErrorType { + private static ErrorType errorType = new ErrorType(); + + public static ErrorType getErrorInstance() { + return errorType; + } + + private ErrorType() { + super(TypeKind.ERROR); + } + + @Override + public List getTypeArguments() { + throw new UnsupportedOperationException(); + } + + @Override + public TypeMirror getEnclosingType() { + throw new UnsupportedOperationException(); + } + + @Override + public Element asElement() { + throw new UnsupportedOperationException(); + } + + @Override + List directSuperTypes() { + throw new UnsupportedOperationException(); + } + } + + private static class ExecutableMethodType extends AbstractTypeMirror + implements javax.lang.model.type.ExecutableType { + private final Method m; + + ExecutableMethodType(Method m) { + super(TypeKind.EXECUTABLE); + this.m = Objects.requireNonNull(m); + } + + @Override + public List getThrownTypes() { + Type[] exceptions = m.getGenericExceptionTypes(); + int len = exceptions.length; + + if (len > 0) { + List res = new ArrayList(len); + for (Type t : exceptions) { + res.add(TypeFactory.instance(t)); + } + return Collections.unmodifiableList(res); + } else { + List ret = Collections.emptyList(); + return ret; + } + } + + @Override + public List getTypeVariables() { + java.lang.reflect.TypeVariable[] variables = m.getTypeParameters(); + int len = variables.length; + + if (len > 0) { + List res = new ArrayList<>(len); + for (java.lang.reflect.TypeVariable t : variables) { + res.add(TypeFactory.typeVariableInstance(t)); + } + return Collections.unmodifiableList(res); + } else { + return Collections.emptyList(); + } + } + + @Override + public TypeMirror getReturnType() { + return TypeFactory.instance(m.getGenericReturnType()); + } + + @Override + public List getParameterTypes() { + Type[] params = m.getGenericParameterTypes(); + int len = params.length; + + if (len > 0) { + List res = new ArrayList(len); + for (Type t : params) { + res.add(TypeFactory.instance(t)); + } + return Collections.unmodifiableList(res); + } else { + return Collections.emptyList(); + } + } + + @Override + List directSuperTypes() { + // Spec says we don't need this + throw new UnsupportedOperationException(); + } + + @Override + TypeMirror erasure() { + return new ErasedMethodType(m); + } + + @Override + public TypeMirror getReceiverType() { + throw new UnsupportedOperationException(); + } + + boolean sameSignature(ExecutableMethodType other){ + if (!m.getName().equals(other.m.getName())) { + return false; + } + + List thisParams = getParameterTypes(); + List otherParams = other.getParameterTypes(); + if (thisParams.size() != otherParams.size()) { + return false; + } + for (int i = 0; i < thisParams.size(); i++) { + if (!CoreReflTypes.instance().isSameType(thisParams.get(i), otherParams.get(i))) { + return false; + } + } + return true; + } + } + + private static class GenericTypes { + public static boolean isSameGenericType(Type t1, Type t2) { + if (t1 instanceof Class) { + return ((Class)t1).equals(t2); + } else if (t1 instanceof ParameterizedType) { + return ((ParameterizedType)t1).equals(t2); + } + throw new UnsupportedOperationException(); + } + + public static Type getEnclosingType(Type t1) { + if (t1 instanceof Class) { + return ((Class)t1).getEnclosingClass(); + } else if (t1 instanceof ParameterizedType) { + return ((ParameterizedType)t1).getOwnerType(); + } + throw new UnsupportedOperationException(); + } + } + + private static class IntersectionDeclaredType extends AbstractTypeMirror + implements javax.lang.model.type.DeclaredType { + private Type[] sources = null; + + IntersectionDeclaredType(Type[] sources) { + super(TypeKind.DECLARED); + this.sources = Arrays.copyOf(Objects.requireNonNull(sources), + sources.length); + } + + @Override + public TypeMirror getEnclosingType() { + return NoType.getNoneInstance(); + } + + @Override + public Element asElement() { + throw new UnsupportedOperationException(); + } + + @Override + public List getTypeArguments() { + throw new UnsupportedOperationException(); + } + + @Override + List directSuperTypes() { + int len = sources.length; + + if (len > 0) { + List res = new ArrayList(len); + for (Type c : sources) { + res.add(TypeFactory.instance(c)); + } + return Collections.unmodifiableList(res); + } else { + return Collections.emptyList(); + } + } + } + + private static class ModelWildcardType extends AbstractTypeMirror + implements javax.lang.model.type.WildcardType { + private java.lang.reflect.WildcardType genericSource; + + ModelWildcardType(java.lang.reflect.WildcardType genericSource) { + super(TypeKind.WILDCARD); + this.genericSource = Objects.requireNonNull(genericSource); + } + + @Override + List directSuperTypes() { + // TODO Add support for this operation + throw new UnsupportedOperationException(); + } + + @Override + public TypeMirror getExtendsBound() { + Type[] t = genericSource.getUpperBounds(); + + if (t.length == 1) { + if (t[0].equals(Object.class) && getSuperBound() != null) { // can't have both lower and upper explicit + return null; + } + return TypeFactory.instance(t[0]); + } + throw new UnsupportedOperationException(); // TODO: intersection type? + } + + @Override + public TypeMirror getSuperBound() { + Type[] t = genericSource.getLowerBounds(); + + if (t.length == 0) { // bound is null + return null; + } else if (t.length == 1) { + return TypeFactory.instance(t[0]); + } + throw new UnsupportedOperationException(); // TODO: intersection type? + } + + @Override + public String toString() { + return getKind() + " " + genericSource.toString(); + } + } + + private static class NoType extends AbstractTypeMirror + implements javax.lang.model.type.NoType { + private static NoType noneType = new NoType(TypeKind.NONE, "none"); + private static NoType packageType = new NoType(TypeKind.PACKAGE, "package"); + private static NoType voidType = new NoType(TypeKind.VOID, "void"); + + private String str; + + public static NoType getNoneInstance() { + return noneType; + } + + public static NoType getPackageInstance() { + return packageType; + } + + public static NoType getVoidInstance() { + return voidType; + } + + private NoType(TypeKind k, String str) { + super(k); + this.str = str; + } + + @Override + List directSuperTypes() { + // TODO We don't need this for the Package instance, how about the others? + throw new UnsupportedOperationException(); + } + + @Override + public String toString() { + return str; + } + } + + private static class CoreReflNullType extends AbstractTypeMirror + implements javax.lang.model.type.NullType { + private static CoreReflNullType nullType = new CoreReflNullType(); + + public static NullType getInstance() { + return nullType; + } + + private CoreReflNullType() { + super(TypeKind.NULL); + } + + @Override + List directSuperTypes() { + // JLS 4.10.2 says: + // "The direct supertypes of the null type are all reference types other than the null type itself." + // TODO return null? an empty list? the error type? anyhow fix this + throw new UnsupportedOperationException(); + } + } + + private static interface Reifiable { + Class getSource(); + } + + private static class PrimitiveType extends AbstractTypeMirror + implements javax.lang.model.type.PrimitiveType, + Reifiable { + private Class source; + + private static PrimitiveType booleanInstance = new PrimitiveType(TypeKind.BOOLEAN, boolean.class); + private static PrimitiveType byteInstance = new PrimitiveType(TypeKind.BYTE, byte.class); + private static PrimitiveType charInstance = new PrimitiveType(TypeKind.CHAR, char.class); + private static PrimitiveType shortInstance = new PrimitiveType(TypeKind.SHORT, short.class); + private static PrimitiveType intInstance = new PrimitiveType(TypeKind.INT, int.class); + private static PrimitiveType longInstance = new PrimitiveType(TypeKind.LONG, long.class); + private static PrimitiveType floatInstance = new PrimitiveType(TypeKind.FLOAT, float.class); + private static PrimitiveType doubleInstance = new PrimitiveType(TypeKind.DOUBLE, double.class); + + private PrimitiveType(TypeKind kind, Class source) { + super(kind); + this.source = source; + } + + @Override + public Class getSource() { + return source; + } + + static PrimitiveType instance(Class c) { + switch(c.getName()) { + case "boolean": + return booleanInstance; + case "byte": + return byteInstance; + case "char": + return charInstance; + case "short": + return shortInstance; + case "int": + return intInstance; + case "long": + return longInstance; + case "float": + return floatInstance; + case "double": + return doubleInstance; + default: + throw new IllegalArgumentException(); + } + } + + static PrimitiveType instance(TypeKind k) { + switch(k) { + case BOOLEAN: + return booleanInstance; + case BYTE: + return byteInstance; + case CHAR: + return charInstance; + case SHORT: + return shortInstance; + case INT: + return intInstance; + case LONG: + return longInstance; + case FLOAT: + return floatInstance; + case DOUBLE: + return doubleInstance; + default: + throw new IllegalArgumentException(); + } + } + + @Override + public String toString() { + return source.getName(); + } + + //Types methods + @Override + List directSuperTypes() { + switch (getKind()) { + case DOUBLE: + return Collections.emptyList(); + case FLOAT: + return Arrays.asList(doubleInstance); + case LONG: + return Arrays.asList(floatInstance); + case INT: + return Arrays.asList(longInstance); + case CHAR: + return Arrays.asList(intInstance); + case SHORT: + return Arrays.asList(intInstance); + case BYTE: + return Arrays.asList(shortInstance); + default: + return Collections.emptyList(); + } + } + } + + private static class TypeFactory { + private TypeFactory() { }// no instances for you + + public static TypeMirror instance(Class c) { + if (c.isPrimitive()) { + if (c.getName().equals("void")) { + return NoType.getVoidInstance(); + } else { + return PrimitiveType.instance(c); + } + } else if (c.isArray()) { + return new CoreReflArrayType(c); + } else if (c.isAnonymousClass() || + c.isLocalClass() || + c.isMemberClass() || + c.isInterface() || // covers annotations + c.isEnum()) { + return CoreReflDeclaredType.instance(c); + } else { // plain old class ?? + return CoreReflDeclaredType.instance(c); + } + } + + public static TypeMirror instance(Type t) { + if (t instanceof Class) { + return instance((Class)t); + } else if (t instanceof ParameterizedType) { + ParameterizedType tmp = (ParameterizedType)t; + Type raw = tmp.getRawType(); + if (!(raw instanceof Class)) { + throw new IllegalArgumentException(t + " " + raw ); + } + return CoreReflDeclaredType.instance((Class)raw, tmp); + } else if (t instanceof java.lang.reflect.WildcardType) { + return new ModelWildcardType((java.lang.reflect.WildcardType)t); + } else if (t instanceof java.lang.reflect.TypeVariable) { + return new CoreReflTypeVariable((java.lang.reflect.TypeVariable)t); + } + throw new IllegalArgumentException("Don't know how to make instance from: " + t.getClass()); + } + + public static TypeMirror instance(Field f) { + return CoreReflDeclaredType.instance(f.getType(), f.getGenericType()); + } + + public static ExecutableType instance(Method m) { + return new ExecutableMethodType(m); + } + + public static javax.lang.model.type.TypeVariable typeVariableInstance(java.lang.reflect.TypeVariable v) { + return new CoreReflTypeVariable(v); + } + + public static javax.lang.model.type.TypeVariable typeVariableInstance(TypeMirror source, + TypeMirror upperBound, + TypeMirror lowerBound) { + return new CaptureTypeVariable(source, upperBound, lowerBound); + } + } + + private static class CoreReflTypeVariable extends AbstractTypeMirror + implements javax.lang.model.type.TypeVariable { + private final java.lang.reflect.TypeVariable source; + private boolean isCapture = false; + + protected CoreReflTypeVariable(java.lang.reflect.TypeVariable source) { + super(TypeKind.TYPEVAR); + Objects.requireNonNull(source); + this.source = source; + } + + @Override + public TypeMirror getUpperBound() { + return new IntersectionDeclaredType(source.getBounds()); + } + + @Override + public TypeMirror getLowerBound() { + return CoreReflTypes.instance().getNullType(); + } + + @Override + public Element asElement() { + return CoreReflectionFactory.createMirror(source); + } + + @Override + List directSuperTypes() { + return ((AbstractTypeMirror)getUpperBound()).directSuperTypes(); + } + + @Override + public int hashCode() { + return source.hashCode(); + } + + @Override + public boolean equals(Object other) { + if (other instanceof CoreReflTypeVariable) { + return this.source.equals(((CoreReflTypeVariable)other).source); + } else { + return false; + } + } + } +}