Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions spring-data-mock/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

<groupId>com.mmnaseri.utils</groupId>
<artifactId>spring-data-mock</artifactId>
<version>2.2.0</version>
<version>2.2.1</version>

<name>Spring Data Mock</name>
<description>A framework for mocking Spring Data repositories</description>
Expand Down Expand Up @@ -327,4 +327,4 @@
</profile>
</profiles>

</project>
</project>
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@
public interface KeyGeneratorAware<S> {

void setKeyGenerator(KeyGenerator<? extends S> keyGenerator);
void setKeyGenerationStrategy(KeyGenerationStrategy strategy);

}
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -64,6 +61,7 @@ public class RepositoryFactoryBuilder
private DataStoreEventListenerContext eventListenerContext;
private NonDataOperationInvocationHandler operationInvocationHandler;
private KeyGenerator<?> defaultKeyGenerator;
private KeyGenerationStrategy defaultKeyGenerationStrategy;

private RepositoryFactoryBuilder() {
metadataResolver = new DefaultRepositoryMetadataResolver();
Expand All @@ -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
Expand Down Expand Up @@ -251,17 +250,28 @@ public RepositoryFactoryConfiguration configure() {
typeMappingContext,
eventListenerContext,
operationInvocationHandler,
defaultKeyGenerator);
defaultKeyGenerator,
defaultKeyGenerationStrategy);
}

@Override
public <S> Implementation generateKeysUsing(KeyGenerator<S> keyGenerator) {
return new RepositoryMockBuilder().useFactory(build()).generateKeysUsing(keyGenerator);
return generateKeysUsing(keyGenerator, defaultKeyGenerationStrategy);
}

@Override
public <S> Implementation generateKeysUsing(KeyGenerator<S> keyGenerator, KeyGenerationStrategy keyGenerationStrategy) {
return new RepositoryMockBuilder().useFactory(build()).generateKeysUsing(keyGenerator, keyGenerationStrategy);
}

@Override
public <S, G extends KeyGenerator<S>> Implementation generateKeysUsing(Class<G> generatorType) {
return new RepositoryMockBuilder().useFactory(build()).generateKeysUsing(generatorType);
return generateKeysUsing(generatorType, defaultKeyGenerationStrategy);
}

@Override
public <S, G extends KeyGenerator<S>> Implementation generateKeysUsing(Class<G> generatorType, KeyGenerationStrategy keyGenerationStrategy) {
return new RepositoryMockBuilder().useFactory(build()).generateKeysUsing(generatorType, keyGenerationStrategy);
}

@Override
Expand Down Expand Up @@ -291,7 +301,8 @@ public static RepositoryFactoryConfiguration defaultConfiguration() {
builder.typeMappingContext,
builder.eventListenerContext,
builder.operationInvocationHandler,
builder.defaultKeyGenerator);
builder.defaultKeyGenerator,
builder.defaultKeyGenerationStrategy);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -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;

/**
Expand All @@ -19,6 +20,17 @@ public interface KeyGeneration extends Implementation {
*/
<S> Implementation generateKeysUsing(KeyGenerator<S> keyGenerator);

/**
* Sets the key generator to the provided instance
*
* @param keyGenerator the key generator
* @param keyGenerationStrategy the key generation strategy
* @param <S> the type of the keys
* @return the rest of the configuration
*/
<S> Implementation generateKeysUsing(
KeyGenerator<S> keyGenerator, KeyGenerationStrategy keyGenerationStrategy);

/**
* Sets the key generator to an instance of the provided type.
*
Expand All @@ -29,6 +41,18 @@ public interface KeyGeneration extends Implementation {
*/
<S, G extends KeyGenerator<S>> Implementation generateKeysUsing(Class<G> 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 <S> the type of the keys the generator will be generating
* @param <G> the type of the generator
* @return the rest of the configuration
*/
<S, G extends KeyGenerator<S>> Implementation generateKeysUsing(
Class<G> generatorType, KeyGenerationStrategy keyGenerationStrategy);

/**
* Tells the builder that we are not going to have any auto-generated keys
*
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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.
Expand All @@ -23,34 +25,36 @@ public class RepositoryMockBuilder implements Start, ImplementationAnd, KeyGener
private final RepositoryFactory factory;
private final List<Class<?>> 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<Class<?>> implementations, KeyGenerator<?> keyGenerator) {
RepositoryFactory factory, List<Class<?>> 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<Class<?>> implementations = new LinkedList<>(this.implementations);
implementations.add(implementation);
return new RepositoryMockBuilder(factory, implementations, keyGenerator);
return new RepositoryMockBuilder(factory, implementations, keyGenerator, keyGenerationStrategy);
}

@Override
Expand All @@ -60,19 +64,29 @@ public ImplementationAnd and(Class<?> implementation) {

@Override
public <S> Implementation generateKeysUsing(KeyGenerator<S> keyGenerator) {
return new RepositoryMockBuilder(factory, implementations, keyGenerator);
return generateKeysUsing(keyGenerator, keyGenerationStrategy);
}

@Override
public <S> Implementation generateKeysUsing(KeyGenerator<S> keyGenerator, KeyGenerationStrategy keyGenerationStrategy) {
return new RepositoryMockBuilder(factory, implementations, keyGenerator, keyGenerationStrategy);
}

@Override
public <S, G extends KeyGenerator<S>> Implementation generateKeysUsing(Class<G> generatorType) {
return generateKeysUsing(generatorType, keyGenerationStrategy);
}

@Override
public <S, G extends KeyGenerator<S>> Implementation generateKeysUsing(Class<G> 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) {
Expand Down Expand Up @@ -108,10 +122,10 @@ public <E> E mock(Class<E> 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]));
}
}
}
Original file line number Diff line number Diff line change
@@ -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;

/**
Expand All @@ -26,9 +27,30 @@ public interface RepositoryFactory {
* @param <E> 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> E getInstance(
KeyGenerator<?> keyGenerator, Class<E> 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 <E> 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> E getInstance(
KeyGenerator<?> keyGenerator, Class<E> repositoryInterface, Class... implementations);
KeyGenerator<?> keyGenerator, KeyGenerationStrategy keyGenerationStrategy, Class<E> repositoryInterface, Class... implementations);

/** @return the configuration bound to this repository factory */
RepositoryFactoryConfiguration getConfiguration();
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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();
}
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -73,7 +67,7 @@ public DefaultRepositoryFactory(RepositoryFactoryConfiguration configuration) {

@Override
public <E> E getInstance(
KeyGenerator<?> keyGenerator, Class<E> repositoryInterface, Class... implementations) {
KeyGenerator<?> keyGenerator, KeyGenerationStrategy keyGenerationStrategy, Class<E> repositoryInterface, Class... implementations) {
final KeyGenerator<?> actualKeyGenerator;
if (keyGenerator == null) {
if (configuration.getDefaultKeyGenerator() != null) {
Expand All @@ -87,6 +81,19 @@ public <E> 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
Expand All @@ -104,7 +111,7 @@ public <E> E getInstance(
log.info(
"Trying to find all the proper type mappings for entity repository " + repositoryInterface);
final List<TypeMapping<?>> typeMappings =
getTypeMappings(metadata, dataStore, actualKeyGenerator, implementations);
getTypeMappings(metadata, dataStore, actualKeyGenerator, actualKeyGenerationStrategy, implementations);
// set up the data operation resolver
final DataOperationResolver operationResolver =
new DefaultDataOperationResolver(
Expand Down Expand Up @@ -176,13 +183,15 @@ 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
*/
private List<TypeMapping<?>> getTypeMappings(
RepositoryMetadata metadata,
DataStore<Object, ?> dataStore,
KeyGenerator<?> keyGenerator,
KeyGenerationStrategy keyGenerationStrategy,
Class[] implementations) {
final TypeMappingContext localContext = new DefaultTypeMappingContext(typeMappingContext);
for (Class implementation : implementations) {
Expand All @@ -203,6 +212,7 @@ private List<TypeMapping<?>> getTypeMappings(
KeyGeneratorAware instance = (KeyGeneratorAware) mapping.getInstance();
//noinspection unchecked
instance.setKeyGenerator(keyGenerator);
instance.setKeyGenerationStrategy(keyGenerationStrategy);
}
if (mapping.getInstance() instanceof RepositoryFactoryConfigurationAware) {
RepositoryFactoryConfigurationAware instance =
Expand Down
Loading