package rtt.annotations.processing; import java.io.InputStream; import java.lang.reflect.Constructor; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; import rtt.annotations.Node.Initialize; public abstract class InitMember<T extends Member> implements Comparable<InitMember<?>> { private static final Class<Initialize> INIT_ANNOTATION = Initialize.class; protected static class InitialConstructor extends InitMember<Constructor<?>> { private Constructor<?> constructor; public InitialConstructor(Constructor<?> constructor, Initialize initAnnotation) { super(constructor, constructor.getParameterTypes(), initAnnotation); this.constructor = constructor; } @Override public Object getResult(InputStream input, List<String> params) throws ReflectiveOperationException { constructor.setAccessible(true); try { if (isWithParams()) { String[] paramArray = params.toArray(new String[params.size()]); return constructor.newInstance(input, paramArray); } else { return constructor.newInstance(input); } } catch (IllegalAccessException | IllegalArgumentException | InstantiationException constructorException) { throw new RuntimeException("Could not access initializing constructor.", constructorException); } } } protected static class InitialMethod extends InitMember<Method> { private Method method; public InitialMethod(Method method, Initialize initAnnotation) { super(method, method.getParameterTypes(), initAnnotation); this.method = method; } @Override public Object getResult(InputStream input, List<String> params) throws ReflectiveOperationException { method.setAccessible(true); Class<?> declaringClass = method.getDeclaringClass(); try { Constructor<?> constructor = declaringClass.getDeclaredConstructor(); constructor.setAccessible(true); Object initialObject = constructor.newInstance(); if (isWithParams()) { String[] paramArray = params.toArray(new String[params.size()]); method.invoke(initialObject, input, paramArray); } else { method.invoke(initialObject, input); } return initialObject; } catch (IllegalAccessException | IllegalArgumentException methodException) { throw new RuntimeException("Could not access initializing method.", methodException); } catch (NoSuchMethodException | InstantiationException constructorException) { throw new RuntimeException("Could not get parameter-less constructor.", constructorException); } } } private T member; private String signature; private Class<?>[] parameterTypes; private Initialize initAnnotation; public InitMember(T member, Class<?>[] parameterTypes, Initialize initAnnotation) { this.member = member; this.parameterTypes = parameterTypes; this.signature = member.getDeclaringClass().getSimpleName() + "." + member.getName() + Arrays.toString(parameterTypes); this.initAnnotation = initAnnotation; } public T getMember() { return member; } public final String getSignature() { return signature; } public Class<?>[] getParameterTypes() { return parameterTypes; } public Initialize getAnnotation() { return initAnnotation; } public boolean isWithParams() { return initAnnotation.withParams(); } public abstract Object getResult(InputStream input, List<String> params) throws ReflectiveOperationException; public static final InitMember<Constructor<?>> create(Constructor<?> constructor) { return new InitialConstructor(constructor, constructor.getAnnotation(INIT_ANNOTATION)); } public static final InitMember<Method> create(Method method) { return new InitialMethod(method, method.getAnnotation(INIT_ANNOTATION)); } @Override public int compareTo(InitMember<?> other) { if (this.equals(other)) { return 0; } return this.signature.compareTo(other.signature); } @Override public int hashCode() { final int prime = 31; return prime + signature.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof InitMember)) { return false; } InitMember<?> other = (InitMember<?>) obj; if (!signature.equals(other.signature)) { return false; } return true; } }