Compare commits
19 Commits
issue/4491
...
3.0.1.RELE
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
88e60070d6 | ||
|
|
6c7039580f | ||
|
|
fba003f215 | ||
|
|
1a3239554c | ||
|
|
37b541931d | ||
|
|
9038280f68 | ||
|
|
75935a2bdb | ||
|
|
d9ca3d7eb3 | ||
|
|
04e77ad5ab | ||
|
|
0ab39a17a7 | ||
|
|
49a6f13797 | ||
|
|
b0fd6f691b | ||
|
|
b5778772d9 | ||
|
|
0f55fb305d | ||
|
|
5ae7547465 | ||
|
|
cf4e04a30e | ||
|
|
89c1dc77d9 | ||
|
|
a2c842b59b | ||
|
|
0cd0be9478 |
10
Jenkinsfile
vendored
10
Jenkinsfile
vendored
@@ -3,7 +3,7 @@ pipeline {
|
||||
|
||||
triggers {
|
||||
pollSCM 'H/10 * * * *'
|
||||
upstream(upstreamProjects: "spring-data-commons/master", threshold: hudson.model.Result.SUCCESS)
|
||||
upstream(upstreamProjects: "spring-data-commons/2.3.x", threshold: hudson.model.Result.SUCCESS)
|
||||
}
|
||||
|
||||
options {
|
||||
@@ -68,7 +68,7 @@ pipeline {
|
||||
stage("test: baseline (jdk8)") {
|
||||
when {
|
||||
anyOf {
|
||||
branch 'master'
|
||||
branch '3.0.x'
|
||||
not { triggeredBy 'UpstreamCause' }
|
||||
}
|
||||
}
|
||||
@@ -94,7 +94,7 @@ pipeline {
|
||||
stage("Test other configurations") {
|
||||
when {
|
||||
anyOf {
|
||||
branch 'master'
|
||||
branch '3.0.x'
|
||||
not { triggeredBy 'UpstreamCause' }
|
||||
}
|
||||
}
|
||||
@@ -164,7 +164,7 @@ pipeline {
|
||||
stage('Release to artifactory') {
|
||||
when {
|
||||
anyOf {
|
||||
branch 'master'
|
||||
branch '3.0.x'
|
||||
not { triggeredBy 'UpstreamCause' }
|
||||
}
|
||||
}
|
||||
@@ -196,7 +196,7 @@ pipeline {
|
||||
|
||||
stage('Publish documentation') {
|
||||
when {
|
||||
branch 'master'
|
||||
branch '3.0.x'
|
||||
}
|
||||
agent {
|
||||
docker {
|
||||
|
||||
8
pom.xml
8
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>3.0.0.RELEASE</version>
|
||||
<version>3.0.1.RELEASE</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Spring Data MongoDB</name>
|
||||
@@ -15,7 +15,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data.build</groupId>
|
||||
<artifactId>spring-data-parent</artifactId>
|
||||
<version>2.3.0.RELEASE</version>
|
||||
<version>2.3.1.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
@@ -26,8 +26,8 @@
|
||||
<properties>
|
||||
<project.type>multi</project.type>
|
||||
<dist.id>spring-data-mongodb</dist.id>
|
||||
<springdata.commons>2.3.0.RELEASE</springdata.commons>
|
||||
<mongo>4.0.3</mongo>
|
||||
<springdata.commons>2.3.1.RELEASE</springdata.commons>
|
||||
<mongo>4.0.4</mongo>
|
||||
<mongo.reactivestreams>${mongo}</mongo.reactivestreams>
|
||||
<jmh.version>1.19</jmh.version>
|
||||
</properties>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>3.0.0.RELEASE</version>
|
||||
<version>3.0.1.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>3.0.0.RELEASE</version>
|
||||
<version>3.0.1.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>3.0.0.RELEASE</version>
|
||||
<version>3.0.1.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -254,7 +254,7 @@ public abstract class MongoDatabaseFactorySupport<C> implements MongoDatabaseFac
|
||||
factory.addAdvice(new SessionAwareMethodInterceptor<>(session, target, ClientSession.class, MongoDatabase.class,
|
||||
this::proxyDatabase, MongoCollection.class, this::proxyCollection));
|
||||
|
||||
return targetType.cast(factory.getProxy());
|
||||
return targetType.cast(factory.getProxy(target.getClass().getClassLoader()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@ public class SimpleReactiveMongoDatabaseFactory implements DisposableBean, React
|
||||
factory.addAdvice(new SessionAwareMethodInterceptor<>(session, target, ClientSession.class, MongoDatabase.class,
|
||||
this::proxyDatabase, MongoCollection.class, this::proxyCollection));
|
||||
|
||||
return targetType.cast(factory.getProxy());
|
||||
return targetType.cast(factory.getProxy(target.getClass().getClassLoader()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,7 +202,7 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
||||
proxyFactory.addInterface(propertyType);
|
||||
proxyFactory.addAdvice(interceptor);
|
||||
|
||||
return handler.populateId(property, dbref, proxyFactory.getProxy());
|
||||
return handler.populateId(property, dbref, proxyFactory.getProxy(LazyLoadingProxy.class.getClassLoader()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -965,7 +965,7 @@ public class QueryMapper {
|
||||
this.entity = entity;
|
||||
this.mappingContext = context;
|
||||
|
||||
this.path = getPath(removePlaceholders(POSITIONAL_PARAMETER_PATTERN, name));
|
||||
this.path = getPath(removePlaceholders(POSITIONAL_PARAMETER_PATTERN, name), property);
|
||||
this.property = path == null ? property : path.getLeafProperty();
|
||||
this.association = findAssociation();
|
||||
}
|
||||
@@ -1079,11 +1079,17 @@ public class QueryMapper {
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
private PersistentPropertyPath<MongoPersistentProperty> getPath(String pathExpression) {
|
||||
private PersistentPropertyPath<MongoPersistentProperty> getPath(String pathExpression,
|
||||
@Nullable MongoPersistentProperty sourceProperty) {
|
||||
|
||||
String rawPath = removePlaceholders(POSITIONAL_OPERATOR,
|
||||
removePlaceholders(DOT_POSITIONAL_PATTERN, pathExpression));
|
||||
|
||||
if (sourceProperty != null && sourceProperty.getOwner().equals(entity)) {
|
||||
return mappingContext
|
||||
.getPersistentPropertyPath(PropertyPath.from(sourceProperty.getName(), entity.getTypeInformation()));
|
||||
}
|
||||
|
||||
PropertyPath path = forName(rawPath);
|
||||
if (path == null || isPathToJavaLangClassProperty(path)) {
|
||||
return null;
|
||||
|
||||
@@ -164,7 +164,7 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
|
||||
@Override
|
||||
public org.springframework.data.mongodb.core.query.Collation getCollation() {
|
||||
|
||||
Object collationValue = collationExpression != null ? expression.getValue(getEvaluationContext(null), String.class)
|
||||
Object collationValue = collationExpression != null ? collationExpression.getValue(getEvaluationContext(null), String.class)
|
||||
: this.collation;
|
||||
|
||||
if (collationValue == null) {
|
||||
|
||||
@@ -61,7 +61,7 @@ class QueryUtils {
|
||||
return combinedSort;
|
||||
});
|
||||
|
||||
return (Query) factory.getProxy();
|
||||
return (Query) factory.getProxy(query.getClass().getClassLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.util.ReactiveWrapperConverters;
|
||||
import org.springframework.data.repository.util.ReactiveWrappers;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
@@ -50,6 +51,7 @@ public class ReactiveMongoQueryMethod extends MongoQueryMethod {
|
||||
private static final ClassTypeInformation<Slice> SLICE_TYPE = ClassTypeInformation.from(Slice.class);
|
||||
|
||||
private final Method method;
|
||||
private final Lazy<Boolean> isCollectionQuery;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ReactiveMongoQueryMethod} from the given {@link Method}.
|
||||
@@ -87,11 +89,13 @@ public class ReactiveMongoQueryMethod extends MongoQueryMethod {
|
||||
|
||||
if (hasParameterOfType(method, Sort.class)) {
|
||||
throw new IllegalStateException(String.format("Method must not have Pageable *and* Sort parameter. "
|
||||
+ "Use sorting capabilities on Pageble instead! Offending method: %s", method.toString()));
|
||||
+ "Use sorting capabilities on Pageable instead! Offending method: %s", method.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
this.method = method;
|
||||
this.isCollectionQuery = Lazy.of(() -> !(isPageQuery() || isSliceQuery())
|
||||
&& ReactiveWrappers.isMultiValueType(metadata.getReturnType(method).getType()));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -109,7 +113,7 @@ public class ReactiveMongoQueryMethod extends MongoQueryMethod {
|
||||
*/
|
||||
@Override
|
||||
public boolean isCollectionQuery() {
|
||||
return !(isPageQuery() || isSliceQuery()) && ReactiveWrappers.isMultiValueType(method.getReturnType());
|
||||
return isCollectionQuery.get();
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.bson.Document;
|
||||
import org.bson.Transformer;
|
||||
import org.bson.codecs.*;
|
||||
import org.bson.codecs.configuration.CodecRegistry;
|
||||
import org.bson.json.JsonParseException;
|
||||
import org.springframework.data.spel.EvaluationContextProvider;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -175,6 +176,7 @@ public class ParameterBindingDocumentCodec implements CollectibleCodec<Document>
|
||||
return this.decode(reader, DecoderContext.builder().build());
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Override
|
||||
public Document decode(final BsonReader reader, final DecoderContext decoderContext) {
|
||||
|
||||
@@ -190,9 +192,27 @@ public class ParameterBindingDocumentCodec implements CollectibleCodec<Document>
|
||||
|
||||
Document document = new Document();
|
||||
reader.readStartDocument();
|
||||
while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) {
|
||||
String fieldName = reader.readName();
|
||||
document.put(fieldName, readValue(reader, decoderContext));
|
||||
|
||||
try {
|
||||
|
||||
while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) {
|
||||
String fieldName = reader.readName();
|
||||
Object value = readValue(reader, decoderContext);
|
||||
document.put(fieldName, value);
|
||||
}
|
||||
} catch (JsonParseException e) {
|
||||
try {
|
||||
|
||||
Object value = readValue(reader, decoderContext);
|
||||
if (value instanceof Map<?, ?>) {
|
||||
if (!((Map) value).isEmpty()) {
|
||||
return new Document((Map<String, Object>) value);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
e.addSuppressed(ex);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
reader.readEndDocument();
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Matcher;
|
||||
@@ -370,26 +371,33 @@ public class ParameterBindingJsonReader extends AbstractBsonReader {
|
||||
|
||||
if (token.getType().equals(JsonTokenType.UNQUOTED_STRING)) {
|
||||
|
||||
if (matcher.find()) {
|
||||
|
||||
int index = computeParameterIndex(matcher.group());
|
||||
bindableValue.setValue(getBindableValueForIndex(index));
|
||||
bindableValue.setType(bsonTypeForValue(getBindableValueForIndex(index)));
|
||||
return bindableValue;
|
||||
}
|
||||
|
||||
Matcher regexMatcher = EXPRESSION_BINDING_PATTERN.matcher(tokenValue);
|
||||
if (regexMatcher.find()) {
|
||||
|
||||
String binding = regexMatcher.group();
|
||||
String expression = binding.substring(3, binding.length() - 1);
|
||||
|
||||
Matcher inSpelMatcher = PARAMETER_BINDING_PATTERN.matcher(expression);
|
||||
while (inSpelMatcher.find()) {
|
||||
|
||||
int index = computeParameterIndex(inSpelMatcher.group());
|
||||
expression = expression.replace(inSpelMatcher.group(), getBindableValueForIndex(index).toString());
|
||||
}
|
||||
|
||||
Object value = evaluateExpression(expression);
|
||||
bindableValue.setValue(value);
|
||||
bindableValue.setType(bsonTypeForValue(value));
|
||||
return bindableValue;
|
||||
}
|
||||
|
||||
if (matcher.find()) {
|
||||
|
||||
int index = computeParameterIndex(matcher.group());
|
||||
bindableValue.setValue(getBindableValueForIndex(index));
|
||||
bindableValue.setType(bsonTypeForValue(getBindableValueForIndex(index)));
|
||||
return bindableValue;
|
||||
}
|
||||
|
||||
bindableValue.setValue(tokenValue);
|
||||
bindableValue.setType(BsonType.STRING);
|
||||
return bindableValue;
|
||||
@@ -398,28 +406,37 @@ public class ParameterBindingJsonReader extends AbstractBsonReader {
|
||||
|
||||
String computedValue = tokenValue;
|
||||
|
||||
boolean matched = false;
|
||||
|
||||
|
||||
Matcher regexMatcher = EXPRESSION_BINDING_PATTERN.matcher(computedValue);
|
||||
|
||||
while (regexMatcher.find()) {
|
||||
|
||||
String binding = regexMatcher.group();
|
||||
String expression = binding.substring(3, binding.length() - 1);
|
||||
|
||||
Matcher inSpelMatcher = PARAMETER_BINDING_PATTERN.matcher(expression);
|
||||
while (inSpelMatcher.find()) {
|
||||
|
||||
int index = computeParameterIndex(inSpelMatcher.group());
|
||||
expression = expression.replace(inSpelMatcher.group(), getBindableValueForIndex(index).toString());
|
||||
}
|
||||
|
||||
computedValue = computedValue.replace(binding, nullSafeToString(evaluateExpression(expression)));
|
||||
|
||||
bindableValue.setValue(computedValue);
|
||||
bindableValue.setType(BsonType.STRING);
|
||||
|
||||
return bindableValue;
|
||||
}
|
||||
|
||||
while (matcher.find()) {
|
||||
|
||||
matched = true;
|
||||
String group = matcher.group();
|
||||
int index = computeParameterIndex(group);
|
||||
computedValue = computedValue.replace(group, nullSafeToString(getBindableValueForIndex(index)));
|
||||
}
|
||||
|
||||
if (!matched) {
|
||||
|
||||
Matcher regexMatcher = EXPRESSION_BINDING_PATTERN.matcher(tokenValue);
|
||||
|
||||
while (regexMatcher.find()) {
|
||||
|
||||
String binding = regexMatcher.group();
|
||||
String expression = binding.substring(3, binding.length() - 1);
|
||||
|
||||
computedValue = computedValue.replace(binding, nullSafeToString(evaluateExpression(expression)));
|
||||
}
|
||||
}
|
||||
|
||||
bindableValue.setValue(computedValue);
|
||||
bindableValue.setType(BsonType.STRING);
|
||||
|
||||
@@ -479,6 +496,9 @@ public class ParameterBindingJsonReader extends AbstractBsonReader {
|
||||
if (ClassUtils.isAssignable(Iterable.class, type)) {
|
||||
return BsonType.ARRAY;
|
||||
}
|
||||
if (ClassUtils.isAssignable(Map.class, type)) {
|
||||
return BsonType.DOCUMENT;
|
||||
}
|
||||
|
||||
return BsonType.UNDEFINED;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.data.mongodb.core.query.Collation;
|
||||
import org.springframework.data.spel.ExtensionAwareEvaluationContextProvider;
|
||||
import org.springframework.data.spel.spi.EvaluationContextExtension;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
@@ -43,6 +44,7 @@ import org.springframework.data.util.ClassTypeInformation;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class BasicMongoPersistentEntityUnitTests {
|
||||
@@ -53,7 +55,7 @@ public class BasicMongoPersistentEntityUnitTests {
|
||||
@Test
|
||||
void subclassInheritsAtDocumentAnnotation() {
|
||||
|
||||
BasicMongoPersistentEntity<Person> entity = new BasicMongoPersistentEntity<Person>(
|
||||
BasicMongoPersistentEntity<Person> entity = new BasicMongoPersistentEntity<>(
|
||||
ClassTypeInformation.from(Person.class));
|
||||
assertThat(entity.getCollection()).isEqualTo("contacts");
|
||||
}
|
||||
@@ -61,7 +63,7 @@ public class BasicMongoPersistentEntityUnitTests {
|
||||
@Test
|
||||
void evaluatesSpELExpression() {
|
||||
|
||||
MongoPersistentEntity<Company> entity = new BasicMongoPersistentEntity<Company>(
|
||||
MongoPersistentEntity<Company> entity = new BasicMongoPersistentEntity<>(
|
||||
ClassTypeInformation.from(Company.class));
|
||||
assertThat(entity.getCollection()).isEqualTo("35");
|
||||
}
|
||||
@@ -74,7 +76,7 @@ public class BasicMongoPersistentEntityUnitTests {
|
||||
|
||||
when(context.getBean("myBean")).thenReturn(provider);
|
||||
|
||||
BasicMongoPersistentEntity<DynamicallyMapped> entity = new BasicMongoPersistentEntity<DynamicallyMapped>(
|
||||
BasicMongoPersistentEntity<DynamicallyMapped> entity = new BasicMongoPersistentEntity<>(
|
||||
ClassTypeInformation.from(DynamicallyMapped.class));
|
||||
entity.setEvaluationContextProvider(new ExtensionAwareEvaluationContextProvider(context));
|
||||
|
||||
@@ -87,7 +89,7 @@ public class BasicMongoPersistentEntityUnitTests {
|
||||
@Test // DATAMONGO-937
|
||||
void shouldDetectLanguageCorrectly() {
|
||||
|
||||
BasicMongoPersistentEntity<DocumentWithLanguage> entity = new BasicMongoPersistentEntity<DocumentWithLanguage>(
|
||||
BasicMongoPersistentEntity<DocumentWithLanguage> entity = new BasicMongoPersistentEntity<>(
|
||||
ClassTypeInformation.from(DocumentWithLanguage.class));
|
||||
|
||||
assertThat(entity.getLanguage()).isEqualTo("spanish");
|
||||
@@ -99,11 +101,11 @@ public class BasicMongoPersistentEntityUnitTests {
|
||||
doReturn(true).when(propertyMock).isExplicitLanguageProperty();
|
||||
doReturn(Number.class).when(propertyMock).getActualType();
|
||||
|
||||
BasicMongoPersistentEntity<AnyDocument> entity = new BasicMongoPersistentEntity<AnyDocument>(
|
||||
BasicMongoPersistentEntity<AnyDocument> entity = new BasicMongoPersistentEntity<>(
|
||||
ClassTypeInformation.from(AnyDocument.class));
|
||||
entity.addPersistentProperty(propertyMock);
|
||||
|
||||
assertThatExceptionOfType(MappingException.class).isThrownBy(() -> entity.verify());
|
||||
assertThatExceptionOfType(MappingException.class).isThrownBy(entity::verify);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1053
|
||||
@@ -112,7 +114,7 @@ public class BasicMongoPersistentEntityUnitTests {
|
||||
doReturn(true).when(propertyMock).isExplicitLanguageProperty();
|
||||
doReturn(String.class).when(propertyMock).getActualType();
|
||||
|
||||
BasicMongoPersistentEntity<AnyDocument> entity = new BasicMongoPersistentEntity<AnyDocument>(
|
||||
BasicMongoPersistentEntity<AnyDocument> entity = new BasicMongoPersistentEntity<>(
|
||||
ClassTypeInformation.from(AnyDocument.class));
|
||||
entity.addPersistentProperty(propertyMock);
|
||||
|
||||
@@ -125,7 +127,7 @@ public class BasicMongoPersistentEntityUnitTests {
|
||||
@Test // DATAMONGO-1053
|
||||
void verifyShouldIgnoreNonExplicitLanguageProperty() {
|
||||
|
||||
BasicMongoPersistentEntity<AnyDocument> entity = new BasicMongoPersistentEntity<AnyDocument>(
|
||||
BasicMongoPersistentEntity<AnyDocument> entity = new BasicMongoPersistentEntity<>(
|
||||
ClassTypeInformation.from(AnyDocument.class));
|
||||
when(propertyMock.isExplicitLanguageProperty()).thenReturn(false);
|
||||
entity.addPersistentProperty(propertyMock);
|
||||
@@ -147,11 +149,11 @@ public class BasicMongoPersistentEntityUnitTests {
|
||||
doReturn(dbRefMock).when(propertyMock).getDBRef();
|
||||
doReturn(true).when(dbRefMock).lazy();
|
||||
|
||||
BasicMongoPersistentEntity<AnyDocument> entity = new BasicMongoPersistentEntity<AnyDocument>(
|
||||
BasicMongoPersistentEntity<AnyDocument> entity = new BasicMongoPersistentEntity<>(
|
||||
ClassTypeInformation.from(AnyDocument.class));
|
||||
entity.addPersistentProperty(propertyMock);
|
||||
|
||||
assertThatExceptionOfType(MappingException.class).isThrownBy(() -> entity.verify());
|
||||
assertThatExceptionOfType(MappingException.class).isThrownBy(entity::verify);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1157
|
||||
@@ -165,11 +167,11 @@ public class BasicMongoPersistentEntityUnitTests {
|
||||
doReturn(dbRefMock).when(propertyMock).getDBRef();
|
||||
doReturn(true).when(dbRefMock).lazy();
|
||||
|
||||
BasicMongoPersistentEntity<AnyDocument> entity = new BasicMongoPersistentEntity<AnyDocument>(
|
||||
BasicMongoPersistentEntity<AnyDocument> entity = new BasicMongoPersistentEntity<>(
|
||||
ClassTypeInformation.from(AnyDocument.class));
|
||||
entity.addPersistentProperty(propertyMock);
|
||||
|
||||
assertThatExceptionOfType(MappingException.class).isThrownBy(() -> entity.verify());
|
||||
assertThatExceptionOfType(MappingException.class).isThrownBy(entity::verify);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1157
|
||||
@@ -183,7 +185,7 @@ public class BasicMongoPersistentEntityUnitTests {
|
||||
doReturn(dbRefMock).when(propertyMock).getDBRef();
|
||||
doReturn(true).when(dbRefMock).lazy();
|
||||
|
||||
BasicMongoPersistentEntity<AnyDocument> entity = new BasicMongoPersistentEntity<AnyDocument>(
|
||||
BasicMongoPersistentEntity<AnyDocument> entity = new BasicMongoPersistentEntity<>(
|
||||
ClassTypeInformation.from(AnyDocument.class));
|
||||
entity.addPersistentProperty(propertyMock);
|
||||
entity.verify();
|
||||
@@ -201,7 +203,7 @@ public class BasicMongoPersistentEntityUnitTests {
|
||||
doReturn(dbRefMock).when(propertyMock).getDBRef();
|
||||
doReturn(false).when(dbRefMock).lazy();
|
||||
|
||||
BasicMongoPersistentEntity<AnyDocument> entity = new BasicMongoPersistentEntity<AnyDocument>(
|
||||
BasicMongoPersistentEntity<AnyDocument> entity = new BasicMongoPersistentEntity<>(
|
||||
ClassTypeInformation.from(AnyDocument.class));
|
||||
entity.addPersistentProperty(propertyMock);
|
||||
entity.verify();
|
||||
@@ -212,7 +214,7 @@ public class BasicMongoPersistentEntityUnitTests {
|
||||
@Test // DATAMONGO-1291
|
||||
void metaInformationShouldBeReadCorrectlyFromInheritedDocumentAnnotation() {
|
||||
|
||||
BasicMongoPersistentEntity<DocumentWithCustomAnnotation> entity = new BasicMongoPersistentEntity<DocumentWithCustomAnnotation>(
|
||||
BasicMongoPersistentEntity<DocumentWithCustomAnnotation> entity = new BasicMongoPersistentEntity<>(
|
||||
ClassTypeInformation.from(DocumentWithCustomAnnotation.class));
|
||||
|
||||
assertThat(entity.getCollection()).isEqualTo("collection-1");
|
||||
@@ -221,7 +223,7 @@ public class BasicMongoPersistentEntityUnitTests {
|
||||
@Test // DATAMONGO-1373
|
||||
void metaInformationShouldBeReadCorrectlyFromComposedDocumentAnnotation() {
|
||||
|
||||
BasicMongoPersistentEntity<DocumentWithComposedAnnotation> entity = new BasicMongoPersistentEntity<DocumentWithComposedAnnotation>(
|
||||
BasicMongoPersistentEntity<DocumentWithComposedAnnotation> entity = new BasicMongoPersistentEntity<>(
|
||||
ClassTypeInformation.from(DocumentWithComposedAnnotation.class));
|
||||
|
||||
assertThat(entity.getCollection()).isEqualTo("custom-collection");
|
||||
@@ -233,7 +235,7 @@ public class BasicMongoPersistentEntityUnitTests {
|
||||
BasicMongoPersistentEntity<MappedWithExtension> entity = new BasicMongoPersistentEntity<>(
|
||||
ClassTypeInformation.from(MappedWithExtension.class));
|
||||
entity.setEvaluationContextProvider(
|
||||
new ExtensionAwareEvaluationContextProvider(Arrays.asList(new SampleExtension())));
|
||||
new ExtensionAwareEvaluationContextProvider(Collections.singletonList(new SampleExtension())));
|
||||
|
||||
assertThat(entity.getCollection()).isEqualTo("collectionName");
|
||||
}
|
||||
@@ -256,6 +258,18 @@ public class BasicMongoPersistentEntityUnitTests {
|
||||
assertThat(entity.getCollation()).isEqualTo(org.springframework.data.mongodb.core.query.Collation.of("en_US"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2565
|
||||
void usesCorrectExpressionsForCollectionAndCollation() {
|
||||
|
||||
BasicMongoPersistentEntity<WithCollectionAndCollationFromSpEL> entity = new BasicMongoPersistentEntity<>(
|
||||
ClassTypeInformation.from(WithCollectionAndCollationFromSpEL.class));
|
||||
entity.setEvaluationContextProvider(
|
||||
new ExtensionAwareEvaluationContextProvider(Collections.singletonList(new SampleExtension())));
|
||||
|
||||
assertThat(entity.getCollection()).isEqualTo("collectionName");
|
||||
assertThat(entity.getCollation()).isEqualTo(Collation.of("en_US"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2341
|
||||
void detectsShardedEntityCorrectly() {
|
||||
|
||||
@@ -340,6 +354,9 @@ public class BasicMongoPersistentEntityUnitTests {
|
||||
@Document(collation = "#{myCollation}")
|
||||
class WithCollationFromSpEL {}
|
||||
|
||||
@Document(collection = "#{myProperty}", collation = "#{myCollation}")
|
||||
class WithCollectionAndCollationFromSpEL {}
|
||||
|
||||
@Document(collation = "en_US")
|
||||
class WithSimpleCollation {}
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@ package org.springframework.data.mongodb.util.json;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -26,6 +29,7 @@ import java.util.List;
|
||||
import org.bson.Document;
|
||||
import org.bson.codecs.DecoderContext;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.spel.EvaluationContextProvider;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
@@ -264,10 +268,92 @@ class ParameterBindingJsonReaderUnitTests {
|
||||
assertThat(target).isEqualTo(Document.parse("{\"$and\": [{\"v1\": {\"$in\": [1]}}]}"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2545
|
||||
void shouldABindArgumentsViaIndexInSpelExpressions() {
|
||||
|
||||
Object[] args = new Object[] { "yess", "nooo" };
|
||||
StandardEvaluationContext evaluationContext = (StandardEvaluationContext) EvaluationContextProvider.DEFAULT
|
||||
.getEvaluationContext(args);
|
||||
|
||||
ParameterBindingJsonReader reader = new ParameterBindingJsonReader(
|
||||
"{ 'isBatman' : ?#{ T(" + this.getClass().getName() + ").isBatman() ? [0] : [1] }}",
|
||||
new ParameterBindingContext((index) -> args[index], new SpelExpressionParser(), evaluationContext));
|
||||
Document target = new ParameterBindingDocumentCodec().decode(reader, DecoderContext.builder().build());
|
||||
|
||||
assertThat(target).isEqualTo(new Document("isBatman", "nooo"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2545
|
||||
void shouldAllowMethodArgumentPlaceholdersInSpelExpressions/*becuase this worked before*/() {
|
||||
|
||||
Object[] args = new Object[] { "yess", "nooo" };
|
||||
StandardEvaluationContext evaluationContext = (StandardEvaluationContext) EvaluationContextProvider.DEFAULT
|
||||
.getEvaluationContext(args);
|
||||
|
||||
ParameterBindingJsonReader reader = new ParameterBindingJsonReader(
|
||||
"{ 'isBatman' : ?#{ T(" + this.getClass().getName() + ").isBatman() ? '?0' : '?1' }}",
|
||||
new ParameterBindingContext((index) -> args[index], new SpelExpressionParser(), evaluationContext));
|
||||
Document target = new ParameterBindingDocumentCodec().decode(reader, DecoderContext.builder().build());
|
||||
|
||||
assertThat(target).isEqualTo(new Document("isBatman", "nooo"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2545
|
||||
void shouldAllowMethodArgumentPlaceholdersInQuotedSpelExpressions/*because this worked before*/() {
|
||||
|
||||
Object[] args = new Object[] { "yess", "nooo" };
|
||||
StandardEvaluationContext evaluationContext = (StandardEvaluationContext) EvaluationContextProvider.DEFAULT
|
||||
.getEvaluationContext(args);
|
||||
|
||||
ParameterBindingJsonReader reader = new ParameterBindingJsonReader(
|
||||
"{ 'isBatman' : \"?#{ T(" + this.getClass().getName() + ").isBatman() ? '?0' : '?1' }\" }",
|
||||
new ParameterBindingContext((index) -> args[index], new SpelExpressionParser(), evaluationContext));
|
||||
Document target = new ParameterBindingDocumentCodec().decode(reader, DecoderContext.builder().build());
|
||||
|
||||
assertThat(target).isEqualTo(new Document("isBatman", "nooo"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2545
|
||||
void evaluatesSpelExpressionDefiningEntireQuery() {
|
||||
|
||||
Object[] args = new Object[] {};
|
||||
StandardEvaluationContext evaluationContext = (StandardEvaluationContext) EvaluationContextProvider.DEFAULT
|
||||
.getEvaluationContext(args);
|
||||
evaluationContext.setRootObject(new DummySecurityObject(new DummyWithId("wonderwoman")));
|
||||
|
||||
String json = "?#{ T(" + this.getClass().getName()
|
||||
+ ").isBatman() ? {'_class': { '$eq' : 'region' }} : { '$and' : { {'_class': { '$eq' : 'region' } }, {'user.supervisor': principal.id } } } }";
|
||||
|
||||
ParameterBindingJsonReader reader = new ParameterBindingJsonReader(json,
|
||||
new ParameterBindingContext((index) -> args[index], new SpelExpressionParser(), evaluationContext));
|
||||
Document target = new ParameterBindingDocumentCodec().decode(reader, DecoderContext.builder().build());
|
||||
|
||||
assertThat(target)
|
||||
.isEqualTo(new Document("$and", Arrays.asList(new Document("_class", new Document("$eq", "region")),
|
||||
new Document("user.supervisor", "wonderwoman"))));
|
||||
}
|
||||
|
||||
private static Document parse(String json, Object... args) {
|
||||
|
||||
ParameterBindingJsonReader reader = new ParameterBindingJsonReader(json, args);
|
||||
return new ParameterBindingDocumentCodec().decode(reader, DecoderContext.builder().build());
|
||||
}
|
||||
|
||||
// DATAMONGO-2545
|
||||
public static boolean isBatman() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public static class DummySecurityObject {
|
||||
DummyWithId principal;
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public static class DummyWithId {
|
||||
String id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.repository.query
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext
|
||||
import org.springframework.data.mongodb.repository.Person
|
||||
import org.springframework.data.projection.SpelAwareProxyProjectionFactory
|
||||
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata
|
||||
import org.springframework.data.repository.kotlin.CoroutineCrudRepository
|
||||
import kotlin.coroutines.Continuation
|
||||
|
||||
/**
|
||||
* Unit tests for [ReactiveMongoQueryMethod] using Coroutine repositories.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class ReactiveMongoQueryMethodCoroutineUnitTests {
|
||||
|
||||
val projectionFactory = SpelAwareProxyProjectionFactory()
|
||||
|
||||
interface PersonRepository : CoroutineCrudRepository<Person, String> {
|
||||
|
||||
suspend fun findSuspendAllByName(): Flow<Person>
|
||||
|
||||
fun findAllByName(): Flow<Person>
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2562
|
||||
internal fun `should consider methods returning Flow as collection queries`() {
|
||||
|
||||
val method = PersonRepository::class.java.getMethod("findAllByName")
|
||||
val queryMethod = ReactiveMongoQueryMethod(method, DefaultRepositoryMetadata(PersonRepository::class.java), projectionFactory, MongoMappingContext())
|
||||
|
||||
assertThat(queryMethod.isCollectionQuery).isTrue()
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2562
|
||||
internal fun `should consider suspended methods returning Flow as collection queries`() {
|
||||
|
||||
val method = PersonRepository::class.java.getMethod("findSuspendAllByName", Continuation::class.java)
|
||||
val queryMethod = ReactiveMongoQueryMethod(method, DefaultRepositoryMetadata(PersonRepository::class.java), projectionFactory, MongoMappingContext())
|
||||
|
||||
assertThat(queryMethod.isCollectionQuery).isTrue()
|
||||
}
|
||||
}
|
||||
@@ -87,7 +87,7 @@
|
||||
* Out-of-the-box support for `java.util.Currency` in object mapping.
|
||||
* Support for the bulk operations introduced in MongoDB 2.6.
|
||||
* Upgrade to Querydsl 4.
|
||||
* Assert compatibility with MongoDB 3.0 and MongoDB Java Driver 3.2 (see: <<mongo.mongo-3>>).
|
||||
* Assert compatibility with MongoDB 3.0 and MongoDB Java Driver 3.2.
|
||||
|
||||
[[new-features.1-8-0]]
|
||||
== What's New in Spring Data MongoDB 1.8
|
||||
@@ -101,7 +101,7 @@
|
||||
[[new-features.1-7-0]]
|
||||
== What's New in Spring Data MongoDB 1.7
|
||||
|
||||
* Assert compatibility with MongoDB 3.0 and MongoDB Java Driver 3-beta3 (see: <<mongo.mongo-3>>).
|
||||
* Assert compatibility with MongoDB 3.0 and MongoDB Java Driver 3-beta3.
|
||||
* Support JSR-310 and ThreeTen back-port date/time types.
|
||||
* Allow `Stream` as a query method return type (see: <<mongodb.repositories.queries>>).
|
||||
* https://geojson.org/[GeoJSON] support in both domain types and queries (see: <<mongo.geo-json>>).
|
||||
|
||||
@@ -1,6 +1,36 @@
|
||||
Spring Data MongoDB Changelog
|
||||
=============================
|
||||
|
||||
Changes in version 3.0.1.RELEASE (2020-06-10)
|
||||
---------------------------------------------
|
||||
* DATAMONGO-2565 - MongoPersistentEntity.getCollation(...) evaluates document expression instead of collation expression.
|
||||
* DATAMONGO-2562 - CoroutineCrudRepository findAllBy throwing IncorrectResultSizeDataAccessException when more than 1 result.
|
||||
* DATAMONGO-2560 - Upgrade MongoDB drivers to 4.0.4.
|
||||
* DATAMONGO-2553 - Reference documentation contains links to removed sections.
|
||||
* DATAMONGO-2547 - java.lang.IllegalArgumentException: com.mongodb.client.MongoDatabase referenced from a method is not visible from class loader.
|
||||
* DATAMONGO-2545 - Backwards incompatibilities on @Query.
|
||||
* DATAMONGO-2543 - Release 3.0.1 (Neumann SR1).
|
||||
* DATAMONGO-2542 - Don't attempt to map query operator keywords to properties.
|
||||
|
||||
|
||||
Changes in version 2.2.8.RELEASE (2020-06-10)
|
||||
---------------------------------------------
|
||||
* DATAMONGO-2565 - MongoPersistentEntity.getCollation(...) evaluates document expression instead of collation expression.
|
||||
* DATAMONGO-2547 - java.lang.IllegalArgumentException: com.mongodb.client.MongoDatabase referenced from a method is not visible from class loader.
|
||||
* DATAMONGO-2545 - Backwards incompatibilities on @Query.
|
||||
* DATAMONGO-2542 - Don't attempt to map query operator keywords to properties.
|
||||
* DATAMONGO-2535 - Remove Travis CI.
|
||||
* DATAMONGO-2533 - Release 2.2.8 (Moore SR8).
|
||||
* DATAMONGO-2509 - Polish documentation for 3.0 release.
|
||||
|
||||
|
||||
Changes in version 2.1.18.RELEASE (2020-06-10)
|
||||
----------------------------------------------
|
||||
* DATAMONGO-2547 - java.lang.IllegalArgumentException: com.mongodb.client.MongoDatabase referenced from a method is not visible from class loader.
|
||||
* DATAMONGO-2535 - Remove Travis CI.
|
||||
* DATAMONGO-2532 - Release 2.1.18 (Lovelace SR18).
|
||||
|
||||
|
||||
Changes in version 3.0.0.RELEASE (2020-05-12)
|
||||
---------------------------------------------
|
||||
* DATAMONGO-2541 - Upgrade to MongoDB 4.0.3 Drivers.
|
||||
@@ -3029,3 +3059,5 @@ Repository
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Spring Data MongoDB 3.0 GA
|
||||
Spring Data MongoDB 3.0.1
|
||||
Copyright (c) [2010-2019] Pivotal Software, Inc.
|
||||
|
||||
This product is licensed to you under the Apache License, Version 2.0 (the "License").
|
||||
@@ -15,3 +15,4 @@ conditions of the subcomponent's license, as noted in the LICENSE file.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user