aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/ftbsc/lll/proxies/MethodProxy.java
diff options
context:
space:
mode:
author zaaarf <zaaarf@proton.me>2023-03-01 18:05:02 +0100
committer zaaarf <zaaarf@proton.me>2023-03-01 18:05:02 +0100
commitbc649ed0f10a15585e6379551da0b169de1e0c64 (patch)
treef45aac119e946d99b298b729b1db37595b2d7d72 /src/main/java/ftbsc/lll/proxies/MethodProxy.java
parente8b85872f9fb6d8e5719c6224e36d412c35aba7d (diff)
feat: implemented field and method proxies
Diffstat (limited to 'src/main/java/ftbsc/lll/proxies/MethodProxy.java')
-rw-r--r--src/main/java/ftbsc/lll/proxies/MethodProxy.java223
1 files changed, 223 insertions, 0 deletions
diff --git a/src/main/java/ftbsc/lll/proxies/MethodProxy.java b/src/main/java/ftbsc/lll/proxies/MethodProxy.java
new file mode 100644
index 0000000..1df4678
--- /dev/null
+++ b/src/main/java/ftbsc/lll/proxies/MethodProxy.java
@@ -0,0 +1,223 @@
+package ftbsc.lll.proxies;
+
+import ftbsc.lll.tools.DescriptorBuilder;
+import org.objectweb.asm.Type;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A container for information about class methods to be used
+ * in ASM patching.
+ * @since 0.3.0
+ */
+public class MethodProxy extends AbstractProxy {
+
+ /**
+ * The parameters of the method.
+ * It holds fully qualified names for objects, and {@link Class}
+ * objects for primitives.
+ */
+ private final Object[] parameters;
+
+ /**
+ * The return type of the method.
+ * It contains if it's an object, or a {@link Class}
+ * object for primitives.
+ */
+ private final Object returnType;
+
+ /**
+ * Caches the the descriptor after generating it once for
+ * performance.
+ */
+ private String descriptorCache;
+
+ /**
+ * 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(), m.getModifiers(), Type.getInternalName(m.getDeclaringClass()));
+ List<Object> parameters = new ArrayList<>();
+ for(Class<?> p : m.getParameterTypes())
+ parameters.add(p.isPrimitive() ? p : new TypeContainer(p));
+ this.parameters = parameters.toArray();
+ Class<?> returnType = m.getReturnType();
+ this.returnType = returnType.isPrimitive() ? returnType : new TypeContainer(returnType);
+ }
+
+ /**
+ * A protected constructor, called only from the builder.
+ * @param srgName the SRG name of the method
+ * @param modifiers the modifiers of the method
+ * @param parent the FQN of the parent class of the method
+ * @param parameters the parameters of the method
+ * @param returnType the return type of the method
+ */
+ protected MethodProxy(String srgName, int modifiers, String parent, Object[] parameters, Object returnType) {
+ super(srgName, modifiers, parent);
+ this.parameters = parameters;
+ this.returnType = returnType;
+ this.descriptorCache = null;
+ }
+
+ /**
+ * Builds (or returns from cache if present)
+ * the method's descriptor.
+ * @return the method's descriptor
+ */
+ @Override
+ public String getDescriptor() {
+ if(this.descriptorCache != null)
+ return this.descriptorCache;
+ DescriptorBuilder b = new DescriptorBuilder();
+ for(Object p : this.parameters)
+ addParameterToBuilder(b, p);
+ addParameterToBuilder(b, this.returnType);
+ this.descriptorCache = b.build();
+ return this.descriptorCache;
+ }
+
+ /**
+ * A static method used internally to correctly insert a
+ * {@link TypeContainer} into a {@link DescriptorBuilder}.
+ * @param b the {@link DescriptorBuilder}
+ * @param p the {@link TypeContainer}
+ */
+ private static void addParameterToBuilder(DescriptorBuilder b, Object p) {
+ if(p instanceof TypeContainer) {
+ TypeContainer param = (TypeContainer) p;
+ b.addParameter(param.fqn, param.arrayLevel);
+ } else b.addParameter((Class<?>) p);
+ }
+
+ /**
+ * Returns a new instance of {@link MethodProxy.Builder}.
+ * @param srgName the SRG name of the method
+ * @return the builder object for method proxies
+ */
+ public static Builder builder(String srgName) {
+ return new Builder(srgName);
+ }
+
+ /**
+ * A builder object for {@link MethodProxy}.
+ */
+ public static class Builder extends AbstractProxy.Builder<MethodProxy> {
+ /**
+ * The parameters of the method.
+ */
+ private final List<Object> parameters;
+
+ /**
+ * The return type of the method. Defaults to void.
+ */
+ private Object returnType;
+
+ /**
+ * The constructor of the builder, used only internally.
+ * @param srgName the SRG name of the method
+ */
+ Builder(String srgName) {
+ super(srgName);
+ this.parameters = new ArrayList<>();
+ this.returnType = void.class;
+ }
+
+ /**
+ * Adds a parameter of a given type.
+ * @param fqn the fully qualified name of the parameter type
+ * @param arrayLevel the array level of the parameter type
+ * @return the builder's state after the change
+ */
+ public Builder addParameter(String fqn, int arrayLevel) {
+ this.parameters.add(new TypeContainer(fqn, arrayLevel));
+ return this;
+ }
+
+ /**
+ * Adds a parameter of a given type.
+ * @param paramType the {@link Class} object corresponding to
+ * the parameter type.
+ * @return the builder's state after the change
+ */
+ public Builder addParameter(Class<?> paramType) {
+ this.parameters.add(paramType);
+ return this;
+ }
+
+ /**
+ * Sets the return type to the given type.
+ * @param fqn the fully qualified name of the return type
+ * @param arrayLevel the array level of the return type
+ * @return the builder's state after the change
+ */
+ public Builder setReturnType(String fqn, int arrayLevel) {
+ this.returnType = new TypeContainer(fqn, arrayLevel);
+ return this;
+ }
+
+ /**
+ * Sets the return type to the given type.
+ * @param returnType the {@link Class} object corresponding to
+ * the return type
+ * @return the builder's state after the change
+ */
+ public Builder setReturnType(Class<?> returnType) {
+ this.returnType = returnType;
+ return this;
+ }
+
+ /**
+ * Builds a {@link MethodProxy} of the given kind.
+ * @return the built {@link MethodProxy}
+ */
+ @Override
+ public MethodProxy build() {
+ return new MethodProxy(srgName, modifiers, parent, parameters.toArray(), returnType);
+ }
+ }
+
+ /**
+ * A container class, holding information about a given type.
+ */
+ protected static class TypeContainer {
+ /**
+ * The fully qualified name of the type.
+ */
+ public final String fqn;
+
+ /**
+ * The array level of the type.
+ */
+ public final int arrayLevel;
+
+ /**
+ * Public constructor for the class.
+ * @param fqn the fully qualified name of the type
+ * @param arrayLevel the array level of the type
+ */
+ public TypeContainer(String fqn, int arrayLevel) {
+ this.fqn = fqn;
+ this.arrayLevel = arrayLevel;
+ }
+
+ /**
+ * Public constructor for the class, extracting the
+ * necessary information from a {@link Class} object.
+ * @param clazz the class object
+ */
+ public TypeContainer(Class<?> clazz) {
+ int arrayLevel = 0;
+ while(clazz.isArray()) {
+ arrayLevel++;
+ clazz = clazz.getComponentType();
+ }
+ this.arrayLevel = arrayLevel;
+ this.fqn = clazz.getCanonicalName();
+ }
+ }
+}