diff options
author | zaaarf <zaaarf@proton.me> | 2023-03-01 18:05:02 +0100 |
---|---|---|
committer | zaaarf <zaaarf@proton.me> | 2023-03-01 18:05:02 +0100 |
commit | bc649ed0f10a15585e6379551da0b169de1e0c64 (patch) | |
tree | f45aac119e946d99b298b729b1db37595b2d7d72 /src/main/java/ftbsc/lll/proxies/MethodProxy.java | |
parent | e8b85872f9fb6d8e5719c6224e36d412c35aba7d (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.java | 223 |
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(); + } + } +} |