Skip to content

Commit

Permalink
Finished reoganizing ClassDiscovery system.
Browse files Browse the repository at this point in the history
The changes include support for ConstructorMirrors now and general support
for finding constructors. Additionally, completed changes to AnnotationChecks,
to allow for @ForceImplementation on methods now, as well as constructors.
  • Loading branch information
LadyCailin committed Feb 1, 2016
1 parent acae175 commit a94cc98
Show file tree
Hide file tree
Showing 17 changed files with 10,421 additions and 139 deletions.
Binary file added .hs_err_pid1404.log.swp
Binary file not shown.
366 changes: 366 additions & 0 deletions hs_err_pid1196.log

Large diffs are not rendered by default.

367 changes: 367 additions & 0 deletions hs_err_pid1404.log

Large diffs are not rendered by default.

355 changes: 355 additions & 0 deletions hs_err_pid1556.log

Large diffs are not rendered by default.

368 changes: 368 additions & 0 deletions hs_err_pid816.log

Large diffs are not rendered by default.

2,260 changes: 2,260 additions & 0 deletions replay_pid1196.log

Large diffs are not rendered by default.

2,000 changes: 2,000 additions & 0 deletions replay_pid1404.log

Large diffs are not rendered by default.

1,154 changes: 1,154 additions & 0 deletions replay_pid1556.log

Large diffs are not rendered by default.

3,183 changes: 3,183 additions & 0 deletions replay_pid816.log

Large diffs are not rendered by default.

@@ -1,8 +1,10 @@
package com.laytonsmith.PureUtilities.ClassLoading;

import com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.AbstractMethodMirror;
import com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.ClassMirror;
import com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.ClassMirrorVisitor;
import com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.ClassReferenceMirror;
import com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.ConstructorMirror;
import com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.FieldMirror;
import com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.MethodMirror;
import com.laytonsmith.PureUtilities.Common.ClassUtils;
Expand Down Expand Up @@ -35,7 +37,6 @@
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;

import org.objectweb.asm.ClassReader;

/**
Expand Down Expand Up @@ -141,6 +142,11 @@ public ClassDiscovery() {
* cache, this is cleared.
*/
private final Map<Class<? extends Annotation>, Set<MethodMirror>> methodAnnotationCache = new HashMap<>();
/**
* Cache for constructor annotations. Whenever a new URL is added to the URL cache,
* this is cleared.
*/
private final Map<Class<? extends Annotation>, Set<ConstructorMirror>> constructorAnnotationCache = new HashMap<>();
/**
* By default null, but this can be set per instance.
*/
Expand Down Expand Up @@ -357,8 +363,8 @@ public void handle(String filename, InputStream in) {
} else {
throw new RuntimeException("Unknown url type: " + rootLocation);
}
} catch(Exception e){
e.printStackTrace();;
} catch(RuntimeException e){
e.printStackTrace(System.err);
} finally {
if(debug){
StreamUtils.GetSystemOut().println("Scans finished for " + rootLocation + ", taking " + (System.currentTimeMillis() - start) + " ms.");
Expand Down Expand Up @@ -469,6 +475,7 @@ public void invalidateCaches() {
classAnnotationCache.clear();
fieldAnnotationCache.clear();
methodAnnotationCache.clear();
constructorAnnotationCache.clear();
dirtyURLs.addAll(urlCache);
}

Expand Down Expand Up @@ -829,14 +836,11 @@ public Set<FieldMirror> getFieldsWithAnnotation(Class<? extends Annotation> anno
fieldAnnotationCache.put(annotation, mirrors);
return mirrors;
}

/**
* Returns a list of methods that have been annotated with the specified
* annotation. This will work with annotations that have been declared with
* the {@link RetentionPolicy#CLASS} property.
*
* Returns all methods, including constructors, with the specified annotations
* @param annotation
* @return
* @return
*/
public Set<MethodMirror> getMethodsWithAnnotation(Class<? extends Annotation> annotation) {
if (methodAnnotationCache.containsKey(annotation)) {
Expand Down Expand Up @@ -893,23 +897,47 @@ public Set<Method> loadMethodsWithAnnotation(Class<? extends Annotation> annotat
}
}

public Set<MethodMirror> getConstructorsWithAnnotation(Class<? extends Annotation> annotation){
Set<MethodMirror> set = new HashSet<>();
for(MethodMirror m : getMethodsWithAnnotation(annotation)){
if("<init>".equals(m.getName())){
set.add(m);
/**
* Returns all ConstructorMirrors with the given annotation.
* @param annotation
* @return
*/
public Set<ConstructorMirror> getConstructorsWithAnnotation(Class<? extends Annotation> annotation){
if (constructorAnnotationCache.containsKey(annotation)) {
return new HashSet<>(constructorAnnotationCache.get(annotation));
}
doDiscovery();
Set<ConstructorMirror> mirrors = new HashSet<>();
for (ClassMirror m : getKnownClasses()) {
for (ConstructorMirror mm : m.getConstructors()) {
if (mm.hasAnnotation(annotation)) {
mirrors.add(mm);
}
}
}
return set;
constructorAnnotationCache.put(annotation, mirrors);
return mirrors;
}

/**
* Loads all Constructors with the given annotation.
* @param annotation
* @return
*/
public Set<Constructor> loadConstructorsWithAnnotation(Class<? extends Annotation> annotation){
return loadConstructorsWithAnnotation(annotation, getDefaultClassLoader(), true);
}

/**
* Loads all Constructors with the given annotation, using the specified classloader.
* @param annotation
* @param loader
* @param initialize
* @return
*/
public Set<Constructor> loadConstructorsWithAnnotation(Class<? extends Annotation> annotation, ClassLoader loader, boolean initialize){
Set<Constructor> set = new HashSet<>();
for(MethodMirror m : getConstructorsWithAnnotation(annotation)){
for(AbstractMethodMirror m : getConstructorsWithAnnotation(annotation)){
try {
Class c = m.getDeclaringClass().loadClass(loader, initialize);
outer: for(Constructor cc : c.getDeclaredConstructors()){
Expand Down
Expand Up @@ -4,6 +4,8 @@
import com.laytonsmith.PureUtilities.Common.ClassUtils;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
Expand Down Expand Up @@ -59,9 +61,14 @@ protected AbstractElementMirror(Field field){
Objects.requireNonNull(this.parent);
}

protected AbstractElementMirror(Method method){
protected AbstractElementMirror(Executable method){
Objects.requireNonNull(method);
this.type = ClassReferenceMirror.fromClass(method.getReturnType());
if(method instanceof Method){
this.type = ClassReferenceMirror.fromClass(((Method)method).getReturnType());
} else {
//It's a constructor. I hope.
this.type = ClassReferenceMirror.fromClass(((Constructor)method).getDeclaringClass());
}
this.modifiers = new ModifierMirror(method.getModifiers());
this.name = method.getName();
List<AnnotationMirror> list = new ArrayList<>();
Expand Down
@@ -0,0 +1,152 @@
package com.laytonsmith.PureUtilities.ClassLoading.ClassMirror;

import com.laytonsmith.PureUtilities.Common.StringUtils;
import java.lang.reflect.Executable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
* An {@link AbstractMethodMirror} encompasses both methods and constructors.
*/
public abstract class AbstractMethodMirror extends AbstractElementMirror {
private static final long serialVersionUID = 1L;

private final List<ClassReferenceMirror> params;
private boolean isVararg = false;
private boolean isSynthetic = false;

private Executable underlyingMethod = null;

public AbstractMethodMirror(ClassReferenceMirror parentClass, List<AnnotationMirror> annotations, ModifierMirror modifiers,
ClassReferenceMirror type, String name, List<ClassReferenceMirror> params, boolean isVararg, boolean isSynthetic){
super(parentClass, annotations, modifiers, type, name);
this.params = params;
this.isVararg = isVararg;
this.isSynthetic = isSynthetic;
}

public AbstractMethodMirror(Executable method){
super(method);
this.underlyingMethod = method;
this.params = null;
}

/* package */ AbstractMethodMirror(ClassReferenceMirror parentClass, ModifierMirror modifiers, ClassReferenceMirror type,
String name, List<ClassReferenceMirror> params, boolean isVararg, boolean isSynthetic){
super(parentClass, null, modifiers, type, name);
annotations = new ArrayList<>();
this.params = params;
this.isVararg = isVararg;
this.isSynthetic = isSynthetic;
}

/**
* Returns a list of params in this method.
* @return
*/
public List<ClassReferenceMirror> getParams(){
if(underlyingMethod != null){
List<ClassReferenceMirror> list = new ArrayList<>();
for(Class p : underlyingMethod.getParameterTypes()){
list.add(ClassReferenceMirror.fromClass(p));
}
return list;
}
return new ArrayList<>(params);
}

/**
* Returns true if this method is vararg.
* @return
*/
public boolean isVararg(){
if(underlyingMethod != null){
return underlyingMethod.isVarArgs();
}
return isVararg;
}

/**
* Returns true if this method is synthetic.
* @return
*/
public boolean isSynthetic(){
if(underlyingMethod != null){
return underlyingMethod.isSynthetic();
}
return isSynthetic;
}

@Override
public String toString() {
if(underlyingMethod != null){
return underlyingMethod.toString();
}
List<String> sParams = new ArrayList<>();
for(int i = 0; i < params.size(); i++){
if(i == params.size() - 1 && isVararg){
sParams.add(params.get(i).getComponentType().toString() + "...");
} else {
sParams.add(params.get(i).toString());
}
}
return StringUtils.Join(annotations, "\n") + (annotations.isEmpty()?"":"\n") + (modifiers.toString()
+ " " + type).trim() + " " + name + "(" + StringUtils.Join(sParams, ", ") + "){}";
}

@Override
public boolean equals(Object obj) {
if(!(obj instanceof MethodMirror)){
return false;
}
if(!super.equals(obj)){
return false;
}
AbstractMethodMirror m = (AbstractMethodMirror)obj;
return
this.params.equals(m.params)
&& this.isVararg == m.isVararg
&& this.isSynthetic == m.isSynthetic;
}

@Override
public int hashCode() {
int hash = 5;
hash = 31 * hash + super.hashCode();
hash = 31 * hash + Objects.hashCode(this.params);
hash = 31 * hash + (this.isVararg ? 1 : 0);
hash = 31 * hash + (this.isSynthetic ? 1 : 0);
return hash;
}

/**
* Returns the underlying executable (or null, if it was constructed artificially).
* @return
*/
protected Executable getExecutable(){
return underlyingMethod;
}

/**
* Loads the class that contains this method, using the default class loader.
* @return
* @throws java.lang.ClassNotFoundException
*/
public Class loadParentClass() throws ClassNotFoundException{
return loadParentClass(AbstractMethodMirror.class.getClassLoader(), true);
}

/**
* Loads the class that contains this method, using the default class loader.
* @param loader
* @param initialize
* @return
* @throws java.lang.ClassNotFoundException
*/
public Class loadParentClass(ClassLoader loader, boolean initialize) throws ClassNotFoundException{
ClassReferenceMirror p = getDeclaringClass();
Objects.requireNonNull(p, "Declaring class is null!");
return p.loadClass(loader, initialize);
}
}
Expand Up @@ -4,11 +4,6 @@
import com.laytonsmith.PureUtilities.ClassLoading.ClassDiscovery;
import com.laytonsmith.PureUtilities.Common.ClassUtils;
import com.laytonsmith.PureUtilities.Common.StringUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.annotation.RetentionPolicy;
Expand All @@ -19,15 +14,6 @@
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

/**
* This class gathers information about a class, without actually loading
Expand Down Expand Up @@ -324,6 +310,34 @@ public FieldMirror getField(String name) throws NoSuchFieldException {
* @return
*/
public MethodMirror[] getMethods(){
List<MethodMirror> l = new ArrayList<>();
for(AbstractMethodMirror m : getAllMethods()){
if(m instanceof MethodMirror){
l.add((MethodMirror)m);
}
}
return l.toArray(new MethodMirror[l.size()]);
}

/**
* Returns the Constructors in this class.
* @return
*/
public ConstructorMirror[] getConstructors(){
List<ConstructorMirror> l = new ArrayList<>();
for(AbstractMethodMirror m : getAllMethods()){
if(m instanceof ConstructorMirror){
l.add((ConstructorMirror)m);
}
}
return l.toArray(new ConstructorMirror[l.size()]);
}

/**
* Returns all methods in this class, including constructors.
* @return
*/
public AbstractMethodMirror[] getAllMethods(){
if(underlyingClass != null){
MethodMirror[] mirrors = new MethodMirror[underlyingClass.getDeclaredMethods().length];
for(int i = 0; i < mirrors.length; i++){
Expand Down Expand Up @@ -363,9 +377,9 @@ public MethodMirror getMethod(String name, Class...params) throws NoSuchMethodEx
public MethodMirror getMethod(String name, ClassReferenceMirror... params) throws NoSuchMethodException {
List<ClassReferenceMirror> crmParams = new ArrayList<>();
crmParams.addAll(Arrays.asList(params));
for(MethodMirror m : getMethods()){
if(m.getName().equals(name) && m.getParams().equals(crmParams)){
return m;
for(AbstractMethodMirror m : getAllMethods()){
if(m instanceof MethodMirror && m.getName().equals(name) && m.getParams().equals(crmParams)){
return (MethodMirror)m;
}
}
throw new NoSuchMethodException("No method matching the signature " + name + "(" + StringUtils.Join(crmParams, ", ") + ") was found.");
Expand Down Expand Up @@ -531,6 +545,6 @@ protected static class ClassInfo implements Serializable {
public boolean isEnum = false;
public ClassReferenceMirror classReferenceMirror;
public List<FieldMirror> fields = new ArrayList<>();
public List<MethodMirror> methods = new ArrayList<>();
public List<AbstractMethodMirror> methods = new ArrayList<>();
}
}

0 comments on commit a94cc98

Please sign in to comment.