summaryrefslogtreecommitdiff
path: root/src/main/java/ftbsc/lll/proxies
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/ftbsc/lll/proxies')
-rw-r--r--src/main/java/ftbsc/lll/proxies/AbstractProxy.java33
-rw-r--r--src/main/java/ftbsc/lll/proxies/ClassProxy.java122
-rw-r--r--src/main/java/ftbsc/lll/proxies/FieldProxy.java37
-rw-r--r--src/main/java/ftbsc/lll/proxies/MethodProxy.java86
-rw-r--r--src/main/java/ftbsc/lll/proxies/PackageProxy.java51
-rw-r--r--src/main/java/ftbsc/lll/proxies/QualifiableProxy.java68
6 files changed, 296 insertions, 101 deletions
diff --git a/src/main/java/ftbsc/lll/proxies/AbstractProxy.java b/src/main/java/ftbsc/lll/proxies/AbstractProxy.java
index 4dd2a72..93eaec8 100644
--- a/src/main/java/ftbsc/lll/proxies/AbstractProxy.java
+++ b/src/main/java/ftbsc/lll/proxies/AbstractProxy.java
@@ -14,7 +14,6 @@ public abstract class AbstractProxy {
*/
public final String name;
-
/**
* The {@link Type} corresponding to this element.
*/
@@ -24,7 +23,7 @@ public abstract class AbstractProxy {
* The fully qualified name (i.e. java.lang.String) of
* the parent class.
*/
- public final String parent;
+ public final QualifiableProxy parent;
/**
* The modifiers of the element, as a packed int.
@@ -39,7 +38,7 @@ public abstract class AbstractProxy {
* @param modifiers the modifiers, as a packed int
* @param parent the FQN of the parent class
*/
- protected AbstractProxy(String name, Type type, int modifiers, String parent) {
+ protected AbstractProxy(String name, Type type, int modifiers, QualifiableProxy parent) {
this.name = name;
this.type = type;
this.modifiers = modifiers;
@@ -47,6 +46,22 @@ public abstract class AbstractProxy {
}
/**
+ * Indicates whether the given object is a proxy for the same element as this.
+ * @param obj the object to perform
+ * @return true if it's equal
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if(obj instanceof AbstractProxy) {
+ AbstractProxy p = (AbstractProxy) obj;
+ return p.parent.equals(this.parent)
+ && p.name.equals(this.name)
+ && p.modifiers == this.modifiers
+ && p.type.equals(this.type);
+ } else return false;
+ }
+
+ /**
* A Builder for the generic proxy.
* @param <T> the type of proxy
*/
@@ -65,7 +80,7 @@ public abstract class AbstractProxy {
/**
* The fully qualified name of the parent.
*/
- protected String parent;
+ protected QualifiableProxy parent;
/**
* The {@link Type} corresponding to the element.
@@ -81,7 +96,6 @@ public abstract class AbstractProxy {
this.modifiers = 0;
}
-
/**
* @param newModifier the modifier to add
* @return the current state of the builder
@@ -101,11 +115,11 @@ public abstract class AbstractProxy {
}
/**
- * @param parentFQN the fully qualified name of the parent
+ * @param parent the {@link QualifiableProxy} representing the parent
* @return the current state of the builder
*/
- public Builder<T> setParent(String parentFQN) {
- this.parent = parentFQN;
+ public Builder<T> setParent(QualifiableProxy parent) {
+ this.parent = parent;
return this;
}
@@ -118,7 +132,6 @@ public abstract class AbstractProxy {
return this;
}
-
/**
* Sets {@link Type} for this element from the descriptor, passed as a {@link String}.
* @param descriptor the descriptor passed as a {@link String}
@@ -128,8 +141,6 @@ public abstract class AbstractProxy {
return this.setType(Type.getType(descriptor));
}
-
-
/**
* @return the built proxy object
*/
diff --git a/src/main/java/ftbsc/lll/proxies/ClassProxy.java b/src/main/java/ftbsc/lll/proxies/ClassProxy.java
index c369231..41e9bb8 100644
--- a/src/main/java/ftbsc/lll/proxies/ClassProxy.java
+++ b/src/main/java/ftbsc/lll/proxies/ClassProxy.java
@@ -2,36 +2,25 @@ package ftbsc.lll.proxies;
import org.objectweb.asm.Type;
+import java.lang.reflect.Modifier;
+
+import static ftbsc.lll.tools.DescriptorBuilder.nameToDescriptor;
+
/**
* A container for information about classes to be used
* in ASM patching.
* @since 0.4.0
*/
-public class ClassProxy extends AbstractProxy {
-
- /**
- * The fully-qualified name of the class represented by this proxy.
- */
- public final String fqn;
-
- /**
- * The {@link ClassProxy} representing the class which contains the
- * class represented by this proxy. May be null if the class represented
- * by this proxy is not an inner class.
- */
- public final ClassProxy containerClass;
-
+public class ClassProxy extends QualifiableProxy {
/**
* Protected constructor, called only from the builder.
* @param name the name of the class
* @param type the {@link Type} of the class
* @param modifiers the modifiers of the class
- * @param parent the FQN of the parent class of the class
+ * @param parent the package containing this class
*/
protected ClassProxy(String name, Type type, int modifiers, String parent) {
- super(name, type, modifiers, parent);
- this.fqn = String.format("%s.%s", name, parent);
- this.containerClass = null;
+ super(type, modifiers, PackageProxy.from(parent), String.format("%s.%s", name, parent));
}
/**
@@ -41,31 +30,35 @@ public class ClassProxy extends AbstractProxy {
* @param modifiers the modifiers of the class
* @param containerClass the FQN of the parent class of the class
*/
- protected ClassProxy(String name, Type type, int modifiers, ClassProxy containerClass) {
- super(name, type, modifiers, containerClass.fqn);
- this.fqn = String.format("%s$%s", name, parent);
- this.containerClass = containerClass;
+ protected ClassProxy(String name, Type type, int modifiers, QualifiableProxy containerClass) {
+ super(type, modifiers, containerClass, String.format("%s$%s", name, containerClass.fullyQualifiedName));
+ }
+
+ /**
+ * Builds a {@link ClassProxy} from a {@link Type} and modifiers.
+ * @param type the {@link Type} representing this Class
+ * @param modifiers the modifiers of the class
+ */
+ public static ClassProxy from(Type type, int modifiers) {
+ String fqn = type.getInternalName().replace('/', '.');
+ String simpleName = extractSimpleNameFromFQN(fqn);
+ String parent = extractParentFromFQN(fqn);
+ if(fqn.contains("$"))
+ return new ClassProxy(simpleName, type, modifiers, from(parent, 0, Modifier.PUBLIC));
+ else return new ClassProxy(simpleName, type, modifiers, parent);
}
/**
* Builds a {@link ClassProxy} given only the fully-qualified name and modifiers.
* @param fqn the fully qualified name of the desired class
+ * @param arrayLevel the array level for this type
* @param modifiers the access modifiers of the desired class
+ * @implNote If present, parent classes will be assumed to have {@code public} as
+ * their only modifier.
* @return the built {@link ClassProxy}
*/
- protected static ClassProxy from(String fqn, int modifiers) {
- Type type = Type.getObjectType(fqn.replace('.', '/'));
- if(fqn.contains("$")) {
- String[] split = fqn.split("\\$");
- String simpleName = split[split.length - 1];
- ClassProxy parentClass = from(fqn.replace("$" + simpleName, ""), 0);
- return new ClassProxy(simpleName, type, modifiers, parentClass);
- } else {
- String[] split = fqn.split("\\.");
- String simpleName = split[split.length - 1];
- String parent = fqn.replace("." + simpleName, "");
- return new ClassProxy(simpleName, type, modifiers, parent);
- }
+ protected static ClassProxy from(String fqn, int arrayLevel, int modifiers) {
+ return from(Type.getObjectType(nameToDescriptor(fqn, arrayLevel)), modifiers);
}
/**
@@ -73,8 +66,9 @@ public class ClassProxy extends AbstractProxy {
* @param clazz the {@link Class} object representing the target class
* @return the built {@link ClassProxy}
*/
- protected static ClassProxy from(Class<?> clazz) {
- if(clazz.getEnclosingClass() == null)
+ public static ClassProxy from(Class<?> clazz) {
+ Class<?> parentClass = clazz.getEnclosingClass();
+ if(parentClass == null)
return new ClassProxy(
clazz.getSimpleName(),
Type.getType(clazz),
@@ -86,7 +80,7 @@ public class ClassProxy extends AbstractProxy {
clazz.getSimpleName(),
Type.getType(clazz),
clazz.getModifiers(),
- from(clazz.getEnclosingClass())
+ from(parentClass)
);
}
@@ -100,19 +94,26 @@ public class ClassProxy extends AbstractProxy {
}
/**
+ * Indicates whether the given object is a proxy for the same element as this.
+ * @param obj the object to perform
+ * @return true if it's equal
+ */
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof ClassProxy && super.equals(obj);
+ }
+
+ /**
* A builder object for {@link ClassProxy}.
*/
public static class Builder extends AbstractProxy.Builder<ClassProxy> {
-
- private ClassProxy containerClass;
-
+
/**
* The constructor of the builder, used only internally.
* @param name the "simple name" of the class
*/
Builder(String name) {
super(name);
- this.containerClass = null;
}
/**
@@ -122,42 +123,33 @@ public class ClassProxy extends AbstractProxy {
* container class
* @return the builder's state after the change
*/
- public Builder setContainerClass(Class<?> containerClass) {
- this.containerClass = ClassProxy.from(containerClass);
- return this;
- }
-
- /**
- * Sets this class as an inner class and sets the containing
- * class to the given proxy.
- * @param containerClass the {@link ClassProxy} representing
- * the container class
- * @return the builder's state after the change
- */
- public Builder setContainerClass(ClassProxy containerClass) {
- this.containerClass = containerClass;
+ public Builder setParent(Class<?> containerClass) {
+ super.setParent(ClassProxy.from(containerClass));
return this;
}
/**
* Sets this class as an inner class and builds a {@link ClassProxy}
* from the given parent and modifiers.
- * @param parentFQN the fully qualified name of the parent
+ * @param parentFQN the fully qualified name of the parent
+ * @param modifiers the modifiers of the parent (if it's a class)
+ * @param isParentPackage whether this parent should be interpreted as a package or class
* @return the builder's state after the change
*/
- public Builder setParent(String parentFQN, int modifiers) {
- return this.setContainerClass(ClassProxy.from(parentFQN, modifiers));
+ public Builder setParent(String parentFQN, int modifiers, boolean isParentPackage) {
+ super.setParent(isParentPackage ? PackageProxy.from(parentFQN) : ClassProxy.from(parentFQN, 0, modifiers));
+ return this;
}
/**
* Sets this class as an inner class and builds a {@link ClassProxy}
* from the given parent.
- * @param parentFQN the fully qualified name of the parent
+ * @param parentFQN the fully qualified name of the parent
+ * @param isParentPackage whether this parent should be interpreted as a package or class
* @return the builder's state after the change
*/
- @Override
- public Builder setParent(String parentFQN) {
- return this.setParent(parentFQN, 0);
+ public Builder setParent(String parentFQN, boolean isParentPackage) {
+ return this.setParent(parentFQN, 0, isParentPackage);
}
/**
@@ -166,9 +158,7 @@ public class ClassProxy extends AbstractProxy {
*/
@Override
public ClassProxy build() {
- if(this.containerClass == null)
- return new ClassProxy(this.name, this.type, this.modifiers, this.parent);
- else return new ClassProxy(this.name, this.type, this.modifiers, this.containerClass);
+ return new ClassProxy(this.name, this.type, this.modifiers, this.parent);
}
}
} \ No newline at end of file
diff --git a/src/main/java/ftbsc/lll/proxies/FieldProxy.java b/src/main/java/ftbsc/lll/proxies/FieldProxy.java
index 72a4e40..8855cd8 100644
--- a/src/main/java/ftbsc/lll/proxies/FieldProxy.java
+++ b/src/main/java/ftbsc/lll/proxies/FieldProxy.java
@@ -16,7 +16,7 @@ public class FieldProxy extends AbstractProxy {
* @param f the {@link Field} object corresponding to this.
*/
public FieldProxy(Field f) {
- super(f.getName(), Type.getType(f.getType()), f.getModifiers(), Type.getInternalName(f.getDeclaringClass()));
+ super(f.getName(), Type.getType(f.getType()), f.getModifiers(), ClassProxy.from(f.getDeclaringClass()));
}
/**
@@ -24,9 +24,9 @@ public class FieldProxy extends AbstractProxy {
* @param name the name of the field
* @param type the {@link Type} of the field
* @param modifiers the modifiers of the field
- * @param parent the FQN of the parent class of the field
+ * @param parent the {@link QualifiableProxy} for the parent
*/
- protected FieldProxy(String name, Type type, int modifiers, String parent) {
+ protected FieldProxy(String name, Type type, int modifiers, QualifiableProxy parent) {
super(name, type, modifiers, parent);
}
@@ -40,6 +40,16 @@ public class FieldProxy extends AbstractProxy {
}
/**
+ * Indicates whether the given object is a proxy for the same element as this.
+ * @param obj the object to perform
+ * @return true if it's equal
+ */
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof FieldProxy && super.equals(obj);
+ }
+
+ /**
* A builder object for {@link FieldProxy}.
*/
public static class Builder extends AbstractProxy.Builder<FieldProxy> {
@@ -52,6 +62,27 @@ public class FieldProxy extends AbstractProxy {
}
/**
+ * Sets the parent class of this field to the one described by the
+ * fully qualified name and with the given modifiers.
+ * @param parentFQN the fully qualified name of the parent
+ * @return the builder's state after the change
+ */
+ public Builder setParent(String parentFQN, int modifiers) {
+ super.setParent(ClassProxy.from(parentFQN, 0, modifiers));
+ return this;
+ }
+
+ /**
+ * Sets the parent class of this field to the one described by the
+ * fully qualified name.
+ * @param parentFQN the fully qualified name of the parent
+ * @return the builder's state after the change
+ */
+ public Builder setParent(String parentFQN) {
+ return this.setParent(parentFQN, 0);
+ }
+
+ /**
* Builds a {@link FieldProxy} of the given kind.
* @return the built {@link FieldProxy}
*/
diff --git a/src/main/java/ftbsc/lll/proxies/MethodProxy.java b/src/main/java/ftbsc/lll/proxies/MethodProxy.java
index 5f80c08..5d014e9 100644
--- a/src/main/java/ftbsc/lll/proxies/MethodProxy.java
+++ b/src/main/java/ftbsc/lll/proxies/MethodProxy.java
@@ -4,6 +4,7 @@ import org.objectweb.asm.Type;
import java.lang.reflect.Method;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import static ftbsc.lll.tools.DescriptorBuilder.nameToDescriptor;
@@ -16,39 +17,43 @@ import static ftbsc.lll.tools.DescriptorBuilder.nameToDescriptor;
public class MethodProxy extends AbstractProxy {
/**
- * The parameters of the method.
+ * An array of {@link ClassProxy} each representing the parameters of the method.
*/
- public final Type[] parameters;
+ public final ClassProxy[] parameters;
/**
- * The return type of the method.
+ * The {@link ClassProxy} for the return type of the method.
*/
- public final Type returnType;
-
- /**
- * A public constructor, builds a proxy from a {@link Method}
- * obtained from reflection.
- * @param m the {@link Method} object corresponding to this.
- */
- public MethodProxy(Method m) {
- super(m.getName(), Type.getType(m), m.getModifiers(), Type.getInternalName(m.getDeclaringClass()));
- Type mt = Type.getType(m);
- this.parameters = mt.getArgumentTypes();
- this.returnType = mt.getReturnType();
- }
+ public final ClassProxy returnType;
/**
* A protected constructor, called only from the builder.
* @param name the name of the method
* @param modifiers the modifiers of the method
- * @param parent the FQN of the parent class of the method
+ * @param parent the {@link QualifiableProxy} for the parent
* @param parameters the parameters of the method
* @param returnType the return type of the method
*/
- protected MethodProxy(String name, int modifiers, String parent, Type[] parameters, Type returnType) {
+ protected MethodProxy(String name, int modifiers, QualifiableProxy parent, Type[] parameters, Type returnType) {
super(name, Type.getMethodType(returnType, parameters), modifiers, parent);
- this.parameters = parameters;
- this.returnType = returnType;
+ this.parameters = Arrays.stream(parameters)
+ .map(t -> ClassProxy.from(t, 0))
+ .toArray(ClassProxy[]::new);
+ this.returnType = ClassProxy.from(returnType, 0);
+ }
+
+ /**
+ * A public constructor, builds a proxy from a {@link Method}
+ * obtained from reflection.
+ * @param m the {@link Method} object corresponding to this.
+ */
+ public MethodProxy(Method m) {
+ this(m.getName(),
+ m.getModifiers(),
+ ClassProxy.from(m.getDeclaringClass()),
+ Type.getArgumentTypes(m),
+ Type.getReturnType(m)
+ );
}
/**
@@ -61,6 +66,19 @@ public class MethodProxy extends AbstractProxy {
}
/**
+ * Indicates whether the given object is a proxy for the same element as this.
+ * @param obj the object to perform
+ * @return true if it's equal
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if(obj instanceof MethodProxy) {
+ MethodProxy m = (MethodProxy) obj;
+ return super.equals(obj) && m.returnType.equals(this.returnType) && Arrays.equals(m.parameters, this.parameters);
+ } else return false;
+ }
+
+ /**
* A builder object for {@link MethodProxy}.
*/
public static class Builder extends AbstractProxy.Builder<MethodProxy> {
@@ -118,6 +136,27 @@ public class MethodProxy extends AbstractProxy {
}
/**
+ * Sets the parent class of this method to the one described by the
+ * fully qualified name and with the given modifiers.
+ * @param parentFQN the fully qualified name of the parent
+ * @return the builder's state after the change
+ */
+ public Builder setParent(String parentFQN, int modifiers) {
+ super.setParent(ClassProxy.from(parentFQN, 0, modifiers));
+ return this;
+ }
+
+ /**
+ * Sets the parent class of this method to the one described by the
+ * fully qualified name.
+ * @param parentFQN the fully qualified name of the parent
+ * @return the builder's state after the change
+ */
+ public Builder setParent(String parentFQN) {
+ return this.setParent(parentFQN, 0);
+ }
+
+ /**
* Sets the return type to the given type.
* @param returnType the {@link Class} object corresponding to
* the return type
@@ -134,7 +173,12 @@ public class MethodProxy extends AbstractProxy {
*/
@Override
public MethodProxy build() {
- return new MethodProxy(name, modifiers, parent, parameters.toArray(new Type[0]), returnType);
+ return new MethodProxy(
+ this.name,
+ this.modifiers,
+ this.parent,
+ this.parameters.toArray(new Type[0]),
+ this.returnType);
}
}
}
diff --git a/src/main/java/ftbsc/lll/proxies/PackageProxy.java b/src/main/java/ftbsc/lll/proxies/PackageProxy.java
new file mode 100644
index 0000000..fbfe6c0
--- /dev/null
+++ b/src/main/java/ftbsc/lll/proxies/PackageProxy.java
@@ -0,0 +1,51 @@
+package ftbsc.lll.proxies;
+
+/**
+ * A container for information about a package.
+ * @since 0.4.0
+ */
+public class PackageProxy extends QualifiableProxy {
+
+ /**
+ * The {@link PackageProxy} representing the root package.
+ */
+ public static final PackageProxy ROOT = new PackageProxy(null, "");
+
+ /**
+ * The protected constructor, called only from {@link PackageProxy#from(String)}.
+ * @param parent the {@link PackageProxy} representing the parent
+ * @param fqn the fully-qualified name of this package
+ */
+ protected PackageProxy(PackageProxy parent, String fqn) {
+ super(null, 0, parent, fqn);
+ }
+
+ /**
+ * Builds a {@link PackageProxy} from its fully-qualified name.
+ * @param fqn the fully-qualified name of the package
+ * @return the built {@link PackageProxy}
+ */
+ protected static PackageProxy from(String fqn) {
+ if(fqn == null || fqn.equals("")) return ROOT;
+ return new PackageProxy(from(extractParentFromFQN(fqn)), fqn);
+ }
+
+ /**
+ * Builds a {@link PackageProxy} from a reflective {@link Package} object.
+ * @param p the {@link Package} object
+ * @return the built {@link PackageProxy}
+ */
+ protected static PackageProxy from(Package p) {
+ return from(extractParentFromFQN(p.getName()));
+ }
+
+ /**
+ * Indicates whether the given object is a proxy for the same element as this.
+ * @param obj the object to perform
+ * @return true if it's equal
+ */
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof PackageProxy && super.equals(obj);
+ }
+}
diff --git a/src/main/java/ftbsc/lll/proxies/QualifiableProxy.java b/src/main/java/ftbsc/lll/proxies/QualifiableProxy.java
new file mode 100644
index 0000000..2efada8
--- /dev/null
+++ b/src/main/java/ftbsc/lll/proxies/QualifiableProxy.java
@@ -0,0 +1,68 @@
+package ftbsc.lll.proxies;
+
+import org.objectweb.asm.Type;
+
+/**
+ * A container for information about an element which has a fully-qualified name.
+ * @see ClassProxy
+ * @see PackageProxy
+ * @since 0.4.0
+ */
+public abstract class QualifiableProxy extends AbstractProxy {
+ /**
+ * The fully-qualified name of the element represented by this proxy.
+ */
+ public final String fullyQualifiedName;
+
+ /**
+ * The "internal name" (fully-qualified with slashes) of the element
+ * represented by this proxy.
+ */
+ public final String internalName;
+
+ /**
+ * The protected constructor, should be called by all classes extending this in theirs.
+ * @param type the {@link Type} for the element
+ * @param modifiers the modifiers, as a packed int
+ * @param parent the {@link QualifiableProxy} representing the parent of this element
+ * @param fullyQualifiedName the FQN of the element
+ */
+ protected QualifiableProxy(Type type, int modifiers, QualifiableProxy parent, String fullyQualifiedName) {
+ super(extractSimpleNameFromFQN(fullyQualifiedName), type, modifiers, parent);
+ this.fullyQualifiedName = fullyQualifiedName;
+ this.internalName = this.fullyQualifiedName.replace('.', '/');
+ }
+
+ /**
+ * Returns a {@link String} containing the FQN of the parent element
+ * to this, which may represent a package or class.
+ * @return the parent, or null if the parent was the root element
+ */
+ protected static String extractParentFromFQN(String fqn) {
+ String lastSeparator = fqn.contains("$") ? "\\$" : "\\.";
+ String[] split = fqn.split(lastSeparator);
+ if(split.length == 1) return null;
+ return fqn.substring(0, split[split.length - 1].length() - 1);
+ }
+
+ /**
+ * Returns a {@link String} containing the simple name of the element
+ * @return the simple name
+ */
+ protected static String extractSimpleNameFromFQN(String fqn) {
+ String lastSeparator = fqn.contains("$") ? "\\$" : "\\.";
+ String[] split = fqn.split(lastSeparator);
+ if(split.length == 1) return fqn;
+ else return split[split.length - 1];
+ }
+
+ /**
+ * Indicates whether the given object is a proxy for the same element as this.
+ * @param obj the object to perform
+ * @return true if it's equal
+ */
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof QualifiableProxy && super.equals(obj) && ((QualifiableProxy) obj).fullyQualifiedName.equals(fullyQualifiedName);
+ }
+}