diff options
Diffstat (limited to 'src/main/java/ftbsc/lll/proxies/impl')
-rw-r--r-- | src/main/java/ftbsc/lll/proxies/impl/FieldProxy.java | 98 | ||||
-rw-r--r-- | src/main/java/ftbsc/lll/proxies/impl/MethodProxy.java | 188 | ||||
-rw-r--r-- | src/main/java/ftbsc/lll/proxies/impl/PackageProxy.java | 54 | ||||
-rw-r--r-- | src/main/java/ftbsc/lll/proxies/impl/TypeProxy.java | 199 |
4 files changed, 539 insertions, 0 deletions
diff --git a/src/main/java/ftbsc/lll/proxies/impl/FieldProxy.java b/src/main/java/ftbsc/lll/proxies/impl/FieldProxy.java new file mode 100644 index 0000000..ceb8277 --- /dev/null +++ b/src/main/java/ftbsc/lll/proxies/impl/FieldProxy.java @@ -0,0 +1,98 @@ +package ftbsc.lll.proxies.impl; + +import ftbsc.lll.proxies.AbstractProxy; +import ftbsc.lll.proxies.ProxyType; +import ftbsc.lll.proxies.QualifiableProxy; +import org.objectweb.asm.Type; + +import java.lang.reflect.Field; + +/** + * A container for information about class fields to be used + * in ASM patching. + * @since 0.3.0 + */ +public class FieldProxy extends AbstractProxy { + /** + * Protected constructor, called only from the builder. + * @param name the name of the field + * @param descriptor the descriptor of the field + * @param modifiers the modifiers of the field + * @param parent the {@link QualifiableProxy} for the parent + */ + protected FieldProxy(String name, String descriptor, int modifiers, QualifiableProxy parent) { + super(name, descriptor, modifiers, parent, ProxyType.FIELD); + } + + /** + * A public constructor, builds a proxy from a {@link Field} + * obtained from reflection. + * @param f the {@link Field} object corresponding to this. + */ + public FieldProxy(Field f) { + this(f.getName(), Type.getDescriptor(f.getType()), f.getModifiers(), TypeProxy.from(f.getDeclaringClass())); + } + + /** + * Returns a new instance of {@link FieldProxy.Builder}. + * @param name the name of the field + * @return the builder object for field proxies + */ + public static Builder builder(String name) { + return new Builder(name); + } + + /** + * Indicates whether the given object is a proxy for the same element as this. + * @param obj the object to perform + * @return true if it's equal + */ + @Override + public boolean equals(Object obj) { + return obj instanceof FieldProxy && super.equals(obj); + } + + /** + * A builder object for {@link FieldProxy}. + */ + public static class Builder extends AbstractProxy.Builder<FieldProxy> { + /** + * The constructor of the builder, used only internally. + * @param name the name of the field + */ + Builder(String name) { + super(name); + } + + /** + * Sets the parent class of this field to the one described by the + * fully qualified name and with the given modifiers. + * @param parentFQN the fully qualified name of the parent + * @param modifiers the modifiers of the parent + * @return the builder's state after the change + */ + public Builder setParent(String parentFQN, int modifiers) { + super.setParent(TypeProxy.from(parentFQN, 0, modifiers)); + return this; + } + + /** + * Sets the parent class of this field to the one described by the + * fully qualified name. + * @param parentFQN the fully qualified name of the parent + * @return the builder's state after the change + */ + public Builder setParent(String parentFQN) { + return this.setParent(parentFQN, 0); + } + + /** + * Builds a {@link FieldProxy} of the given kind. + * @return the built {@link FieldProxy} + */ + @Override + public FieldProxy build() { + return new FieldProxy(this.name, this.descriptor, this.modifiers, this.parent); + } + } +} diff --git a/src/main/java/ftbsc/lll/proxies/impl/MethodProxy.java b/src/main/java/ftbsc/lll/proxies/impl/MethodProxy.java new file mode 100644 index 0000000..3710d36 --- /dev/null +++ b/src/main/java/ftbsc/lll/proxies/impl/MethodProxy.java @@ -0,0 +1,188 @@ +package ftbsc.lll.proxies.impl; + +import ftbsc.lll.proxies.AbstractProxy; +import ftbsc.lll.proxies.ProxyType; +import ftbsc.lll.proxies.QualifiableProxy; +import org.objectweb.asm.Type; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static ftbsc.lll.tools.DescriptorBuilder.nameToDescriptor; + +/** + * A container for information about class methods to be used + * in ASM patching. + * @since 0.3.0 + */ +public class MethodProxy extends AbstractProxy { + + /** + * An array of {@link TypeProxy} each representing the parameters of the method. + */ + public final TypeProxy[] parameters; + + /** + * The {@link TypeProxy} for the return type of the method. + */ + public final TypeProxy returnType; + + /** + * A protected constructor, called only from the builder. + * @param name the name of the method + * @param modifiers the modifiers of the method + * @param parent the {@link QualifiableProxy} for the parent + * @param parameters the parameters of the method + * @param returnType the return type of the method + */ + protected MethodProxy(String name, int modifiers, QualifiableProxy parent, Type[] parameters, Type returnType) { + super(name, Type.getMethodDescriptor(returnType, parameters), modifiers, parent, ProxyType.METHOD); + this.parameters = Arrays.stream(parameters) + .map(t -> TypeProxy.from(t, 0)) + .toArray(TypeProxy[]::new); + this.returnType = TypeProxy.from(returnType, 0); + } + + /** + * 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) { + this(m.getName(), + m.getModifiers(), + TypeProxy.from(m.getDeclaringClass()), + Type.getArgumentTypes(m), + Type.getReturnType(m) + ); + } + + /** + * Returns a new instance of {@link MethodProxy.Builder}. + * @param name the name of the method + * @return the builder object for method proxies + */ + public static Builder builder(String name) { + return new Builder(name); + } + + /** + * Indicates whether the given object is a proxy for the same element as this. + * @param obj the object to perform + * @return true if it's equal + */ + @Override + public boolean equals(Object obj) { + if(obj instanceof MethodProxy) { + MethodProxy m = (MethodProxy) obj; + return super.equals(obj) && m.returnType.equals(this.returnType) && Arrays.equals(m.parameters, this.parameters); + } else return false; + } + + /** + * A builder object for {@link MethodProxy}. + */ + public static class Builder extends AbstractProxy.Builder<MethodProxy> { + /** + * The parameters of the method. + */ + private final List<Type> parameters; + + /** + * The return type of the method. Defaults to void. + */ + private Type returnType; + + /** + * The constructor of the builder, used only internally. + * @param name the name of the method + */ + Builder(String name) { + super(name); + this.parameters = new ArrayList<>(); + this.returnType = Type.getType(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(Type.getType(nameToDescriptor(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(Type.getType(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 = Type.getType(nameToDescriptor(fqn, arrayLevel)); + return this; + } + + /** + * Sets the parent class of this method to the one described by the + * fully qualified name and with the given modifiers. + * @param parentFQN the fully qualified name of the parent + * @param modifiers the modifiers of the parent + * @return the builder's state after the change + */ + public Builder setParent(String parentFQN, int modifiers) { + super.setParent(TypeProxy.from(parentFQN, 0, modifiers)); + return this; + } + + /** + * Sets the parent class of this method to the one described by the + * fully qualified name. + * @param parentFQN the fully qualified name of the parent + * @return the builder's state after the change + */ + public Builder setParent(String parentFQN) { + return this.setParent(parentFQN, 0); + } + + /** + * 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 = Type.getType(returnType); + return this; + } + + /** + * Builds a {@link MethodProxy} of the given kind. + * @return the built {@link MethodProxy} + */ + @Override + public MethodProxy build() { + return new MethodProxy( + this.name, + this.modifiers, + this.parent, + this.parameters.toArray(new Type[0]), + this.returnType); + } + } +} diff --git a/src/main/java/ftbsc/lll/proxies/impl/PackageProxy.java b/src/main/java/ftbsc/lll/proxies/impl/PackageProxy.java new file mode 100644 index 0000000..5989da3 --- /dev/null +++ b/src/main/java/ftbsc/lll/proxies/impl/PackageProxy.java @@ -0,0 +1,54 @@ +package ftbsc.lll.proxies.impl; + +import ftbsc.lll.proxies.ProxyType; +import ftbsc.lll.proxies.QualifiableProxy; + +/** + * A container for information about a package. + * @since 0.4.0 + */ +public class PackageProxy extends QualifiableProxy { + + /** + * The {@link PackageProxy} representing the root package. + */ + public static final PackageProxy ROOT = new PackageProxy(null, ""); + + /** + * The protected constructor, called only from {@link PackageProxy#from(String)}. + * @param parent the {@link PackageProxy} representing the parent + * @param fqn the fully-qualified name of this package + */ + protected PackageProxy(PackageProxy parent, String fqn) { + super(null, 0, parent, fqn, ProxyType.PACKAGE); + } + + /** + * Builds a {@link PackageProxy} from its fully-qualified name. + * @param fqn the fully-qualified name of the package + * @return the built {@link PackageProxy} + */ + protected static PackageProxy from(String fqn) { + if(fqn == null || fqn.equals("")) return ROOT; + return new PackageProxy(from(extractParentFromFQN(fqn)), fqn); + } + + /** + * Builds a {@link PackageProxy} from a reflective {@link Package} object. + * @param p the {@link Package} object + * @return the built {@link PackageProxy} + */ + protected static PackageProxy from(Package p) { + return from(extractParentFromFQN(p.getName())); + } + + /** + * Indicates whether the given object is a proxy for the same element as this. + * @param obj the object to perform + * @return true if it's equal + */ + @Override + public boolean equals(Object obj) { + return obj instanceof PackageProxy && super.equals(obj); + } +} diff --git a/src/main/java/ftbsc/lll/proxies/impl/TypeProxy.java b/src/main/java/ftbsc/lll/proxies/impl/TypeProxy.java new file mode 100644 index 0000000..9f613b0 --- /dev/null +++ b/src/main/java/ftbsc/lll/proxies/impl/TypeProxy.java @@ -0,0 +1,199 @@ +package ftbsc.lll.proxies.impl; + +import ftbsc.lll.proxies.AbstractProxy; +import ftbsc.lll.proxies.ProxyType; +import ftbsc.lll.proxies.QualifiableProxy; +import org.objectweb.asm.Type; + +import java.lang.reflect.Modifier; + +import static ftbsc.lll.tools.DescriptorBuilder.nameToDescriptor; + +/** + * A container for information about classes to be used + * in ASM patching. + * @since 0.4.0 + */ +public class TypeProxy extends QualifiableProxy { + /** + * Whether this proxy represents a primitive. + */ + public final boolean primitive; + + /** + * Protected constructor, called only from the builder. + * @param name the name of the class + * @param descriptor the descriptor of the class + * @param modifiers the modifiers of the class + * @param parent the package containing this class + * @param primitive whether the proxy is a primitive + */ + protected TypeProxy(String name, String descriptor, int modifiers, String parent, boolean primitive) { + super(descriptor, modifiers, PackageProxy.from(parent), String.format("%s.%s", name, parent), ProxyType.TYPE); + this.primitive = primitive; + } + + /** + * Protected constructor, called only from the builder. + * @param name the name of the class + * @param descriptor the descriptor of the element + * @param modifiers the modifiers of the class + * @param primitive whether the proxy is a primitive + * @param containerClass the FQN of the parent class of the class + */ + protected TypeProxy(String name, String descriptor, int modifiers, QualifiableProxy containerClass, boolean primitive) { + super(descriptor, modifiers, containerClass, String.format("%s$%s", name, containerClass.fullyQualifiedName), ProxyType.TYPE); + this.primitive = primitive; + } + + /** + * Builds a {@link TypeProxy} from a {@link Type} and modifiers. + * @param type the {@link Type} representing this Class + * @param modifiers the modifiers of the class + * @return the builty {@link TypeProxy} + */ + public static TypeProxy from(Type type, int modifiers) { + while(type.getSort() == Type.ARRAY) + type = type.getElementType(); + String fqn = type.getInternalName().replace('/', '.'); + String simpleName = extractSimpleNameFromFQN(fqn); + String parent = extractParentFromFQN(fqn); + boolean primitive = type.getSort() < Type.ARRAY; + if(fqn.contains("$")) + return new TypeProxy(simpleName, type.getDescriptor(), modifiers, from(type, Modifier.PUBLIC), primitive); + else return new TypeProxy(simpleName, type.getDescriptor(), modifiers, parent, primitive); + } + + /** + * Builds a {@link TypeProxy} given only the fully-qualified name and modifiers. + * If present, parent classes will be assumed to have {@code public} as their + * only modifier. + * @param fqn the fully qualified name of the desired class + * @param arrayLevel the array level for this type + * @param modifiers the access modifiers of the desired class + * @return the built {@link TypeProxy} + */ + protected static TypeProxy from(String fqn, int arrayLevel, int modifiers) { + return from(Type.getObjectType(nameToDescriptor(fqn, arrayLevel)), modifiers); + } + + /** + * Builds a {@link TypeProxy} from a {@link Class} object. + * @param clazz the {@link Class} object representing the target class + * @return the built {@link TypeProxy} + */ + public static TypeProxy from(Class<?> clazz) { + Class<?> parentClass = clazz.getEnclosingClass(); + if(parentClass == null) + return new TypeProxy( + clazz.getSimpleName(), + Type.getDescriptor(clazz), + clazz.getModifiers(), + clazz.getPackage().getName(), + clazz.isPrimitive() + ); + else + return new TypeProxy( + clazz.getSimpleName(), + Type.getDescriptor(clazz), + clazz.getModifiers(), + from(parentClass), + clazz.isPrimitive() + ); + } + + /** + * Returns a new instance of {@link TypeProxy.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); + } + + /** + * Indicates whether the given object is a proxy for the same element as this. + * @param obj the object to perform + * @return true if it's equal + */ + @Override + public boolean equals(Object obj) { + return obj instanceof TypeProxy && super.equals(obj); + } + + /** + * A builder object for {@link TypeProxy}. + */ + public static class Builder extends AbstractProxy.Builder<TypeProxy> { + + /** + * Whether the proxy represents a primitive. + */ + private boolean primitive; + + /** + * The constructor of the builder, used only internally. + * @param name the "simple name" of the class + */ + Builder(String name) { + super(name); + this.primitive = false; + } + + /** + * 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 setParent(Class<?> containerClass) { + super.setParent(TypeProxy.from(containerClass)); + return this; + } + + /** + * Sets this class as an inner class and builds a {@link TypeProxy} + * from the given parent and modifiers. + * @param parentFQN the fully qualified name of the parent + * @param modifiers the modifiers of the parent (if it's a class) + * @param isParentPackage whether this parent should be interpreted as a package or class + * @return the builder's state after the change + */ + public Builder setParent(String parentFQN, int modifiers, boolean isParentPackage) { + super.setParent(isParentPackage ? PackageProxy.from(parentFQN) : TypeProxy.from(parentFQN, 0, modifiers)); + return this; + } + + /** + * Sets this class as an inner class and builds a {@link TypeProxy} + * from the given parent. + * @param parentFQN the fully qualified name of the parent + * @param isParentPackage whether this parent should be interpreted as a package or class + * @return the builder's state after the change + */ + public Builder setParent(String parentFQN, boolean isParentPackage) { + return this.setParent(parentFQN, 0, isParentPackage); + } + + /** + * Sets the primitive flag to true or false, to signal that the type here specified + * is a primitive. + * @param primitive the new state of the primitive flag + * @return the builder's state after the change + */ + public Builder setPrimitive(boolean primitive) { + this.primitive = primitive; + return this; + } + + /** + * Builds a {@link TypeProxy} of the given kind. + * @return the built {@link TypeProxy} + */ + @Override + public TypeProxy build() { + return new TypeProxy(this.name, this.descriptor, this.modifiers, this.parent, this.primitive); + } + } +}
\ No newline at end of file |