diff --git a/Reflect/pom.xml b/Reflect/pom.xml
index faff0f6..29f5a90 100644
--- a/Reflect/pom.xml
+++ b/Reflect/pom.xml
@@ -17,6 +17,12 @@
annotations-java5
RELEASE
+
+ org.projectlombok
+ lombok
+ 1.16.10
+ provided
+
junit
junit
diff --git a/Reflect/src/main/java/eu/mikroskeem/utils/reflect/Validate.java b/Reflect/src/main/java/eu/mikroskeem/utils/reflect/Validate.java
new file mode 100644
index 0000000..a750151
--- /dev/null
+++ b/Reflect/src/main/java/eu/mikroskeem/utils/reflect/Validate.java
@@ -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 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);
+ }
+ }
+}
diff --git a/Reflect/src/test/java/eu/mikroskeem/utils/test/reflect/TestValidate.java b/Reflect/src/test/java/eu/mikroskeem/utils/test/reflect/TestValidate.java
new file mode 100644
index 0000000..c2624d4
--- /dev/null
+++ b/Reflect/src/test/java/eu/mikroskeem/utils/test/reflect/TestValidate.java
@@ -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, "", desc, null, null);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(Object.class), "", 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"));
+ }
+}