From 2fe5c35460f88b39576c546b28248f3cd58b7dd3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Piotr=20Jo=C5=84ski?=
Date: Sat, 16 Dec 2017 21:04:53 +0100
Subject: [PATCH] 217. Classes can be instantiated by user defined
instantiators.
---
.../api/AbstractObjectInstantiator.java | 40 +++++++
.../api/assertion/AbstractAssertion.java | 108 +++++++++++++-----
.../AbstractInternalInstantiator.java | 17 +++
.../AbstractMultiConstructorInstantiator.java | 87 ++++----------
.../AbstractObjectInstantiator.java | 20 ----
.../instantiator/ArrayInstantiator.java | 10 +-
.../BestConstructorInstantiator.java | 15 +--
.../instantiator/CollectionInstantiator.java | 10 +-
.../DefaultConstructorInstantiator.java | 10 +-
.../instantiator/EnumInstantiator.java | 10 +-
.../internal/instantiator/Instantiable.java | 63 +++++-----
.../instantiator/JavaTypeInstantiator.java | 10 +-
.../instantiator/ObjectGenerator.java | 11 +-
.../instantiator/ProxyInstantiator.java | 25 ++--
.../instantiator/SupplierInstantiator.java | 25 ++++
.../UserDefinedConstructorInstantiator.java | 60 +++++-----
.../internal/tester/AbstractTester.java | 28 ++---
.../internal/tester/ConstructorTester.java | 38 +-----
.../java/helpers/MultiValuedMapMatcher.java | 35 ------
.../api/assertion/AbstractAssertionTest.java | 57 ++++-----
...tractMultiConstructorInstantiatorTest.java | 45 +-------
.../instantiator/ArrayInstantiatorTest.java | 4 +-
.../BestConstructorInstantiatorTest.java | 36 +++---
.../CollectionInstantiatorTest.java | 7 +-
.../DefaultConstructorInstantiatorTest.java | 7 +-
.../instantiator/EnumInstantiatorTest.java | 7 +-
.../instantiator/InstantiableTest.java | 31 +++--
.../JavaTypeInstantiatorTest.java | 7 +-
.../instantiator/ObjectGeneratorFastTest.java | 28 ++---
.../instantiator/ObjectGeneratorTest.java | 28 ++---
.../instantiator/ProxyInstantiatorTest.java | 11 +-
...serDefinedConstructorInstantiatorTest.java | 27 +----
.../internal/tester/AbstractTesterTest.java | 10 +-
.../tester/ConstructorTesterTest.java | 58 +---------
34 files changed, 401 insertions(+), 584 deletions(-)
create mode 100644 src/main/java/pl/pojo/tester/api/AbstractObjectInstantiator.java
create mode 100644 src/main/java/pl/pojo/tester/internal/instantiator/AbstractInternalInstantiator.java
delete mode 100644 src/main/java/pl/pojo/tester/internal/instantiator/AbstractObjectInstantiator.java
create mode 100644 src/main/java/pl/pojo/tester/internal/instantiator/SupplierInstantiator.java
delete mode 100644 src/test/java/helpers/MultiValuedMapMatcher.java
diff --git a/src/main/java/pl/pojo/tester/api/AbstractObjectInstantiator.java b/src/main/java/pl/pojo/tester/api/AbstractObjectInstantiator.java
new file mode 100644
index 00000000..d8cb7c0d
--- /dev/null
+++ b/src/main/java/pl/pojo/tester/api/AbstractObjectInstantiator.java
@@ -0,0 +1,40 @@
+package pl.pojo.tester.api;
+
+/**
+ * This is a base class for all instantiators.
+ *
+ * @author Piotr JoĊski
+ * @since 0.8.0
+ */
+public abstract class AbstractObjectInstantiator {
+
+ protected final Class> clazz;
+
+ /**
+ * Creates new instantiator for defined class.
+ *
+ * @param clazz class that will be instantiated
+ */
+ public AbstractObjectInstantiator(final Class> clazz) {
+ this.clazz = clazz;
+ }
+
+ /**
+ * Produces new instances of given class.
+ *
+ * @return new object that class is defined in constructor.
+ */
+ public abstract Object instantiate();
+
+ /**
+ * @return class defined in constructor.
+ */
+ public Class> getClazz() {
+ return clazz;
+ }
+
+ @Override
+ public String toString() {
+ return "AbstractObjectInstantiator{clazz=" + clazz + '}';
+ }
+}
diff --git a/src/main/java/pl/pojo/tester/api/assertion/AbstractAssertion.java b/src/main/java/pl/pojo/tester/api/assertion/AbstractAssertion.java
index de87273d..630eee3c 100644
--- a/src/main/java/pl/pojo/tester/api/assertion/AbstractAssertion.java
+++ b/src/main/java/pl/pojo/tester/api/assertion/AbstractAssertion.java
@@ -1,20 +1,24 @@
package pl.pojo.tester.api.assertion;
-import org.apache.commons.collections4.MultiValuedMap;
-import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
import org.slf4j.Logger;
+import pl.pojo.tester.api.AbstractObjectInstantiator;
import pl.pojo.tester.api.ClassAndFieldPredicatePair;
import pl.pojo.tester.api.ConstructorParameters;
import pl.pojo.tester.internal.field.AbstractFieldValueChanger;
+import pl.pojo.tester.internal.instantiator.SupplierInstantiator;
+import pl.pojo.tester.internal.instantiator.UserDefinedConstructorInstantiator;
+import pl.pojo.tester.internal.tester.AbstractTester;
+import pl.pojo.tester.internal.utils.ClassLoader;
import pl.pojo.tester.internal.utils.Permutator;
import pl.pojo.tester.internal.utils.SublistFieldPermutator;
import pl.pojo.tester.internal.utils.ThoroughFieldPermutator;
-import pl.pojo.tester.internal.tester.AbstractTester;
-import pl.pojo.tester.internal.utils.ClassLoader;
import java.util.Arrays;
import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
import java.util.Set;
+import java.util.function.Supplier;
import java.util.stream.Collectors;
import static pl.pojo.tester.internal.preconditions.ParameterPreconditions.checkNotBlank;
@@ -40,7 +44,7 @@ public abstract class AbstractAssertion {
.forEach(DEFAULT_TESTERS::add);
}
- private final MultiValuedMap, ConstructorParameters> constructorParameters = new ArrayListValuedHashMap<>();
+ private final List instantiators = new LinkedList<>();
Set testers = new HashSet<>();
private AbstractFieldValueChanger abstractFieldValueChanger;
private Permutator permutator = new ThoroughFieldPermutator();
@@ -109,26 +113,6 @@ public AbstractAssertion testing(final Method method) {
return this;
}
- /**
- * Performs specified tests on classes using declared field value changer.
- *
- * @see Method
- * @see AbstractFieldValueChanger
- */
- public void areWellImplemented() {
- if (testers.isEmpty()) {
- testers = DEFAULT_TESTERS;
- }
- if (abstractFieldValueChanger != null) {
- testers.forEach(tester -> tester.setFieldValuesChanger(abstractFieldValueChanger));
- }
-
- testers.forEach(tester -> tester.setPermutator(permutator));
- testers.forEach(tester -> tester.setUserDefinedConstructors(constructorParameters));
-
- runAssertions();
- }
-
/**
* Indicates, that class should be constructed using given constructor parameters. Constructor will be selected
* based on constructor parameter's types.
@@ -164,8 +148,8 @@ public AbstractAssertion create(final String qualifiedClassName,
checkNotNull("constructorParameters", constructorParameters);
final Class> clazz = ClassLoader.loadClass(qualifiedClassName);
- this.constructorParameters.put(clazz, constructorParameters);
- return this;
+
+ return create(clazz, constructorParameters);
}
/**
@@ -188,7 +172,6 @@ public AbstractAssertion create(final Class> clazz,
return create(clazz, constructorParameter);
}
-
/**
* Indicates, that class should be constructed using given constructor parameters. Constructor will be selected
* based on constructor parameter's types.
@@ -202,10 +185,76 @@ public AbstractAssertion create(final Class> clazz, final ConstructorParameter
checkNotNull("clazz", clazz);
checkNotNull("constructorParameters", constructorParameters);
- this.constructorParameters.put(clazz, constructorParameters);
+ final UserDefinedConstructorInstantiator instantiator = new UserDefinedConstructorInstantiator(clazz,
+ constructorParameters);
+ return create(clazz, instantiator);
+ }
+
+ /**
+ * Indicates, that class should be constructed using given instantiator.
+ *
+ * @param instantiator instantiator which will create instance of given class
+ * @return itself
+ * @see ConstructorParameters
+ */
+ public AbstractAssertion create(final AbstractObjectInstantiator instantiator) {
+ checkNotNull("clazz", instantiator.getClazz());
+ checkNotNull("instantiator", instantiator);
+
+ return create(instantiator.getClazz(), instantiator::instantiate);
+ }
+
+ /**
+ * Indicates, that class should be constructed using given instantiator.
+ *
+ * @param clazz class to instantiate
+ * @param instantiator instantiator which will create instance of given class
+ * @return itself
+ * @see ConstructorParameters
+ */
+ public AbstractAssertion create(final Class> clazz, final AbstractObjectInstantiator instantiator) {
+ checkNotNull("clazz", clazz);
+ checkNotNull("instantiator", instantiator);
+
+ return create(clazz, instantiator::instantiate);
+ }
+
+ /**
+ * Indicates, that class should be constructed using given supplier.
+ *
+ * @param clazz class to instantiate
+ * @param supplier supplier that will create given class
+ * @return itself
+ * @see ConstructorParameters
+ */
+ public AbstractAssertion create(final Class> clazz, final Supplier> supplier) {
+ checkNotNull("clazz", clazz);
+ checkNotNull("supplier", supplier);
+
+ this.instantiators.add(new SupplierInstantiator(clazz, supplier));
return this;
}
+ /**
+ * Performs specified tests on classes using declared field value changer.
+ *
+ * @see Method
+ * @see AbstractFieldValueChanger
+ */
+ public void areWellImplemented() {
+ if (testers.isEmpty()) {
+ testers = DEFAULT_TESTERS;
+ }
+ if (abstractFieldValueChanger != null) {
+ testers.forEach(tester -> tester.setFieldValuesChanger(abstractFieldValueChanger));
+ }
+
+ testers.forEach(tester -> tester.setPermutator(permutator));
+ testers.forEach(tester -> tester.setUserDefinedInstantiators(instantiators));
+
+ runAssertions();
+ }
+
protected abstract void runAssertions();
protected void logTestersAndClasses(final Logger logger,
@@ -218,6 +267,7 @@ protected void logTestersAndClasses(final Logger logger,
logger.debug("Running {} testers on {} classes", testers.size(), classAndFieldPredicatePairs.length);
logger.debug("Testers: {}", testers);
logger.debug("Classes: {}", classes);
+ logger.debug("Predefined instantiators: {}", instantiators);
}
}
}
diff --git a/src/main/java/pl/pojo/tester/internal/instantiator/AbstractInternalInstantiator.java b/src/main/java/pl/pojo/tester/internal/instantiator/AbstractInternalInstantiator.java
new file mode 100644
index 00000000..d5be0fc5
--- /dev/null
+++ b/src/main/java/pl/pojo/tester/internal/instantiator/AbstractInternalInstantiator.java
@@ -0,0 +1,17 @@
+package pl.pojo.tester.internal.instantiator;
+
+import pl.pojo.tester.api.AbstractObjectInstantiator;
+
+abstract class AbstractInternalInstantiator extends AbstractObjectInstantiator {
+
+ AbstractInternalInstantiator(final Class> clazz) {
+ super(clazz);
+ }
+
+ abstract boolean canInstantiate();
+
+ @Override
+ public String toString() {
+ return "AbstractInternalInstantiator{clazz=" + clazz + '}';
+ }
+}
diff --git a/src/main/java/pl/pojo/tester/internal/instantiator/AbstractMultiConstructorInstantiator.java b/src/main/java/pl/pojo/tester/internal/instantiator/AbstractMultiConstructorInstantiator.java
index 220e11be..8c37ee29 100644
--- a/src/main/java/pl/pojo/tester/internal/instantiator/AbstractMultiConstructorInstantiator.java
+++ b/src/main/java/pl/pojo/tester/internal/instantiator/AbstractMultiConstructorInstantiator.java
@@ -1,66 +1,35 @@
package pl.pojo.tester.internal.instantiator;
-import org.apache.commons.collections4.MultiValuedMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import pl.pojo.tester.api.ConstructorParameters;
-import pl.pojo.tester.internal.utils.CollectionUtils;
+import pl.pojo.tester.api.AbstractObjectInstantiator;
import java.lang.reflect.Constructor;
-import java.lang.reflect.Modifier;
import java.util.Arrays;
-import java.util.Collection;
+import java.util.List;
import java.util.Objects;
-import java.util.stream.Stream;
+import java.util.Optional;
-abstract class AbstractMultiConstructorInstantiator extends AbstractObjectInstantiator {
+abstract class AbstractMultiConstructorInstantiator extends AbstractInternalInstantiator {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractMultiConstructorInstantiator.class);
+ private final List instantiators;
- AbstractMultiConstructorInstantiator(final Class> clazz,
- final MultiValuedMap, ConstructorParameters> constructorParameters) {
- super(clazz, constructorParameters);
+ AbstractMultiConstructorInstantiator(final Class> clazz, final List instantiators) {
+ super(clazz);
+ this.instantiators = instantiators;
}
- protected Object instantiateUsingUserParameters() {
- final Collection userConstructorParameters = constructorParameters.get(clazz);
- if (userDefinedOwnParametersForThisClass(userConstructorParameters)) {
- final Object result = tryToInstantiateUsing(userConstructorParameters);
- if (result != null) {
- return result;
- }
- LOGGER.warn("Could not instantiate class {} with user defined parameters. "
- + "Trying create instance finding best constructor", clazz);
- }
- return null;
- }
-
- private boolean userDefinedOwnParametersForThisClass(final Collection userConstructorParameters) {
- return CollectionUtils.isNotEmpty(userConstructorParameters);
- }
+ protected Object createFindingBestConstructor() {
+ final Optional instantiator = findFirstMatchingInPredefined();
- private Object tryToInstantiateUsing(final Collection userConstructorParameters) {
- for (final ConstructorParameters param : userConstructorParameters) {
- Class>[] parameterTypes = param.getParametersTypes();
- try {
- Object[] parameters = param.getParameters();
- if (isInnerClass()) {
- parameterTypes = putEnclosingClassAsFirstParameterType(clazz.getEnclosingClass(), parameterTypes);
- final Object enclosingClassInstance = instantiateEnclosingClass();
- parameters = putEnclosingClassInstanceAsFirstParameter(enclosingClassInstance, parameters);
- }
- return createObjectFromArgsConstructor(parameterTypes, parameters);
- } catch (final ObjectInstantiationException e) {
- LOGGER.debug("ObjectInstantiationException:", e);
- // ignore, try all user defined constructor parameters and types
- }
+ if (instantiator.isPresent()) {
+ return instantiator.get()
+ .instantiate();
}
- return null;
- }
- protected Object createFindingBestConstructor() {
final Constructor>[] constructors = clazz.getDeclaredConstructors();
return Arrays.stream(constructors)
.map(this::createObjectFromConstructor)
@@ -69,34 +38,18 @@ protected Object createFindingBestConstructor() {
.orElseThrow(this::createObjectInstantiationException);
}
+ private Optional findFirstMatchingInPredefined() {
+ return instantiators.stream()
+ .filter(eachInstantiator -> clazz.equals(eachInstantiator.getClazz()))
+ .findFirst();
+ }
+
protected abstract Object createObjectFromArgsConstructor(final Class>[] parameterTypes, Object[] parameters);
protected abstract Object createObjectFromNoArgsConstructor(final Constructor> constructor);
protected abstract ObjectInstantiationException createObjectInstantiationException();
- private Object instantiateEnclosingClass() {
- final Class> enclosingClass = clazz.getEnclosingClass();
- return Instantiable.forClass(enclosingClass, constructorParameters)
- .instantiate();
- }
-
- private Class[] putEnclosingClassAsFirstParameterType(final Class> enclosingClass,
- final Class>[] constructorParametersTypes) {
- return Stream.concat(Stream.of(enclosingClass), Arrays.stream(constructorParametersTypes))
- .toArray(Class[]::new);
- }
-
- private boolean isInnerClass() {
- return clazz.getEnclosingClass() != null && !Modifier.isStatic(clazz.getModifiers());
- }
-
- private Object[] putEnclosingClassInstanceAsFirstParameter(final Object enclosingClassInstance,
- final Object[] arguments) {
- return Stream.concat(Stream.of(enclosingClassInstance), Arrays.stream(arguments))
- .toArray(Object[]::new);
- }
-
private Object createObjectFromConstructor(final Constructor> constructor) {
makeAccessible(constructor);
if (constructor.getParameterCount() == 0) {
@@ -104,7 +57,7 @@ private Object createObjectFromConstructor(final Constructor> constructor) {
} else {
try {
final Object[] parameters = Instantiable.instantiateClasses(constructor.getParameterTypes(),
- constructorParameters);
+ instantiators);
return createObjectFromArgsConstructor(constructor.getParameterTypes(), parameters);
} catch (final Exception e) {
LOGGER.debug("Exception:", e);
diff --git a/src/main/java/pl/pojo/tester/internal/instantiator/AbstractObjectInstantiator.java b/src/main/java/pl/pojo/tester/internal/instantiator/AbstractObjectInstantiator.java
deleted file mode 100644
index 18964897..00000000
--- a/src/main/java/pl/pojo/tester/internal/instantiator/AbstractObjectInstantiator.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package pl.pojo.tester.internal.instantiator;
-
-import org.apache.commons.collections4.MultiValuedMap;
-import pl.pojo.tester.api.ConstructorParameters;
-
-abstract class AbstractObjectInstantiator {
-
- protected final Class> clazz;
- protected final MultiValuedMap, ConstructorParameters> constructorParameters;
-
- AbstractObjectInstantiator(final Class> clazz,
- final MultiValuedMap, ConstructorParameters> constructorParameters) {
- this.clazz = clazz;
- this.constructorParameters = constructorParameters;
- }
-
- public abstract Object instantiate();
-
- public abstract boolean canInstantiate();
-}
diff --git a/src/main/java/pl/pojo/tester/internal/instantiator/ArrayInstantiator.java b/src/main/java/pl/pojo/tester/internal/instantiator/ArrayInstantiator.java
index 9465e99d..d5e36baa 100644
--- a/src/main/java/pl/pojo/tester/internal/instantiator/ArrayInstantiator.java
+++ b/src/main/java/pl/pojo/tester/internal/instantiator/ArrayInstantiator.java
@@ -1,17 +1,13 @@
package pl.pojo.tester.internal.instantiator;
-import org.apache.commons.collections4.MultiValuedMap;
-import pl.pojo.tester.api.ConstructorParameters;
-
import java.lang.reflect.Array;
-class ArrayInstantiator extends AbstractObjectInstantiator {
+class ArrayInstantiator extends AbstractInternalInstantiator {
private static final int DEFAULT_ARRAY_LENGTH = 0;
- ArrayInstantiator(final Class> clazz,
- final MultiValuedMap, ConstructorParameters> constructorParameters) {
- super(clazz, constructorParameters);
+ ArrayInstantiator(final Class> clazz) {
+ super(clazz);
}
@Override
diff --git a/src/main/java/pl/pojo/tester/internal/instantiator/BestConstructorInstantiator.java b/src/main/java/pl/pojo/tester/internal/instantiator/BestConstructorInstantiator.java
index 142d63e1..9d6e9c82 100644
--- a/src/main/java/pl/pojo/tester/internal/instantiator/BestConstructorInstantiator.java
+++ b/src/main/java/pl/pojo/tester/internal/instantiator/BestConstructorInstantiator.java
@@ -1,30 +1,25 @@
package pl.pojo.tester.internal.instantiator;
-import org.apache.commons.collections4.MultiValuedMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import pl.pojo.tester.api.ConstructorParameters;
+import pl.pojo.tester.api.AbstractObjectInstantiator;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
+import java.util.List;
class BestConstructorInstantiator extends AbstractMultiConstructorInstantiator {
private static final Logger LOGGER = LoggerFactory.getLogger(BestConstructorInstantiator.class);
- BestConstructorInstantiator(final Class> clazz,
- final MultiValuedMap, ConstructorParameters> constructorParameters) {
- super(clazz, constructorParameters);
+ BestConstructorInstantiator(final Class> clazz, final List instantiators) {
+ super(clazz, instantiators);
}
@Override
public Object instantiate() {
- Object result = instantiateUsingUserParameters();
- if (result == null) {
- result = createFindingBestConstructor();
- }
- return result;
+ return createFindingBestConstructor();
}
@Override
diff --git a/src/main/java/pl/pojo/tester/internal/instantiator/CollectionInstantiator.java b/src/main/java/pl/pojo/tester/internal/instantiator/CollectionInstantiator.java
index d1b2c026..67e3cd36 100644
--- a/src/main/java/pl/pojo/tester/internal/instantiator/CollectionInstantiator.java
+++ b/src/main/java/pl/pojo/tester/internal/instantiator/CollectionInstantiator.java
@@ -1,9 +1,6 @@
package pl.pojo.tester.internal.instantiator;
-import org.apache.commons.collections4.MultiValuedMap;
-import pl.pojo.tester.api.ConstructorParameters;
-
import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
@@ -28,7 +25,7 @@
import java.util.Vector;
import java.util.stream.Stream;
-class CollectionInstantiator extends AbstractObjectInstantiator {
+class CollectionInstantiator extends AbstractInternalInstantiator {
private static final Map, Object> PREPARED_OBJECTS = new LinkedHashMap<>();
static {
@@ -58,9 +55,8 @@ class CollectionInstantiator extends AbstractObjectInstantiator {
PREPARED_OBJECTS.put(Iterable.class, new ArrayList<>());
}
- CollectionInstantiator(final Class> clazz,
- final MultiValuedMap, ConstructorParameters> constructorParameters) {
- super(clazz, constructorParameters);
+ CollectionInstantiator(final Class> clazz) {
+ super(clazz);
}
@Override
diff --git a/src/main/java/pl/pojo/tester/internal/instantiator/DefaultConstructorInstantiator.java b/src/main/java/pl/pojo/tester/internal/instantiator/DefaultConstructorInstantiator.java
index 0042159f..067c6861 100644
--- a/src/main/java/pl/pojo/tester/internal/instantiator/DefaultConstructorInstantiator.java
+++ b/src/main/java/pl/pojo/tester/internal/instantiator/DefaultConstructorInstantiator.java
@@ -1,19 +1,15 @@
package pl.pojo.tester.internal.instantiator;
-import org.apache.commons.collections4.MultiValuedMap;
-import pl.pojo.tester.api.ConstructorParameters;
-
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.Arrays;
-class DefaultConstructorInstantiator extends AbstractObjectInstantiator {
+class DefaultConstructorInstantiator extends AbstractInternalInstantiator {
- DefaultConstructorInstantiator(final Class> clazz,
- final MultiValuedMap, ConstructorParameters> constructorParameters) {
- super(clazz, constructorParameters);
+ DefaultConstructorInstantiator(final Class> clazz) {
+ super(clazz);
}
@Override
diff --git a/src/main/java/pl/pojo/tester/internal/instantiator/EnumInstantiator.java b/src/main/java/pl/pojo/tester/internal/instantiator/EnumInstantiator.java
index f17563b2..3625e22e 100644
--- a/src/main/java/pl/pojo/tester/internal/instantiator/EnumInstantiator.java
+++ b/src/main/java/pl/pojo/tester/internal/instantiator/EnumInstantiator.java
@@ -1,16 +1,12 @@
package pl.pojo.tester.internal.instantiator;
-import org.apache.commons.collections4.MultiValuedMap;
-import pl.pojo.tester.api.ConstructorParameters;
-
import java.util.Random;
-class EnumInstantiator extends AbstractObjectInstantiator {
+class EnumInstantiator extends AbstractInternalInstantiator {
- EnumInstantiator(final Class> clazz,
- final MultiValuedMap, ConstructorParameters> constructorParameters) {
- super(clazz, constructorParameters);
+ EnumInstantiator(final Class> clazz) {
+ super(clazz);
}
@Override
diff --git a/src/main/java/pl/pojo/tester/internal/instantiator/Instantiable.java b/src/main/java/pl/pojo/tester/internal/instantiator/Instantiable.java
index 8049da92..a5026eba 100644
--- a/src/main/java/pl/pojo/tester/internal/instantiator/Instantiable.java
+++ b/src/main/java/pl/pojo/tester/internal/instantiator/Instantiable.java
@@ -1,14 +1,14 @@
package pl.pojo.tester.internal.instantiator;
-import org.apache.commons.collections4.MultiValuedMap;
-import pl.pojo.tester.api.ConstructorParameters;
+import pl.pojo.tester.api.AbstractObjectInstantiator;
-import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
+import java.util.Optional;
+import java.util.function.Supplier;
public final class Instantiable {
@@ -16,7 +16,6 @@ public final class Instantiable {
static {
INSTANTIATORS = new LinkedList<>();
- INSTANTIATORS.add(UserDefinedConstructorInstantiator.class);
INSTANTIATORS.add(JavaTypeInstantiator.class);
INSTANTIATORS.add(CollectionInstantiator.class);
INSTANTIATORS.add(DefaultConstructorInstantiator.class);
@@ -30,38 +29,46 @@ private Instantiable() {
}
static Object[] instantiateClasses(final Class>[] classes,
- final MultiValuedMap, ConstructorParameters> constructorParameters) {
+ final List predefinedInstantiators) {
return Arrays.stream(classes)
- .map(clazz -> Instantiable.forClass(clazz, constructorParameters))
+ .map(clazz -> Instantiable.forClass(clazz, predefinedInstantiators))
.map(AbstractObjectInstantiator::instantiate)
.toArray();
}
static AbstractObjectInstantiator forClass(final Class> clazz,
- final MultiValuedMap, ConstructorParameters> constructorParameters) {
- return instantiateInstantiators(clazz, constructorParameters).stream()
- .filter(AbstractObjectInstantiator::canInstantiate)
- .findAny()
- .get();
+ final List predefinedInstantiators) {
+ return findPredefinedInstantiator(clazz, predefinedInstantiators)
+ .orElseGet(findFirstMatchingInstantiator(clazz, predefinedInstantiators));
}
- private static List instantiateInstantiators(final Class> clazz,
- final MultiValuedMap, ConstructorParameters> constructorParameters) {
- final List instantiators = new ArrayList<>();
- try {
- for (final Class extends AbstractObjectInstantiator> instantiator : INSTANTIATORS) {
- final Constructor extends AbstractObjectInstantiator> constructor =
- instantiator.getDeclaredConstructor(Class.class, MultiValuedMap.class);
- constructor.setAccessible(true);
- final AbstractObjectInstantiator abstractObjectInstantiator = constructor.newInstance(clazz,
- constructorParameters);
- instantiators.add(abstractObjectInstantiator);
- }
- } catch (final Exception e) {
- throw new RuntimeException("Cannot load instantiators form pl.pojo.tester.internal.instantiator package.",
- e);
- }
- return instantiators;
+ private static Supplier findFirstMatchingInstantiator(final Class> clazz,
+ final List predefinedInstantiators) {
+ return () -> instantiateInstantiators(clazz, predefinedInstantiators).stream()
+ .filter(AbstractInternalInstantiator::canInstantiate)
+ .findFirst()
+ .get();
+ }
+
+ private static Optional findPredefinedInstantiator(final Class> clazz,
+ final List predefinedInstantiators) {
+ return predefinedInstantiators.stream()
+ .filter(instantiator -> clazz.equals(instantiator.getClazz()))
+ .findFirst();
}
+ private static List instantiateInstantiators(final Class> clazz,
+ final List predefinedInstantiators) {
+ final List instantiators = new ArrayList<>();
+
+ instantiators.add(new JavaTypeInstantiator(clazz));
+ instantiators.add(new CollectionInstantiator(clazz));
+ instantiators.add(new DefaultConstructorInstantiator(clazz));
+ instantiators.add(new EnumInstantiator(clazz));
+ instantiators.add(new ArrayInstantiator(clazz));
+ instantiators.add(new ProxyInstantiator(clazz, predefinedInstantiators));
+ instantiators.add(new BestConstructorInstantiator(clazz, predefinedInstantiators));
+
+ return instantiators;
+ }
}
diff --git a/src/main/java/pl/pojo/tester/internal/instantiator/JavaTypeInstantiator.java b/src/main/java/pl/pojo/tester/internal/instantiator/JavaTypeInstantiator.java
index fa40e318..8cb8bd3c 100644
--- a/src/main/java/pl/pojo/tester/internal/instantiator/JavaTypeInstantiator.java
+++ b/src/main/java/pl/pojo/tester/internal/instantiator/JavaTypeInstantiator.java
@@ -1,9 +1,6 @@
package pl.pojo.tester.internal.instantiator;
-import org.apache.commons.collections4.MultiValuedMap;
-import pl.pojo.tester.api.ConstructorParameters;
-
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.Clock;
@@ -26,7 +23,7 @@
import java.util.Map;
import java.util.UUID;
-class JavaTypeInstantiator extends AbstractObjectInstantiator {
+class JavaTypeInstantiator extends AbstractInternalInstantiator {
private final Map preparedObjects = new HashMap<>();
@@ -76,9 +73,8 @@ class JavaTypeInstantiator extends AbstractObjectInstantiator {
preparedObjects.put(ZoneOffset.class.getName(), ZoneOffset.UTC);
}
- JavaTypeInstantiator(final Class> clazz,
- final MultiValuedMap, ConstructorParameters> constructorParameters) {
- super(clazz, constructorParameters);
+ JavaTypeInstantiator(final Class> clazz) {
+ super(clazz);
}
@Override
diff --git a/src/main/java/pl/pojo/tester/internal/instantiator/ObjectGenerator.java b/src/main/java/pl/pojo/tester/internal/instantiator/ObjectGenerator.java
index d3b1dab2..1e7d40fd 100644
--- a/src/main/java/pl/pojo/tester/internal/instantiator/ObjectGenerator.java
+++ b/src/main/java/pl/pojo/tester/internal/instantiator/ObjectGenerator.java
@@ -1,11 +1,10 @@
package pl.pojo.tester.internal.instantiator;
-import org.apache.commons.collections4.MultiValuedMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import pl.pojo.tester.api.AbstractObjectInstantiator;
import pl.pojo.tester.api.ClassAndFieldPredicatePair;
-import pl.pojo.tester.api.ConstructorParameters;
import pl.pojo.tester.internal.field.AbstractFieldValueChanger;
import pl.pojo.tester.internal.utils.FieldUtils;
import pl.pojo.tester.internal.utils.Permutator;
@@ -27,19 +26,19 @@ public class ObjectGenerator {
private static final Logger LOGGER = LoggerFactory.getLogger(ObjectGenerator.class);
private final AbstractFieldValueChanger abstractFieldValueChanger;
- private final MultiValuedMap, ConstructorParameters> constructorParameters;
+ private final List additionalInstantiators;
private final Permutator permutator;
public ObjectGenerator(final AbstractFieldValueChanger abstractFieldValueChanger,
- final MultiValuedMap, ConstructorParameters> constructorParameters,
+ final List additionalInstantiators,
final Permutator permutator) {
this.abstractFieldValueChanger = abstractFieldValueChanger;
- this.constructorParameters = constructorParameters;
+ this.additionalInstantiators = additionalInstantiators;
this.permutator = permutator;
}
public Object createNewInstance(final Class> clazz) {
- return Instantiable.forClass(clazz, constructorParameters)
+ return Instantiable.forClass(clazz, additionalInstantiators)
.instantiate();
}
diff --git a/src/main/java/pl/pojo/tester/internal/instantiator/ProxyInstantiator.java b/src/main/java/pl/pojo/tester/internal/instantiator/ProxyInstantiator.java
index bc215e1c..54e72446 100644
--- a/src/main/java/pl/pojo/tester/internal/instantiator/ProxyInstantiator.java
+++ b/src/main/java/pl/pojo/tester/internal/instantiator/ProxyInstantiator.java
@@ -2,16 +2,16 @@
import javassist.util.proxy.ProxyFactory;
-import org.apache.commons.collections4.MultiValuedMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import pl.pojo.tester.api.ConstructorParameters;
+import pl.pojo.tester.api.AbstractObjectInstantiator;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
+import java.util.List;
class ProxyInstantiator extends AbstractMultiConstructorInstantiator {
@@ -20,22 +20,21 @@ class ProxyInstantiator extends AbstractMultiConstructorInstantiator {
private final ProxyFactory proxyFactory = new ProxyFactory();
- ProxyInstantiator(final Class> clazz,
- final MultiValuedMap, ConstructorParameters> constructorParameters) {
- super(clazz, constructorParameters);
+ ProxyInstantiator(final Class> clazz, final List instantiators) {
+ super(clazz, instantiators);
}
@Override
public Object instantiate() {
- Object result = instantiateUsingUserParameters();
- if (result == null) {
- if (clazz.isAnnotation() || clazz.isInterface()) {
- result = proxyByJava();
- } else {
- proxyFactory.setSuperclass(clazz);
- result = createFindingBestConstructor();
- }
+ final Object result;
+
+ if (clazz.isAnnotation() || clazz.isInterface()) {
+ result = proxyByJava();
+ } else {
+ proxyFactory.setSuperclass(clazz);
+ result = createFindingBestConstructor();
}
+
return result;
}
diff --git a/src/main/java/pl/pojo/tester/internal/instantiator/SupplierInstantiator.java b/src/main/java/pl/pojo/tester/internal/instantiator/SupplierInstantiator.java
new file mode 100644
index 00000000..944c86f2
--- /dev/null
+++ b/src/main/java/pl/pojo/tester/internal/instantiator/SupplierInstantiator.java
@@ -0,0 +1,25 @@
+package pl.pojo.tester.internal.instantiator;
+
+import pl.pojo.tester.api.AbstractObjectInstantiator;
+
+import java.util.function.Supplier;
+
+public class SupplierInstantiator extends AbstractObjectInstantiator {
+
+ private final Supplier> supplier;
+
+ public SupplierInstantiator(final Class> clazz, final Supplier> supplier) {
+ super(clazz);
+ this.supplier = supplier;
+ }
+
+ @Override
+ public Object instantiate() {
+ return supplier.get();
+ }
+
+ @Override
+ public String toString() {
+ return "SupplierInstantiator{supplier=" + supplier + ", clazz=" + clazz + '}';
+ }
+}
diff --git a/src/main/java/pl/pojo/tester/internal/instantiator/UserDefinedConstructorInstantiator.java b/src/main/java/pl/pojo/tester/internal/instantiator/UserDefinedConstructorInstantiator.java
index 00657d72..9b36a593 100644
--- a/src/main/java/pl/pojo/tester/internal/instantiator/UserDefinedConstructorInstantiator.java
+++ b/src/main/java/pl/pojo/tester/internal/instantiator/UserDefinedConstructorInstantiator.java
@@ -1,55 +1,35 @@
package pl.pojo.tester.internal.instantiator;
-import org.apache.commons.collections4.MultiValuedMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import pl.pojo.tester.api.AbstractObjectInstantiator;
import pl.pojo.tester.api.ConstructorParameters;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.Arrays;
-import java.util.Objects;
+import java.util.LinkedList;
+import java.util.Optional;
import java.util.stream.Stream;
-class UserDefinedConstructorInstantiator extends AbstractObjectInstantiator {
+public class UserDefinedConstructorInstantiator extends AbstractObjectInstantiator {
private static final Logger LOGGER = LoggerFactory.getLogger(BestConstructorInstantiator.class);
+ private final ConstructorParameters constructorParameters;
- UserDefinedConstructorInstantiator(final Class> clazz,
- final MultiValuedMap, ConstructorParameters> constructorParameters) {
- super(clazz, constructorParameters);
+ public UserDefinedConstructorInstantiator(final Class> clazz, final ConstructorParameters constructorParameters) {
+ super(clazz);
+ this.constructorParameters = constructorParameters;
}
@Override
public Object instantiate() {
- return constructorParameters.get(clazz)
- .stream()
- .map(this::createObjectUsingConstructorParameters)
- .filter(Objects::nonNull)
- .findAny()
- .orElseThrow(this::createObjectInstantiationException);
+ return createObjectUsingConstructorParameters(constructorParameters)
+ .orElseThrow(this::createObjectInstantiationException);
}
- @Override
- public boolean canInstantiate() {
- return userDefinedConstructorParameters() && !qualifiesForProxy(clazz);
- }
-
- private boolean userDefinedConstructorParameters() {
- return constructorParameters.containsKey(clazz);
- }
-
- private boolean qualifiesForProxy(final Class> clazz) {
- return clazz.isInterface() || clazz.isAnnotation() || Modifier.isAbstract(clazz.getModifiers());
- }
-
- private ObjectInstantiationException createObjectInstantiationException() {
- return new ObjectInstantiationException(clazz,
- "Could not instantiate object by any user defined constructor types and parameters.");
- }
-
- private Object createObjectUsingConstructorParameters(final ConstructorParameters constructorParameters) {
+ private Optional