package com.laytonsmith.PureUtilities.ClassLoading.ClassMirror; import com.laytonsmith.PureUtilities.Common.ClassUtils; import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Objects; /** * This is the superclass of any element type, such as a field or method. */ abstract class AbstractElementMirror implements Serializable { /** * Version History: * 1 - Initial version * 2 - Parent was added, and it cannot be null. This is an incompatible change, and * all extensions will need to be recompiled to get the compilation caching benefit. * (Old caches will fail, and cause a re-scan, but will work.) */ private static final long serialVersionUID = 2L; /** * Any modifiers on the element */ protected final ModifierMirror modifiers; /** * The name of the element */ protected final String name; /** * The type of the element, or in the case of methods or other * composite types, the return type. */ protected final ClassReferenceMirror type; /** * Any annotations on the element. This isn't final, because * the fields and methods are created before they necessarily know their annotations. */ protected List<AnnotationMirror> annotations; /** * The parent class of the element */ private final ClassReferenceMirror parent; protected AbstractElementMirror(Field field){ Objects.requireNonNull(field); this.type = ClassReferenceMirror.fromClass(field.getType()); this.modifiers = new ModifierMirror(field.getModifiers()); this.name = field.getName(); List<AnnotationMirror> list = new ArrayList<>(); for(Annotation a : field.getDeclaredAnnotations()){ list.add(new AnnotationMirror(a)); } this.annotations = list; this.parent = ClassReferenceMirror.fromClass(field.getDeclaringClass()); Objects.requireNonNull(this.parent); } protected AbstractElementMirror(Method method){ Objects.requireNonNull(method); this.type = ClassReferenceMirror.fromClass(method.getReturnType()); this.modifiers = new ModifierMirror(method.getModifiers()); this.name = method.getName(); List<AnnotationMirror> list = new ArrayList<>(); for(Annotation a : method.getDeclaredAnnotations()){ list.add(new AnnotationMirror(a)); } this.annotations = list; this.parent = ClassReferenceMirror.fromClass(method.getDeclaringClass()); Objects.requireNonNull(this.parent); } protected AbstractElementMirror(ClassReferenceMirror parent, List<AnnotationMirror> annotations, ModifierMirror modifiers, ClassReferenceMirror type, String name){ this.annotations = annotations; if(this.annotations == null){ this.annotations = new ArrayList<>(); } this.modifiers = modifiers; this.type = type; this.name = name; this.parent = parent; Objects.requireNonNull(parent); Objects.requireNonNull(modifiers); Objects.requireNonNull(type); Objects.requireNonNull(name); } /** * Gets the modifiers on this field/method. * @return */ public ModifierMirror getModifiers(){ return modifiers; } /** * Gets the name of this field/method. * @return */ public String getName(){ return name; } /** * Gets the type of this field/method. For methods, this is * the return type. * @return */ public ClassReferenceMirror getType(){ return type; } /** * Returns a list of the annotations on this field/method. * @return */ public List<AnnotationMirror> getAnnotations(){ return new ArrayList<>(annotations); } /** * Gets the annotation on this field/method. * @param annotation * @return */ public AnnotationMirror getAnnotation(Class<? extends Annotation> annotation){ String jvmName = ClassUtils.getJVMName(annotation); for(AnnotationMirror a : getAnnotations()){ if(a.getType().getJVMName().equals(jvmName)){ return a; } } return null; } /** * Returns true if this element has the specified annotation attached to it. * @param annotation * @return */ public boolean hasAnnotation(Class<? extends Annotation> annotation){ return getAnnotation(annotation) != null; } /** * Loads the corresponding Annotation type for this field * or method. This actually loads the Annotation class into memory. * This is equivalent to getAnnotation(type).getProxy(type), however * this checks for null first, and returns null instead of causing a NPE. * @param <T> * @param type * @return */ public <T extends Annotation> T loadAnnotation(Class<T> type) { AnnotationMirror mirror = getAnnotation(type); if(mirror == null){ return null; } return mirror.getProxy(type); } /** * Returns the class that this is declared in. * @return */ public final ClassReferenceMirror getDeclaringClass(){ return this.parent; } /* package */ void addAnnotation(AnnotationMirror annotation){ annotations.add(annotation); } @Override public int hashCode() { int hash = 5; hash = 89 * hash + Objects.hashCode(this.name); hash = 89 * hash + Objects.hashCode(this.parent); return hash; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final AbstractElementMirror other = (AbstractElementMirror) obj; if (!Objects.equals(this.name, other.name)) { return false; } if (!Objects.equals(this.parent, other.parent)) { return false; } return true; } }