diff --git a/spring-data-mock/pom.xml b/spring-data-mock/pom.xml
index cc6e1c95..34c246e7 100644
--- a/spring-data-mock/pom.xml
+++ b/spring-data-mock/pom.xml
@@ -27,7 +27,7 @@
com.mmnaseri.utils
spring-data-mock
- 2.2.0
+ 2.2.1
Spring Data Mock
A framework for mocking Spring Data repositories
@@ -327,4 +327,4 @@
-
\ No newline at end of file
+
diff --git a/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/domain/KeyGenerationStrategy.java b/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/domain/KeyGenerationStrategy.java
new file mode 100644
index 00000000..2e380374
--- /dev/null
+++ b/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/domain/KeyGenerationStrategy.java
@@ -0,0 +1,14 @@
+package com.mmnaseri.utils.spring.data.domain;
+
+public enum KeyGenerationStrategy {
+ /**
+ * Generate a key for {@code null} id values only.
+ */
+ ONLY_NULL,
+
+ /**
+ * Generate a key for all "unmanaged" entites.
+ * Regardless of whether an ID value exists or not.
+ */
+ ALL_UNMANAGED
+}
diff --git a/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/domain/KeyGeneratorAware.java b/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/domain/KeyGeneratorAware.java
index a72f4a10..17dd7c80 100644
--- a/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/domain/KeyGeneratorAware.java
+++ b/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/domain/KeyGeneratorAware.java
@@ -10,4 +10,6 @@
public interface KeyGeneratorAware {
void setKeyGenerator(KeyGenerator extends S> keyGenerator);
+ void setKeyGenerationStrategy(KeyGenerationStrategy strategy);
+
}
diff --git a/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/dsl/factory/RepositoryFactoryBuilder.java b/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/dsl/factory/RepositoryFactoryBuilder.java
index 48af1d96..0cc0f7ce 100644
--- a/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/dsl/factory/RepositoryFactoryBuilder.java
+++ b/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/dsl/factory/RepositoryFactoryBuilder.java
@@ -1,9 +1,6 @@
package com.mmnaseri.utils.spring.data.dsl.factory;
-import com.mmnaseri.utils.spring.data.domain.KeyGenerator;
-import com.mmnaseri.utils.spring.data.domain.Operator;
-import com.mmnaseri.utils.spring.data.domain.OperatorContext;
-import com.mmnaseri.utils.spring.data.domain.RepositoryMetadataResolver;
+import com.mmnaseri.utils.spring.data.domain.*;
import com.mmnaseri.utils.spring.data.domain.impl.DefaultOperatorContext;
import com.mmnaseri.utils.spring.data.domain.impl.DefaultRepositoryMetadataResolver;
import com.mmnaseri.utils.spring.data.domain.impl.MethodQueryDescriptionExtractor;
@@ -64,6 +61,7 @@ public class RepositoryFactoryBuilder
private DataStoreEventListenerContext eventListenerContext;
private NonDataOperationInvocationHandler operationInvocationHandler;
private KeyGenerator> defaultKeyGenerator;
+ private KeyGenerationStrategy defaultKeyGenerationStrategy;
private RepositoryFactoryBuilder() {
metadataResolver = new DefaultRepositoryMetadataResolver();
@@ -76,6 +74,7 @@ private RepositoryFactoryBuilder() {
operationInvocationHandler = new NonDataOperationInvocationHandler();
// by default, we do not want any key generator, unless one is specified
defaultKeyGenerator = null;
+ defaultKeyGenerationStrategy = KeyGenerationStrategy.ONLY_NULL;
}
@Override
@@ -251,17 +250,28 @@ public RepositoryFactoryConfiguration configure() {
typeMappingContext,
eventListenerContext,
operationInvocationHandler,
- defaultKeyGenerator);
+ defaultKeyGenerator,
+ defaultKeyGenerationStrategy);
}
@Override
public Implementation generateKeysUsing(KeyGenerator keyGenerator) {
- return new RepositoryMockBuilder().useFactory(build()).generateKeysUsing(keyGenerator);
+ return generateKeysUsing(keyGenerator, defaultKeyGenerationStrategy);
+ }
+
+ @Override
+ public Implementation generateKeysUsing(KeyGenerator keyGenerator, KeyGenerationStrategy keyGenerationStrategy) {
+ return new RepositoryMockBuilder().useFactory(build()).generateKeysUsing(keyGenerator, keyGenerationStrategy);
}
@Override
public > Implementation generateKeysUsing(Class generatorType) {
- return new RepositoryMockBuilder().useFactory(build()).generateKeysUsing(generatorType);
+ return generateKeysUsing(generatorType, defaultKeyGenerationStrategy);
+ }
+
+ @Override
+ public > Implementation generateKeysUsing(Class generatorType, KeyGenerationStrategy keyGenerationStrategy) {
+ return new RepositoryMockBuilder().useFactory(build()).generateKeysUsing(generatorType, keyGenerationStrategy);
}
@Override
@@ -291,7 +301,8 @@ public static RepositoryFactoryConfiguration defaultConfiguration() {
builder.typeMappingContext,
builder.eventListenerContext,
builder.operationInvocationHandler,
- builder.defaultKeyGenerator);
+ builder.defaultKeyGenerator,
+ builder.defaultKeyGenerationStrategy);
}
/**
diff --git a/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/dsl/mock/KeyGeneration.java b/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/dsl/mock/KeyGeneration.java
index 979904a8..20b58951 100644
--- a/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/dsl/mock/KeyGeneration.java
+++ b/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/dsl/mock/KeyGeneration.java
@@ -1,5 +1,6 @@
package com.mmnaseri.utils.spring.data.dsl.mock;
+import com.mmnaseri.utils.spring.data.domain.KeyGenerationStrategy;
import com.mmnaseri.utils.spring.data.domain.KeyGenerator;
/**
@@ -19,6 +20,17 @@ public interface KeyGeneration extends Implementation {
*/
Implementation generateKeysUsing(KeyGenerator keyGenerator);
+ /**
+ * Sets the key generator to the provided instance
+ *
+ * @param keyGenerator the key generator
+ * @param keyGenerationStrategy the key generation strategy
+ * @param the type of the keys
+ * @return the rest of the configuration
+ */
+ Implementation generateKeysUsing(
+ KeyGenerator keyGenerator, KeyGenerationStrategy keyGenerationStrategy);
+
/**
* Sets the key generator to an instance of the provided type.
*
@@ -29,6 +41,18 @@ public interface KeyGeneration extends Implementation {
*/
> Implementation generateKeysUsing(Class generatorType);
+ /**
+ * Sets the key generator to an instance of the provided type.
+ *
+ * @param generatorType the type of the key generator to use
+ * @param keyGenerationStrategy the key generation strategy
+ * @param the type of the keys the generator will be generating
+ * @param the type of the generator
+ * @return the rest of the configuration
+ */
+ > Implementation generateKeysUsing(
+ Class generatorType, KeyGenerationStrategy keyGenerationStrategy);
+
/**
* Tells the builder that we are not going to have any auto-generated keys
*
diff --git a/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/dsl/mock/RepositoryMockBuilder.java b/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/dsl/mock/RepositoryMockBuilder.java
index 15a885c3..be5e45e6 100644
--- a/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/dsl/mock/RepositoryMockBuilder.java
+++ b/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/dsl/mock/RepositoryMockBuilder.java
@@ -1,5 +1,6 @@
package com.mmnaseri.utils.spring.data.dsl.mock;
+import com.mmnaseri.utils.spring.data.domain.KeyGenerationStrategy;
import com.mmnaseri.utils.spring.data.domain.KeyGenerator;
import com.mmnaseri.utils.spring.data.domain.RepositoryMetadata;
import com.mmnaseri.utils.spring.data.domain.impl.key.NoOpKeyGenerator;
@@ -11,6 +12,7 @@
import java.util.LinkedList;
import java.util.List;
+import java.util.Optional;
/**
* This class implements the interfaces used to define a DSL for mocking a repository.
@@ -23,34 +25,36 @@ public class RepositoryMockBuilder implements Start, ImplementationAnd, KeyGener
private final RepositoryFactory factory;
private final List> implementations;
private final KeyGenerator> keyGenerator;
+ private final KeyGenerationStrategy keyGenerationStrategy;
public RepositoryMockBuilder() {
- this(null, new LinkedList<>(), null);
+ this(null, new LinkedList<>(), null, null);
}
private RepositoryMockBuilder(
- RepositoryFactory factory, List> implementations, KeyGenerator> keyGenerator) {
+ RepositoryFactory factory, List> implementations, KeyGenerator> keyGenerator, KeyGenerationStrategy keyGenerationStrategy) {
this.factory = factory;
this.implementations = implementations;
this.keyGenerator = keyGenerator;
+ this.keyGenerationStrategy = keyGenerationStrategy;
}
@Override
public KeyGeneration useConfiguration(RepositoryFactoryConfiguration configuration) {
return new RepositoryMockBuilder(
- new DefaultRepositoryFactory(configuration), implementations, keyGenerator);
+ new DefaultRepositoryFactory(configuration), implementations, keyGenerator, keyGenerationStrategy);
}
@Override
public KeyGeneration useFactory(RepositoryFactory factory) {
- return new RepositoryMockBuilder(factory, implementations, keyGenerator);
+ return new RepositoryMockBuilder(factory, implementations, keyGenerator, keyGenerationStrategy);
}
@Override
public ImplementationAnd usingImplementation(Class> implementation) {
final LinkedList> implementations = new LinkedList<>(this.implementations);
implementations.add(implementation);
- return new RepositoryMockBuilder(factory, implementations, keyGenerator);
+ return new RepositoryMockBuilder(factory, implementations, keyGenerator, keyGenerationStrategy);
}
@Override
@@ -60,19 +64,29 @@ public ImplementationAnd and(Class> implementation) {
@Override
public Implementation generateKeysUsing(KeyGenerator keyGenerator) {
- return new RepositoryMockBuilder(factory, implementations, keyGenerator);
+ return generateKeysUsing(keyGenerator, keyGenerationStrategy);
+ }
+
+ @Override
+ public Implementation generateKeysUsing(KeyGenerator keyGenerator, KeyGenerationStrategy keyGenerationStrategy) {
+ return new RepositoryMockBuilder(factory, implementations, keyGenerator, keyGenerationStrategy);
}
@Override
public > Implementation generateKeysUsing(Class generatorType) {
+ return generateKeysUsing(generatorType, keyGenerationStrategy);
+ }
+
+ @Override
+ public > Implementation generateKeysUsing(Class generatorType, KeyGenerationStrategy keyGenerationStrategy) {
//noinspection unchecked
final G instance = (G) createKeyGenerator(generatorType);
- return generateKeysUsing(instance);
+ return generateKeysUsing(instance, keyGenerationStrategy);
}
@Override
public Implementation withoutGeneratingKeys() {
- return new RepositoryMockBuilder(factory, implementations, new NoOpKeyGenerator<>());
+ return new RepositoryMockBuilder(factory, implementations, new NoOpKeyGenerator<>(), keyGenerationStrategy);
}
private KeyGenerator> createKeyGenerator(Class extends KeyGenerator> generatorType) {
@@ -108,10 +122,10 @@ public E mock(Class repositoryInterface) {
generatorProvider.getKeyGenerator(identifierType);
evaluatedKeyGenerator = createKeyGenerator(keyGeneratorType);
}
- return generateKeysUsing(evaluatedKeyGenerator).mock(repositoryInterface);
+ return generateKeysUsing(evaluatedKeyGenerator, keyGenerationStrategy).mock(repositoryInterface);
} else {
return repositoryFactory.getInstance(
- keyGenerator, repositoryInterface, implementations.toArray(new Class[0]));
+ keyGenerator, keyGenerationStrategy, repositoryInterface, implementations.toArray(new Class[0]));
}
}
}
diff --git a/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/proxy/RepositoryFactory.java b/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/proxy/RepositoryFactory.java
index c0c893f4..35b20bfe 100644
--- a/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/proxy/RepositoryFactory.java
+++ b/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/proxy/RepositoryFactory.java
@@ -1,5 +1,6 @@
package com.mmnaseri.utils.spring.data.proxy;
+import com.mmnaseri.utils.spring.data.domain.KeyGenerationStrategy;
import com.mmnaseri.utils.spring.data.domain.KeyGenerator;
/**
@@ -26,9 +27,30 @@ public interface RepositoryFactory {
* @param the type of the interface
* @return a prepared instance of the repository
* @throws com.mmnaseri.utils.spring.data.error.RepositoryMockException should anything go wrong
+ * @deprecated Use {@link #getInstance(KeyGenerator, KeyGenerationStrategy, Class, Class[])} instead.
+ */
+ @Deprecated
+ default E getInstance(
+ KeyGenerator> keyGenerator, Class repositoryInterface, Class... implementations) {
+ return getInstance(keyGenerator, KeyGenerationStrategy.ONLY_NULL, repositoryInterface, implementations);
+ }
+
+ /**
+ * Creates an instance of the repository as per the provided configuration.
+ *
+ * @param keyGenerator the key generator to use when inserting items (if auto generation is
+ * required). You can specify a {@literal null} key generator to signify that {@link
+ * RepositoryFactoryConfiguration#getDefaultKeyGenerator() the fallback key generator} should
+ * be used when generating keys.
+ * @param keyGenerationStrategy the strategy when and for which entities a key should be generated.
+ * @param repositoryInterface the repository interface which we want to mock
+ * @param implementations all the concrete classes that can be used to figure out method mappings
+ * @param the type of the interface
+ * @return a prepared instance of the repository
+ * @throws com.mmnaseri.utils.spring.data.error.RepositoryMockException should anything go wrong
*/
E getInstance(
- KeyGenerator> keyGenerator, Class repositoryInterface, Class... implementations);
+ KeyGenerator> keyGenerator, KeyGenerationStrategy keyGenerationStrategy, Class repositoryInterface, Class... implementations);
/** @return the configuration bound to this repository factory */
RepositoryFactoryConfiguration getConfiguration();
diff --git a/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/proxy/RepositoryFactoryConfiguration.java b/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/proxy/RepositoryFactoryConfiguration.java
index a531d9f7..eb7383fd 100644
--- a/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/proxy/RepositoryFactoryConfiguration.java
+++ b/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/proxy/RepositoryFactoryConfiguration.java
@@ -1,5 +1,6 @@
package com.mmnaseri.utils.spring.data.proxy;
+import com.mmnaseri.utils.spring.data.domain.KeyGenerationStrategy;
import com.mmnaseri.utils.spring.data.domain.KeyGenerator;
import com.mmnaseri.utils.spring.data.domain.RepositoryMetadataResolver;
import com.mmnaseri.utils.spring.data.domain.impl.MethodQueryDescriptionExtractor;
@@ -46,4 +47,10 @@ public interface RepositoryFactoryConfiguration {
* specified
*/
KeyGenerator> getDefaultKeyGenerator();
+
+ /**
+ * @return the default key generation strategy that should be used as a fallback when no strategy is
+ * specified
+ */
+ KeyGenerationStrategy getDefaultKeyGenerationStrategy();
}
diff --git a/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/proxy/impl/DefaultRepositoryFactory.java b/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/proxy/impl/DefaultRepositoryFactory.java
index c55cf458..be923e92 100644
--- a/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/proxy/impl/DefaultRepositoryFactory.java
+++ b/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/proxy/impl/DefaultRepositoryFactory.java
@@ -1,12 +1,6 @@
package com.mmnaseri.utils.spring.data.proxy.impl;
-import com.mmnaseri.utils.spring.data.domain.DataStoreAware;
-import com.mmnaseri.utils.spring.data.domain.KeyGenerator;
-import com.mmnaseri.utils.spring.data.domain.KeyGeneratorAware;
-import com.mmnaseri.utils.spring.data.domain.RepositoryAware;
-import com.mmnaseri.utils.spring.data.domain.RepositoryMetadata;
-import com.mmnaseri.utils.spring.data.domain.RepositoryMetadataAware;
-import com.mmnaseri.utils.spring.data.domain.RepositoryMetadataResolver;
+import com.mmnaseri.utils.spring.data.domain.*;
import com.mmnaseri.utils.spring.data.domain.impl.MethodQueryDescriptionExtractor;
import com.mmnaseri.utils.spring.data.domain.impl.key.NoOpKeyGenerator;
import com.mmnaseri.utils.spring.data.proxy.DataOperationResolver;
@@ -73,7 +67,7 @@ public DefaultRepositoryFactory(RepositoryFactoryConfiguration configuration) {
@Override
public E getInstance(
- KeyGenerator> keyGenerator, Class repositoryInterface, Class... implementations) {
+ KeyGenerator> keyGenerator, KeyGenerationStrategy keyGenerationStrategy, Class repositoryInterface, Class... implementations) {
final KeyGenerator> actualKeyGenerator;
if (keyGenerator == null) {
if (configuration.getDefaultKeyGenerator() != null) {
@@ -87,6 +81,19 @@ public E getInstance(
} else {
actualKeyGenerator = keyGenerator;
}
+ final KeyGenerationStrategy actualKeyGenerationStrategy;
+ if (keyGenerationStrategy == null) {
+ if (configuration.getDefaultKeyGenerator() != null) {
+ // if no key generation strategy is passed and there is a default strategy specified, we
+ // fall back to that
+ actualKeyGenerationStrategy = configuration.getDefaultKeyGenerationStrategy();
+ } else {
+ // otherwise, fall back to ONLY_NULL
+ actualKeyGenerationStrategy = KeyGenerationStrategy.ONLY_NULL;
+ }
+ } else {
+ actualKeyGenerationStrategy = keyGenerationStrategy;
+ }
log.info(
"We are going to create a proxy instance of type "
+ repositoryInterface
@@ -104,7 +111,7 @@ public E getInstance(
log.info(
"Trying to find all the proper type mappings for entity repository " + repositoryInterface);
final List> typeMappings =
- getTypeMappings(metadata, dataStore, actualKeyGenerator, implementations);
+ getTypeMappings(metadata, dataStore, actualKeyGenerator, actualKeyGenerationStrategy, implementations);
// set up the data operation resolver
final DataOperationResolver operationResolver =
new DefaultDataOperationResolver(
@@ -176,6 +183,7 @@ public RepositoryFactoryConfiguration getConfiguration() {
* @param metadata the repository metadata
* @param dataStore the data store
* @param keyGenerator the key generator
+ * @param keyGenerationStrategy
* @param implementations the implementations specified by the user
* @return the resolved list of type mappings
*/
@@ -183,6 +191,7 @@ private List> getTypeMappings(
RepositoryMetadata metadata,
DataStore