feat: initial proxy rework, replaced getters with public constants, rely more on ow2 Types instead of homebrew solutions

This commit is contained in:
zaaarf 2023-03-21 12:27:27 +01:00
parent 45ed48b675
commit 1295516232
No known key found for this signature in database
GPG key ID: AD8563472FD43386
3 changed files with 81 additions and 207 deletions

View file

@ -1,5 +1,7 @@
package ftbsc.lll.proxies; package ftbsc.lll.proxies;
import org.objectweb.asm.Type;
/** /**
* Abstract proxy class, implementing common aspects * Abstract proxy class, implementing common aspects
* of {@link MethodProxy} and {@link FieldProxy}. * of {@link MethodProxy} and {@link FieldProxy}.
@ -8,57 +10,38 @@ package ftbsc.lll.proxies;
public abstract class AbstractProxy { public abstract class AbstractProxy {
/** /**
* The name of the corresponding class member. * The name of the corresponding element.
*/ */
private final String name; public final String name;
/**
* The {@link Type} corresponding to this element.
*/
public final Type type;
/** /**
* The fully qualified name (i.e. java.lang.String) of * The fully qualified name (i.e. java.lang.String) of
* the parent class. * the parent class.
*/ */
private final String parent; public final String parent;
/** /**
* The modifiers of the member, as a packed int. * The modifiers of the element, as a packed int.
* @see java.lang.reflect.Modifier * @see java.lang.reflect.Modifier
*/ */
private final int modifiers; public final int modifiers;
/**
* @return the name of the item
*/
public String getName() {
return this.name;
}
/**
* @return the modifiers of the member, as a packed int
* @see java.lang.reflect.Modifier
*/
public int getModifiers() {
return this.modifiers;
}
/**
* @return the fully qualified name of the parent class
*/
public String getParent() {
return this.parent;
}
/**
* @return the descriptor of the member
*/
public abstract String getDescriptor();
/** /**
* The private constructor, should be called by all classes extending this in theirs. * The private constructor, should be called by all classes extending this in theirs.
* @param name the name of the member * @param name the name of the element
* @param type the {@link Type} for the element
* @param modifiers the modifiers, as a packed int * @param modifiers the modifiers, as a packed int
* @param parent the FQN of the parent class * @param parent the FQN of the parent class
*/ */
protected AbstractProxy(String name, int modifiers, String parent) { protected AbstractProxy(String name, Type type, int modifiers, String parent) {
this.name = name; this.name = name;
this.type = type;
this.modifiers = modifiers; this.modifiers = modifiers;
this.parent = parent; this.parent = parent;
} }
@ -70,12 +53,12 @@ public abstract class AbstractProxy {
public abstract static class Builder<T extends AbstractProxy> { public abstract static class Builder<T extends AbstractProxy> {
/** /**
* The name of the member. * The name of the element.
*/ */
protected final String name; protected String name;
/** /**
* The modifiers of the member, as a packed int. * The modifiers of the element, as a packed int.
*/ */
protected int modifiers; protected int modifiers;
@ -84,23 +67,20 @@ public abstract class AbstractProxy {
*/ */
protected String parent; protected String parent;
/**
* The {@link Type} corresponding to the element.
*/
protected Type type;
/** /**
* The constructor. * The constructor.
* @param name the name of the member * @param name the name of the element
*/ */
protected Builder(String name) { protected Builder(String name) {
this.name = name; this.name = name;
this.modifiers = 0; this.modifiers = 0;
} }
/**
* @param parentFQN the fully qualified name of the parent
* @return the current state of the builder
*/
public Builder<T> setParent(String parentFQN) {
this.parent = parentFQN;
return this;
}
/** /**
* @param newModifier the modifier to add * @param newModifier the modifier to add
@ -115,11 +95,41 @@ public abstract class AbstractProxy {
* @param newModifier the new modifier value * @param newModifier the new modifier value
* @return the current state of the builder * @return the current state of the builder
*/ */
public Builder<T> setModifier(int newModifier) { public Builder<T> setModifiers(int newModifier) {
this.modifiers = newModifier; this.modifiers = newModifier;
return this; return this;
} }
/**
* @param parentFQN the fully qualified name of the parent
* @return the current state of the builder
*/
public Builder<T> setParent(String parentFQN) {
this.parent = parentFQN;
return this;
}
/**
* @param type the {@link Type} corresponding to the element
* @return the current state of the builder
*/
public Builder<T> setType(Type type) {
this.type = type;
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}
* @return the builder's state after the change
*/
public Builder<T> setDescriptor(String descriptor) {
return this.setType(Type.getType(descriptor));
}
/** /**
* @return the built proxy object * @return the built proxy object
*/ */

View file

@ -1,6 +1,5 @@
package ftbsc.lll.proxies; package ftbsc.lll.proxies;
import ftbsc.lll.tools.DescriptorBuilder;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
import java.lang.reflect.Field; import java.lang.reflect.Field;
@ -11,40 +10,24 @@ import java.lang.reflect.Field;
* @since 0.3.0 * @since 0.3.0
*/ */
public class FieldProxy extends AbstractProxy { public class FieldProxy extends AbstractProxy {
/**
* The descriptor of the field's type.
*/
private final String typeDescriptor;
/** /**
* A public constructor, builds a proxy from a {@link Field} * A public constructor, builds a proxy from a {@link Field}
* obtained from reflection. * obtained from reflection.
* @param f the {@link Field} object corresponding to this. * @param f the {@link Field} object corresponding to this.
*/ */
public FieldProxy(Field f) { public FieldProxy(Field f) {
super(f.getName(), f.getModifiers(), Type.getInternalName(f.getDeclaringClass())); super(f.getName(), Type.getType(f.getType()), f.getModifiers(), Type.getInternalName(f.getDeclaringClass()));
this.typeDescriptor = Type.getDescriptor(f.getType());
} }
/** /**
* A protected constructor, called only from the builder. * Protected constructor, called only from the builder.
* @param name the name of the field * @param name the name of the field
* @param type the {@link Type} of the field
* @param modifiers the modifiers of the field * @param modifiers the modifiers of the field
* @param parent the FQN of the parent class of the field * @param parent the FQN of the parent class of the field
* @param typeDescriptor the type descriptor of the field
*/ */
FieldProxy(String name, int modifiers, String parent, String typeDescriptor) { protected FieldProxy(String name, Type type, int modifiers, String parent) {
super(name, modifiers, parent); super(name, type, modifiers, parent);
this.typeDescriptor = typeDescriptor;
}
/**
* @return the field's type descriptor
*/
@Override
public String getDescriptor() {
return typeDescriptor;
} }
/** /**
@ -60,11 +43,6 @@ public class FieldProxy extends AbstractProxy {
* A builder object for {@link FieldProxy}. * A builder object for {@link FieldProxy}.
*/ */
public static class Builder extends AbstractProxy.Builder<FieldProxy> { public static class Builder extends AbstractProxy.Builder<FieldProxy> {
/**
* The descriptor of the field's type.
*/
private String typeDescriptor;
/** /**
* The constructor of the builder, used only internally. * The constructor of the builder, used only internally.
* @param name the name of the field * @param name the name of the field
@ -73,44 +51,13 @@ public class FieldProxy extends AbstractProxy {
super(name); super(name);
} }
/**
* Sets the descriptor of the field type to the given {@link String}.
* @param typeDescriptor the descriptor of the field type
* @return the builder's state after the change
*/
public Builder setDescriptor(String typeDescriptor) {
this.typeDescriptor = typeDescriptor;
return this;
}
/**
* Sets the descriptor of the field type to match the give {@link Class}.
* @param fqn the fully qualified name of the field type
* @param arrayLevel the array level of the field type
* @return the builder's state after the change
*/
public Builder setType(String fqn, int arrayLevel) {
this.typeDescriptor = DescriptorBuilder.nameToDescriptor(fqn, arrayLevel);
return this;
}
/**
* Sets the descriptor of the field type to match the give {@link Class}.
* @param type a {@link Class} object representing the field type
* @return the builder's state after the change
*/
public Builder setType(Class<?> type) {
this.typeDescriptor = Type.getDescriptor(type);
return this;
}
/** /**
* Builds a {@link FieldProxy} of the given kind. * Builds a {@link FieldProxy} of the given kind.
* @return the built {@link FieldProxy} * @return the built {@link FieldProxy}
*/ */
@Override @Override
public FieldProxy build() { public FieldProxy build() {
return new FieldProxy(this.name, this.modifiers, this.parent, this.typeDescriptor); return new FieldProxy(this.name, this.type, this.modifiers, this.parent);
} }
} }
} }

View file

@ -1,12 +1,13 @@
package ftbsc.lll.proxies; package ftbsc.lll.proxies;
import ftbsc.lll.tools.DescriptorBuilder;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static ftbsc.lll.tools.DescriptorBuilder.nameToDescriptor;
/** /**
* A container for information about class methods to be used * A container for information about class methods to be used
* in ASM patching. * in ASM patching.
@ -16,23 +17,13 @@ public class MethodProxy extends AbstractProxy {
/** /**
* The parameters of the method. * The parameters of the method.
* It holds fully qualified names for objects, and {@link Class}
* objects for primitives.
*/ */
private final Object[] parameters; public final Type[] parameters;
/** /**
* The return type of the method. * The return type of the method.
* It contains if it's an object, or a {@link Class}
* object for primitives.
*/ */
private final Object returnType; public final Type returnType;
/**
* Caches the the descriptor after generating it once for
* performance.
*/
private String descriptorCache;
/** /**
* A public constructor, builds a proxy from a {@link Method} * A public constructor, builds a proxy from a {@link Method}
@ -40,13 +31,10 @@ public class MethodProxy extends AbstractProxy {
* @param m the {@link Method} object corresponding to this. * @param m the {@link Method} object corresponding to this.
*/ */
public MethodProxy(Method m) { public MethodProxy(Method m) {
super(m.getName(), m.getModifiers(), Type.getInternalName(m.getDeclaringClass())); super(m.getName(), Type.getType(m), m.getModifiers(), Type.getInternalName(m.getDeclaringClass()));
List<Object> parameters = new ArrayList<>(); Type mt = Type.getType(m);
for(Class<?> p : m.getParameterTypes()) this.parameters = mt.getArgumentTypes();
parameters.add(p.isPrimitive() ? p : new TypeContainer(p)); this.returnType = mt.getReturnType();
this.parameters = parameters.toArray();
Class<?> returnType = m.getReturnType();
this.returnType = returnType.isPrimitive() ? returnType : new TypeContainer(returnType);
} }
/** /**
@ -57,41 +45,10 @@ public class MethodProxy extends AbstractProxy {
* @param parameters the parameters of the method * @param parameters the parameters of the method
* @param returnType the return type of the method * @param returnType the return type of the method
*/ */
protected MethodProxy(String name, int modifiers, String parent, Object[] parameters, Object returnType) { protected MethodProxy(String name, int modifiers, String parent, Type[] parameters, Type returnType) {
super(name, modifiers, parent); super(name, Type.getMethodType(returnType, parameters), modifiers, parent);
this.parameters = parameters; this.parameters = parameters;
this.returnType = returnType; 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);
} }
/** /**
@ -110,12 +67,12 @@ public class MethodProxy extends AbstractProxy {
/** /**
* The parameters of the method. * The parameters of the method.
*/ */
private final List<Object> parameters; private final List<Type> parameters;
/** /**
* The return type of the method. Defaults to void. * The return type of the method. Defaults to void.
*/ */
private Object returnType; private Type returnType;
/** /**
* The constructor of the builder, used only internally. * The constructor of the builder, used only internally.
@ -124,7 +81,7 @@ public class MethodProxy extends AbstractProxy {
Builder(String name) { Builder(String name) {
super(name); super(name);
this.parameters = new ArrayList<>(); this.parameters = new ArrayList<>();
this.returnType = void.class; this.returnType = Type.getType(void.class);
} }
/** /**
@ -134,7 +91,7 @@ public class MethodProxy extends AbstractProxy {
* @return the builder's state after the change * @return the builder's state after the change
*/ */
public Builder addParameter(String fqn, int arrayLevel) { public Builder addParameter(String fqn, int arrayLevel) {
this.parameters.add(new TypeContainer(fqn, arrayLevel)); this.parameters.add(Type.getType(nameToDescriptor(fqn, arrayLevel)));
return this; return this;
} }
@ -145,7 +102,7 @@ public class MethodProxy extends AbstractProxy {
* @return the builder's state after the change * @return the builder's state after the change
*/ */
public Builder addParameter(Class<?> paramType) { public Builder addParameter(Class<?> paramType) {
this.parameters.add(paramType); this.parameters.add(Type.getType(paramType));
return this; return this;
} }
@ -156,7 +113,7 @@ public class MethodProxy extends AbstractProxy {
* @return the builder's state after the change * @return the builder's state after the change
*/ */
public Builder setReturnType(String fqn, int arrayLevel) { public Builder setReturnType(String fqn, int arrayLevel) {
this.returnType = new TypeContainer(fqn, arrayLevel); this.returnType = Type.getType(nameToDescriptor(fqn, arrayLevel));
return this; return this;
} }
@ -167,7 +124,7 @@ public class MethodProxy extends AbstractProxy {
* @return the builder's state after the change * @return the builder's state after the change
*/ */
public Builder setReturnType(Class<?> returnType) { public Builder setReturnType(Class<?> returnType) {
this.returnType = returnType; this.returnType = Type.getType(returnType);
return this; return this;
} }
@ -177,47 +134,7 @@ public class MethodProxy extends AbstractProxy {
*/ */
@Override @Override
public MethodProxy build() { public MethodProxy build() {
return new MethodProxy(name, modifiers, parent, parameters.toArray(), returnType); return new MethodProxy(name, modifiers, parent, parameters.toArray(new Type[0]), 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();
} }
} }
} }