Compare commits

..

9 Commits

Author SHA1 Message Date
Mark Paluch
ecb35886f9 Update test to work with Kotlin override properties. 2021-04-19 10:32:53 +02:00
Mark Paluch
2bca4c9a33 Polishing. 2021-04-19 10:32:41 +02:00
Mark Paluch
19d74427f1 Rebase. 2021-04-19 10:32:34 +02:00
Christoph Strobl
4fb6a844dd DATAMONGO-2250 - Switch to DATACMNS-1509 makes the test pass. 2021-04-19 10:10:45 +02:00
Christoph Strobl
51a35273d3 DATAMONGO-2250 - Add test case for Kotlin override properties. 2021-04-19 10:10:22 +02:00
Christoph Strobl
203d2d0187 DATAMONGO-2250 - Prepare issue branch. 2021-04-19 10:10:20 +02:00
Greg L. Turnquist
54f75e653b Migrate to main branch.
See #3616.
2021-04-16 12:27:26 -05:00
Mark Paluch
7b33f56e33 After release cleanups.
See #3616
2021-04-14 14:30:14 +02:00
Mark Paluch
829eed7d6c Prepare next development iteration.
See #3616
2021-04-14 14:30:11 +02:00
32 changed files with 190 additions and 1088 deletions

View File

@@ -1,6 +1,6 @@
= Continuous Integration
image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-mongodb%2Fmaster&subject=Moore%20(master)[link=https://jenkins.spring.io/view/SpringData/job/spring-data-mongodb/]
image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-mongodb%2Fmain&subject=Moore%20(main)[link=https://jenkins.spring.io/view/SpringData/job/spring-data-mongodb/]
image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-mongodb%2F2.1.x&subject=Lovelace%20(2.1.x)[link=https://jenkins.spring.io/view/SpringData/job/spring-data-mongodb/]
image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-mongodb%2F1.10.x&subject=Ingalls%20(1.10.x)[link=https://jenkins.spring.io/view/SpringData/job/spring-data-mongodb/]

View File

@@ -1,3 +1,3 @@
= Spring Data contribution guidelines
You find the contribution guidelines for Spring Data projects https://github.com/spring-projects/spring-data-build/blob/master/CONTRIBUTING.adoc[here].
You find the contribution guidelines for Spring Data projects https://github.com/spring-projects/spring-data-build/blob/main/CONTRIBUTING.adoc[here].

34
Jenkinsfile vendored
View File

@@ -3,7 +3,7 @@ pipeline {
triggers {
pollSCM 'H/10 * * * *'
upstream(upstreamProjects: "spring-data-commons/2.5.x", threshold: hudson.model.Result.SUCCESS)
upstream(upstreamProjects: "spring-data-commons/main", threshold: hudson.model.Result.SUCCESS)
}
options {
@@ -68,7 +68,7 @@ pipeline {
stage("test: baseline (jdk8)") {
when {
anyOf {
branch '3.2.x'
branch 'main'
not { triggeredBy 'UpstreamCause' }
}
}
@@ -76,9 +76,6 @@ pipeline {
label 'data'
}
options { timeout(time: 30, unit: 'MINUTES') }
environment {
ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c')
}
steps {
script {
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
@@ -88,7 +85,7 @@ pipeline {
sh 'sleep 10'
sh 'mongo --eval "rs.initiate({_id: \'rs0\', members:[{_id: 0, host: \'127.0.0.1:27017\'}]});"'
sh 'sleep 15'
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml clean dependency:list test -Duser.name=jenkins -Dsort -U -B'
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw clean dependency:list test -Duser.name=jenkins -Dsort -U -B'
}
}
}
@@ -98,7 +95,7 @@ pipeline {
stage("Test other configurations") {
when {
allOf {
branch '3.2.x'
branch 'main'
not { triggeredBy 'UpstreamCause' }
}
}
@@ -108,9 +105,6 @@ pipeline {
label 'data'
}
options { timeout(time: 30, unit: 'MINUTES') }
environment {
ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c')
}
steps {
script {
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
@@ -120,7 +114,7 @@ pipeline {
sh 'sleep 10'
sh 'mongo --eval "rs.initiate({_id: \'rs0\', members:[{_id: 0, host: \'127.0.0.1:27017\'}]});"'
sh 'sleep 15'
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml clean dependency:list test -Duser.name=jenkins -Dsort -U -B'
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw clean dependency:list test -Duser.name=jenkins -Dsort -U -B'
}
}
}
@@ -132,9 +126,6 @@ pipeline {
label 'data'
}
options { timeout(time: 30, unit: 'MINUTES') }
environment {
ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c')
}
steps {
script {
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
@@ -144,7 +135,7 @@ pipeline {
sh 'sleep 10'
sh 'mongo --eval "rs.initiate({_id: \'rs0\', members:[{_id: 0, host: \'127.0.0.1:27017\'}]});"'
sh 'sleep 15'
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml clean dependency:list test -Duser.name=jenkins -Dsort -U -B'
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw clean dependency:list test -Duser.name=jenkins -Dsort -U -B'
}
}
}
@@ -156,9 +147,6 @@ pipeline {
label 'data'
}
options { timeout(time: 30, unit: 'MINUTES') }
environment {
ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c')
}
steps {
script {
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
@@ -168,7 +156,7 @@ pipeline {
sh 'sleep 10'
sh 'mongo --eval "rs.initiate({_id: \'rs0\', members:[{_id: 0, host: \'127.0.0.1:27017\'}]});"'
sh 'sleep 15'
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml -Pjava11 clean dependency:list test -Duser.name=jenkins -Dsort -U -B'
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -Pjava11 clean dependency:list test -Duser.name=jenkins -Dsort -U -B'
}
}
}
@@ -180,7 +168,7 @@ pipeline {
stage('Release to artifactory') {
when {
anyOf {
branch '3.2.x'
branch 'main'
not { triggeredBy 'UpstreamCause' }
}
}
@@ -197,7 +185,7 @@ pipeline {
script {
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
docker.image('adoptopenjdk/openjdk8:latest').inside('-v $HOME:/tmp/jenkins-home') {
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml -Pci,artifactory ' +
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -Pci,artifactory ' +
'-Dartifactory.server=https://repo.spring.io ' +
"-Dartifactory.username=${ARTIFACTORY_USR} " +
"-Dartifactory.password=${ARTIFACTORY_PSW} " +
@@ -213,7 +201,7 @@ pipeline {
stage('Publish documentation') {
when {
branch '3.2.x'
branch 'main'
}
agent {
label 'data'
@@ -228,7 +216,7 @@ pipeline {
script {
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
docker.image('adoptopenjdk/openjdk8:latest').inside('-v $HOME:/tmp/jenkins-home') {
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml -Pci,distribute ' +
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -Pci,distribute ' +
'-Dartifactory.server=https://repo.spring.io ' +
"-Dartifactory.username=${ARTIFACTORY_USR} " +
"-Dartifactory.password=${ARTIFACTORY_PSW} " +

View File

@@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
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.

View File

@@ -1,6 +1,6 @@
image:https://spring.io/badges/spring-data-mongodb/ga.svg[Spring Data MongoDB,link=https://projects.spring.io/spring-data-mongodb#quick-start] image:https://spring.io/badges/spring-data-mongodb/snapshot.svg[Spring Data MongoDB,link=https://projects.spring.io/spring-data-mongodb#quick-start]
= Spring Data MongoDB image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-mongodb%2Fmaster&subject=Build[link=https://jenkins.spring.io/view/SpringData/job/spring-data-mongodb/] https://gitter.im/spring-projects/spring-data[image:https://badges.gitter.im/spring-projects/spring-data.svg[Gitter]]
= Spring Data MongoDB image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-mongodb%2Fmain&subject=Build[link=https://jenkins.spring.io/view/SpringData/job/spring-data-mongodb/] https://gitter.im/spring-projects/spring-data[image:https://badges.gitter.im/spring-projects/spring-data.svg[Gitter]]
The primary goal of the https://projects.spring.io/spring-data[Spring Data] project is to make it easier to build Spring-powered applications that use new data access technologies such as non-relational databases, map-reduce frameworks, and cloud based data services.

15
pom.xml
View File

@@ -5,7 +5,7 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>3.2.4</version>
<version>3.3.0.DATAMONGO-2250-SNAPSHOT</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.5.4</version>
<version>2.6.0-SNAPSHOT</version>
</parent>
<modules>
@@ -26,7 +26,7 @@
<properties>
<project.type>multi</project.type>
<dist.id>spring-data-mongodb</dist.id>
<springdata.commons>2.5.4</springdata.commons>
<springdata.commons>2.6.0.DATACMNS-1509-SNAPSHOT</springdata.commons>
<mongo>4.2.3</mongo>
<mongo.reactivestreams>${mongo}</mongo.reactivestreams>
<jmh.version>1.19</jmh.version>
@@ -134,8 +134,8 @@
<repositories>
<repository>
<id>spring-libs-release</id>
<url>https://repo.spring.io/libs-release</url>
<id>spring-libs-snapshot</id>
<url>https://repo.spring.io/libs-snapshot</url>
</repository>
<repository>
<id>sonatype-libs-snapshot</id>
@@ -158,6 +158,11 @@
<id>spring-libs-milestone</id>
<url>https://repo.spring.io/libs-milestone</url>
</pluginRepository>
<pluginRepository>
<id>bintray-plugins</id>
<name>bintray-plugins</name>
<url>https://jcenter.bintray.com</url>
</pluginRepository>
</pluginRepositories>
</project>

View File

@@ -1,29 +0,0 @@
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-1.0.0.xsd">
<servers>
<server>
<id>spring-plugins-release</id>
<username>${env.ARTIFACTORY_USR}</username>
<password>${env.ARTIFACTORY_PSW}</password>
</server>
<server>
<id>spring-libs-snapshot</id>
<username>${env.ARTIFACTORY_USR}</username>
<password>${env.ARTIFACTORY_PSW}</password>
</server>
<server>
<id>spring-libs-milestone</id>
<username>${env.ARTIFACTORY_USR}</username>
<password>${env.ARTIFACTORY_PSW}</password>
</server>
<server>
<id>spring-libs-release</id>
<username>${env.ARTIFACTORY_USR}</username>
<password>${env.ARTIFACTORY_PSW}</password>
</server>
</servers>
</settings>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>3.2.4</version>
<version>3.3.0.DATAMONGO-2250-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -14,7 +14,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>3.2.4</version>
<version>3.3.0.DATAMONGO-2250-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -11,7 +11,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>3.2.4</version>
<version>3.3.0.DATAMONGO-2250-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -141,6 +141,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
this::getWriteTarget);
this.idMapper = new QueryMapper(this);
this.spELContext = new SpELContext(DocumentPropertyAccessor.INSTANCE);
this.dbRefProxyHandler = new DefaultDbRefProxyHandler(spELContext, mappingContext,
(prop, bson, evaluator, path) -> {
@@ -160,8 +161,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
Assert.notNull(path, "ObjectPath must not be null");
return new ConversionContext(conversions, path, this::readDocument, this::readCollectionOrArray, this::readMap,
this::readDBRef, this::getPotentiallyConvertedSimpleRead);
return new ConversionContext(path, this::readDocument, this::readCollectionOrArray, this::readMap, this::readDBRef,
this::getPotentiallyConvertedSimpleRead);
}
/**
@@ -375,7 +376,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
}
private <S> S populateProperties(ConversionContext context, MongoPersistentEntity<S> entity,
DocumentAccessor documentAccessor, SpELExpressionEvaluator evaluator, S instance) {
DocumentAccessor documentAccessor,
SpELExpressionEvaluator evaluator, S instance) {
PersistentPropertyAccessor<S> accessor = new ConvertingPropertyAccessor<>(entity.getPropertyAccessor(instance),
conversionService);
@@ -421,7 +423,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
@Nullable
private Object readIdValue(ConversionContext context, SpELExpressionEvaluator evaluator,
MongoPersistentProperty idProperty, Object rawId) {
MongoPersistentProperty idProperty,
Object rawId) {
String expression = idProperty.getSpelExpression();
Object resolvedValue = expression != null ? evaluator.evaluate(expression) : rawId;
@@ -431,7 +434,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
private void readProperties(ConversionContext context, MongoPersistentEntity<?> entity,
PersistentPropertyAccessor<?> accessor, DocumentAccessor documentAccessor,
MongoDbPropertyValueProvider valueProvider, SpELExpressionEvaluator evaluator) {
MongoDbPropertyValueProvider valueProvider,
SpELExpressionEvaluator evaluator) {
DbRefResolverCallback callback = null;
@@ -501,7 +505,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
@Nullable
private Object readUnwrapped(ConversionContext context, DocumentAccessor documentAccessor,
MongoPersistentProperty prop, MongoPersistentEntity<?> unwrappedEntity) {
MongoPersistentProperty prop,
MongoPersistentEntity<?> unwrappedEntity) {
if (prop.findAnnotation(Unwrapped.class).onEmpty().equals(OnEmpty.USE_EMPTY)) {
return read(context, unwrappedEntity, (Document) documentAccessor.getDocument());
@@ -1040,7 +1045,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
@SuppressWarnings({ "rawtypes", "unchecked" })
private Object getPotentiallyConvertedSimpleRead(Object value, @Nullable Class<?> target) {
if (target == null) {
if (target == null || ClassUtils.isAssignableValue(target, value)) {
return value;
}
@@ -1048,10 +1053,6 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
return doConvert(value, target);
}
if (ClassUtils.isAssignableValue(target, value)) {
return value;
}
if (Enum.class.isAssignableFrom(target)) {
return Enum.valueOf((Class<Enum>) target, value.toString());
}
@@ -1140,7 +1141,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
}
for (Object element : source) {
items.add(element != null ? context.convert(element, componentType) : element);
items.add(context.convert(element, componentType));
}
return getPotentiallyConvertedSimpleRead(items, targetType.getType());
@@ -1205,7 +1206,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
}
Object value = entry.getValue();
map.put(key, value == null ? value : context.convert(value, valueType));
map.put(key, context.convert(value, valueType));
}
return map;
@@ -1446,7 +1447,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
T target = null;
if (document != null) {
maybeEmitEvent(new AfterLoadEvent<>(document, (Class<T>) type.getType(), collectionName));
maybeEmitEvent(
new AfterLoadEvent<>(document, (Class<T>) type.getType(), collectionName));
target = (T) readDocument(context, document, type);
}
@@ -1539,10 +1541,9 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
}
@SuppressWarnings("ConstantConditions")
private <T extends Object> T doConvert(Object value, Class<? extends T> target,
@Nullable Class<? extends T> fallback) {
private <T extends Object> T doConvert(Object value, Class<? extends T> target, @Nullable Class<? extends T> fallback) {
if (conversionService.canConvert(value.getClass(), target) || fallback == null) {
if(conversionService.canConvert(value.getClass(), target) || fallback == null) {
return conversionService.convert(value, target);
}
return conversionService.convert(value, fallback);
@@ -1852,7 +1853,6 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
*/
protected static class ConversionContext {
private final org.springframework.data.convert.CustomConversions conversions;
private final ObjectPath path;
private final ContainerValueConverter<Bson> documentConverter;
private final ContainerValueConverter<Collection<?>> collectionConverter;
@@ -1860,12 +1860,10 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
private final ContainerValueConverter<DBRef> dbRefConverter;
private final ValueConverter<Object> elementConverter;
ConversionContext(org.springframework.data.convert.CustomConversions customConversions, ObjectPath path,
ContainerValueConverter<Bson> documentConverter, ContainerValueConverter<Collection<?>> collectionConverter,
ContainerValueConverter<Bson> mapConverter, ContainerValueConverter<DBRef> dbRefConverter,
ValueConverter<Object> elementConverter) {
ConversionContext(ObjectPath path, ContainerValueConverter<Bson> documentConverter,
ContainerValueConverter<Collection<?>> collectionConverter, ContainerValueConverter<Bson> mapConverter,
ContainerValueConverter<DBRef> dbRefConverter, ValueConverter<Object> elementConverter) {
this.conversions = customConversions;
this.path = path;
this.documentConverter = documentConverter;
this.collectionConverter = collectionConverter;
@@ -1884,13 +1882,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
@SuppressWarnings("unchecked")
public <S extends Object> S convert(Object source, TypeInformation<? extends S> typeHint) {
Assert.notNull(source, "Source must not be null");
Assert.notNull(typeHint, "TypeInformation must not be null");
if (conversions.hasCustomReadTarget(source.getClass(), typeHint.getType())) {
return (S) elementConverter.convert(source, typeHint);
}
if (source instanceof Collection) {
Class<?> rawType = typeHint.getType();
@@ -1907,16 +1900,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
}
if (typeHint.isMap()) {
if(ClassUtils.isAssignable(Document.class, typeHint.getType())) {
return (S) documentConverter.convert(this, BsonUtils.asBson(source), typeHint);
}
if (BsonUtils.supportsBson(source)) {
return (S) mapConverter.convert(this, BsonUtils.asBson(source), typeHint);
}
throw new IllegalArgumentException(String.format("Expected map like structure but found %s", source.getClass()));
return (S) mapConverter.convert(this, (Bson) source, typeHint);
}
if (source instanceof DBRef) {
@@ -1928,8 +1912,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
String.format(INCOMPATIBLE_TYPES, source, BasicDBList.class, typeHint.getType(), getPath()));
}
if (BsonUtils.supportsBson(source)) {
return (S) documentConverter.convert(this, BsonUtils.asBson(source), typeHint);
if (source instanceof Bson) {
return (S) documentConverter.convert(this, (Bson) source, typeHint);
}
return (S) elementConverter.convert(source, typeHint);
@@ -1945,8 +1929,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
Assert.notNull(currentPath, "ObjectPath must not be null");
return new ConversionContext(conversions, currentPath, documentConverter, collectionConverter, mapConverter,
dbRefConverter, elementConverter);
return new ConversionContext(currentPath, documentConverter, collectionConverter, mapConverter, dbRefConverter,
elementConverter);
}
public ObjectPath getPath() {

View File

@@ -19,14 +19,11 @@ import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.bson.BsonValue;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.domain.Example;
@@ -68,12 +65,9 @@ import com.mongodb.DBRef;
* @author Thomas Darimont
* @author Christoph Strobl
* @author Mark Paluch
* @author David Julia
*/
public class QueryMapper {
protected static final Logger LOGGER = LoggerFactory.getLogger(QueryMapper.class);
private static final List<String> DEFAULT_ID_NAMES = Arrays.asList("id", "_id");
private static final Document META_TEXT_SCORE = new Document("$meta", "textScore");
static final ClassTypeInformation<?> NESTED_DOCUMENT = ClassTypeInformation.from(NestedDocument.class);
@@ -195,7 +189,19 @@ public class QueryMapper {
return new Document();
}
Document mappedSort = mapFieldsToPropertyNames(sortObject, entity);
sortObject = filterUnwrappedObjects(sortObject, entity);
Document mappedSort = new Document();
for (Map.Entry<String, Object> entry : BsonUtils.asMap(sortObject).entrySet()) {
Field field = createPropertyField(entity, entry.getKey(), mappingContext);
if (field.getProperty() != null && field.getProperty().isUnwrapped()) {
continue;
}
mappedSort.put(field.getMappedKey(), entry.getValue());
}
mapMetaAttributes(mappedSort, entity, MetaMapping.WHEN_PRESENT);
return mappedSort;
}
@@ -213,30 +219,13 @@ public class QueryMapper {
Assert.notNull(fieldsObject, "FieldsObject must not be null!");
Document mappedFields = mapFieldsToPropertyNames(fieldsObject, entity);
fieldsObject = filterUnwrappedObjects(fieldsObject, entity);
Document mappedFields = getMappedObject(fieldsObject, entity);
mapMetaAttributes(mappedFields, entity, MetaMapping.FORCE);
return mappedFields;
}
private Document mapFieldsToPropertyNames(Document fields, @Nullable MongoPersistentEntity<?> entity) {
if (fields.isEmpty()) {
return new Document();
}
Document target = new Document();
for (Map.Entry<String, Object> entry : BsonUtils.asMap(filterUnwrappedObjects(fields, entity)).entrySet()) {
Field field = createPropertyField(entity, entry.getKey(), mappingContext);
if (field.getProperty() != null && field.getProperty().isUnwrapped()) {
continue;
}
target.put(field.getMappedKey(), entry.getValue());
}
return target;
}
private void mapMetaAttributes(Document source, @Nullable MongoPersistentEntity<?> entity, MetaMapping metaMapping) {
if (entity == null) {
@@ -455,10 +444,6 @@ public class QueryMapper {
}
}
if (value == null) {
return null;
}
if (isNestedKeyword(value)) {
return getMappedKeyword(new Keyword((Bson) value), documentField.getPropertyEntity());
}
@@ -721,7 +706,7 @@ public class QueryMapper {
* @param candidate
* @return
*/
protected boolean isNestedKeyword(@Nullable Object candidate) {
protected boolean isNestedKeyword(Object candidate) {
if (!(candidate instanceof Document)) {
return false;
@@ -766,13 +751,12 @@ public class QueryMapper {
* converted one by one.
*
* @param documentField the field and its meta data
* @param value the actual value. Can be {@literal null}.
* @param value the actual value
* @return the potentially converted target value.
*/
@Nullable
private Object applyFieldTargetTypeHintToValue(Field documentField, @Nullable Object value) {
private Object applyFieldTargetTypeHintToValue(Field documentField, Object value) {
if (value == null || documentField.getProperty() == null || !documentField.getProperty().hasExplicitWriteTarget()) {
if (documentField.getProperty() == null || !documentField.getProperty().hasExplicitWriteTarget()) {
return value;
}
@@ -803,6 +787,7 @@ public class QueryMapper {
*/
static class Keyword {
private static final String N_OR_PATTERN = "\\$.*or";
private static final Set<String> NON_DBREF_CONVERTING_KEYWORDS = new HashSet<>(
Arrays.asList("$", "$size", "$slice", "$gt", "$lt"));
@@ -833,7 +818,7 @@ public class QueryMapper {
}
public boolean isOrOrNor() {
return key.equalsIgnoreCase("$or") || key.equalsIgnoreCase("$nor");
return key.matches(N_OR_PATTERN);
}
/**
@@ -1184,8 +1169,8 @@ public class QueryMapper {
removePlaceholders(DOT_POSITIONAL_PATTERN, pathExpression));
if (sourceProperty != null && sourceProperty.getOwner().equals(entity)) {
return mappingContext.getPersistentPropertyPath(
PropertyPath.from(Pattern.quote(sourceProperty.getName()), entity.getTypeInformation()));
return mappingContext
.getPersistentPropertyPath(PropertyPath.from(Pattern.quote(sourceProperty.getName()), entity.getTypeInformation()));
}
PropertyPath path = forName(rawPath);
@@ -1193,47 +1178,29 @@ public class QueryMapper {
return null;
}
PersistentPropertyPath<MongoPersistentProperty> propertyPath = tryToResolvePersistentPropertyPath(path);
if (propertyPath == null) {
if (QueryMapper.LOGGER.isInfoEnabled()) {
String types = StringUtils.collectionToDelimitedString(
path.stream().map(it -> it.getType().getSimpleName()).collect(Collectors.toList()), " -> ");
QueryMapper.LOGGER.info(
"Could not map '{}'. Maybe a fragment in '{}' is considered a simple type. Mapper continues with {}.",
path, types, pathExpression);
}
return null;
}
Iterator<MongoPersistentProperty> iterator = propertyPath.iterator();
boolean associationDetected = false;
while (iterator.hasNext()) {
MongoPersistentProperty property = iterator.next();
if (property.isAssociation()) {
associationDetected = true;
continue;
}
if (associationDetected && !property.isIdProperty()) {
throw new MappingException(String.format(INVALID_ASSOCIATION_REFERENCE, pathExpression));
}
}
return propertyPath;
}
@Nullable
private PersistentPropertyPath<MongoPersistentProperty> tryToResolvePersistentPropertyPath(PropertyPath path) {
try {
return mappingContext.getPersistentPropertyPath(path);
} catch (MappingException e) {
PersistentPropertyPath<MongoPersistentProperty> propertyPath = mappingContext.getPersistentPropertyPath(path);
Iterator<MongoPersistentProperty> iterator = propertyPath.iterator();
boolean associationDetected = false;
while (iterator.hasNext()) {
MongoPersistentProperty property = iterator.next();
if (property.isAssociation()) {
associationDetected = true;
continue;
}
if (associationDetected && !property.isIdProperty()) {
throw new MappingException(String.format(INVALID_ASSOCIATION_REFERENCE, pathExpression));
}
}
return propertyPath;
} catch (InvalidPersistentPropertyPath e) {
return null;
}
}
@@ -1362,17 +1329,12 @@ public class QueryMapper {
static class KeyMapper {
private final Iterator<String> iterator;
private int currentIndex;
private String currentPropertyRoot;
private final List<String> pathParts;
public KeyMapper(String key,
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
this.pathParts = Arrays.asList(key.split("\\."));
this.iterator = pathParts.iterator();
this.currentPropertyRoot = iterator.next();
this.currentIndex = 0;
this.iterator = Arrays.asList(key.split("\\.")).iterator();
this.iterator.next();
}
/**
@@ -1384,31 +1346,21 @@ public class QueryMapper {
protected String mapPropertyName(MongoPersistentProperty property) {
StringBuilder mappedName = new StringBuilder(PropertyToFieldNameConverter.INSTANCE.convert(property));
boolean inspect = iterator.hasNext();
while (inspect) {
String partial = iterator.next();
currentIndex++;
boolean isPositional = isPositionalParameter(partial) && property.isCollectionLike() ;
if(property.isMap() && currentPropertyRoot.equals(partial) && iterator.hasNext()){
partial = iterator.next();
currentIndex++;
}
boolean isPositional = isPositionalParameter(partial) && property.isCollectionLike();
if (isPositional || property.isMap() && !currentPropertyRoot.equals(partial)) {
if (isPositional || property.isMap()) {
mappedName.append(".").append(partial);
}
inspect = isPositional && iterator.hasNext();
}
if(currentIndex + 1 < pathParts.size()) {
currentIndex++;
currentPropertyRoot = pathParts.get(currentIndex);
}
return mappedName.toString();
}

View File

@@ -16,7 +16,7 @@
package org.springframework.data.mongodb.core.geo;
/**
* Interface definition for structures defined in <a href="https://geojson.org/">GeoJSON</a> format.
* Interface definition for structures defined in <a href="https://geojson.org/>GeoJSON</a> format.
*
* @author Christoph Strobl
* @since 1.7

View File

@@ -353,7 +353,7 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
if (existingProperty != null) {
throw new MappingException(
String.format(AMBIGUOUS_FIELD_MAPPING, property.toString(), existingProperty.toString(), fieldName));
String.format(AMBIGUOUS_FIELD_MAPPING, property, existingProperty, fieldName));
}
properties.put(fieldName, property);

View File

@@ -15,11 +15,8 @@
*/
package org.springframework.data.mongodb.core.mapping;
import org.springframework.util.ObjectUtils;
/**
* @author Christoph Strobl
* @author Rogério Meneguelli Gatto
* @since 3.2
*/
class UnwrapEntityContext {
@@ -33,32 +30,4 @@ class UnwrapEntityContext {
public MongoPersistentProperty getProperty() {
return property;
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
UnwrapEntityContext that = (UnwrapEntityContext) obj;
return ObjectUtils.nullSafeEquals(property, that.property);
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return ObjectUtils.nullSafeHashCode(property);
}
}

View File

@@ -24,13 +24,11 @@ import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
/**
* Unwrapped variant of {@link MongoPersistentProperty}.
*
* @author Christoph Strobl
* @author Rogério Meneguelli Gatto
* @since 3.2
* @see Unwrapped
*/
@@ -306,38 +304,4 @@ class UnwrappedMongoPersistentProperty implements MongoPersistentProperty {
public <T> PersistentPropertyAccessor<T> getAccessorForOwner(T owner) {
return delegate.getAccessorForOwner(owner);
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
UnwrappedMongoPersistentProperty that = (UnwrappedMongoPersistentProperty) obj;
if (!ObjectUtils.nullSafeEquals(delegate, that.delegate)) {
return false;
}
return ObjectUtils.nullSafeEquals(context, that.context);
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int result = ObjectUtils.nullSafeHashCode(delegate);
result = 31 * result + ObjectUtils.nullSafeHashCode(context);
return result;
}
}

View File

@@ -39,6 +39,7 @@ import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryComposition.RepositoryFragments;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.core.support.RepositoryFragment;
import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
@@ -91,21 +92,8 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport {
*/
@Override
protected RepositoryFragments getRepositoryFragments(RepositoryMetadata metadata) {
return getRepositoryFragments(metadata, operations);
}
/**
* Creates {@link RepositoryFragments} based on {@link RepositoryMetadata} to add Mongo-specific extensions. Typically
* adds a {@link QuerydslMongoPredicateExecutor} if the repository interface uses Querydsl.
* <p>
* Can be overridden by subclasses to customize {@link RepositoryFragments}.
*
* @param metadata repository metadata.
* @param operations the MongoDB operations manager.
* @return
* @since 3.2.1
*/
protected RepositoryFragments getRepositoryFragments(RepositoryMetadata metadata, MongoOperations operations) {
RepositoryFragments fragments = RepositoryFragments.empty();
boolean isQueryDslRepository = QUERY_DSL_PRESENT
&& QuerydslPredicateExecutor.class.isAssignableFrom(metadata.getRepositoryInterface());
@@ -117,11 +105,14 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport {
"Cannot combine Querydsl and reactive repository support in a single interface");
}
return RepositoryFragments
.just(new QuerydslMongoPredicateExecutor<>(getEntityInformation(metadata.getDomainType()), operations));
MongoEntityInformation<?, Serializable> entityInformation = getEntityInformation(metadata.getDomainType(),
metadata);
fragments = fragments.append(RepositoryFragment.implemented(
getTargetRepositoryViaReflection(QuerydslMongoPredicateExecutor.class, entityInformation, operations)));
}
return RepositoryFragments.empty();
return fragments;
}
/*

View File

@@ -212,10 +212,6 @@ public class QuerydslMongoPredicateExecutor<T> extends QuerydslPredicateExecutor
*/
private SpringDataMongodbQuery<T> applyPagination(SpringDataMongodbQuery<T> query, Pageable pageable) {
if (pageable.isUnpaged()) {
return query;
}
query = query.offset(pageable.getOffset()).limit(pageable.getPageSize());
return applySorting(query, pageable.getSort());
}

View File

@@ -488,49 +488,6 @@ public class BsonUtils {
return null;
}
/**
* Returns the given source object as {@link Bson}, i.e. {@link Document}s and maps as is or throw
* {@link IllegalArgumentException}.
*
* @param source
* @return the converted/casted source object.
* @throws IllegalArgumentException if {@code source} cannot be converted/cast to {@link Bson}.
* @since 3.2.3
* @see #supportsBson(Object)
*/
@SuppressWarnings("unchecked")
public static Bson asBson(Object source) {
if (source instanceof Document) {
return (Document) source;
}
if (source instanceof BasicDBObject) {
return (BasicDBObject) source;
}
if (source instanceof DBObject) {
return new Document(((DBObject) source).toMap());
}
if (source instanceof Map) {
return new Document((Map<String, Object>) source);
}
throw new IllegalArgumentException(String.format("Cannot convert %s to Bson", source));
}
/**
* Returns the given source can be used/converted as {@link Bson}.
*
* @param source
* @return {@literal true} if the given source can be converted to {@link Bson}.
* @since 3.2.3
*/
public static boolean supportsBson(Object source) {
return source instanceof DBObject || source instanceof Map;
}
/**
* Returns given object as {@link Collection}. Will return the {@link Collection} as is if the source is a
* {@link Collection} already, will convert an array into a {@link Collection} or simply create a single element

View File

@@ -30,7 +30,7 @@ import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import org.bson.types.Binary;
import org.assertj.core.api.Assertions;
import org.bson.types.Code;
import org.bson.types.Decimal128;
import org.bson.types.ObjectId;
@@ -42,7 +42,6 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.factory.annotation.Value;
@@ -82,8 +81,6 @@ import org.springframework.data.mongodb.core.mapping.TextScore;
import org.springframework.data.mongodb.core.mapping.Unwrapped;
import org.springframework.data.mongodb.core.mapping.event.AfterConvertCallback;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.test.util.ReflectionTestUtils;
import com.mongodb.BasicDBList;
@@ -530,7 +527,7 @@ class MappingMongoConverterUnitTests {
}
@Test
void convertsObjectsIfNecessary() {
public void convertsObjectsIfNecessary() {
ObjectId id = new ObjectId();
assertThat(converter.convertToMongoType(id)).isEqualTo(id);
@@ -934,11 +931,10 @@ class MappingMongoConverterUnitTests {
assertThat(readResult.iterator().next()).isInstanceOf(Address.class);
}
@Test // DATAMONGO-402, GH-3702
@Test // DATAMONGO-402
void readsMemberClassCorrectly() {
org.bson.Document document = new org.bson.Document("inner",
new LinkedHashMap<>(new org.bson.Document("value", "FOO!")));
org.bson.Document document = new org.bson.Document("inner", new org.bson.Document("value", "FOO!"));
Outer outer = converter.read(Outer.class, document);
assertThat(outer.inner).isNotNull();
@@ -2115,21 +2111,21 @@ class MappingMongoConverterUnitTests {
}
@Test // DATAMONGO-2479
void entityCallbacksAreNotSetByDefault() {
assertThat(ReflectionTestUtils.getField(converter, "entityCallbacks")).isNull();
public void entityCallbacksAreNotSetByDefault() {
Assertions.assertThat(ReflectionTestUtils.getField(converter, "entityCallbacks")).isNull();
}
@Test // DATAMONGO-2479
void entityCallbacksShouldBeInitiatedOnSettingApplicationContext() {
public void entityCallbacksShouldBeInitiatedOnSettingApplicationContext() {
ApplicationContext ctx = new StaticApplicationContext();
converter.setApplicationContext(ctx);
assertThat(ReflectionTestUtils.getField(converter, "entityCallbacks")).isNotNull();
Assertions.assertThat(ReflectionTestUtils.getField(converter, "entityCallbacks")).isNotNull();
}
@Test // DATAMONGO-2479
void setterForEntityCallbackOverridesContextInitializedOnes() {
public void setterForEntityCallbackOverridesContextInitializedOnes() {
ApplicationContext ctx = new StaticApplicationContext();
converter.setApplicationContext(ctx);
@@ -2137,11 +2133,11 @@ class MappingMongoConverterUnitTests {
EntityCallbacks callbacks = EntityCallbacks.create();
converter.setEntityCallbacks(callbacks);
assertThat(ReflectionTestUtils.getField(converter, "entityCallbacks")).isSameAs(callbacks);
Assertions.assertThat(ReflectionTestUtils.getField(converter, "entityCallbacks")).isSameAs(callbacks);
}
@Test // DATAMONGO-2479
void setterForApplicationContextShouldNotOverrideAlreadySetEntityCallbacks() {
public void setterForApplicationContextShouldNotOverrideAlreadySetEntityCallbacks() {
EntityCallbacks callbacks = EntityCallbacks.create();
ApplicationContext ctx = new StaticApplicationContext();
@@ -2149,11 +2145,11 @@ class MappingMongoConverterUnitTests {
converter.setEntityCallbacks(callbacks);
converter.setApplicationContext(ctx);
assertThat(ReflectionTestUtils.getField(converter, "entityCallbacks")).isSameAs(callbacks);
Assertions.assertThat(ReflectionTestUtils.getField(converter, "entityCallbacks")).isSameAs(callbacks);
}
@Test // DATAMONGO-2479
void resolveDBRefMapValueShouldInvokeCallbacks() {
public void resolveDBRefMapValueShouldInvokeCallbacks() {
AfterConvertCallback<Person> afterConvertCallback = spy(new ReturningAfterConvertCallback());
converter.setEntityCallbacks(EntityCallbacks.create(afterConvertCallback));
@@ -2170,7 +2166,7 @@ class MappingMongoConverterUnitTests {
}
@Test // DATAMONGO-2300
void readAndConvertDBRefNestedByMapCorrectly() {
public void readAndConvertDBRefNestedByMapCorrectly() {
org.bson.Document cluster = new org.bson.Document("_id", 100L);
DBRef dbRef = new DBRef("clusters", 100L);
@@ -2432,178 +2428,6 @@ class MappingMongoConverterUnitTests {
verify(subTypeOfGenericTypeConverter).convert(eq(source));
}
@Test // GH-3660
void usesCustomConverterForMapTypesOnWrite() {
converter = new MappingMongoConverter(resolver, mappingContext);
converter.setCustomConversions(MongoCustomConversions.create(it -> {
it.registerConverter(new TypeImplementingMapToDocumentConverter());
}));
converter.afterPropertiesSet();
TypeImplementingMap source = new TypeImplementingMap("one", 2);
org.bson.Document target = new org.bson.Document();
converter.write(source, target);
assertThat(target).containsEntry("1st", "one").containsEntry("2nd", 2);
}
@Test // GH-3660
void usesCustomConverterForTypesImplementingMapOnWrite() {
converter = new MappingMongoConverter(resolver, mappingContext);
converter.setCustomConversions(MongoCustomConversions.create(it -> {
it.registerConverter(new TypeImplementingMapToDocumentConverter());
}));
converter.afterPropertiesSet();
TypeImplementingMap source = new TypeImplementingMap("one", 2);
org.bson.Document target = new org.bson.Document();
converter.write(source, target);
assertThat(target).containsEntry("1st", "one").containsEntry("2nd", 2);
}
@Test // GH-3660
void usesCustomConverterForTypesImplementingMapOnRead() {
converter = new MappingMongoConverter(resolver, mappingContext);
converter.setCustomConversions(MongoCustomConversions.create(it -> {
it.registerConverter(new DocumentToTypeImplementingMapConverter());
}));
converter.afterPropertiesSet();
org.bson.Document source = new org.bson.Document("1st", "one")
.append("2nd", 2)
.append("_class", TypeImplementingMap.class.getName());
TypeImplementingMap target = converter.read(TypeImplementingMap.class, source);
assertThat(target).isEqualTo(new TypeImplementingMap("one", 2));
}
@Test // GH-3660
void usesCustomConverterForPropertiesUsingTypesThatImplementMapOnWrite() {
converter = new MappingMongoConverter(resolver, mappingContext);
converter.setCustomConversions(MongoCustomConversions.create(it -> {
it.registerConverter(new TypeImplementingMapToDocumentConverter());
}));
converter.afterPropertiesSet();
TypeWrappingTypeImplementingMap source = new TypeWrappingTypeImplementingMap();
source.typeImplementingMap = new TypeImplementingMap("one", 2);
org.bson.Document target = new org.bson.Document();
converter.write(source, target);
assertThat(target).containsEntry("typeImplementingMap", new org.bson.Document("1st", "one").append("2nd", 2));
}
@Test // GH-3660
void usesCustomConverterForPropertiesUsingTypesImplementingMapOnRead() {
converter = new MappingMongoConverter(resolver, mappingContext);
converter.setCustomConversions(MongoCustomConversions.create(it -> {
it.registerConverter(new DocumentToTypeImplementingMapConverter());
}));
converter.afterPropertiesSet();
org.bson.Document source = new org.bson.Document("typeImplementingMap",
new org.bson.Document("1st", "one")
.append("2nd", 2))
.append("_class", TypeWrappingTypeImplementingMap.class.getName());
TypeWrappingTypeImplementingMap target = converter.read(TypeWrappingTypeImplementingMap.class, source);
assertThat(target.typeImplementingMap).isEqualTo(new TypeImplementingMap("one", 2));
}
@Test // GH-3686
void readsCollectionContainingNullValue() {
org.bson.Document source = new org.bson.Document("items", Arrays.asList(new org.bson.Document("itemKey", "i1"), null, new org.bson.Document("itemKey", "i3")));
Order target = converter.read(Order.class, source);
assertThat(target.items)
.map(it -> it != null ? it.itemKey : null)
.containsExactly("i1", null, "i3");
}
@Test // GH-3686
void readsArrayContainingNullValue() {
org.bson.Document source = new org.bson.Document("arrayOfStrings", Arrays.asList("i1", null, "i3"));
WithArrays target = converter.read(WithArrays.class, source);
assertThat(target.arrayOfStrings).containsExactly("i1", null, "i3");
}
@Test // GH-3686
void readsMapContainingNullValue() {
org.bson.Document source = new org.bson.Document("mapOfObjects", new org.bson.Document("item1", "i1").append("item2", null).append("item3", "i3"));
ClassWithMapProperty target = converter.read(ClassWithMapProperty.class, source);
assertThat(target.mapOfObjects)
.containsEntry("item1", "i1")
.containsEntry("item2", null)
.containsEntry("item3", "i3");
}
@Test // GH-3670
void appliesCustomConverterEvenToSimpleTypes() {
converter = new MappingMongoConverter(resolver, mappingContext);
converter.setCustomConversions(MongoCustomConversions.create(it -> {
it.registerConverter(new MongoSimpleTypeConverter());
}));
converter.afterPropertiesSet();
org.bson.Document source = new org.bson.Document("content", new Binary(new byte[] {0x00, 0x42}));
GenericType<Object> target = converter.read(GenericType.class, source);
assertThat(target.content).isInstanceOf(byte[].class);
}
@Test // GH-3702
void readsRawDocument() {
org.bson.Document source = new org.bson.Document("_id", "id-1").append("raw", new org.bson.Document("simple", 1).append("document", new org.bson.Document("inner-doc", 1)));
WithRawDocumentProperties target = converter.read(WithRawDocumentProperties.class, source);
assertThat(target.raw).isInstanceOf(org.bson.Document.class).isEqualTo( new org.bson.Document("simple", 1).append("document", new org.bson.Document("inner-doc", 1)));
}
@Test // GH-3702
void readsListOfRawDocument() {
org.bson.Document source = new org.bson.Document("_id", "id-1").append("listOfRaw", Arrays.asList(new org.bson.Document("simple", 1).append("document", new org.bson.Document("inner-doc", 1))));
WithRawDocumentProperties target = converter.read(WithRawDocumentProperties.class, source);
assertThat(target.listOfRaw)
.containsExactly(new org.bson.Document("simple", 1).append("document", new org.bson.Document("inner-doc", 1)));
}
@Test // GH-3692
void readsMapThatDoesNotComeAsDocument() {
org.bson.Document source = new org.bson.Document("_id", "id-1").append("mapOfObjects", Collections.singletonMap("simple", 1));
ClassWithMapProperty target = converter.read(ClassWithMapProperty.class, source);
assertThat(target.mapOfObjects).containsEntry("simple",1);
}
static class GenericType<T> {
T content;
}
@@ -2965,10 +2789,6 @@ class MappingMongoConverterUnitTests {
}
static class WithArrays {
String[] arrayOfStrings;
}
// DATAMONGO-1898
// DATACMNS-1278
@@ -3151,122 +2971,4 @@ class MappingMongoConverterUnitTests {
return target;
}
}
@WritingConverter
static class TypeImplementingMapToDocumentConverter implements Converter<TypeImplementingMap, org.bson.Document> {
@Nullable
@Override
public org.bson.Document convert(TypeImplementingMap source) {
return new org.bson.Document("1st", source.val1).append("2nd", source.val2);
}
}
@ReadingConverter
static class DocumentToTypeImplementingMapConverter implements Converter<org.bson.Document, TypeImplementingMap> {
@Nullable
@Override
public TypeImplementingMap convert(org.bson.Document source) {
return new TypeImplementingMap(source.getString("1st"), source.getInteger("2nd"));
}
}
@ReadingConverter
public static class MongoSimpleTypeConverter implements Converter<Binary, Object> {
@Override
public byte[] convert(Binary source) {
return source.getData();
}
}
static class TypeWrappingTypeImplementingMap {
String id;
TypeImplementingMap typeImplementingMap;
}
@EqualsAndHashCode
static class TypeImplementingMap implements Map<String,String> {
String val1;
int val2;
TypeImplementingMap(String val1, int val2) {
this.val1 = val1;
this.val2 = val2;
}
@Override
public int size() {
return 0;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean containsKey(Object key) {
return false;
}
@Override
public boolean containsValue(Object value) {
return false;
}
@Override
public String get(Object key) {
return null;
}
@Nullable
@Override
public String put(String key, String value) {
return null;
}
@Override
public String remove(Object key) {
return null;
}
@Override
public void putAll(@NonNull Map<? extends String, ? extends String> m) {
}
@Override
public void clear() {
}
@NonNull
@Override
public Set<String> keySet() {
return null;
}
@NonNull
@Override
public Collection<String> values() {
return null;
}
@NonNull
@Override
public Set<Entry<String, String>> entrySet() {
return null;
}
}
static class WithRawDocumentProperties {
String id;
org.bson.Document raw;
List<org.bson.Document> listOfRaw;
}
}

View File

@@ -36,13 +36,8 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.convert.WritingConverter;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.geo.Point;
@@ -55,7 +50,6 @@ import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.FieldType;
import org.springframework.data.mongodb.core.mapping.MongoId;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.TextScore;
@@ -77,10 +71,8 @@ import com.mongodb.client.model.Filters;
* @author Thomas Darimont
* @author Christoph Strobl
* @author Mark Paluch
* @author David Julia
*/
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
public class QueryMapperUnitTests {
private QueryMapper mapper;
@@ -740,28 +732,6 @@ public class QueryMapperUnitTests {
assertThat(document).containsKey("map.1.stringProperty");
}
@Test // GH-3688
void mappingShouldRetainNestedNumericMapKeys() {
Query query = query(where("outerMap.1.map.2.stringProperty").is("ba'alzamon"));
org.bson.Document document = mapper.getMappedObject(query.getQueryObject(),
context.getPersistentEntity(EntityWithIntKeyedMapOfMap.class));
assertThat(document).containsKey("outerMap.1.map.2.stringProperty");
}
@Test // GH-3688
void mappingShouldAllowSettingEntireNestedNumericKeyedMapValue() {
Query query = query(where("outerMap.1.map").is(null)); //newEntityWithComplexValueTypeMap()
org.bson.Document document = mapper.getMappedObject(query.getQueryObject(),
context.getPersistentEntity(EntityWithIntKeyedMapOfMap.class));
assertThat(document).containsKey("outerMap.1.map");
}
@Test // DATAMONGO-1269
void mappingShouldRetainNumericPositionInList() {
@@ -1287,52 +1257,6 @@ public class QueryMapperUnitTests {
assertThat(document).isEqualTo(new org.bson.Document("double_underscore.renamed", new org.bson.Document("$exists", true)));
}
@Test // GH-3633
void mapsNullValueForFieldWithCustomTargetType() {
Query query = query(where("stringAsOid").is(null));
org.bson.Document document = mapper.getMappedObject(query.getQueryObject(),
context.getPersistentEntity(NonIdFieldWithObjectIdTargetType.class));
assertThat(document).isEqualTo(new org.bson.Document("stringAsOid", null));
}
@Test // GH-3635
void $floorKeywordDoesNotMatch$or$norPattern() {
Query query = new BasicQuery(" { $expr: { $gt: [ \"$spent\" , { $floor : \"$budget\" } ] } }");
assertThatNoException()
.isThrownBy(() -> mapper.getMappedObject(query.getQueryObject(), context.getPersistentEntity(Foo.class)));
}
@Test // GH-3659
void allowsUsingFieldPathsForPropertiesHavingCustomConversionRegistered() {
Query query = query(where("address.street").is("1007 Mountain Drive"));
MongoCustomConversions mongoCustomConversions = new MongoCustomConversions(Collections.singletonList(new MyAddressToDocumentConverter()));
this.context = new MongoMappingContext();
this.context.setSimpleTypeHolder(mongoCustomConversions.getSimpleTypeHolder());
this.context.afterPropertiesSet();
this.converter = new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, context);
this.converter.setCustomConversions(mongoCustomConversions);
this.converter.afterPropertiesSet();
this.mapper = new QueryMapper(converter);
assertThat(mapper.getMappedSort(query.getQueryObject(), context.getPersistentEntity(Customer.class))).isEqualTo(new org.bson.Document("address.street", "1007 Mountain Drive"));
}
@Test // GH-3668
void mapStringIdFieldProjection() {
org.bson.Document mappedFields = mapper.getMappedFields(new org.bson.Document("id", 1), context.getPersistentEntity(WithStringId.class));
assertThat(mappedFields).containsEntry("_id", 1);
}
class WithDeepArrayNesting {
List<WithNestedArray> level0;
@@ -1396,12 +1320,6 @@ public class QueryMapperUnitTests {
@Id private String foo;
}
class WithStringId {
@MongoId String id;
String name;
}
class BigIntegerId {
@Id private BigInteger id;
@@ -1478,22 +1396,18 @@ public class QueryMapperUnitTests {
@Field("geoJsonPointWithNameViaFieldAnnotation") GeoJsonPoint namedGeoJsonPoint;
}
static class SimpleEntityWithoutId {
static class SimpeEntityWithoutId {
String stringProperty;
Integer integerProperty;
}
static class EntityWithComplexValueTypeMap {
Map<Integer, SimpleEntityWithoutId> map;
}
static class EntityWithIntKeyedMapOfMap{
Map<Integer, EntityWithComplexValueTypeMap> outerMap;
Map<Integer, SimpeEntityWithoutId> map;
}
static class EntityWithComplexValueTypeList {
List<SimpleEntityWithoutId> list;
List<SimpeEntityWithoutId> list;
}
static class WithExplicitTargetTypes {
@@ -1573,28 +1487,4 @@ public class QueryMapperUnitTests {
@Field("renamed")
String renamed_fieldname_with_underscores;
}
@Document
static class Customer {
@Id
private ObjectId id;
private String name;
private MyAddress address;
}
static class MyAddress {
private String street;
}
@WritingConverter
public static class MyAddressToDocumentConverter implements Converter<MyAddress, org.bson.Document> {
@Override
public org.bson.Document convert(MyAddress address) {
org.bson.Document doc = new org.bson.Document();
doc.put("street", address.street);
return doc;
}
}
}

View File

@@ -66,7 +66,6 @@ import com.mongodb.DBRef;
* @author Thomas Darimont
* @author Mark Paluch
* @author Pavel Vodrazka
* @author David Julia
*/
@ExtendWith(MockitoExtension.class)
class UpdateMapperUnitTests {
@@ -1180,16 +1179,6 @@ class UpdateMapperUnitTests {
assertThat(mappedUpdate).isEqualTo("{\"$set\": {\"map.601218778970110001827396.value\": \"testing\"}}");
}
@Test // GH-3688
void multipleNumericKeysInNestedPath() {
Update update = new Update().set("intKeyedMap.12345.map.0", "testing");
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
context.getPersistentEntity(EntityWithIntKeyedMap.class));
assertThat(mappedUpdate).isEqualTo("{\"$set\": {\"intKeyedMap.12345.map.0\": \"testing\"}}");
}
@Test // GH-3566
void mapsObjectClassPropertyFieldInMapValueTypeAsKey() {
@@ -1436,10 +1425,6 @@ class UpdateMapperUnitTests {
Map<Object, NestedDocument> concreteMap;
}
static class EntityWithIntKeyedMap{
Map<Integer, EntityWithObjectMap> intKeyedMap;
}
static class ClassWithEnum {
Allocation allocation;

View File

@@ -60,9 +60,7 @@ import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.repository.Person.Sex;
import org.springframework.data.mongodb.repository.SampleEvaluationContextExtension.SampleSecurityContextHolder;
import org.springframework.data.mongodb.test.util.EnableIfMongoServerVersion;
@@ -1424,14 +1422,4 @@ public abstract class AbstractPersonRepositoryIntegrationTests {
Person target = repository.findWithAggregationInProjection(alicia.getId());
assertThat(target.getFirstname()).isEqualTo(alicia.getFirstname().toUpperCase());
}
@Test // GH-3633
void annotatedQueryWithNullEqualityCheckShouldWork() {
operations.updateFirst(Query.query(Criteria.where("id").is(dave.getId())), Update.update("age", null), Person.class);
Person byQueryWithNullEqualityCheck = repository.findByQueryWithNullEqualityCheck();
assertThat(byQueryWithNullEqualityCheck.getId()).isEqualTo(dave.getId());
}
}

View File

@@ -410,7 +410,4 @@ public interface PersonRepository extends MongoRepository<Person, String>, Query
List<Person> findByUnwrappedUserUsername(String username);
List<Person> findByUnwrappedUser(User user);
@Query("{ 'age' : null }")
Person findByQueryWithNullEqualityCheck();
}

View File

@@ -27,8 +27,6 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.dao.PermissionDeniedDataAccessException;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mongodb.MongoDatabaseFactory;
@@ -124,20 +122,6 @@ public class QuerydslMongoPredicateExecutorIntegrationTests {
.containsExactly(dave);
}
@Test // GH-3751
public void findPage() {
assertThat(repository
.findAll(person.lastname.startsWith(oliver.getLastname()).and(person.firstname.startsWith(dave.getFirstname())),
PageRequest.of(0, 10))
.getContent()).containsExactly(dave);
assertThat(repository
.findAll(person.lastname.startsWith(oliver.getLastname()).and(person.firstname.startsWith(dave.getFirstname())),
Pageable.unpaged())
.getContent()).containsExactly(dave);
}
@Test // DATAMONGO-362, DATAMONGO-1848
public void springDataMongodbQueryShouldAllowJoinOnDBref() {

View File

@@ -119,9 +119,6 @@ public class MongoTestTemplateConfiguration {
mappingContext = new MongoMappingContext();
mappingContext.setInitialEntitySet(mappingContextConfigurer.initialEntitySet());
mappingContext.setAutoIndexCreation(mappingContextConfigurer.autocreateIndex);
if(mongoConverterConfigurer.customConversions != null) {
mappingContext.setSimpleTypeHolder(mongoConverterConfigurer.customConversions.getSimpleTypeHolder());
}
mappingContext.afterPropertiesSet();
}

View File

@@ -19,7 +19,7 @@ import static org.assertj.core.api.Assertions.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.bson.BsonDouble;
import org.bson.BsonInt32;
@@ -29,16 +29,10 @@ import org.bson.BsonString;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.junit.jupiter.api.Test;
import org.springframework.data.mongodb.util.BsonUtils;
import com.mongodb.BasicDBList;
/**
* Unit tests for {@link BsonUtils}.
*
* @author Christoph Strobl
* @author Mark Paluch
*/
class BsonUtilsTest {
@@ -117,13 +111,4 @@ class BsonUtilsTest {
assertThat((Collection)BsonUtils.asCollection(source)).containsExactly(source);
}
@Test // GH-3702
void supportsBsonShouldReportIfConversionSupported() {
assertThat(BsonUtils.supportsBson("foo")).isFalse();
assertThat(BsonUtils.supportsBson(new Document())).isTrue();
assertThat(BsonUtils.supportsBson(new BasicDBList())).isTrue();
assertThat(BsonUtils.supportsBson(Collections.emptyMap())).isTrue();
}
}

View File

@@ -383,13 +383,6 @@ class ParameterBindingJsonReaderUnitTests {
.parse("{ 'stores.location' : { $geoWithin: { $centerSphere: [ [ 1.948516, 48.799029 ] , 0.004 ] } } }"));
}
@Test // GH-3633
void parsesNullValue() {
Document target = parse("{ 'parent' : null }");
assertThat(target).isEqualTo(new Document("parent", null));
}
private static Document parse(String json, Object... args) {
ParameterBindingJsonReader reader = new ParameterBindingJsonReader(json, args);

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2019 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.core
import com.mongodb.client.MongoClients
import org.junit.Test
import org.springframework.data.mongodb.core.mapping.Field
import org.springframework.data.mongodb.repository.MongoRepository
import org.springframework.data.mongodb.repository.support.MongoRepositoryFactory
import org.springframework.data.mongodb.test.util.Assertions.assertThat
open class SuperType(open var field: Int)
class SubType(val id: String, @Field("foo") override var field: Int = 1) :
SuperType(field) {
fun setFields(v: Int) {
field = v
super.field = v
}
}
interface MyRepository : MongoRepository<SubType, String>
class `KotlinOverridePropertyTests` {
val template = MongoTemplate(MongoClients.create(), "kotlin-tests")
@Test // DATAMONGO-2250
fun `Ambiguous field mapping for override val field`() {
val repository =
MongoRepositoryFactory(template).getRepository(MyRepository::class.java)
var subType = SubType("id-1")
subType.setFields(3)
repository.save(subType)
assertThat(repository.findById(subType.id).get().field).isEqualTo(subType.field)
}
}

View File

@@ -214,7 +214,7 @@ public class AppConfig {
----
====
To access the `com.mongodb.client.MongoClient` object created by the `MongoClientFactoryBean` in other `@Configuration` classes or your own classes, use a `private @Autowired MongoClient mongoClient;` field.
To access the `com.mongodb.client.MongoClient` object created by the `MongoClientFactoryBean` in other `@Configuration` classes or your own classes, use a `private @Autowired Mongo mongo;` field.
[[mongo.mongo-xml-config]]
=== Registering a Mongo Instance by Using XML-based Metadata
@@ -2444,8 +2444,9 @@ A `TypedAggregation`, just like an `Aggregation`, holds the instructions of the
At runtime, field references get checked against the given input type, considering potential `@Field` annotations.
[NOTE]
====
Changed in 3.2 referencing non-existent properties does no longer raise errors. To restore the previous behaviour use the `strictMapping` option of `AggregationOptions`.
Changed in 3.2 referencing none-xistent properties does no longer raise errors. To restore the previous behaviour use the `strictMapping` option of `AggregationOptions`.
====
+
* `AggregationDefinition`
+
An `AggregationDefinition` represents a MongoDB aggregation pipeline operation and describes the processing that should be performed in this aggregation step. Although you could manually create an `AggregationDefinition`, we recommend using the static factory methods provided by the `Aggregate` class to construct an `AggregateOperation`.

View File

@@ -1,47 +1,6 @@
Spring Data MongoDB Changelog
=============================
Changes in version 3.2.3 (2021-07-16)
-------------------------------------
* #3702 - `MappingMongoConverter` incorrectly processes an object property of type `org.bson.Document`.
* #3689 - Fix Regression in generating queries with nested maps with numeric keys.
* #3688 - Multiple maps with numeric keys in a single update produces the wrong query (Regression).
* #3686 - reading a document with a list with a null element fails with Spring Data Mongo 3.2.2, works with 3.2.1.
* #3684 - Add equals and hashcode to UnwrappedMongoPersistentProperty (fixes #3683).
* #3683 - Memory Leak: instances of UnwrappedMongoPersistentProperty are accumulating in PreferredConstructor.isPropertyParameterCache.
* #3670 - `Binary` not deserialized to `byte[]` for property of type `Object`.
Changes in version 3.2.2 (2021-06-22)
-------------------------------------
* #3677 - Add missing double quote to GeoJson.java JSDoc header.
* #3668 - Projection on the _id field returns wrong result when using `@MongoId` (MongoDB 4.4).
* #3666 - Documentation references outdated `Mongo` client.
* #3660 - MappingMongoConverter problem: ConversionContext#convert does not try to use custom converters first.
* #3659 - [3.2.1] Indexing Class with Custom Converter -> Couldn't find PersistentEntity for property private [...].
* #3635 - $floor isOrOrNor() return true.
* #3633 - NPE in QueryMapper when use Query with `null` as value.
Changes in version 3.1.10 (2021-06-22)
--------------------------------------
* #3677 - Add missing double quote to GeoJson.java JSDoc header.
* #3666 - Documentation references outdated `Mongo` client.
* #3659 - [3.2.1] Indexing Class with Custom Converter -> Couldn't find PersistentEntity for property private [...].
* #3635 - $floor isOrOrNor() return true.
* #3633 - NPE in QueryMapper when use Query with `null` as value.
Changes in version 3.2.1 (2021-05-14)
-------------------------------------
* #3638 - Introduce template method for easier customization of fragments.
* #3632 - Fix bullet points in aggregations framework asciidoc.
Changes in version 3.1.9 (2021-05-14)
-------------------------------------
Changes in version 3.2.0 (2021-04-14)
-------------------------------------
* #3623 - `@Aggregation` repository query method causes `NullPointerException` when the result is empty.
@@ -3467,11 +3426,6 @@ Repository

View File

@@ -1,4 +1,4 @@
Spring Data MongoDB 3.2.4 (2021.0.4)
Spring Data MongoDB 3.2 GA (2021.0.0)
Copyright (c) [2010-2019] Pivotal Software, Inc.
This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -24,10 +24,6 @@ conditions of the subcomponent's license, as noted in the LICENSE file.