feat: added ClassProxy

This commit is contained in:
zaaarf 2023-03-21 14:05:14 +01:00
parent 8c11b0b4d8
commit 40686b8c92
No known key found for this signature in database
GPG key ID: 82240E075E31FA4C
2 changed files with 182 additions and 7 deletions

View file

@ -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);
}
}
}

View file

@ -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
*/