Add class validation utilities

This commit is contained in:
Mark Vainomaa 2017-01-18 03:55:47 +02:00
parent 7a737ad335
commit 15f6897c14
3 changed files with 148 additions and 0 deletions

View File

@ -17,6 +17,12 @@
<artifactId>annotations-java5</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>

View File

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

View File

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