Add class validation utilities
This commit is contained in:
parent
7a737ad335
commit
15f6897c14
@ -17,6 +17,12 @@
|
|||||||
<artifactId>annotations-java5</artifactId>
|
<artifactId>annotations-java5</artifactId>
|
||||||
<version>RELEASE</version>
|
<version>RELEASE</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>1.16.10</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
|
@ -0,0 +1,97 @@
|
|||||||
|
package eu.mikroskeem.utils.reflect;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class Validate {
|
||||||
|
/* Code got from Google Guava */
|
||||||
|
private static <T> T checkNotNull(T reference, @Nullable Object errorMessage) {
|
||||||
|
if(reference == null) {
|
||||||
|
throw new NullPointerException(String.valueOf(errorMessage));
|
||||||
|
} else {
|
||||||
|
return reference;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void checkMethods(ClassDescriptor classDescriptor, Validate.MethodDescriptor... methods) {
|
||||||
|
checkClass(classDescriptor);
|
||||||
|
Stream.of(methods).forEach(methodDescriptor ->
|
||||||
|
checkNotNull(Reflect.getMethod(classDescriptor.getClazz(),
|
||||||
|
methodDescriptor.getMethodName(),
|
||||||
|
methodDescriptor.getArguments()),
|
||||||
|
String.format("Method %s(%s) not found",
|
||||||
|
methodDescriptor.getMethodName(),
|
||||||
|
Arrays.toString(methodDescriptor.getArguments())
|
||||||
|
))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void checkConstructors(ClassDescriptor classDescriptor,
|
||||||
|
Validate.ConstructorDescriptor... constructors) {
|
||||||
|
checkClass(classDescriptor);
|
||||||
|
Stream.of(constructors).forEach(constructorDescriptor -> {
|
||||||
|
try {
|
||||||
|
checkNotNull(classDescriptor.getClazz().getConstructor(constructorDescriptor.getArguments()),
|
||||||
|
String.format("Constructor (%s) not found",
|
||||||
|
Arrays.toString(constructorDescriptor.getArguments())
|
||||||
|
));
|
||||||
|
} catch (Exception e){
|
||||||
|
throw new NullPointerException(e.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void checkClass(ClassDescriptor classDescriptor){
|
||||||
|
checkNotNull(classDescriptor.getClazz(), "Class is null");
|
||||||
|
Stream.of(classDescriptor.getExtendingClasses()).forEach(clazz->{
|
||||||
|
if(!clazz.isAssignableFrom(classDescriptor.getClazz())){
|
||||||
|
throw new NullPointerException(String.format("Class doesn't extend %s", clazz.getSimpleName()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @Getter class ClassDescriptor {
|
||||||
|
private final Class<?> clazz;
|
||||||
|
private final Class<?>[] extendingClasses;
|
||||||
|
private ClassDescriptor(Class<?> clazz, Class<?>... arguments){
|
||||||
|
this.clazz = clazz;
|
||||||
|
this.extendingClasses = arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ClassDescriptor newClassDescriptor(Class<?> clazz, Class<?>... classes){
|
||||||
|
return new ClassDescriptor(clazz, classes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ClassDescriptor newClassDescriptor(String clazzName, Class<?>... classes){
|
||||||
|
Class<?> clazz = Reflect.getClass(clazzName);
|
||||||
|
return new ClassDescriptor(clazz, classes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @Getter class ConstructorDescriptor {
|
||||||
|
private final Class[] arguments;
|
||||||
|
private ConstructorDescriptor(Class... arguments){
|
||||||
|
this.arguments = arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ConstructorDescriptor newConstructorDescriptor(Class... arguments){
|
||||||
|
return new ConstructorDescriptor(arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @Getter class MethodDescriptor {
|
||||||
|
private final String methodName;
|
||||||
|
private final Class[] arguments;
|
||||||
|
private MethodDescriptor(String methodName, Class... arguments){
|
||||||
|
this.methodName = methodName;
|
||||||
|
this.arguments = arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodDescriptor newMethodDescriptor(String methodName, Class... arguments){
|
||||||
|
return new MethodDescriptor(methodName, arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
package eu.mikroskeem.utils.test.reflect;
|
||||||
|
|
||||||
|
import eu.mikroskeem.utils.reflect.Reflect;
|
||||||
|
import eu.mikroskeem.utils.reflect.Validate;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.objectweb.asm.ClassWriter;
|
||||||
|
import org.objectweb.asm.MethodVisitor;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
|
||||||
|
import static eu.mikroskeem.utils.reflect.Validate.ClassDescriptor.newClassDescriptor;
|
||||||
|
import static eu.mikroskeem.utils.reflect.Validate.MethodDescriptor.newMethodDescriptor;
|
||||||
|
import static eu.mikroskeem.utils.reflect.Validate.checkClass;
|
||||||
|
import static eu.mikroskeem.utils.reflect.Validate.checkMethods;
|
||||||
|
import static org.objectweb.asm.Opcodes.*;
|
||||||
|
|
||||||
|
public class TestValidate {
|
||||||
|
@Test
|
||||||
|
public void testMethodNoArguments() throws Exception {
|
||||||
|
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
|
||||||
|
cw.visit(V1_8, ACC_PUBLIC+ACC_SUPER, "eu/mikroskeem/utils/test/reflect/TestClass1",
|
||||||
|
null, Type.getInternalName(Object.class), null);
|
||||||
|
String desc = String.format("(%s)%s", "", "V");
|
||||||
|
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", desc, null, null);
|
||||||
|
mv.visitVarInsn(ALOAD, 0);
|
||||||
|
mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", desc, false);
|
||||||
|
mv.visitInsn(RETURN);
|
||||||
|
mv.visitMaxs(0, 0);
|
||||||
|
mv.visitEnd();
|
||||||
|
desc = String.format("(%s)%s", "", Type.getDescriptor(String.class));
|
||||||
|
mv = cw.visitMethod(ACC_PUBLIC, "toString", desc, null, null);
|
||||||
|
mv.visitLdcInsn("TestClass1 instance");
|
||||||
|
mv.visitInsn(ARETURN);
|
||||||
|
mv.visitMaxs(0, 0);
|
||||||
|
mv.visitEnd();
|
||||||
|
cw.visitEnd();
|
||||||
|
Class<?> clazz = Reflect.defineClass(
|
||||||
|
ClassLoader.getSystemClassLoader(),
|
||||||
|
"eu.mikroskeem.utils.test.reflect.TestClass1",
|
||||||
|
cw.toByteArray());
|
||||||
|
Validate.ClassDescriptor cd = newClassDescriptor(clazz, Object.class);
|
||||||
|
|
||||||
|
checkClass(cd);
|
||||||
|
checkMethods(cd, newMethodDescriptor("toString"));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user