|
| 1 | +package pl.pojo.tester.internal.instantiator; |
| 2 | + |
| 3 | +import java.lang.reflect.Constructor; |
| 4 | +import java.lang.reflect.InvocationTargetException; |
| 5 | +import java.lang.reflect.Modifier; |
| 6 | +import java.util.Arrays; |
| 7 | +import java.util.Map; |
| 8 | +import java.util.stream.Stream; |
| 9 | + |
| 10 | +class UserDefinedConstructorInstantiator extends ObjectInstantiator { |
| 11 | + |
| 12 | + private final Map<Class<?>, Object[]> classAndConstructorParameters; |
| 13 | + |
| 14 | + UserDefinedConstructorInstantiator(final Class<?> clazz, final Map<Class<?>, Object[]> classAndConstructorParameters) { |
| 15 | + super(clazz); |
| 16 | + this.classAndConstructorParameters = classAndConstructorParameters; |
| 17 | + } |
| 18 | + |
| 19 | + @Override |
| 20 | + public Object instantiate() { |
| 21 | + try { |
| 22 | + final Object[] constructorParameters = classAndConstructorParameters.get(clazz); |
| 23 | + Class[] constructorParametersTypes = convertToParameterTypes(constructorParameters); |
| 24 | + Object[] arguments = constructorParameters; |
| 25 | + |
| 26 | + if (isInnerClass()) { |
| 27 | + constructorParametersTypes = putEnclosingClassAsFirstParameterType(clazz.getEnclosingClass(), constructorParameters); |
| 28 | + final Object enclosingClassInstance = instantiateEnclosingClass(); |
| 29 | + arguments = putEnclosingClassInstanceAsFirstParameter(enclosingClassInstance, arguments); |
| 30 | + } |
| 31 | + |
| 32 | + final Constructor<?> constructor = clazz.getDeclaredConstructor(constructorParametersTypes); |
| 33 | + constructor.setAccessible(true); |
| 34 | + return constructor.newInstance(arguments); |
| 35 | + } catch (final NoSuchMethodException | InstantiationException | InvocationTargetException | IllegalAccessException | IllegalArgumentException e) { |
| 36 | + throw new ObjectInstantiationException(clazz, e); |
| 37 | + } |
| 38 | + } |
| 39 | + |
| 40 | + private Object instantiateEnclosingClass() { |
| 41 | + final Class<?> enclosingClass = clazz.getEnclosingClass(); |
| 42 | + return Instantiable.forClass(enclosingClass, classAndConstructorParameters) |
| 43 | + .instantiate(); |
| 44 | + } |
| 45 | + |
| 46 | + private Object[] putEnclosingClassInstanceAsFirstParameter(final Object enclosingClassInstance, final Object[] arguments) { |
| 47 | + return Stream.concat(Stream.of(enclosingClassInstance), Arrays.stream(arguments)) |
| 48 | + .toArray(Object[]::new); |
| 49 | + } |
| 50 | + |
| 51 | + |
| 52 | + private Class[] putEnclosingClassAsFirstParameterType(final Class<?> enclosingClass, final Object[] constructorParameters) { |
| 53 | + final Class[] parameterTypes = convertToParameterTypes(constructorParameters); |
| 54 | + return Stream.concat(Stream.of(enclosingClass), Arrays.stream(parameterTypes)) |
| 55 | + .toArray(Class[]::new); |
| 56 | + } |
| 57 | + |
| 58 | + private boolean isInnerClass() { |
| 59 | + return clazz.getEnclosingClass() != null && !Modifier.isStatic(clazz.getModifiers()); |
| 60 | + } |
| 61 | + |
| 62 | + private Class[] convertToParameterTypes(final Object[] constructorParameters) { |
| 63 | + return Arrays.stream(constructorParameters) |
| 64 | + .map(Object::getClass) |
| 65 | + .toArray(Class[]::new); |
| 66 | + } |
| 67 | +} |
0 commit comments