aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author zaaarf <zaaarf@proton.me>2023-03-21 14:05:14 +0100
committer zaaarf <zaaarf@proton.me>2023-03-21 14:05:14 +0100
commit40686b8c929279bd486529fceae1d8dd7fa2735f (patch)
treece314f8c939571121468aae975b60a30d27c97a5
parent8c11b0b4d89b1d340bdd620d96e5127c05c2e066 (diff)
feat: added ClassProxy
-rw-r--r--src/main/java/ftbsc/lll/proxies/ClassProxy.java174
-rw-r--r--src/main/java/ftbsc/lll/tools/DescriptorBuilder.java15
2 files changed, 182 insertions, 7 deletions
diff --git a/src/main/java/ftbsc/lll/proxies/ClassProxy.java b/src/main/java/ftbsc/lll/proxies/ClassProxy.java
new file mode 100644
index 0000000..c369231
--- /dev/null
+++ b/src/main/java/ftbsc/lll/proxies/ClassProxy.java
@@ -0,0 +1,174 @@
+package ftbsc.lll.proxies;
+
+import org.objectweb.asm.Type;
+
+/**
+ * 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;
+
+ /**
+ * 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
+ */
+ 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;
+ }
+
+ /**
+ * 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 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;
+ }
+
+ /**
+ * Builds a {@link ClassProxy} given only the fully-qualified name and modifiers.
+ * @param fqn the fully qualified name of the desired class
+ * @param modifiers the access modifiers of the desired class
+ * @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);
+ }
+ }
+
+ /**
+ * Builds a {@link ClassProxy} from a {@link Class} object.
+ * @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)
+ return new ClassProxy(
+ clazz.getSimpleName(),
+ Type.getType(clazz),
+ clazz.getModifiers(),
+ clazz.getPackage().getName()
+ );
+ else
+ return new ClassProxy(
+ clazz.getSimpleName(),
+ Type.getType(clazz),
+ clazz.getModifiers(),
+ from(clazz.getEnclosingClass())
+ );
+ }
+
+ /**
+ * Returns a new instance of {@link ClassProxy.Builder}.
+ * @param name the name of the class
+ * @return the builder object for class proxies
+ */
+ public static Builder builder(String name) {
+ return new Builder(name);
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Sets this class as an inner class and sets the containing
+ * class to the given class object.
+ * @param containerClass the {@link Class} representing the
+ * 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;
+ 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
+ * @return the builder's state after the change
+ */
+ public Builder setParent(String parentFQN, int modifiers) {
+ return this.setContainerClass(ClassProxy.from(parentFQN, modifiers));
+ }
+
+ /**
+ * 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
+ * @return the builder's state after the change
+ */
+ @Override
+ public Builder setParent(String parentFQN) {
+ return this.setParent(parentFQN, 0);
+ }
+
+ /**
+ * Builds a {@link ClassProxy} of the given kind.
+ * @return the built {@link ClassProxy}
+ */
+ @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);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/ftbsc/lll/tools/DescriptorBuilder.java b/src/main/java/ftbsc/lll/tools/DescriptorBuilder.java
index d59f97d..252c2a8 100644
--- a/src/main/java/ftbsc/lll/tools/DescriptorBuilder.java
+++ b/src/main/java/ftbsc/lll/tools/DescriptorBuilder.java
@@ -26,16 +26,16 @@ public class DescriptorBuilder {
* Initialises default values.
*/
public DescriptorBuilder() {
-
this.returnType = Type.getDescriptor(void.class);
this.params = new ArrayList<>();
}
/**
* Sets the return type to the given type.
- * WARNING: will most likely cause problems if used with objects outside the
- * Java SDK. Pass the fully qualified name as a String rather than the Class
- * object for non-standard types (such as Minecraft classes).
+ * @implNote Passing a {@link Class} may cause problems if used with objects outside
+ * the Java SDK. Pass the fully qualified name as a {@link String} rather
+ * than the {@link Class} object for non-standard types (such as Minecraft
+ * classes).
* @param returnType the Class object corresponding to the return type
* @return the builder's state after the change
*/
@@ -72,9 +72,10 @@ public class DescriptorBuilder {
/**
* Adds a parameter of the given class type to the method.
* Parameter order matters.
- * WARNING: will most likely cause problems if used with objects outside the
- * Java SDK. Pass the fully qualified name as a String rather than the Class
- * object for non-standard types (such as Minecraft classes).
+ * @implNote Passing a {@link Class} may cause problems if used with objects outside
+ * the Java SDK. Pass the fully qualified name as a {@link String} rather
+ * than the {@link Class} object for non-standard types (such as Minecraft
+ * classes).
* @param param the Class object corresponding to the parameter
* @return the builder's state after the change
*/