Compare commits

..

154 Commits

Author SHA1 Message Date
Mark Paluch
af917b9465 Release version 4.0 RC1 (2022.0.0).
See #4175
2022-10-13 17:24:25 +02:00
Mark Paluch
ee545487b8 Prepare 4.0 RC1 (2022.0.0).
See #4175
2022-10-13 17:24:03 +02:00
Mark Paluch
240e53794c Fix Javadoc.
See #4139
Original pull request: #4182.
2022-10-12 15:59:33 +02:00
Christoph Strobl
7b6a06888d Update javadoc.
See: #4184
See: #4197
Original pull request: #4203.
2022-10-12 15:25:13 +02:00
Christoph Strobl
034a3528af Preserve given Id on insert.
This commit fixes an issue where an existing Id got replaced with a generated one when using MongoId annotation.

Closes: #4184
Closes: #4197
Original pull request: #4203.
2022-10-12 15:24:50 +02:00
Christoph Strobl
ff28789507 Polishing.
See #4139
Original pull request: #4182.
2022-10-12 15:12:42 +02:00
Christoph Strobl
cdfdeafdac Update aggregation reference documentation.
See #4139
Original pull request: #4182.
2022-10-12 15:12:38 +02:00
Christoph Strobl
16a35e0329 Add support for $densify aggregation stage.
See #4139
Original pull request: #4182.
2022-10-12 15:12:38 +02:00
Christoph Strobl
79f05c3d7f Move Expr operator one level up.
The Expr operator should be held within ExpressionOperators not its factory.

See #4139
Original pull request: #4182.
2022-10-12 15:12:37 +02:00
Christoph Strobl
9217821472 Add support for $locf aggregation operator.
See #4139
Original pull request: #4182.
2022-10-12 15:12:37 +02:00
Christoph Strobl
8d223abd05 Add support for $tsSecond aggregation operator.
See #4139
Original pull request: #4182.
2022-10-12 15:12:37 +02:00
Christoph Strobl
6a973b245f Add support for $tsIncrement aggregation operator.
See #4139
Original pull request: #4182.
2022-10-12 15:12:37 +02:00
Christoph Strobl
714b23e0ce Add support for $sortArray aggregation operator.
See #4139
Original pull request: #4182.
2022-10-12 15:12:37 +02:00
Christoph Strobl
d4a6614c11 Add support for $setField aggregation operator.
See #4139
Original pull request: #4182.
2022-10-12 15:11:48 +02:00
Christoph Strobl
82ce0abe1a Add support for $getField aggregation operator.
See #4139
Original pull request: #4182.
2022-10-12 15:11:46 +02:00
Christoph Strobl
dec7c125d6 Add support for $dateTrunc aggregation operator.
See #4139
Original pull request: #4182.
2022-10-12 15:11:43 +02:00
Christoph Strobl
db12c4ba5a Add support for $dateSubtract aggregation operator.
See #4139
Original pull request: #4182.
2022-10-12 15:11:41 +02:00
Christoph Strobl
5bbe481e98 Add support for $minN aggregation operator.
See #4139
Original pull request: #4182.
2022-10-12 15:11:38 +02:00
Christoph Strobl
fb39c31986 Add support for $maxN aggregation operator.
See #4139
Original pull request: #4182.
2022-10-12 15:11:31 +02:00
Christoph Strobl
dd446472bc Polishing.
See #4139
Original pull request: #4182.
2022-10-12 15:11:22 +02:00
Christoph Strobl
72d82d3083 Add support for $top & $topN aggregation operators.
Closes #4139
Original pull request: #4182.
2022-10-12 15:11:20 +02:00
Christoph Strobl
cdfe2a0b59 Add support for $lastN aggregation operator.
Closes #4139
Original pull request: #4182.
2022-10-12 15:11:18 +02:00
Christoph Strobl
5525a4fbf9 Add support for $firstN aggregation operator.
Closes #4139
Original pull request: #4182.
2022-10-12 15:11:15 +02:00
Christoph Strobl
59464f3b3c Add support for $bottomN aggregation operator.
Closes #4139
Original pull request: #4182.
2022-10-12 15:11:09 +02:00
Christoph Strobl
052cfdfd45 Add support for $bottom aggregation operator.
Closes #4139
Original pull request: #4182.
2022-10-12 15:10:40 +02:00
Christoph Strobl
b31c21bb91 Upgrade to MongoDB driver 4.8.0-beta0.
Closes: #4200
2022-10-11 16:47:23 +02:00
Christoph Strobl
5b6e5ca568 Update tests.
Original Pull Request: #4196
2022-10-11 11:53:26 +02:00
gongxuanzhang
1a9136c0c1 Fix json schema type name for boolean.
Was boolean should have been bool.

Closes: #4196
2022-10-11 11:53:25 +02:00
Mark Paluch
59753bb55a Adapt to changed AOT packages in Spring Data Commons.
Closes #4199
2022-10-11 11:39:00 +02:00
Christoph Strobl
8d963fc5da Add option to configure change stream behaviour at collection creation time.
Introduce CollectionChangeStreamOptions which allows to define the changeStreamPreAndPostImages of the createCollection command.

Original Pull Request: #4193
2022-10-10 11:54:32 +02:00
Christoph Strobl
c1de745014 Polishing.
Update javadoc, format imports and add issue references.

Original Pull Request: #4193
2022-10-10 11:54:08 +02:00
myroslav.kosinskyi
aa35aaeb70 Add fullDocumentBeforeChange support for change streams.
Closes: #4187
Original Pull Request: #4193
2022-10-10 11:53:39 +02:00
Mark Paluch
a5725806f5 Remove references to ClassTypeInformation from TypeInformation.
Closes #4195
2022-10-06 16:21:30 +02:00
Christoph Strobl
d715414683 Switch to micrometer 1.10 snapshots.
Follow signature changes.

See: #4191
See: spring-projects/spring-data-build#1810
2022-10-06 15:44:51 +02:00
Christoph Strobl
f2c2451b7d Add hint how to use $search aggregation operator to reference documentation.
Closes: #4183
2022-10-06 13:56:57 +02:00
Christoph Strobl
5b8d0d08ee Update reactive transaction sample in reference documentation.
Closes: #4190
2022-10-06 13:03:56 +02:00
Christoph Ahlers
18186f26e2 Remove unused imports.
Closes: #4178
2022-10-06 10:21:50 +02:00
Christoph Ahlers
10acc14c14 Fix javadoc parameter names.
Closes: #4179
2022-10-04 12:31:34 +02:00
Wan Bachtiar
87effb9013 Fix typo in reference documentation.
Closes: #4180
2022-10-04 12:24:23 +02:00
Mark Paluch
19819680f9 Adopt to SLF4J 2.0 upgrade.
Exclude transitive Micrometer Test dependencies that ship outdated SLF4J implementations.

Closes #4189
2022-09-30 13:38:52 +02:00
Mark Paluch
2d2f67cc93 Prefer Java configuration over XML.
Closes #4186
2022-09-28 15:29:10 +02:00
Seungwoo Jo
e9818fe11a Fix documentation typo in BasicQuery.
Closes #4169
Original pull request: #4170.
2022-09-21 11:15:12 +02:00
Christoph Strobl
a63db5586c Add missing aggregation system variables.
Move inner class SystemVariable to upper level and add missing values (NOW, CLUSTER_TIME, DECEND, PRUNE, KEEP & SEARCH_META)

Original pull request: #4176.
Closes #4145
2022-09-21 10:51:00 +02:00
Mark Paluch
68ab74a5bf Polishing.
Reformat code.

See #4004
Original pull request: #4006.
2022-09-21 10:48:22 +02:00
Christoph Strobl
de33734118 Polishing
Update Javadoc to mention unit of measure for min/maxDistance depending on usage of geoJson.
Also remove unused imports from tests

See #4004
Original pull request: #4006.
2022-09-21 10:48:22 +02:00
Christoph Strobl
c272c7317e Fix rewrite near & nearSphere count queries using geoJson to geoWithin.
$near and $nearSphere queries are not supported via countDocuments and the used aggregation match stage and need to be rewritten to $geoWithin. The existing logic did not cover usage of geoJson types, which is fixed now. In case of nearSphere it is also required to convert the $maxDistance argument (given in meters for geoJson) to radians which is used by $geoWithin $centerSphere.

Closes #4004
Original pull request: #4006.
Related to #2925
2022-09-21 10:48:21 +02:00
Spring Builds
d7fc605f7b After release cleanups.
See #4117
2022-09-19 14:39:07 +00:00
Spring Builds
3b805b9e03 Prepare next development iteration.
See #4117
2022-09-19 14:38:55 +00:00
Spring Builds
91cca3f2c4 Release version 4.0 M6 (2022.0.0).
See #4117
2022-09-19 14:15:22 +00:00
Spring Builds
2de6384d0f Prepare 4.0 M6 (2022.0.0).
See #4117
2022-09-19 14:12:56 +00:00
Christoph Strobl
ab1c0ff7b8 Apply conversion on document reference lookup using nested property.
Closes #4033
Original pull request: #4044.
2022-09-19 09:57:24 +02:00
Christoph Strobl
ae2846c5bf Generate and convert id on insert if explicitly defined.
We now make sure to provide an id value that matches the desired target type when no id is set, and the property defines an explicit conversion target.
Previously a new ObjectId would have been generated which leads to type inconsistencies when querying for _id.

Closes #4026
Original pull request: #4057.
2022-09-19 09:47:18 +02:00
Christoph Strobl
e88c9cf791 Fix issue with reference conversion in updates.
We now make sure to convert references in update operations targeting collection like fields when using eg. the push modifier.

Closes #4041
Original pull request: #4045.
2022-09-19 08:54:26 +02:00
Christoph Strobl
fadca10f62 Support @DocumentReference via Querydsl.
Closes #4037
Original pull request: #4069.
2022-09-16 15:57:30 +02:00
Mark Paluch
40320136f3 Polishing.
See #4061
Original pull request: #4062.
2022-09-16 14:52:00 +02:00
Christoph Strobl
bc575de3b0 Improve exception message when deriving collection name from type.
We now provide a better worded exception message when trying to derive the collection name for a type that is not considered a user types (such as org.bson.Document).
Update the Javadoc to hint to the error.

Closes #4061
Original pull request: #4062.
2022-09-16 14:51:54 +02:00
Christoph Strobl
09b2afa79d Initialize lists with size where possible.
Closes #3941
Original pull request: #3974.
2022-09-16 14:45:34 +02:00
Mark Paluch
96b564eb9a Polishing.
Reformat code.

See #4167.
Original pull request: #4168.
2022-09-16 14:40:34 +02:00
Christoph Strobl
38390d3475 Fix usage of change stream option startAfter.
We now make sure to apply the token to startAfter method of the driver. Before this change it had been incorrectly applied to resumeAfter.

Closes #4167.
Original pull request: #4168.
2022-09-16 14:40:27 +02:00
Mark Paluch
6937bb519b Polishing.
Move off more deprecated API.

See #4164
Original pull request: #4165.
2022-09-16 11:11:17 +02:00
Christoph Strobl
6e4d463053 Move off deprecated API.
Closes #4164
Original pull request: #4165.
2022-09-16 11:11:12 +02:00
Mark Paluch
a9d2050806 Polishing.
Fix generics. Add warning suppressions for nullability checks.

See: #4104
Original pull request: #4156.
2022-09-14 14:06:44 +02:00
Christoph Strobl
6676389062 Fix GeoJson polygon conversion for polygons with inner ring.
Closes: #4104
Original pull request: #4156.
2022-09-14 14:06:35 +02:00
Mark Paluch
81f85b8cca Polishing.
Tweak Javadoc, make ViewOptions.collation final.

See: #2594
Original pull request: #4142.
2022-09-14 11:31:14 +02:00
Christoph Strobl
77f318bd77 Add support to create views via reactive/template API.
This commit introduces support to create MongoDB Views directly via the Reactive-/MongoOperations API.

Closes: #2594
Original pull request: #4142.
2022-09-14 11:30:24 +02:00
Brian Clozel
7c7e70418f Replace deprecated StreamUtils API
As of spring-projects/spring-framework#29125,
`StreamUtils..emptyInput()` is deprecated in favor of
`InputStream.nullInputStream()` from the JDK.

Closes: #4160
2022-09-14 08:14:06 +02:00
Mark Paluch
44a1123034 Adopt to changed Mockk artifact name.
Closes #4161
2022-09-12 14:08:14 +02:00
Mark Paluch
e487c08b0c Polishing.
Reformat pom.xml

See #4161
2022-09-12 10:18:38 +02:00
Mark Paluch
a002d30aa9 Polishing.
Reformat pom.xml

See #4161
2022-09-12 10:17:58 +02:00
Tommy Ludwig
36ddd26edc Adapt to SampleTestRunner refactor.
See: micrometer-metrics/tracing#57
Closes: #4159
2022-09-09 19:13:57 +02:00
Tommy Ludwig
6197655e98 Adapt to ObservationConvention location change
See: micrometer-metrics/micrometer#3387
Closes: #4158
2022-09-09 19:06:28 +02:00
Christoph Strobl
929faea88b Add snapshot plugin repository for micrometer docs.
See: #4151.
2022-09-07 14:51:57 +02:00
Greg L. Turnquist
1fe1c13531 Upgrade to Micrometer 1.10.0-SNAPSHOT.
Closes #4151.
2022-09-07 12:17:16 +02:00
Kirill Gavrilov
838ddb5d26 Align signature of Kotlin extension functions to match Java API.
Closes: #4153
Original Pull Request: #4154
Related issues: #2602 #3187
2022-09-07 09:48:48 +02:00
Christoph Strobl
33c7f0980f Remove usage SynthesizedAnnotation.
Closes: #4155
2022-09-07 08:54:41 +02:00
Mark Paluch
4bbc443a0e Polishing.
Refine assertions.

See #4132
Original pull request: #4147.
2022-08-25 15:45:29 +02:00
Christoph Strobl
655dbc9783 Favor relaxed type mapping over strict one for aggregateStream.
Align aggregation context usage of aggregate and aggregate stream methods.

Closes #4132
Original pull request: #4147.
2022-08-25 15:45:13 +02:00
Christoph Strobl
0d752fd6e6 Introduce dedicated Collation annotation.
The Collation annotation mainly serves as a meta annotation that allows common access to retrieving collation values for annotated queries, aggregations, etc.

Original Pull Request: #4131
2022-08-25 09:03:43 +02:00
Christoph Strobl
8aabf2fa5e Polishing.
Resolve collation from template expression & update issue references + Javadoc.

Original Pull Request: #4131
2022-08-25 09:00:51 +02:00
Stefan Tirea
ff9d338bd7 Add collation for an index via @CompoundIndex and @Index annotations.
Closes #3002, closes #4130

Original Pull Request: #4131
2022-08-25 09:00:17 +02:00
Mark Paluch
2a4ee12363 Document BulkOperations limitations.
Closes #4082
2022-08-23 15:39:59 +02:00
Christoph Strobl
a66438fc20 Resolve cglib proxies during AOT processing.
We now make sure to run the enhancer during AOT which allows the infrastructure to pick up the generated type.
Along the lines we removed the no longer supported asserts for class proxies and followed changes in FW6.

Closes: #4148
2022-08-23 11:48:23 +02:00
Mark Paluch
0ccc037b8e Polishing.
Introduce JUnit extension to declare tests that dirty or provide their state.

See #3817
Original pull request: #3987.
2022-08-23 10:00:16 +02:00
Christoph Strobl
00792192c3 Close clients created during tests.
See #3817
Original pull request: #3987.
2022-08-23 09:54:29 +02:00
Christoph Strobl
e064b505c9 Prevent sync client from being created in reactive test config.
Closes #3817
Original pull request: #3987.
2022-08-23 09:53:58 +02:00
Christoph Strobl
7df2bdf8ff Upgrade to MongoDB driver 4.7.1
Closes: #4144
2022-08-22 07:59:57 +02:00
Mark Paluch
2f9fc1618e Use mongosh instead of mongo CLI.
Switch from the deprecated command to its replacement.

See #4138
2022-08-17 12:56:26 +02:00
Mark Paluch
9e2aecf4ae Polishing.
Fix required Java version.

See #4140
2022-08-17 10:58:13 +02:00
Mark Paluch
c32c4beb59 Remove new & noteworthy section in favor of our release notes.
The release notes now outline new and noteworthy changes.

Closes #4140
2022-08-17 10:51:01 +02:00
Mark Paluch
d48f3ec535 Polishing.
Use && syntax to catch commands that exit with non-success exit codes.

See #4139
2022-08-17 10:44:11 +02:00
Mark Paluch
5f16aecd13 Assert compatibility with MongoDB 6.0.
Closes #4138
2022-08-17 10:42:57 +02:00
Mark Paluch
5fc49b1649 Polishing.
Encapsulate nested object lookup. Refine method signatures and tweak Javadoc.

See #4098
Original pull request: #4133.
2022-08-05 15:59:31 +02:00
Christoph Strobl
1e7dc7ce66 Fix non-association mapping when id value matches already resolved instance of same type.
This commit ensures to fully resolve non association values from the given source document instead of trying attempt a by id lookup in already resolved instances.

Closes: #4098
Original pull request: #4133.
2022-08-05 15:59:04 +02:00
Christoph Strobl
234783f442 Allow referencing the $id field of dbrefs within an aggregation pipeline.
Closes: #4123
Original pull request: #4125.
2022-08-05 14:19:29 +02:00
Sojin
3429350964 Fix AKNOWLEDGED typo in reference documentation.
Two typos found have been updated

Closes #4135
2022-08-05 14:07:54 +02:00
Mark Paluch
d130984bdc Allow disabling entity lifecycle events.
We now support disabling lifecycle events through the Template API to reduce the framework overhead when events are not needed.

Closes #4107
2022-07-20 16:07:01 +02:00
Christoph Strobl
f5378bf825 Upgrade to MongoDB driver 4.7.0
Closes: #4124
2022-07-20 08:13:53 +02:00
Mark Paluch
21057c3d17 Fix DTO projection instantiation.
We now correctly instantiate DTO projection classes by using the actual constructor argument type. Previously, we did not update the conversion context to fetch the correct type but used the type of the DTO projection class instead of the constructor argument.

Closes #4120
2022-07-19 11:17:40 +02:00
Christoph Strobl
d0a98eb71d After release cleanups.
See #4054
2022-07-15 15:30:53 +02:00
Christoph Strobl
bc95c4d390 Prepare next development iteration.
See #4054
2022-07-15 15:30:45 +02:00
Christoph Strobl
d56a4ea77d Release version 4.0 M5 (2022.0.0).
See #4054
2022-07-15 15:18:29 +02:00
Christoph Strobl
5a09626cbf Prepare 4.0 M5 (2022.0.0).
See #4054
2022-07-15 15:17:56 +02:00
John Blum
029291a1dd Adapt to repackaging of the AOT RuntimeHintsPredicate.
Closes #4111.
2022-07-12 18:05:46 -07:00
Mark Paluch
989a2596cb Upgrade to MongoDB driver 4.7.0-beta0.
Closes #4110
2022-07-12 15:40:36 +02:00
Greg L. Turnquist
f5c520dbc8 Upgrade Micrometer's tracing artifact to micrometer-tracing.
Closes #4106.
2022-07-11 08:24:41 -05:00
Mark Paluch
80c843eb20 Update README.adoc
See #4054
2022-07-11 15:06:12 +02:00
Christoph Strobl
9b136537c0 Simplify auditing configuration.
Use IsNewAwareAuditingHandler factory method to avoid exposing additional beans.

See: #4022
2022-07-08 08:57:34 +02:00
Mark Paluch
d334c5a44c Polishing.
Adopt to Framework changes.
Simplify auditing bean registration.
Remove ImportRuntimeHints in EnableMongoAuditing.
Refine ManagedTypes bean definitions.
Consistently use mongo as bean name prefix. Depend on store-specific ManagedTypes.
Rewrite ReactiveMongoAuditingRegistrar to avoid inner beans.
Reduce AOT processor visibility. Cleanup imports. Improve type naming. Update Javadoc.

Original Pull Request: #4093
2022-07-05 09:55:41 +02:00
Christoph Strobl
cfd55be95b Add AOT repository support
We now use the AOT infrastructure of Spring Framework 6 and data commons to provide AOT support building the foundation for native image compilation.
Additionally we register hints for GraalVM native image.

See: #4022
Original Pull Request: #4093
2022-07-05 09:55:10 +02:00
Mark Paluch
079c5a95aa Adopt test to Spring Framework 6 changes.
See #4054
2022-07-05 07:38:35 +02:00
Mark Paluch
3f6821f11f Adopt to Reactor 2022.0.0-M4 changes.
Closes #4100
2022-07-04 14:28:55 +02:00
Mark Paluch
1a868ae35e Avoid duplicate bean registrations in MappingMongoConverterParser.
We now ensure to not override `ValidatingMongoEventListener` and `LocalValidatorFactoryBean` bean definitions by avoiding duplicate registrations and checking whether a bean with the given name is already registered.

Closes #4087
2022-06-28 10:24:56 +02:00
Mark Paluch
248bcfa177 Polishing.
Simplify code.

Original pull request: #4059.
See #4038
2022-06-27 15:42:55 +02:00
Christoph Strobl
ee076ec02f Simplify usage of user provided aggregation operations.
Introduce Aggregation.stage which allows to use a plain JSON String or any valid Bson representation to be used within an aggregation pipeline stage, without having to implement AggregationOperation directly.
The change allows to make use of driver native builder API for aggregates.

Original pull request: #4059.
Closes #4038
2022-06-27 15:42:55 +02:00
Mark Paluch
1184d6ee2d Upgrade to Kotlin 1.7.
Adopt to stricter nullability checks.

Closes #4096
2022-06-24 11:53:12 +02:00
Christoph Strobl
062b4e8757 Provide Module Identifier via MongoRepositoryConfigurationExtension
Closes: #4092
2022-06-21 08:00:06 +02:00
Christoph Strobl
30a417d810 Retain parameter type when binding parameters in annotated Query/Aggregation.
This commit ensures the parameter type is preserved when binding parameters used within the value of the Query or Aggregation annotation

Closes: #4089
2022-06-20 10:37:49 +02:00
Christoph Strobl
1671f960b6 Upgrade to MongoDB driver 4.6.1
Closes: #4081
2022-06-20 09:10:40 +02:00
Mark Paluch
d4cce9ac00 Wrap SpEL documentation with admonition.
Closes #4085
2022-06-14 09:11:46 +02:00
Mark Paluch
8f9576aa42 Polishing.
Reformat asciidoc source.

See #4085
2022-06-14 09:04:20 +02:00
John Blum
f15fd2a418 Remove punctuation in Exception messages.
Closes #4079.
2022-06-08 15:21:22 -07:00
Mark Paluch
01656db002 Upgrade to Maven Wrapper 3.8.5.
See #4073
2022-06-03 09:32:40 +02:00
John Blum
84faff6bd4 Remove Docker Registry login.
Closes #4056.
2022-05-16 12:55:12 -07:00
Greg L. Turnquist
d72e1531d3 Adapt to changes in Micrometer APIs.
Micrometer has updated some of its APIs and we must adjust.

Closes: #4055
2022-05-16 14:34:50 -05:00
Mark Paluch
ac59cf930a Update driver compatibility matrix.
Closes #4052
2022-05-16 15:11:38 +02:00
Christoph Strobl
7bdc8d3aac Fix pom.xml formatting.
This commit reverts formatting changes introduced via 140fb2e9ea.

See #4005
2022-05-13 12:59:40 +02:00
Christoph Strobl
47548a21ea After release cleanups.
See #4005
2022-05-13 10:53:26 +02:00
Christoph Strobl
5aaa8f79e7 Prepare next development iteration.
See #4005
2022-05-13 10:53:23 +02:00
Christoph Strobl
1a77b1bc56 Release version 4.0 M4 (2022.0.0).
See #4005
2022-05-13 10:43:59 +02:00
Christoph Strobl
140fb2e9ea Prepare 4.0 M4 (2022.0.0).
See #4005
2022-05-13 10:43:20 +02:00
Jay Bryant
b571c8958d Editing pass for new content in reference documentation.
Closes: #4049
2022-05-11 05:38:24 +02:00
Christoph Strobl
8d54cae54d Polishing.
Update Query javadoc.

Original Pull Request: #3999
2022-05-10 16:33:19 +02:00
Raul Mello Silva
14a71f0498 Update Query.limit javadoc.
This commit explains usage of Query.limit(int), which will be set to unlimited when set to zero or a negative value.

Closes: #3999
2022-05-10 16:19:07 +02:00
Christoph Strobl
14c265f3a1 Provide additional meta information via pom.xml
Add scm & issueManagement.

Closes: #4048
2022-05-10 12:31:29 +02:00
nniesen
440a289ac6 Update spring.io project urls.
This commit updates outdated projects.spring.io links to spring.io/projects.

Closes: #4042
2022-05-09 13:57:49 +02:00
John Blum
9663a2227b Adapt to API changes in PropertyValueConverters.
Closes #4040.
2022-05-02 17:19:17 -07:00
Mark Paluch
b134e1916d Upgrade to MongoDB driver 4.6.0.
Closes #4027
2022-04-19 10:05:37 +02:00
Greg L. Turnquist
65b02f92b4 Use updated coordinates for Hibernate Validator.
See #4024.
2022-04-15 10:45:58 -05:00
Greg L. Turnquist
667b71e073 Switch to Micrometer 1.10's tracing APIs.
Micrometer Tracing 1.10 has some breaking APIs.

See #4023.
2022-04-15 10:04:41 -05:00
Mark Paluch
225dbee15f Simplify dependency version arrangement.
We now inherit the version number and repositories from the parent pom.

See #4017
2022-04-07 09:53:10 +02:00
Mark Paluch
c04ceb163b Polishing.
Reformat code.

See #4017
2022-04-07 09:44:42 +02:00
Greg L. Turnquist
711ac343fe Fix Micrometer-based deployment issues.
When deploying to artifactory, a Micrometer-based plugin can't be found.

See #4017.
2022-04-06 09:25:44 -05:00
Mark Paluch
852a4ecc59 Polishing.
Refine default conversions creation.

See #4014
Original pull request: #4015.
2022-04-05 10:07:51 +02:00
Christoph Strobl
7ab2428c64 Make sure to initialize PropvertyValueConversions in Converter setup.
Closes #4014
Original pull request: #4015.
2022-04-05 10:07:46 +02:00
Oliver Drotbohm
350acf66bc Adapt to API changes in Spring Data Commons.
spring-projects/spring-data-commons#2518 introduced TypeInformation.getTypeDescriptor() which we need to implement in our custom FieldTypeInformation.
2022-04-04 18:21:04 +02:00
Christoph Strobl
ab94a94b2e Upgrade to MongoDB driver 4.5.1
Resolves: #4013
2022-04-04 10:20:20 +02:00
Christoph Strobl
4c77763cd3 Introduce Observability with Micrometer and Micrometer Tracing.
See #3942.
2022-03-29 13:09:07 -05:00
Christoph Strobl
f197953480 Update build triggers.
See: #4005
2022-03-24 13:53:25 +01:00
Mark Paluch
44afd4939e After release cleanups.
See #4003
2022-03-22 14:07:38 +01:00
Mark Paluch
575917435e Prepare next development iteration.
See #4003
2022-03-22 14:07:36 +01:00
Mark Paluch
2db55ab0aa Release version 4.0 M3 (2022.0.0).
See #4003
2022-03-22 14:00:23 +01:00
Mark Paluch
79602b7dbe Prepare 4.0 M3 (2022.0.0).
See #4003
2022-03-22 14:00:02 +01:00
Mark Paluch
d5d2371b9e After release cleanups.
See #3937
2022-03-21 16:44:41 +01:00
Mark Paluch
c95e8a5748 Prepare next development iteration.
See #3937
2022-03-21 16:44:39 +01:00
434 changed files with 10561 additions and 3133 deletions

View File

@@ -1,2 +1,2 @@
#Mon Oct 11 14:30:24 CEST 2021
distributionUrl=https\://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.3/apache-maven-3.8.3-bin.zip
#Fri Jun 03 09:32:40 CEST 2022
distributionUrl=https\://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.5/apache-maven-3.8.5-bin.zip

99
Jenkinsfile vendored
View File

@@ -9,7 +9,7 @@ pipeline {
triggers {
pollSCM 'H/10 * * * *'
upstream(upstreamProjects: "spring-data-commons/3.0.x", threshold: hudson.model.Result.SUCCESS)
upstream(upstreamProjects: "spring-data-commons/main", threshold: hudson.model.Result.SUCCESS)
}
options {
@@ -58,6 +58,25 @@ pipeline {
}
}
}
stage('Publish JDK (Java 17) + MongoDB 6.0') {
when {
anyOf {
changeset "ci/openjdk17-mongodb-6.0/**"
changeset "ci/pipeline.properties"
}
}
agent { label 'data' }
options { timeout(time: 30, unit: 'MINUTES') }
steps {
script {
def image = docker.build("springci/spring-data-with-mongodb-6.0:${p['java.main.tag']}", "--build-arg BASE=${p['docker.java.main.image']} --build-arg MONGODB=${p['docker.mongodb.6.0.version']} ci/openjdk17-mongodb-6.0/")
docker.withRegistry(p['docker.registry'], p['docker.credentials']) {
image.push()
}
}
}
}
}
}
@@ -78,15 +97,13 @@ pipeline {
}
steps {
script {
docker.withRegistry(p['docker.registry'], p['docker.credentials']) {
docker.image("harbor-repo.vmware.com/dockerhub-proxy-cache/springci/spring-data-with-mongodb-4.4:${p['java.main.tag']}").inside(p['docker.java.inside.basic']) {
sh 'mkdir -p /tmp/mongodb/db /tmp/mongodb/log'
sh 'mongod --setParameter transactionLifetimeLimitSeconds=90 --setParameter maxTransactionLockRequestTimeoutMillis=10000 --dbpath /tmp/mongodb/db --replSet rs0 --fork --logpath /tmp/mongodb/log/mongod.log &'
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'
}
docker.image("harbor-repo.vmware.com/dockerhub-proxy-cache/springci/spring-data-with-mongodb-4.4:${p['java.main.tag']}").inside(p['docker.java.inside.basic']) {
sh 'mkdir -p /tmp/mongodb/db /tmp/mongodb/log'
sh 'mongod --setParameter transactionLifetimeLimitSeconds=90 --setParameter maxTransactionLockRequestTimeoutMillis=10000 --dbpath /tmp/mongodb/db --replSet rs0 --fork --logpath /tmp/mongodb/log/mongod.log &'
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'
}
}
}
@@ -102,7 +119,7 @@ pipeline {
}
parallel {
stage("test: mongodb 5.0 (Java 17)") {
stage("test: MongoDB 5.0 (Java 17)") {
agent {
label 'data'
}
@@ -112,15 +129,35 @@ pipeline {
}
steps {
script {
docker.withRegistry(p['docker.registry'], p['docker.credentials']) {
docker.image("harbor-repo.vmware.com/dockerhub-proxy-cache/springci/spring-data-with-mongodb-5.0:${p['java.main.tag']}").inside(p['docker.java.inside.basic']) {
sh 'mkdir -p /tmp/mongodb/db /tmp/mongodb/log'
sh 'mongod --setParameter transactionLifetimeLimitSeconds=90 --setParameter maxTransactionLockRequestTimeoutMillis=10000 --dbpath /tmp/mongodb/db --replSet rs0 --fork --logpath /tmp/mongodb/log/mongod.log &'
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'
}
docker.image("harbor-repo.vmware.com/dockerhub-proxy-cache/springci/spring-data-with-mongodb-5.0:${p['java.main.tag']}").inside(p['docker.java.inside.basic']) {
sh 'mkdir -p /tmp/mongodb/db /tmp/mongodb/log'
sh 'mongod --setParameter transactionLifetimeLimitSeconds=90 --setParameter maxTransactionLockRequestTimeoutMillis=10000 --dbpath /tmp/mongodb/db --replSet rs0 --fork --logpath /tmp/mongodb/log/mongod.log &'
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'
}
}
}
}
stage("test: MongoDB 6.0 (Java 17)") {
agent {
label 'data'
}
options { timeout(time: 30, unit: 'MINUTES') }
environment {
ARTIFACTORY = credentials("${p['artifactory.credentials']}")
}
steps {
script {
docker.image("harbor-repo.vmware.com/dockerhub-proxy-cache/springci/spring-data-with-mongodb-6.0:${p['java.main.tag']}").inside(p['docker.java.inside.basic']) {
sh 'mkdir -p /tmp/mongodb/db /tmp/mongodb/log'
sh 'mongod --setParameter transactionLifetimeLimitSeconds=90 --setParameter maxTransactionLockRequestTimeoutMillis=10000 --dbpath /tmp/mongodb/db --replSet rs0 --fork --logpath /tmp/mongodb/log/mongod.log &'
sh 'sleep 10'
sh 'mongosh --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'
}
}
}
@@ -147,18 +184,16 @@ pipeline {
steps {
script {
docker.withRegistry(p['docker.registry'], p['docker.credentials']) {
docker.image(p['docker.java.main.image']).inside(p['docker.java.inside.basic']) {
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -v'
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml -Pci,artifactory ' +
'-Dartifactory.server=https://repo.spring.io ' +
"-Dartifactory.username=${ARTIFACTORY_USR} " +
"-Dartifactory.password=${ARTIFACTORY_PSW} " +
"-Dartifactory.staging-repository=libs-snapshot-local " +
"-Dartifactory.build-name=spring-data-mongodb " +
"-Dartifactory.build-number=${BUILD_NUMBER} " +
'-Dmaven.test.skip=true clean deploy -U -B'
}
docker.image(p['docker.java.main.image']).inside(p['docker.java.inside.basic']) {
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -v'
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml -Pci,artifactory ' +
'-Dartifactory.server=https://repo.spring.io ' +
"-Dartifactory.username=${ARTIFACTORY_USR} " +
"-Dartifactory.password=${ARTIFACTORY_PSW} " +
"-Dartifactory.staging-repository=libs-snapshot-local " +
"-Dartifactory.build-name=spring-data-mongodb " +
"-Dartifactory.build-number=${BUILD_NUMBER} " +
'-Dmaven.test.skip=true clean deploy -U -B'
}
}
}

View File

@@ -1,8 +1,8 @@
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]
image:https://spring.io/badges/spring-data-mongodb/ga.svg[Spring Data MongoDB,link=https://spring.io/projects/spring-data-mongodb#quick-start] image:https://spring.io/badges/spring-data-mongodb/snapshot.svg[Spring Data MongoDB,link=https://spring.io/projects/spring-data-mongodb#quick-start]
= 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.
The primary goal of the https://spring.io/projects/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.
The Spring Data MongoDB project aims to provide a familiar and consistent Spring-based programming model for new datastores while retaining store-specific features and capabilities.
The Spring Data MongoDB project provides integration with the MongoDB document database.
@@ -115,7 +115,7 @@ Use `<mongo:client-settings cluster-hosts="..." />` instead
| `<mongo:db-factory writeConcern="..." />`
| NONE, NORMAL, SAFE, FSYNC_SAFE, REPLICAS_SAFE, MAJORITY
| W1, W2, W3, UNAKNOWLEDGED, AKNOWLEDGED, JOURNALED, MAJORITY
| W1, W2, W3, UNACKNOWLEDGED, ACKNOWLEDGED, JOURNALED, MAJORITY
|===
.Removed XML Namespace Elements and Attributes:
@@ -277,12 +277,12 @@ and accessible from Maven using the Maven configuration noted <<maven-configurat
NOTE: Configuration for Gradle is similar to Maven.
The best way to get started is by creating a Spring Boot project using MongoDB on https://start.spring.io[start.spring.io].
Follow this https://start.spring.io/#type=maven-project&language=java&platformVersion=2.5.4&packaging=jar&jvmVersion=1.8&groupId=com.example&artifactId=demo&name=demo&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.demo&dependencies=data-mongodb[link]
to build an imperative application and this https://start.spring.io/#type=maven-project&language=java&platformVersion=2.5.4&packaging=jar&jvmVersion=1.8&groupId=com.example&artifactId=demo&name=demo&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.demo&dependencies=data-mongodb-reactive[link]
Follow this https://start.spring.io/#type=maven-project&language=java&platformVersion=3.0.0&packaging=jar&jvmVersion=17&groupId=com.example&artifactId=demo&name=demo&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.demo&dependencies=data-mongodb[link]
to build an imperative application and this https://start.spring.io/#type=maven-project&language=java&platformVersion=3.0.0&packaging=jar&jvmVersion=17&groupId=com.example&artifactId=demo&name=demo&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.demo&dependencies=data-mongodb-reactive[link]
to build a reactive one.
However, if you want to try out the latest and greatest, Spring Data MongoDB can be easily built with the https://github.com/takari/maven-wrapper[Maven wrapper]
and minimally, JDK 8 (https://www.oracle.com/java/technologies/downloads/[JDK downloads]).
and minimally, JDK 17 (https://www.oracle.com/java/technologies/downloads/[JDK downloads]).
In order to build Spring Data MongoDB, you will need to https://www.mongodb.com/try/download/community[download]
and https://docs.mongodb.com/manual/installation/[install a MongoDB distribution].
@@ -341,7 +341,7 @@ Now you are ready to build Spring Data MongoDB. Simply enter the following `mvnw
$ ./mvnw clean install
----
If you want to build with the regular `mvn` command, you will need https://maven.apache.org/run-maven/index.html[Maven v3.5.0 or above].
If you want to build with the regular `mvn` command, you will need https://maven.apache.org/run-maven/index.html[Maven v3.8.0 or above].
_Also see link:CONTRIBUTING.adoc[CONTRIBUTING.adoc] if you wish to submit pull requests, and in particular, please sign
the https://cla.pivotal.io/sign/spring[Contributors Agreement] before your first non-trivial change._

View File

@@ -7,15 +7,15 @@ ENV TZ=Etc/UTC
ENV DEBIAN_FRONTEND=noninteractive
RUN set -eux; \
sed -i -e 's/archive.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list; \
sed -i -e 's/security.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list; \
sed -i -e 's/http/https/g' /etc/apt/sources.list ; \
apt-get update && apt-get install -y apt-transport-https apt-utils gnupg2 ; \
apt-key adv --keyserver hkps://keyserver.ubuntu.com:443 --recv 656408E390CFB1F5 ; \
echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.4 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-4.4.list; \
echo ${TZ} > /etc/timezone;
sed -i -e 's/archive.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list && \
sed -i -e 's/security.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list && \
sed -i -e 's/http/https/g' /etc/apt/sources.list && \
apt-get update && apt-get install -y apt-transport-https apt-utils gnupg2 && \
apt-key adv --keyserver hkps://keyserver.ubuntu.com:443 --recv 656408E390CFB1F5 && \
echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.4 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-4.4.list && \
echo ${TZ} > /etc/timezone
RUN apt-get update ; \
apt-get install -y mongodb-org=${MONGODB} mongodb-org-server=${MONGODB} mongodb-org-shell=${MONGODB} mongodb-org-mongos=${MONGODB} mongodb-org-tools=${MONGODB} ; \
apt-get clean; \
rm -rf /var/lib/apt/lists/*;
RUN apt-get update && \
apt-get install -y mongodb-org=${MONGODB} mongodb-org-server=${MONGODB} mongodb-org-shell=${MONGODB} mongodb-org-mongos=${MONGODB} mongodb-org-tools=${MONGODB} && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

View File

@@ -7,17 +7,17 @@ ENV TZ=Etc/UTC
ENV DEBIAN_FRONTEND=noninteractive
RUN set -eux; \
sed -i -e 's/archive.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list; \
sed -i -e 's/security.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list; \
sed -i -e 's/http/https/g' /etc/apt/sources.list ; \
apt-get update && apt-get install -y apt-transport-https apt-utils gnupg2 wget ; \
sed -i -e 's/archive.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list && \
sed -i -e 's/security.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list && \
sed -i -e 's/http/https/g' /etc/apt/sources.list && \
apt-get update && apt-get install -y apt-transport-https apt-utils gnupg2 wget && \
# MongoDB 5.0 release signing key
apt-key adv --keyserver hkps://keyserver.ubuntu.com:443 --recv B00A0BD1E2C63C11 ; \
apt-key adv --keyserver hkps://keyserver.ubuntu.com:443 --recv B00A0BD1E2C63C11 && \
# Needed when MongoDB creates a 5.0 folder.
echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/5.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-5.0.list; \
echo ${TZ} > /etc/timezone;
echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/5.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-5.0.list && \
echo ${TZ} > /etc/timezone
RUN apt-get update; \
apt-get install -y mongodb-org=${MONGODB} mongodb-org-server=${MONGODB} mongodb-org-shell=${MONGODB} mongodb-org-mongos=${MONGODB} mongodb-org-tools=${MONGODB} ; \
apt-get clean; \
rm -rf /var/lib/apt/lists/*;
RUN apt-get update && \
apt-get install -y mongodb-org=${MONGODB} mongodb-org-server=${MONGODB} mongodb-org-shell=${MONGODB} mongodb-org-mongos=${MONGODB} mongodb-org-tools=${MONGODB} && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

View File

@@ -0,0 +1,23 @@
ARG BASE
FROM ${BASE}
# Any ARG statements before FROM are cleared.
ARG MONGODB
ENV TZ=Etc/UTC
ENV DEBIAN_FRONTEND=noninteractive
RUN set -eux; \
sed -i -e 's/archive.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list && \
sed -i -e 's/security.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list && \
sed -i -e 's/http/https/g' /etc/apt/sources.list && \
apt-get update && apt-get install -y apt-transport-https apt-utils gnupg2 wget && \
# MongoDB 6.0 release signing key
wget -qO - https://www.mongodb.org/static/pgp/server-6.0.asc | apt-key add - && \
# Needed when MongoDB creates a 6.0 folder.
echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/6.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-6.0.list && \
echo ${TZ} > /etc/timezone
RUN apt-get update && \
apt-get install -y mongodb-org=${MONGODB} mongodb-org-server=${MONGODB} mongodb-org-shell=${MONGODB} mongodb-org-mongos=${MONGODB} mongodb-org-tools=${MONGODB} && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

View File

@@ -7,6 +7,7 @@ docker.java.main.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/ecli
# Supported versions of MongoDB
docker.mongodb.4.4.version=4.4.12
docker.mongodb.5.0.version=5.0.6
docker.mongodb.6.0.version=6.0.0
# Supported versions of Redis
docker.redis.6.version=6.2.6

25
pom.xml
View File

@@ -5,17 +5,17 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.0.0-M2</version>
<version>4.0.0-RC1</version>
<packaging>pom</packaging>
<name>Spring Data MongoDB</name>
<description>MongoDB support for Spring Data</description>
<url>https://projects.spring.io/spring-data-mongodb</url>
<url>https://spring.io/projects/spring-data-mongodb</url>
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>3.0.0-M2</version>
<version>3.0.0-RC1</version>
</parent>
<modules>
@@ -24,11 +24,10 @@
</modules>
<properties>
<source.level>16</source.level>
<project.type>multi</project.type>
<dist.id>spring-data-mongodb</dist.id>
<springdata.commons>3.0.0-M2</springdata.commons>
<mongo>4.5.0</mongo>
<springdata.commons>3.0.0-RC1</springdata.commons>
<mongo>4.8.0-beta0</mongo>
<mongo.reactivestreams>${mongo}</mongo.reactivestreams>
<jmh.version>1.19</jmh.version>
</properties>
@@ -113,6 +112,17 @@
</developer>
</developers>
<scm>
<connection>scm:git:https://github.com/spring-projects/spring-data-mongodb.git</connection>
<developerConnection>scm:git:git@github.com:spring-projects/spring-data-mongodb.git</developerConnection>
<url>https://github.com/spring-projects/spring-data-mongodb</url>
</scm>
<issueManagement>
<system>GitHub</system>
<url>https://github.com/spring-projects/spring-data-mongodb/issues</url>
</issueManagement>
<profiles>
<profile>
<id>benchmarks</id>
@@ -137,6 +147,9 @@
<repository>
<id>spring-libs-milestone</id>
<url>https://repo.spring.io/libs-milestone</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>sonatype-libs-snapshot</id>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.0.0-M2</version>
<version>4.0.0-RC1</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -322,7 +322,7 @@ public class AbstractMicrobenchmark {
try {
ResultsWriter.forUri(uri).write(results);
} catch (Exception e) {
System.err.println(String.format("Cannot save benchmark results to '%s'. Error was %s.", uri, e));
System.err.println(String.format("Cannot save benchmark results to '%s'; Error was %s", uri, e));
}
}
}

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
@@ -14,13 +15,18 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.0.0-M2</version>
<version>4.0.0-RC1</version>
<relativePath>../pom.xml</relativePath>
</parent>
<properties>
<project.root>${basedir}/..</project.root>
<dist.key>SDMONGO</dist.key>
<!-- Observability -->
<micrometer-docs-generator.inputPath>${maven.multiModuleProjectDirectory}/spring-data-mongodb/</micrometer-docs-generator.inputPath>
<micrometer-docs-generator.inclusionPattern>.*</micrometer-docs-generator.inclusionPattern>
<micrometer-docs-generator.outputPath>${maven.multiModuleProjectDirectory}/target/</micrometer-docs-generator.outputPath>
</properties>
<build>
@@ -29,12 +35,63 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>generate-metrics-metadata</id>
<phase>prepare-package</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>io.micrometer.docs.metrics.DocsFromSources
</mainClass>
</configuration>
</execution>
<execution>
<id>generate-tracing-metadata</id>
<phase>prepare-package</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>io.micrometer.docs.spans.DocsFromSources
</mainClass>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-docs-generator-spans</artifactId>
<version>${micrometer-docs-generator}</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-docs-generator-metrics</artifactId>
<version>${micrometer-docs-generator}</version>
<type>jar</type>
</dependency>
</dependencies>
<configuration>
<includePluginDependencies>true</includePluginDependencies>
<arguments>
<argument>${micrometer-docs-generator.inputPath}</argument>
<argument>${micrometer-docs-generator.inclusionPattern}</argument>
<argument>${micrometer-docs-generator.outputPath}</argument>
</arguments>
</configuration>
</plugin>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<configuration>
<attributes>
<mongo-reactivestreams>${mongo.reactivestreams}</mongo-reactivestreams>
<mongo-reactivestreams>${mongo.reactivestreams}
</mongo-reactivestreams>
<reactor>${reactor}</reactor>
</attributes>
</configuration>
@@ -43,4 +100,15 @@
</build>
<pluginRepositories>
<pluginRepository>
<id>spring-plugins-release</id>
<url>https://repo.spring.io/plugins-release</url>
</pluginRepository>
<pluginRepository>
<id>spring-plugins-snapshot</id>
<url>https://repo.spring.io/libs-snapshot</url>
</pluginRepository>
</pluginRepositories>
</project>

View File

@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
@@ -11,7 +13,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.0.0-M2</version>
<version>4.0.0-RC1</version>
<relativePath>../pom.xml</relativePath>
</parent>
@@ -194,7 +196,19 @@
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-observation</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>7.0.1.Final</version>
<scope>test</scope>
@@ -290,11 +304,34 @@
<dependency>
<groupId>io.mockk</groupId>
<artifactId>mockk</artifactId>
<artifactId>mockk-jvm</artifactId>
<version>${mockk}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock-jre8-standalone</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-integration-test</artifactId>
<scope>test</scope>
</dependency>
<!-- jMolecules -->
<dependency>
@@ -328,8 +365,11 @@
<goal>test-process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-test-sources</outputDirectory>
<processor>org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor</processor>
<outputDirectory>target/generated-test-sources
</outputDirectory>
<processor>
org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor
</processor>
</configuration>
</execution>
</executions>
@@ -349,7 +389,9 @@
<exclude>**/ReactivePerformanceTests.java</exclude>
</excludes>
<systemPropertyVariables>
<java.util.logging.config.file>src/test/resources/logging.properties</java.util.logging.config.file>
<java.util.logging.config.file>
src/test/resources/logging.properties
</java.util.logging.config.file>
<reactor.trace.cancel>true</reactor.trace.cancel>
</systemPropertyVariables>
</configuration>

View File

@@ -62,7 +62,7 @@ public interface CodecRegistryProvider {
*/
default <T> Optional<Codec<T>> getCodecFor(Class<T> type) {
Assert.notNull(type, "Type must not be null!");
Assert.notNull(type, "Type must not be null");
try {
return Optional.of(getCodecRegistry().get(type));

View File

@@ -102,7 +102,7 @@ public class MongoDatabaseUtils {
private static MongoDatabase doGetMongoDatabase(@Nullable String dbName, MongoDatabaseFactory factory,
SessionSynchronization sessionSynchronization) {
Assert.notNull(factory, "Factory must not be null!");
Assert.notNull(factory, "Factory must not be null");
if (sessionSynchronization == SessionSynchronization.NEVER
|| !TransactionSynchronizationManager.isSynchronizationActive()) {

View File

@@ -0,0 +1,81 @@
/*
* Copyright 2022 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;
import java.util.Arrays;
import java.util.function.Consumer;
import org.springframework.data.domain.ManagedTypes;
/**
* @author Christoph Strobl
* @since 4.0
*/
public final class MongoManagedTypes implements ManagedTypes {
private final ManagedTypes delegate;
private MongoManagedTypes(ManagedTypes types) {
this.delegate = types;
}
/**
* Wraps an existing {@link ManagedTypes} object with {@link MongoManagedTypes}.
*
* @param managedTypes
* @return
*/
public static MongoManagedTypes from(ManagedTypes managedTypes) {
return new MongoManagedTypes(managedTypes);
}
/**
* Factory method used to construct {@link MongoManagedTypes} from the given array of {@link Class types}.
*
* @param types array of {@link Class types} used to initialize the {@link ManagedTypes}; must not be {@literal null}.
* @return new instance of {@link MongoManagedTypes} initialized from {@link Class types}.
*/
public static MongoManagedTypes from(Class<?>... types) {
return fromIterable(Arrays.asList(types));
}
/**
* Factory method used to construct {@link MongoManagedTypes} from the given, required {@link Iterable} of
* {@link Class types}.
*
* @param types {@link Iterable} of {@link Class types} used to initialize the {@link ManagedTypes}; must not be
* {@literal null}.
* @return new instance of {@link MongoManagedTypes} initialized the given, required {@link Iterable} of {@link Class
* types}.
*/
public static MongoManagedTypes fromIterable(Iterable<? extends Class<?>> types) {
return from(ManagedTypes.fromIterable(types));
}
/**
* Factory method to return an empty {@link MongoManagedTypes} object.
*
* @return an empty {@link MongoManagedTypes} object.
*/
public static MongoManagedTypes empty() {
return from(ManagedTypes.empty());
}
@Override
public void forEach(Consumer<Class<?>> action) {
delegate.forEach(action);
}
}

View File

@@ -68,7 +68,7 @@ class MongoResourceHolder extends ResourceHolderSupport {
ClientSession session = getSession();
if (session == null) {
throw new IllegalStateException("No session available!");
throw new IllegalStateException("No session available");
}
return session;

View File

@@ -100,7 +100,7 @@ public class MongoTransactionManager extends AbstractPlatformTransactionManager
*/
public MongoTransactionManager(MongoDatabaseFactory dbFactory, @Nullable TransactionOptions options) {
Assert.notNull(dbFactory, "DbFactory must not be null!");
Assert.notNull(dbFactory, "DbFactory must not be null");
this.dbFactory = dbFactory;
this.options = options;
@@ -266,7 +266,7 @@ public class MongoTransactionManager extends AbstractPlatformTransactionManager
*/
public void setDbFactory(MongoDatabaseFactory dbFactory) {
Assert.notNull(dbFactory, "DbFactory must not be null!");
Assert.notNull(dbFactory, "DbFactory must not be null");
this.dbFactory = dbFactory;
}
@@ -315,7 +315,7 @@ public class MongoTransactionManager extends AbstractPlatformTransactionManager
private MongoDatabaseFactory getRequiredDbFactory() {
Assert.state(dbFactory != null,
"MongoTransactionManager operates upon a MongoDbFactory. Did you forget to provide one? It's required.");
"MongoTransactionManager operates upon a MongoDbFactory; Did you forget to provide one; It's required");
return dbFactory;
}
@@ -450,14 +450,14 @@ public class MongoTransactionManager extends AbstractPlatformTransactionManager
private MongoResourceHolder getRequiredResourceHolder() {
Assert.state(resourceHolder != null, "MongoResourceHolder is required but not present. o_O");
Assert.state(resourceHolder != null, "MongoResourceHolder is required but not present; o_O");
return resourceHolder;
}
private ClientSession getRequiredSession() {
ClientSession session = getSession();
Assert.state(session != null, "A Session is required but it turned out to be null.");
Assert.state(session != null, "A Session is required but it turned out to be null");
return session;
}

View File

@@ -136,7 +136,7 @@ public class ReactiveMongoDatabaseUtils {
private static Mono<MongoDatabase> doGetMongoDatabase(@Nullable String dbName, ReactiveMongoDatabaseFactory factory,
SessionSynchronization sessionSynchronization) {
Assert.notNull(factory, "DatabaseFactory must not be null!");
Assert.notNull(factory, "DatabaseFactory must not be null");
if (sessionSynchronization == SessionSynchronization.NEVER) {
return getMongoDatabaseOrDefault(dbName, factory);

View File

@@ -104,7 +104,7 @@ public class ReactiveMongoTransactionManager extends AbstractReactiveTransaction
public ReactiveMongoTransactionManager(ReactiveMongoDatabaseFactory databaseFactory,
@Nullable TransactionOptions options) {
Assert.notNull(databaseFactory, "DatabaseFactory must not be null!");
Assert.notNull(databaseFactory, "DatabaseFactory must not be null");
this.databaseFactory = databaseFactory;
this.options = options;
@@ -281,7 +281,7 @@ public class ReactiveMongoTransactionManager extends AbstractReactiveTransaction
*/
public void setDatabaseFactory(ReactiveMongoDatabaseFactory databaseFactory) {
Assert.notNull(databaseFactory, "DatabaseFactory must not be null!");
Assert.notNull(databaseFactory, "DatabaseFactory must not be null");
this.databaseFactory = databaseFactory;
}
@@ -323,7 +323,7 @@ public class ReactiveMongoTransactionManager extends AbstractReactiveTransaction
private ReactiveMongoDatabaseFactory getRequiredDatabaseFactory() {
Assert.state(databaseFactory != null,
"ReactiveMongoTransactionManager operates upon a ReactiveMongoDatabaseFactory. Did you forget to provide one? It's required.");
"ReactiveMongoTransactionManager operates upon a ReactiveMongoDatabaseFactory; Did you forget to provide one; It's required");
return databaseFactory;
}
@@ -458,14 +458,14 @@ public class ReactiveMongoTransactionManager extends AbstractReactiveTransaction
private ReactiveMongoResourceHolder getRequiredResourceHolder() {
Assert.state(resourceHolder != null, "ReactiveMongoResourceHolder is required but not present. o_O");
Assert.state(resourceHolder != null, "ReactiveMongoResourceHolder is required but not present; o_O");
return resourceHolder;
}
private ClientSession getRequiredSession() {
ClientSession session = getSession();
Assert.state(session != null, "A Session is required but it turned out to be null.");
Assert.state(session != null, "A Session is required but it turned out to be null");
return session;
}

View File

@@ -76,13 +76,13 @@ public class SessionAwareMethodInterceptor<D, C> implements MethodInterceptor {
Class<D> databaseType, ClientSessionOperator<D> databaseDecorator, Class<C> collectionType,
ClientSessionOperator<C> collectionDecorator) {
Assert.notNull(session, "ClientSession must not be null!");
Assert.notNull(target, "Target must not be null!");
Assert.notNull(sessionType, "SessionType must not be null!");
Assert.notNull(databaseType, "Database type must not be null!");
Assert.notNull(databaseDecorator, "Database ClientSessionOperator must not be null!");
Assert.notNull(collectionType, "Collection type must not be null!");
Assert.notNull(collectionDecorator, "Collection ClientSessionOperator must not be null!");
Assert.notNull(session, "ClientSession must not be null");
Assert.notNull(target, "Target must not be null");
Assert.notNull(sessionType, "SessionType must not be null");
Assert.notNull(databaseType, "Database type must not be null");
Assert.notNull(databaseDecorator, "Database ClientSessionOperator must not be null");
Assert.notNull(collectionType, "Collection type must not be null");
Assert.notNull(collectionDecorator, "Collection ClientSessionOperator must not be null");
this.session = session;
this.target = target;

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2022 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.aot;
import org.springframework.aot.generate.GenerationContext;
import org.springframework.data.aot.TypeContributor;
import org.springframework.data.repository.aot.AotRepositoryContext;
import org.springframework.data.repository.aot.RepositoryRegistrationAotProcessor;
/**
* @author Christoph Strobl
*/
public class AotMongoRepositoryPostProcessor extends RepositoryRegistrationAotProcessor {
private final LazyLoadingProxyAotProcessor lazyLoadingProxyAotProcessor = new LazyLoadingProxyAotProcessor();
@Override
protected void contribute(AotRepositoryContext repositoryContext, GenerationContext generationContext) {
// do some custom type registration here
super.contribute(repositoryContext, generationContext);
repositoryContext.getResolvedTypes().stream().filter(MongoAotPredicates.IS_SIMPLE_TYPE.negate()).forEach(type -> {
TypeContributor.contribute(type, it -> true, generationContext);
lazyLoadingProxyAotProcessor.registerLazyLoadingProxyIfNeeded(type, generationContext);
});
}
}

View File

@@ -0,0 +1,103 @@
/*
* Copyright 2022 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.aot;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.springframework.aot.generate.GenerationContext;
import org.springframework.aot.hint.TypeReference;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.data.annotation.Reference;
import org.springframework.data.aot.TypeUtils;
import org.springframework.data.mongodb.core.convert.LazyLoadingProxyFactory;
import org.springframework.data.mongodb.core.convert.LazyLoadingProxyFactory.LazyLoadingInterceptor;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.DocumentReference;
/**
* @author Christoph Strobl
* @since 4.0
*/
class LazyLoadingProxyAotProcessor {
private boolean generalLazyLoadingProxyContributed = false;
void registerLazyLoadingProxyIfNeeded(Class<?> type, GenerationContext generationContext) {
Set<Field> refFields = getFieldsWithAnnotationPresent(type, Reference.class);
if (refFields.isEmpty()) {
return;
}
refFields.stream() //
.filter(LazyLoadingProxyAotProcessor::isLazyLoading) //
.forEach(field -> {
if (!generalLazyLoadingProxyContributed) {
generationContext.getRuntimeHints().proxies().registerJdkProxy(
TypeReference.of(org.springframework.data.mongodb.core.convert.LazyLoadingProxy.class),
TypeReference.of(org.springframework.aop.SpringProxy.class),
TypeReference.of(org.springframework.aop.framework.Advised.class),
TypeReference.of(org.springframework.core.DecoratingProxy.class));
generalLazyLoadingProxyContributed = true;
}
if (field.getType().isInterface()) {
List<Class<?>> interfaces = new ArrayList<>(
TypeUtils.resolveTypesInSignature(ResolvableType.forField(field, type)));
interfaces.add(0, org.springframework.data.mongodb.core.convert.LazyLoadingProxy.class);
interfaces.add(org.springframework.aop.SpringProxy.class);
interfaces.add(org.springframework.aop.framework.Advised.class);
interfaces.add(org.springframework.core.DecoratingProxy.class);
generationContext.getRuntimeHints().proxies().registerJdkProxy(interfaces.toArray(Class[]::new));
} else {
LazyLoadingProxyFactory.resolveProxyType(field.getType(), () -> LazyLoadingInterceptor.none());
}
});
}
private static boolean isLazyLoading(Field field) {
if (AnnotatedElementUtils.isAnnotated(field, DBRef.class)) {
return AnnotatedElementUtils.findMergedAnnotation(field, DBRef.class).lazy();
}
if (AnnotatedElementUtils.isAnnotated(field, DocumentReference.class)) {
return AnnotatedElementUtils.findMergedAnnotation(field, DocumentReference.class).lazy();
}
return false;
}
private static Set<Field> getFieldsWithAnnotationPresent(Class<?> type, Class<? extends Annotation> annotation) {
Set<Field> fields = new LinkedHashSet<>();
for (Field field : type.getDeclaredFields()) {
if (MergedAnnotations.from(field).get(annotation).isPresent()) {
fields.add(field);
}
}
return fields;
}
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2022 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.aot;
import java.util.function.Predicate;
import org.springframework.data.aot.TypeUtils;
import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes;
/**
* @author Christoph Strobl
* @since 4.0
*/
class MongoAotPredicates {
static final Predicate<Class<?>> IS_SIMPLE_TYPE = (type) -> MongoSimpleTypes.HOLDER.isSimpleType(type) || TypeUtils.type(type).isPartOf("org.bson");
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2022 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.aot;
import org.springframework.aot.generate.GenerationContext;
import org.springframework.core.ResolvableType;
import org.springframework.data.aot.ManagedTypesBeanRegistrationAotProcessor;
import org.springframework.data.mongodb.MongoManagedTypes;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
/**
* @author Christoph Strobl
* @since 2022/06
*/
class MongoManagedTypesBeanRegistrationAotProcessor extends ManagedTypesBeanRegistrationAotProcessor {
private final LazyLoadingProxyAotProcessor lazyLoadingProxyAotProcessor = new LazyLoadingProxyAotProcessor();
public MongoManagedTypesBeanRegistrationAotProcessor() {
setModuleIdentifier("mongo");
}
@Override
protected boolean isMatch(@Nullable Class<?> beanType, @Nullable String beanName) {
return isMongoManagedTypes(beanType) || super.isMatch(beanType, beanName);
}
protected boolean isMongoManagedTypes(@Nullable Class<?> beanType) {
return beanType != null && ClassUtils.isAssignable(MongoManagedTypes.class, beanType);
}
@Override
protected void contributeType(ResolvableType type, GenerationContext generationContext) {
if (MongoAotPredicates.IS_SIMPLE_TYPE.test(type.toClass())) {
return;
}
super.contributeType(type, generationContext);
lazyLoadingProxyAotProcessor.registerLazyLoadingProxyIfNeeded(type.toClass(), generationContext);
}
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2022 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.aot;
import java.util.Arrays;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
import org.springframework.data.mongodb.core.mapping.event.AfterConvertCallback;
import org.springframework.data.mongodb.core.mapping.event.AfterSaveCallback;
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertCallback;
import org.springframework.data.mongodb.core.mapping.event.BeforeSaveCallback;
import org.springframework.data.mongodb.core.mapping.event.ReactiveAfterConvertCallback;
import org.springframework.data.mongodb.core.mapping.event.ReactiveAfterSaveCallback;
import org.springframework.data.mongodb.core.mapping.event.ReactiveBeforeConvertCallback;
import org.springframework.data.mongodb.core.mapping.event.ReactiveBeforeSaveCallback;
import org.springframework.data.repository.util.ReactiveWrappers;
import org.springframework.lang.Nullable;
/**
* {@link RuntimeHintsRegistrar} for repository types and entity callbacks.
*
* @author Christoph Strobl
* @author Mark Paluch
* @since 4.0
*/
class MongoRuntimeHints implements RuntimeHintsRegistrar {
private static final boolean PROJECT_REACTOR_PRESENT = ReactiveWrappers
.isAvailable(ReactiveWrappers.ReactiveLibrary.PROJECT_REACTOR);
@Override
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
hints.reflection().registerTypes(
Arrays.asList(TypeReference.of("org.springframework.data.mongodb.repository.support.SimpleMongoRepository"),
TypeReference.of(BeforeConvertCallback.class), TypeReference.of(BeforeSaveCallback.class),
TypeReference.of(AfterConvertCallback.class), TypeReference.of(AfterSaveCallback.class)),
builder -> builder.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INVOKE_PUBLIC_METHODS));
if (PROJECT_REACTOR_PRESENT) {
hints.reflection()
.registerTypes(Arrays.asList(
TypeReference.of("org.springframework.data.mongodb.repository.support.SimpleReactiveMongoRepository"),
TypeReference.of(ReactiveBeforeConvertCallback.class), TypeReference.of(ReactiveBeforeSaveCallback.class),
TypeReference.of(ReactiveAfterConvertCallback.class), TypeReference.of(ReactiveAfterSaveCallback.class)),
builder -> builder.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INVOKE_PUBLIC_METHODS));
}
}
}

View File

@@ -80,10 +80,10 @@ public abstract class AbstractMongoClientConfiguration extends MongoConfiguratio
/**
* Creates a {@link MappingMongoConverter} using the configured {@link #mongoDbFactory()} and
* {@link #mongoMappingContext(MongoCustomConversions)}. Will get {@link #customConversions()} applied.
* {@link #mongoMappingContext(MongoCustomConversions, org.springframework.data.mongodb.MongoManagedTypes)}. Will get {@link #customConversions()} applied.
*
* @see #customConversions()
* @see #mongoMappingContext(MongoCustomConversions)
* @see #mongoMappingContext(MongoCustomConversions, org.springframework.data.mongodb.MongoManagedTypes)
* @see #mongoDbFactory()
*/
@Bean

View File

@@ -84,10 +84,10 @@ public abstract class AbstractReactiveMongoConfiguration extends MongoConfigurat
/**
* Creates a {@link MappingMongoConverter} using the configured {@link #reactiveMongoDbFactory()} and
* {@link #mongoMappingContext(MongoCustomConversions)}. Will get {@link #customConversions()} applied.
* {@link #mongoMappingContext(MongoCustomConversions, org.springframework.data.mongodb.MongoManagedTypes)}. Will get {@link #customConversions()} applied.
*
* @see #customConversions()
* @see #mongoMappingContext(MongoCustomConversions)
* @see #mongoMappingContext(MongoCustomConversions, org.springframework.data.mongodb.MongoManagedTypes)
* @see #reactiveMongoDbFactory()
* @return never {@literal null}.
*/

View File

@@ -24,7 +24,6 @@ import java.util.List;
import java.util.Set;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference;
@@ -64,6 +63,7 @@ import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
/**
@@ -135,9 +135,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
new BeanComponentDefinition(indexOperationsProviderBuilder.getBeanDefinition(), "indexOperationsProvider"));
}
try {
registry.getBeanDefinition(INDEX_HELPER_BEAN_NAME);
} catch (NoSuchBeanDefinitionException ignored) {
if (!registry.containsBeanDefinition(INDEX_HELPER_BEAN_NAME)) {
BeanDefinitionBuilder indexHelperBuilder = BeanDefinitionBuilder
.genericBeanDefinition(MongoPersistentEntityIndexCreator.class);
@@ -151,7 +149,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
BeanDefinition validatingMongoEventListener = potentiallyCreateValidatingMongoEventListener(element, parserContext);
if (validatingMongoEventListener != null) {
if (validatingMongoEventListener != null && !registry.containsBeanDefinition(VALIDATING_EVENT_LISTENER_BEAN_NAME)) {
parserContext.registerBeanComponent(
new BeanComponentDefinition(validatingMongoEventListener, VALIDATING_EVENT_LISTENER_BEAN_NAME));
}
@@ -165,15 +163,16 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
private BeanDefinition potentiallyCreateValidatingMongoEventListener(Element element, ParserContext parserContext) {
String disableValidation = element.getAttribute("disable-validation");
boolean validationDisabled = StringUtils.hasText(disableValidation) && Boolean.valueOf(disableValidation);
boolean validationDisabled = StringUtils.hasText(disableValidation) && Boolean.parseBoolean(disableValidation);
if (!validationDisabled) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
RuntimeBeanReference validator = getValidator(builder, parserContext);
RuntimeBeanReference validator = getValidator(element, parserContext);
if (validator != null) {
builder.getRawBeanDefinition().setBeanClass(ValidatingMongoEventListener.class);
builder.getRawBeanDefinition().setSource(element);
builder.addConstructorArgValue(validator);
return builder.getBeanDefinition();
@@ -195,7 +194,6 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
validatorDef.setSource(source);
validatorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String validatorName = parserContext.getReaderContext().registerWithGeneratedName(validatorDef);
parserContext.registerBeanComponent(new BeanComponentDefinition(validatorDef, validatorName));
return new RuntimeBeanReference(validatorName);
}
@@ -255,7 +253,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
&& Boolean.parseBoolean(abbreviateFieldNames);
if (fieldNamingStrategyReferenced && abbreviationActivated) {
context.error("Field name abbreviation cannot be activated if a field-naming-strategy-ref is configured!",
context.error("Field name abbreviation cannot be activated if a field-naming-strategy-ref is configured",
element);
return;
}

View File

@@ -18,18 +18,14 @@ package org.springframework.data.mongodb.config;
import java.lang.annotation.Annotation;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.Ordered;
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
import org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport;
import org.springframework.data.auditing.config.AuditingConfiguration;
import org.springframework.data.config.ParsingUtils;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.event.AuditingEntityCallback;
import org.springframework.util.Assert;
@@ -39,8 +35,9 @@ import org.springframework.util.Assert;
* @author Thomas Darimont
* @author Oliver Gierke
* @author Mark Paluch
* @author Christoph Strobl
*/
class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport implements Ordered {
@Override
protected Class<? extends Annotation> getAnnotation() {
@@ -53,34 +50,27 @@ class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
}
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
protected void postProcess(BeanDefinitionBuilder builder, AuditingConfiguration configuration,
BeanDefinitionRegistry registry) {
Assert.notNull(annotationMetadata, "AnnotationMetadata must not be null!");
Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");
super.registerBeanDefinitions(annotationMetadata, registry);
builder.setFactoryMethod("from").addConstructorArgReference("mongoMappingContext");
}
@Override
protected BeanDefinitionBuilder getAuditHandlerBeanDefinitionBuilder(AuditingConfiguration configuration) {
Assert.notNull(configuration, "AuditingConfiguration must not be null!");
Assert.notNull(configuration, "AuditingConfiguration must not be null");
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(IsNewAwareAuditingHandler.class);
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(org.springframework.data.repository.config.PersistentEntitiesFactoryBean.class);
definition.addConstructorArgValue(new RuntimeBeanReference(MappingContext.class));
builder.addConstructorArgValue(definition.getBeanDefinition());
return configureDefaultAuditHandlerAttributes(configuration, builder);
return configureDefaultAuditHandlerAttributes(configuration,
BeanDefinitionBuilder.rootBeanDefinition(IsNewAwareAuditingHandler.class));
}
@Override
protected void registerAuditListenerBeanDefinition(BeanDefinition auditingHandlerDefinition,
BeanDefinitionRegistry registry) {
Assert.notNull(auditingHandlerDefinition, "BeanDefinition must not be null!");
Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");
Assert.notNull(auditingHandlerDefinition, "BeanDefinition must not be null");
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
BeanDefinitionBuilder listenerBeanDefinitionBuilder = BeanDefinitionBuilder
.rootBeanDefinition(AuditingEntityCallback.class);
@@ -91,4 +81,8 @@ class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
AuditingEntityCallback.class.getName(), registry);
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}

View File

@@ -30,6 +30,7 @@ import org.springframework.data.convert.CustomConversions;
import org.springframework.data.mapping.model.CamelCaseAbbreviatingFieldNamingStrategy;
import org.springframework.data.mapping.model.FieldNamingStrategy;
import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
import org.springframework.data.mongodb.MongoManagedTypes;
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
import org.springframework.data.mongodb.core.convert.MongoCustomConversions.MongoConverterConfigurationAdapter;
import org.springframework.data.mongodb.core.mapping.Document;
@@ -76,14 +77,13 @@ public abstract class MongoConfigurationSupport {
*
* @see #getMappingBasePackages()
* @return
* @throws ClassNotFoundException
*/
@Bean
public MongoMappingContext mongoMappingContext(MongoCustomConversions customConversions)
throws ClassNotFoundException {
public MongoMappingContext mongoMappingContext(MongoCustomConversions customConversions,
MongoManagedTypes mongoManagedTypes) {
MongoMappingContext mappingContext = new MongoMappingContext();
mappingContext.setInitialEntitySet(getInitialEntitySet());
mappingContext.setManagedTypes(mongoManagedTypes);
mappingContext.setSimpleTypeHolder(customConversions.getSimpleTypeHolder());
mappingContext.setFieldNamingStrategy(fieldNamingStrategy());
mappingContext.setAutoIndexCreation(autoIndexCreation());
@@ -91,6 +91,16 @@ public abstract class MongoConfigurationSupport {
return mappingContext;
}
/**
* @return new instance of {@link MongoManagedTypes}.
* @throws ClassNotFoundException
* @since 4.0
*/
@Bean
public MongoManagedTypes mongoManagedTypes() throws ClassNotFoundException {
return MongoManagedTypes.fromIterable(getInitialEntitySet());
}
/**
* Register custom {@link Converter}s in a {@link CustomConversions} object if required. These
* {@link CustomConversions} will be registered with the

View File

@@ -117,7 +117,7 @@ public class MongoCredentialPropertyEditor extends PropertyEditorSupport {
userNameAndPassword[1].toCharArray()));
} else {
throw new IllegalArgumentException(
String.format("Cannot create MongoCredentials for unknown auth mechanism '%s'!", authMechanism));
String.format("Cannot create MongoCredentials for unknown auth mechanism '%s'", authMechanism));
}
}
} else {
@@ -194,7 +194,7 @@ public class MongoCredentialPropertyEditor extends PropertyEditorSupport {
String[] optionArgs = option.split("=");
if (optionArgs.length == 1) {
throw new IllegalArgumentException(String.format("Query parameter '%s' has no value!", optionArgs[0]));
throw new IllegalArgumentException(String.format("Query parameter '%s' has no value", optionArgs[0]));
}
properties.put(optionArgs[0], optionArgs[1]);
@@ -209,21 +209,21 @@ public class MongoCredentialPropertyEditor extends PropertyEditorSupport {
if (source.length != 2) {
throw new IllegalArgumentException(
"Credentials need to specify username and password like in 'username:password@database'!");
"Credentials need to specify username and password like in 'username:password@database'");
}
}
private static void verifyDatabasePresent(String source) {
if (!StringUtils.hasText(source)) {
throw new IllegalArgumentException("Credentials need to specify database like in 'username:password@database'!");
throw new IllegalArgumentException("Credentials need to specify database like in 'username:password@database'");
}
}
private static void verifyUserNamePresent(String[] source) {
if (source.length == 0 || !StringUtils.hasText(source[0])) {
throw new IllegalArgumentException("Credentials need to specify username!");
throw new IllegalArgumentException("Credentials need to specify username");
}
}
@@ -231,7 +231,7 @@ public class MongoCredentialPropertyEditor extends PropertyEditorSupport {
try {
return URLDecoder.decode(it, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException("o_O UTF-8 not supported!", e);
throw new IllegalArgumentException("o_O UTF-8 not supported", e);
}
}
}

View File

@@ -163,7 +163,7 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
if (element.getAttributes().getLength() > allowedAttributesCount) {
parserContext.getReaderContext().error("Configure either MongoDB " + type + " or details individually!",
parserContext.getReaderContext().error("Configure either MongoDB " + type + " or details individually",
parserContext.extractSource(element));
}

View File

@@ -18,11 +18,9 @@ package org.springframework.data.mongodb.config;
import java.lang.annotation.Annotation;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.auditing.ReactiveIsNewAwareAuditingHandler;
import org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport;
import org.springframework.data.auditing.config.AuditingConfiguration;
@@ -34,6 +32,7 @@ import org.springframework.util.Assert;
* {@link ImportBeanDefinitionRegistrar} to enable {@link EnableReactiveMongoAuditing} annotation.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 3.1
*/
class ReactiveMongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
@@ -48,26 +47,27 @@ class ReactiveMongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupp
return "reactiveMongoAuditingHandler";
}
@Override
protected void postProcess(BeanDefinitionBuilder builder, AuditingConfiguration configuration,
BeanDefinitionRegistry registry) {
builder.setFactoryMethod("from").addConstructorArgReference("mongoMappingContext");
}
@Override
protected BeanDefinitionBuilder getAuditHandlerBeanDefinitionBuilder(AuditingConfiguration configuration) {
Assert.notNull(configuration, "AuditingConfiguration must not be null!");
Assert.notNull(configuration, "AuditingConfiguration must not be null");
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ReactiveIsNewAwareAuditingHandler.class);
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(PersistentEntitiesFactoryBean.class);
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
builder.addConstructorArgValue(definition.getBeanDefinition());
return configureDefaultAuditHandlerAttributes(configuration, builder);
return configureDefaultAuditHandlerAttributes(configuration,
BeanDefinitionBuilder.rootBeanDefinition(ReactiveIsNewAwareAuditingHandler.class));
}
@Override
protected void registerAuditListenerBeanDefinition(BeanDefinition auditingHandlerDefinition,
BeanDefinitionRegistry registry) {
Assert.notNull(auditingHandlerDefinition, "BeanDefinition must not be null!");
Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");
Assert.notNull(auditingHandlerDefinition, "BeanDefinition must not be null");
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ReactiveAuditingEntityCallback.class);

View File

@@ -43,7 +43,7 @@ public class ServerAddressPropertyEditor extends PropertyEditorSupport {
* A port is a number without a leading 0 at the end of the address that is proceeded by just a single :.
*/
private static final String HOST_PORT_SPLIT_PATTERN = "(?<!:):(?=[123456789]\\d*$)";
private static final String COULD_NOT_PARSE_ADDRESS_MESSAGE = "Could not parse address %s '%s'. Check your replica set configuration!";
private static final String COULD_NOT_PARSE_ADDRESS_MESSAGE = "Could not parse address %s '%s'; Check your replica set configuration";
private static final Log LOG = LogFactory.getLog(ServerAddressPropertyEditor.class);
@Override
@@ -68,7 +68,7 @@ public class ServerAddressPropertyEditor extends PropertyEditorSupport {
if (serverAddresses.isEmpty()) {
throw new IllegalArgumentException(
"Could not resolve at least one server of the replica set configuration! Validate your config!");
"Could not resolve at least one server of the replica set configuration; Validate your config");
}
setValue(serverAddresses.toArray(new ServerAddress[serverAddresses.size()]));
@@ -125,7 +125,7 @@ public class ServerAddressPropertyEditor extends PropertyEditorSupport {
*/
private String[] extractHostAddressAndPort(String addressAndPortSource) {
Assert.notNull(addressAndPortSource, "Address and port source must not be null!");
Assert.notNull(addressAndPortSource, "Address and port source must not be null");
String[] hostAndPort = addressAndPortSource.split(HOST_PORT_SPLIT_PATTERN);
String hostAddress = hostAndPort[0];

View File

@@ -15,8 +15,6 @@
*/
package org.springframework.data.mongodb.core;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@@ -24,22 +22,16 @@ import java.util.stream.Collectors;
import org.bson.Document;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext;
import org.springframework.data.mongodb.core.aggregation.AggregationOptions;
import org.springframework.data.mongodb.core.aggregation.AggregationOptions.DomainTypeMapping;
import org.springframework.data.mongodb.core.aggregation.CountOperation;
import org.springframework.data.mongodb.core.aggregation.RelaxedTypeBasedAggregationOperationContext;
import org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOperationContext;
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
import org.springframework.data.mongodb.core.convert.QueryMapper;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.util.Lazy;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**

View File

@@ -24,10 +24,14 @@ import org.springframework.data.util.Pair;
import com.mongodb.bulk.BulkWriteResult;
/**
* Bulk operations for insert/update/remove actions on a collection. These bulks operation are available since MongoDB
* 2.6 and make use of low level bulk commands on the protocol level. This interface defines a fluent API to add
* multiple single operations or list of similar operations in sequence which can then eventually be executed by calling
* Bulk operations for insert/update/remove actions on a collection. Bulk operations are available since MongoDB 2.6 and
* make use of low level bulk commands on the protocol level. This interface defines a fluent API to add multiple single
* operations or list of similar operations in sequence which can then eventually be executed by calling
* {@link #execute()}.
* <p>
* Bulk operations are issued as one batch that pulls together all insert, update, and delete operations. Operations
* that require individual operation results such as optimistic locking (using {@code @Version}) are not supported and
* the version field remains not populated.
*
* @author Tobias Trelle
* @author Oliver Gierke

View File

@@ -36,21 +36,29 @@ import com.mongodb.client.model.changestream.OperationType;
*
* @author Christoph Strobl
* @author Mark Paluch
* @author Myroslav Kosinskyi
* @since 2.1
*/
public class ChangeStreamEvent<T> {
@SuppressWarnings("rawtypes") //
private static final AtomicReferenceFieldUpdater<ChangeStreamEvent, Object> CONVERTED_UPDATER = AtomicReferenceFieldUpdater
.newUpdater(ChangeStreamEvent.class, Object.class, "converted");
private static final AtomicReferenceFieldUpdater<ChangeStreamEvent, Object> CONVERTED_FULL_DOCUMENT_UPDATER = AtomicReferenceFieldUpdater
.newUpdater(ChangeStreamEvent.class, Object.class, "convertedFullDocument");
@SuppressWarnings("rawtypes") //
private static final AtomicReferenceFieldUpdater<ChangeStreamEvent, Object> CONVERTED_FULL_DOCUMENT_BEFORE_CHANGE_UPDATER = AtomicReferenceFieldUpdater
.newUpdater(ChangeStreamEvent.class, Object.class, "convertedFullDocumentBeforeChange");
private final @Nullable ChangeStreamDocument<Document> raw;
private final Class<T> targetType;
private final MongoConverter converter;
// accessed through CONVERTED_UPDATER.
private volatile @Nullable T converted;
// accessed through CONVERTED_FULL_DOCUMENT_UPDATER.
private volatile @Nullable T convertedFullDocument;
// accessed through CONVERTED_FULL_DOCUMENT_BEFORE_CHANGE_UPDATER.
private volatile @Nullable T convertedFullDocumentBeforeChange;
/**
* @param raw can be {@literal null}.
@@ -147,27 +155,43 @@ public class ChangeStreamEvent<T> {
@Nullable
public T getBody() {
if (raw == null) {
if (raw == null || raw.getFullDocument() == null) {
return null;
}
Document fullDocument = raw.getFullDocument();
return getConvertedFullDocument(raw.getFullDocument());
}
if (fullDocument == null) {
return targetType.cast(fullDocument);
/**
* Get the potentially converted {@link ChangeStreamDocument#getFullDocumentBeforeChange() document} before being changed.
*
* @return {@literal null} when {@link #getRaw()} or {@link ChangeStreamDocument#getFullDocumentBeforeChange()} is
* {@literal null}.
* @since 4.0
*/
@Nullable
public T getBodyBeforeChange() {
if (raw == null || raw.getFullDocumentBeforeChange() == null) {
return null;
}
return getConverted(fullDocument);
return getConvertedFullDocumentBeforeChange(raw.getFullDocumentBeforeChange());
}
@SuppressWarnings("unchecked")
private T getConverted(Document fullDocument) {
return (T) doGetConverted(fullDocument);
private T getConvertedFullDocumentBeforeChange(Document fullDocument) {
return (T) doGetConverted(fullDocument, CONVERTED_FULL_DOCUMENT_BEFORE_CHANGE_UPDATER);
}
private Object doGetConverted(Document fullDocument) {
@SuppressWarnings("unchecked")
private T getConvertedFullDocument(Document fullDocument) {
return (T) doGetConverted(fullDocument, CONVERTED_FULL_DOCUMENT_UPDATER);
}
Object result = CONVERTED_UPDATER.get(this);
private Object doGetConverted(Document fullDocument, AtomicReferenceFieldUpdater<ChangeStreamEvent, Object> updater) {
Object result = updater.get(this);
if (result != null) {
return result;
@@ -176,13 +200,13 @@ public class ChangeStreamEvent<T> {
if (ClassUtils.isAssignable(Document.class, fullDocument.getClass())) {
result = converter.read(targetType, fullDocument);
return CONVERTED_UPDATER.compareAndSet(this, null, result) ? result : CONVERTED_UPDATER.get(this);
return updater.compareAndSet(this, null, result) ? result : updater.get(this);
}
if (converter.getConversionService().canConvert(fullDocument.getClass(), targetType)) {
result = converter.getConversionService().convert(fullDocument, targetType);
return CONVERTED_UPDATER.compareAndSet(this, null, result) ? result : CONVERTED_UPDATER.get(this);
return updater.compareAndSet(this, null, result) ? result : updater.get(this);
}
throw new IllegalArgumentException(

View File

@@ -32,6 +32,7 @@ import org.springframework.util.ObjectUtils;
import com.mongodb.client.model.changestream.ChangeStreamDocument;
import com.mongodb.client.model.changestream.FullDocument;
import com.mongodb.client.model.changestream.FullDocumentBeforeChange;
/**
* Options applicable to MongoDB <a href="https://docs.mongodb.com/manual/changeStreams/">Change Streams</a>. Intended
@@ -40,6 +41,7 @@ import com.mongodb.client.model.changestream.FullDocument;
*
* @author Christoph Strobl
* @author Mark Paluch
* @author Myroslav Kosinskyi
* @since 2.1
*/
public class ChangeStreamOptions {
@@ -47,6 +49,7 @@ public class ChangeStreamOptions {
private @Nullable Object filter;
private @Nullable BsonValue resumeToken;
private @Nullable FullDocument fullDocumentLookup;
private @Nullable FullDocumentBeforeChange fullDocumentBeforeChangeLookup;
private @Nullable Collation collation;
private @Nullable Object resumeTimestamp;
private Resume resume = Resume.UNDEFINED;
@@ -74,6 +77,14 @@ public class ChangeStreamOptions {
return Optional.ofNullable(fullDocumentLookup);
}
/**
* @return {@link Optional#empty()} if not set.
* @since 4.0
*/
public Optional<FullDocumentBeforeChange> getFullDocumentBeforeChangeLookup() {
return Optional.ofNullable(fullDocumentBeforeChangeLookup);
}
/**
* @return {@link Optional#empty()} if not set.
*/
@@ -148,7 +159,7 @@ public class ChangeStreamOptions {
}
throw new IllegalArgumentException(
"o_O that should actually not happen. The timestamp should be an Instant or a BsonTimestamp but was "
"o_O that should actually not happen; The timestamp should be an Instant or a BsonTimestamp but was "
+ ObjectUtils.nullSafeClassName(timestamp));
}
@@ -170,6 +181,9 @@ public class ChangeStreamOptions {
if (!ObjectUtils.nullSafeEquals(this.fullDocumentLookup, that.fullDocumentLookup)) {
return false;
}
if (!ObjectUtils.nullSafeEquals(this.fullDocumentBeforeChangeLookup, that.fullDocumentBeforeChangeLookup)) {
return false;
}
if (!ObjectUtils.nullSafeEquals(this.collation, that.collation)) {
return false;
}
@@ -184,6 +198,7 @@ public class ChangeStreamOptions {
int result = ObjectUtils.nullSafeHashCode(filter);
result = 31 * result + ObjectUtils.nullSafeHashCode(resumeToken);
result = 31 * result + ObjectUtils.nullSafeHashCode(fullDocumentLookup);
result = 31 * result + ObjectUtils.nullSafeHashCode(fullDocumentBeforeChangeLookup);
result = 31 * result + ObjectUtils.nullSafeHashCode(collation);
result = 31 * result + ObjectUtils.nullSafeHashCode(resumeTimestamp);
result = 31 * result + ObjectUtils.nullSafeHashCode(resume);
@@ -220,6 +235,7 @@ public class ChangeStreamOptions {
private @Nullable Object filter;
private @Nullable BsonValue resumeToken;
private @Nullable FullDocument fullDocumentLookup;
private @Nullable FullDocumentBeforeChange fullDocumentBeforeChangeLookup;
private @Nullable Collation collation;
private @Nullable Object resumeTimestamp;
private Resume resume = Resume.UNDEFINED;
@@ -234,7 +250,7 @@ public class ChangeStreamOptions {
*/
public ChangeStreamOptionsBuilder collation(Collation collation) {
Assert.notNull(collation, "Collation must not be null nor empty!");
Assert.notNull(collation, "Collation must not be null nor empty");
this.collation = collation;
return this;
@@ -258,7 +274,7 @@ public class ChangeStreamOptions {
*/
public ChangeStreamOptionsBuilder filter(Aggregation filter) {
Assert.notNull(filter, "Filter must not be null!");
Assert.notNull(filter, "Filter must not be null");
this.filter = filter;
return this;
@@ -287,7 +303,7 @@ public class ChangeStreamOptions {
*/
public ChangeStreamOptionsBuilder resumeToken(BsonValue resumeToken) {
Assert.notNull(resumeToken, "ResumeToken must not be null!");
Assert.notNull(resumeToken, "ResumeToken must not be null");
this.resumeToken = resumeToken;
@@ -316,12 +332,38 @@ public class ChangeStreamOptions {
*/
public ChangeStreamOptionsBuilder fullDocumentLookup(FullDocument lookup) {
Assert.notNull(lookup, "Lookup must not be null!");
Assert.notNull(lookup, "Lookup must not be null");
this.fullDocumentLookup = lookup;
return this;
}
/**
* Set the {@link FullDocumentBeforeChange} lookup to use.
*
* @param lookup must not be {@literal null}.
* @return this.
* @since 4.0
*/
public ChangeStreamOptionsBuilder fullDocumentBeforeChangeLookup(FullDocumentBeforeChange lookup) {
Assert.notNull(lookup, "Lookup must not be null");
this.fullDocumentBeforeChangeLookup = lookup;
return this;
}
/**
* Return the full document before being changed if it is available.
*
* @return this.
* @since 4.0
* @see #fullDocumentBeforeChangeLookup(FullDocumentBeforeChange)
*/
public ChangeStreamOptionsBuilder returnFullDocumentBeforeChange() {
return fullDocumentBeforeChangeLookup(FullDocumentBeforeChange.WHEN_AVAILABLE);
}
/**
* Set the cluster time to resume from.
*
@@ -330,7 +372,7 @@ public class ChangeStreamOptions {
*/
public ChangeStreamOptionsBuilder resumeAt(Instant resumeTimestamp) {
Assert.notNull(resumeTimestamp, "ResumeTimestamp must not be null!");
Assert.notNull(resumeTimestamp, "ResumeTimestamp must not be null");
this.resumeTimestamp = resumeTimestamp;
return this;
@@ -345,7 +387,7 @@ public class ChangeStreamOptions {
*/
public ChangeStreamOptionsBuilder resumeAt(BsonTimestamp resumeTimestamp) {
Assert.notNull(resumeTimestamp, "ResumeTimestamp must not be null!");
Assert.notNull(resumeTimestamp, "ResumeTimestamp must not be null");
this.resumeTimestamp = resumeTimestamp;
return this;
@@ -391,6 +433,7 @@ public class ChangeStreamOptions {
options.filter = this.filter;
options.resumeToken = this.resumeToken;
options.fullDocumentLookup = this.fullDocumentLookup;
options.fullDocumentBeforeChangeLookup = this.fullDocumentBeforeChangeLookup;
options.collation = this.collation;
options.resumeTimestamp = this.resumeTimestamp;
options.resume = this.resume;

View File

@@ -46,10 +46,11 @@ public class CollectionOptions {
private @Nullable Collation collation;
private ValidationOptions validationOptions;
private @Nullable TimeSeriesOptions timeSeriesOptions;
private @Nullable CollectionChangeStreamOptions changeStreamOptions;
private CollectionOptions(@Nullable Long size, @Nullable Long maxDocuments, @Nullable Boolean capped,
@Nullable Collation collation, ValidationOptions validationOptions,
@Nullable TimeSeriesOptions timeSeriesOptions) {
@Nullable TimeSeriesOptions timeSeriesOptions, @Nullable CollectionChangeStreamOptions changeStreamOptions) {
this.maxDocuments = maxDocuments;
this.size = size;
@@ -57,6 +58,7 @@ public class CollectionOptions {
this.collation = collation;
this.validationOptions = validationOptions;
this.timeSeriesOptions = timeSeriesOptions;
this.changeStreamOptions = changeStreamOptions;
}
/**
@@ -68,9 +70,9 @@ public class CollectionOptions {
*/
public static CollectionOptions just(Collation collation) {
Assert.notNull(collation, "Collation must not be null!");
Assert.notNull(collation, "Collation must not be null");
return new CollectionOptions(null, null, null, collation, ValidationOptions.none(), null);
return new CollectionOptions(null, null, null, collation, ValidationOptions.none(), null, null);
}
/**
@@ -80,7 +82,7 @@ public class CollectionOptions {
* @since 2.0
*/
public static CollectionOptions empty() {
return new CollectionOptions(null, null, null, null, ValidationOptions.none(), null);
return new CollectionOptions(null, null, null, null, ValidationOptions.none(), null, null);
}
/**
@@ -97,6 +99,18 @@ public class CollectionOptions {
return empty().timeSeries(TimeSeriesOptions.timeSeries(timeField));
}
/**
* Quick way to set up {@link CollectionOptions} for emitting (pre & post) change events.
*
* @return new instance of {@link CollectionOptions}.
* @see #changeStream(CollectionChangeStreamOptions)
* @see CollectionChangeStreamOptions#preAndPostImages(boolean)
* @since 4.0
*/
public static CollectionOptions emitChangedRevisions() {
return empty().changeStream(CollectionChangeStreamOptions.preAndPostImages(true));
}
/**
* Create new {@link CollectionOptions} with already given settings and capped set to {@literal true}. <br />
* <strong>NOTE</strong> Using capped collections requires defining {@link #size(long)}.
@@ -105,7 +119,7 @@ public class CollectionOptions {
* @since 2.0
*/
public CollectionOptions capped() {
return new CollectionOptions(size, maxDocuments, true, collation, validationOptions, null);
return new CollectionOptions(size, maxDocuments, true, collation, validationOptions, timeSeriesOptions, changeStreamOptions);
}
/**
@@ -116,7 +130,7 @@ public class CollectionOptions {
* @since 2.0
*/
public CollectionOptions maxDocuments(long maxDocuments) {
return new CollectionOptions(size, maxDocuments, capped, collation, validationOptions, timeSeriesOptions);
return new CollectionOptions(size, maxDocuments, capped, collation, validationOptions, timeSeriesOptions, changeStreamOptions);
}
/**
@@ -127,7 +141,7 @@ public class CollectionOptions {
* @since 2.0
*/
public CollectionOptions size(long size) {
return new CollectionOptions(size, maxDocuments, capped, collation, validationOptions, timeSeriesOptions);
return new CollectionOptions(size, maxDocuments, capped, collation, validationOptions, timeSeriesOptions, changeStreamOptions);
}
/**
@@ -138,7 +152,7 @@ public class CollectionOptions {
* @since 2.0
*/
public CollectionOptions collation(@Nullable Collation collation) {
return new CollectionOptions(size, maxDocuments, capped, collation, validationOptions, timeSeriesOptions);
return new CollectionOptions(size, maxDocuments, capped, collation, validationOptions, timeSeriesOptions, changeStreamOptions);
}
/**
@@ -230,7 +244,7 @@ public class CollectionOptions {
*/
public CollectionOptions schemaValidationLevel(ValidationLevel validationLevel) {
Assert.notNull(validationLevel, "ValidationLevel must not be null!");
Assert.notNull(validationLevel, "ValidationLevel must not be null");
return validation(validationOptions.validationLevel(validationLevel));
}
@@ -244,7 +258,7 @@ public class CollectionOptions {
*/
public CollectionOptions schemaValidationAction(ValidationAction validationAction) {
Assert.notNull(validationAction, "ValidationAction must not be null!");
Assert.notNull(validationAction, "ValidationAction must not be null");
return validation(validationOptions.validationAction(validationAction));
}
@@ -257,8 +271,8 @@ public class CollectionOptions {
*/
public CollectionOptions validation(ValidationOptions validationOptions) {
Assert.notNull(validationOptions, "ValidationOptions must not be null!");
return new CollectionOptions(size, maxDocuments, capped, collation, validationOptions, timeSeriesOptions);
Assert.notNull(validationOptions, "ValidationOptions must not be null");
return new CollectionOptions(size, maxDocuments, capped, collation, validationOptions, timeSeriesOptions, changeStreamOptions);
}
/**
@@ -270,8 +284,21 @@ public class CollectionOptions {
*/
public CollectionOptions timeSeries(TimeSeriesOptions timeSeriesOptions) {
Assert.notNull(timeSeriesOptions, "TimeSeriesOptions must not be null!");
return new CollectionOptions(size, maxDocuments, capped, collation, validationOptions, timeSeriesOptions);
Assert.notNull(timeSeriesOptions, "TimeSeriesOptions must not be null");
return new CollectionOptions(size, maxDocuments, capped, collation, validationOptions, timeSeriesOptions, changeStreamOptions);
}
/**
* Create new {@link CollectionOptions} with the given {@link TimeSeriesOptions}.
*
* @param changeStreamOptions must not be {@literal null}.
* @return new instance of {@link CollectionOptions}.
* @since 3.3
*/
public CollectionOptions changeStream(CollectionChangeStreamOptions changeStreamOptions) {
Assert.notNull(changeStreamOptions, "ChangeStreamOptions must not be null");
return new CollectionOptions(size, maxDocuments, capped, collation, validationOptions, timeSeriesOptions, changeStreamOptions);
}
/**
@@ -332,6 +359,16 @@ public class CollectionOptions {
return Optional.ofNullable(timeSeriesOptions);
}
/**
* Get the {@link CollectionChangeStreamOptions} if available.
*
* @return {@link Optional#empty()} if not specified.
* @since 4.0
*/
public Optional<CollectionChangeStreamOptions> getChangeStreamOptions() {
return Optional.ofNullable(changeStreamOptions);
}
/**
* Encapsulation of ValidationOptions options.
*
@@ -428,6 +465,34 @@ public class CollectionOptions {
}
}
/**
* Encapsulation of options applied to define collections change stream behaviour.
*
* @author Christoph Strobl
* @since 4.0
*/
public static class CollectionChangeStreamOptions {
private final boolean preAndPostImages;
private CollectionChangeStreamOptions(boolean emitChangedRevisions) {
this.preAndPostImages = emitChangedRevisions;
}
/**
* Output the version of a document before and after changes (the document pre- and post-images).
*
* @return new instance of {@link CollectionChangeStreamOptions}.
*/
public static CollectionChangeStreamOptions preAndPostImages(boolean emitChangedRevisions) {
return new CollectionChangeStreamOptions(true);
}
public boolean getPreAndPostImages() {
return preAndPostImages;
}
}
/**
* Options applicable to Time Series collections.
*
@@ -446,7 +511,7 @@ public class CollectionOptions {
private TimeSeriesOptions(String timeField, @Nullable String metaField, GranularityDefinition granularity) {
Assert.hasText(timeField, "Time field must not be empty or null!");
Assert.hasText(timeField, "Time field must not be empty or null");
this.timeField = timeField;
this.metaField = metaField;

View File

@@ -23,8 +23,8 @@ import java.util.List;
import java.util.Map;
import org.bson.Document;
import org.springframework.data.geo.Point;
import org.springframework.data.mongodb.core.query.MetricConversion;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
@@ -38,7 +38,7 @@ import org.springframework.util.ObjectUtils;
*/
class CountQuery {
private Document source;
private final Document source;
private CountQuery(Document source) {
this.source = source;
@@ -101,7 +101,7 @@ class CountQuery {
}
if (valueToInspect instanceof Collection) {
return requiresRewrite((Collection) valueToInspect);
return requiresRewrite((Collection<?>) valueToInspect);
}
return false;
@@ -157,12 +157,14 @@ class CountQuery {
* @param $and potentially existing {@code $and} condition.
* @return the rewritten query {@link Document}.
*/
@SuppressWarnings("unchecked")
private static Document createGeoWithin(String key, Document source, @Nullable Object $and) {
boolean spheric = source.containsKey("$nearSphere");
Object $near = spheric ? source.get("$nearSphere") : source.get("$near");
Number maxDistance = source.containsKey("$maxDistance") ? (Number) source.get("$maxDistance") : Double.MAX_VALUE;
Number maxDistance = getMaxDistance(source, $near, spheric);
List<Object> $centerMax = Arrays.asList(toCenterCoordinates($near), maxDistance);
Document $geoWithinMax = new Document("$geoWithin",
new Document(spheric ? "$centerSphere" : "$center", $centerMax));
@@ -176,23 +178,51 @@ class CountQuery {
Document $geoWithinMin = new Document("$geoWithin",
new Document(spheric ? "$centerSphere" : "$center", $centerMin));
List<Document> criteria = new ArrayList<>();
List<Document> criteria;
if ($and != null) {
if ($and instanceof Collection) {
criteria.addAll((Collection) $and);
Collection<Document> andElements = (Collection<Document>) $and;
criteria = new ArrayList<>(andElements.size() + 2);
criteria.addAll(andElements);
} else {
throw new IllegalArgumentException(
"Cannot rewrite query as it contains an '$and' element that is not a Collection!: Offending element: "
"Cannot rewrite query as it contains an '$and' element that is not a Collection: Offending element: "
+ $and);
}
} else {
criteria = new ArrayList<>(2);
}
criteria.add(new Document("$nor", Collections.singletonList(new Document(key, $geoWithinMin))));
criteria.add(new Document(key, $geoWithinMax));
return new Document("$and", criteria);
}
private static Number getMaxDistance(Document source, Object $near, boolean spheric) {
Number maxDistance = Double.MAX_VALUE;
if (source.containsKey("$maxDistance")) { // legacy coordinate pair
return (Number) source.get("$maxDistance");
}
if ($near instanceof Document nearDoc) {
if (nearDoc.containsKey("$maxDistance")) {
maxDistance = (Number) nearDoc.get("$maxDistance");
// geojson is in Meters but we need radians x/(6378.1*1000)
if (spheric && nearDoc.containsKey("$geometry")) {
maxDistance = MetricConversion.metersToRadians(maxDistance.doubleValue());
}
}
}
return maxDistance;
}
private static boolean containsNear(Document source) {
return source.containsKey("$near") || source.containsKey("$nearSphere");
}
@@ -216,10 +246,16 @@ class CountQuery {
return Arrays.asList(((Point) value).getX(), ((Point) value).getY());
}
if (value instanceof Document && ((Document) value).containsKey("x")) {
if (value instanceof Document document) {
Document point = (Document) value;
return Arrays.asList(point.get("x"), point.get("y"));
if (document.containsKey("x")) {
return Arrays.asList(document.get("x"), document.get("y"));
}
if (document.containsKey("$geometry")) {
Document geoJsonPoint = document.get("$geometry", Document.class);
return geoJsonPoint.get("coordinates");
}
}
return value;

View File

@@ -61,8 +61,8 @@ public interface CursorPreparer extends ReadPreferenceAware {
default FindIterable<Document> initiateFind(MongoCollection<Document> collection,
Function<MongoCollection<Document>, FindIterable<Document>> find) {
Assert.notNull(collection, "Collection must not be null!");
Assert.notNull(find, "Find function must not be null!");
Assert.notNull(collection, "Collection must not be null");
Assert.notNull(find, "Find function must not be null");
if (hasReadPreference()) {
collection = collection.withReadPreference(getReadPreference());

View File

@@ -90,9 +90,9 @@ class DefaultBulkOperations implements BulkOperations {
DefaultBulkOperations(MongoOperations mongoOperations, String collectionName,
BulkOperationContext bulkOperationContext) {
Assert.notNull(mongoOperations, "MongoOperations must not be null!");
Assert.hasText(collectionName, "CollectionName must not be null nor empty!");
Assert.notNull(bulkOperationContext, "BulkOperationContext must not be null!");
Assert.notNull(mongoOperations, "MongoOperations must not be null");
Assert.hasText(collectionName, "CollectionName must not be null nor empty");
Assert.notNull(bulkOperationContext, "BulkOperationContext must not be null");
this.mongoOperations = mongoOperations;
this.collectionName = collectionName;
@@ -112,7 +112,7 @@ class DefaultBulkOperations implements BulkOperations {
@Override
public BulkOperations insert(Object document) {
Assert.notNull(document, "Document must not be null!");
Assert.notNull(document, "Document must not be null");
maybeEmitEvent(new BeforeConvertEvent<>(document, collectionName));
Object source = maybeInvokeBeforeConvertCallback(document);
@@ -124,7 +124,7 @@ class DefaultBulkOperations implements BulkOperations {
@Override
public BulkOperations insert(List<? extends Object> documents) {
Assert.notNull(documents, "Documents must not be null!");
Assert.notNull(documents, "Documents must not be null");
documents.forEach(this::insert);
@@ -135,8 +135,8 @@ class DefaultBulkOperations implements BulkOperations {
@SuppressWarnings("unchecked")
public BulkOperations updateOne(Query query, Update update) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(update, "Update must not be null!");
Assert.notNull(query, "Query must not be null");
Assert.notNull(update, "Update must not be null");
return updateOne(Collections.singletonList(Pair.of(query, update)));
}
@@ -144,7 +144,7 @@ class DefaultBulkOperations implements BulkOperations {
@Override
public BulkOperations updateOne(List<Pair<Query, Update>> updates) {
Assert.notNull(updates, "Updates must not be null!");
Assert.notNull(updates, "Updates must not be null");
for (Pair<Query, Update> update : updates) {
update(update.getFirst(), update.getSecond(), false, false);
@@ -157,8 +157,8 @@ class DefaultBulkOperations implements BulkOperations {
@SuppressWarnings("unchecked")
public BulkOperations updateMulti(Query query, Update update) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(update, "Update must not be null!");
Assert.notNull(query, "Query must not be null");
Assert.notNull(update, "Update must not be null");
return updateMulti(Collections.singletonList(Pair.of(query, update)));
}
@@ -166,7 +166,7 @@ class DefaultBulkOperations implements BulkOperations {
@Override
public BulkOperations updateMulti(List<Pair<Query, Update>> updates) {
Assert.notNull(updates, "Updates must not be null!");
Assert.notNull(updates, "Updates must not be null");
for (Pair<Query, Update> update : updates) {
update(update.getFirst(), update.getSecond(), false, true);
@@ -193,7 +193,7 @@ class DefaultBulkOperations implements BulkOperations {
@Override
public BulkOperations remove(Query query) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(query, "Query must not be null");
DeleteOptions deleteOptions = new DeleteOptions();
query.getCollation().map(Collation::toMongoCollation).ifPresent(deleteOptions::collation);
@@ -206,7 +206,7 @@ class DefaultBulkOperations implements BulkOperations {
@Override
public BulkOperations remove(List<Query> removes) {
Assert.notNull(removes, "Removals must not be null!");
Assert.notNull(removes, "Removals must not be null");
for (Query query : removes) {
remove(query);
@@ -218,9 +218,9 @@ class DefaultBulkOperations implements BulkOperations {
@Override
public BulkOperations replaceOne(Query query, Object replacement, FindAndReplaceOptions options) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(replacement, "Replacement must not be null!");
Assert.notNull(options, "Options must not be null!");
Assert.notNull(query, "Query must not be null");
Assert.notNull(replacement, "Replacement must not be null");
Assert.notNull(options, "Options must not be null");
ReplaceOptions replaceOptions = new ReplaceOptions();
replaceOptions.upsert(options.isUpsert());
@@ -241,7 +241,7 @@ class DefaultBulkOperations implements BulkOperations {
com.mongodb.bulk.BulkWriteResult result = mongoOperations.execute(collectionName, this::bulkWriteTo);
Assert.state(result != null, "Result must not be null.");
Assert.state(result != null, "Result must not be null");
models.forEach(this::maybeEmitAfterSaveEvent);
models.forEach(this::maybeInvokeAfterSaveCallback);
@@ -308,8 +308,8 @@ class DefaultBulkOperations implements BulkOperations {
*/
private BulkOperations update(Query query, Update update, boolean upsert, boolean multi) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(update, "Update must not be null!");
Assert.notNull(query, "Query must not be null");
Assert.notNull(update, "Update must not be null");
UpdateOptions options = computeUpdateOptions(query, update, upsert);
@@ -470,7 +470,7 @@ class DefaultBulkOperations implements BulkOperations {
return options.ordered(false);
}
throw new IllegalStateException("BulkMode was null!");
throw new IllegalStateException("BulkMode was null");
}
/**

View File

@@ -83,9 +83,9 @@ public class DefaultIndexOperations implements IndexOperations {
public DefaultIndexOperations(MongoDatabaseFactory mongoDbFactory, String collectionName, QueryMapper queryMapper,
@Nullable Class<?> type) {
Assert.notNull(mongoDbFactory, "MongoDbFactory must not be null!");
Assert.notNull(collectionName, "Collection name can not be null!");
Assert.notNull(queryMapper, "QueryMapper must not be null!");
Assert.notNull(mongoDbFactory, "MongoDbFactory must not be null");
Assert.notNull(collectionName, "Collection name can not be null");
Assert.notNull(queryMapper, "QueryMapper must not be null");
this.collectionName = collectionName;
this.mapper = queryMapper;
@@ -103,8 +103,8 @@ public class DefaultIndexOperations implements IndexOperations {
*/
public DefaultIndexOperations(MongoOperations mongoOperations, String collectionName, @Nullable Class<?> type) {
Assert.notNull(mongoOperations, "MongoOperations must not be null!");
Assert.hasText(collectionName, "Collection name must not be null or empty!");
Assert.notNull(mongoOperations, "MongoOperations must not be null");
Assert.hasText(collectionName, "Collection name must not be null or empty");
this.mongoOperations = mongoOperations;
this.mapper = new QueryMapper(mongoOperations.getConverter());
@@ -172,7 +172,8 @@ public class DefaultIndexOperations implements IndexOperations {
private List<IndexInfo> getIndexData(MongoCursor<Document> cursor) {
List<IndexInfo> indexInfoList = new ArrayList<>();
int available = cursor.available();
List<IndexInfo> indexInfoList = available > 0 ? new ArrayList<>(available) : new ArrayList<>();
while (cursor.hasNext()) {
@@ -189,7 +190,7 @@ public class DefaultIndexOperations implements IndexOperations {
@Nullable
public <T> T execute(CollectionCallback<T> callback) {
Assert.notNull(callback, "CollectionCallback must not be null!");
Assert.notNull(callback, "CollectionCallback must not be null");
if (type != null) {
return mongoOperations.execute(type, callback);

View File

@@ -76,9 +76,9 @@ public class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
private DefaultReactiveIndexOperations(ReactiveMongoOperations mongoOperations, String collectionName,
QueryMapper queryMapper, Optional<Class<?>> type) {
Assert.notNull(mongoOperations, "ReactiveMongoOperations must not be null!");
Assert.notNull(collectionName, "Collection must not be null!");
Assert.notNull(queryMapper, "QueryMapper must not be null!");
Assert.notNull(mongoOperations, "ReactiveMongoOperations must not be null");
Assert.notNull(collectionName, "Collection must not be null");
Assert.notNull(queryMapper, "QueryMapper must not be null");
this.mongoOperations = mongoOperations;
this.collectionName = collectionName;

View File

@@ -31,7 +31,6 @@ import org.bson.types.ObjectId;
import org.springframework.dao.DataAccessException;
import org.springframework.data.mongodb.core.script.ExecutableMongoScript;
import org.springframework.data.mongodb.core.script.NamedMongoScript;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
@@ -65,7 +64,7 @@ class DefaultScriptOperations implements ScriptOperations {
*/
public DefaultScriptOperations(MongoOperations mongoOperations) {
Assert.notNull(mongoOperations, "MongoOperations must not be null!");
Assert.notNull(mongoOperations, "MongoOperations must not be null");
this.mongoOperations = mongoOperations;
}
@@ -78,7 +77,7 @@ class DefaultScriptOperations implements ScriptOperations {
@Override
public NamedMongoScript register(NamedMongoScript script) {
Assert.notNull(script, "Script must not be null!");
Assert.notNull(script, "Script must not be null");
mongoOperations.save(script, SCRIPT_COLLECTION_NAME);
return script;
@@ -87,7 +86,7 @@ class DefaultScriptOperations implements ScriptOperations {
@Override
public Object execute(final ExecutableMongoScript script, final Object... args) {
Assert.notNull(script, "Script must not be null!");
Assert.notNull(script, "Script must not be null");
return mongoOperations.execute(new DbCallback<Object>() {
@@ -106,7 +105,7 @@ class DefaultScriptOperations implements ScriptOperations {
@Override
public Object call(final String scriptName, final Object... args) {
Assert.hasText(scriptName, "ScriptName must not be null or empty!");
Assert.hasText(scriptName, "ScriptName must not be null or empty");
return mongoOperations.execute(new DbCallback<Object>() {
@@ -122,7 +121,7 @@ class DefaultScriptOperations implements ScriptOperations {
@Override
public boolean exists(String scriptName) {
Assert.hasText(scriptName, "ScriptName must not be null or empty!");
Assert.hasText(scriptName, "ScriptName must not be null or empty");
return mongoOperations.exists(query(where("_id").is(scriptName)), NamedMongoScript.class, SCRIPT_COLLECTION_NAME);
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2022 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 org.springframework.context.ApplicationEventPublisher;
import org.springframework.lang.Nullable;
/**
* Delegate class to encapsulate lifecycle event configuration and publishing.
*
* @author Mark Paluch
* @since 4.0
* @see ApplicationEventPublisher
*/
class EntityLifecycleEventDelegate {
private @Nullable ApplicationEventPublisher publisher;
private boolean eventsEnabled = true;
public void setPublisher(@Nullable ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
public boolean isEventsEnabled() {
return eventsEnabled;
}
public void setEventsEnabled(boolean eventsEnabled) {
this.eventsEnabled = eventsEnabled;
}
/**
* Publish an application event if event publishing is enabled.
*
* @param event the application event.
*/
public void publishEvent(Object event) {
if (canPublishEvent()) {
publisher.publishEvent(event);
}
}
private boolean canPublishEvent() {
return publisher != null && eventsEnabled;
}
}

View File

@@ -21,7 +21,6 @@ import java.util.Map;
import java.util.Optional;
import org.bson.Document;
import org.springframework.core.convert.ConversionService;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.convert.CustomConversions;
@@ -57,6 +56,7 @@ import org.springframework.util.MultiValueMap;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import com.mongodb.client.model.ChangeStreamPreAndPostImagesOptions;
import com.mongodb.client.model.CreateCollectionOptions;
import com.mongodb.client.model.TimeSeriesGranularity;
import com.mongodb.client.model.ValidationOptions;
@@ -112,7 +112,7 @@ class EntityOperations {
@SuppressWarnings({ "unchecked", "rawtypes" })
<T> Entity<T> forEntity(T entity) {
Assert.notNull(entity, "Bean must not be null!");
Assert.notNull(entity, "Bean must not be null");
if (entity instanceof String) {
return new UnmappedEntity(parse(entity.toString()));
@@ -135,8 +135,8 @@ class EntityOperations {
@SuppressWarnings({ "unchecked", "rawtypes" })
<T> AdaptibleEntity<T> forEntity(T entity, ConversionService conversionService) {
Assert.notNull(entity, "Bean must not be null!");
Assert.notNull(conversionService, "ConversionService must not be null!");
Assert.notNull(entity, "Bean must not be null");
Assert.notNull(conversionService, "ConversionService must not be null");
if (entity instanceof String) {
return new UnmappedEntity(parse(entity.toString()));
@@ -171,10 +171,17 @@ class EntityOperations {
if (entityClass == null) {
throw new InvalidDataAccessApiUsageException(
"No class parameter provided, entity collection can't be determined!");
"No class parameter provided, entity collection can't be determined");
}
return context.getRequiredPersistentEntity(entityClass).getCollection();
MongoPersistentEntity<?> persistentEntity = context.getPersistentEntity(entityClass);
if (persistentEntity == null) {
throw new MappingException(String.format(
"Cannot determine collection name from type '%s'. Is it a store native type?", entityClass.getName()));
}
return persistentEntity.getCollection();
}
public Query getByIdInQuery(Collection<?> entities) {
@@ -201,7 +208,7 @@ class EntityOperations {
*/
public String getIdPropertyName(Class<?> type) {
Assert.notNull(type, "Type must not be null!");
Assert.notNull(type, "Type must not be null");
MongoPersistentEntity<?> persistentEntity = context.getPersistentEntity(type);
@@ -240,12 +247,12 @@ class EntityOperations {
try {
return Document.parse(source);
} catch (org.bson.json.JsonParseException o_O) {
throw new MappingException("Could not parse given String to save into a JSON document!", o_O);
throw new MappingException("Could not parse given String to save into a JSON document", o_O);
} catch (RuntimeException o_O) {
// legacy 3.x exception
if (ClassUtils.matchesTypeName(o_O.getClass(), "JSONParseException")) {
throw new MappingException("Could not parse given String to save into a JSON document!", o_O);
throw new MappingException("Could not parse given String to save into a JSON document", o_O);
}
throw o_O;
}
@@ -334,6 +341,9 @@ class EntityOperations {
result.timeSeriesOptions(options);
});
collectionOptions.getChangeStreamOptions().ifPresent(it -> result
.changeStreamPreAndPostImagesOptions(new ChangeStreamPreAndPostImagesOptions(it.getPreAndPostImages())));
return result;
}
@@ -518,7 +528,7 @@ class EntityOperations {
@Override
public Query getQueryForVersion() {
throw new MappingException("Cannot query for version on plain Documents!");
throw new MappingException("Cannot query for version on plain Documents");
}
@Override
@@ -614,7 +624,7 @@ class EntityOperations {
public Query getByIdQuery() {
if (!entity.hasIdProperty()) {
throw new MappingException("No id property found for object of type " + entity.getType() + "!");
throw new MappingException("No id property found for object of type " + entity.getType());
}
MongoPersistentProperty idProperty = entity.getRequiredIdProperty();
@@ -662,7 +672,7 @@ class EntityOperations {
if (!MongoSimpleTypes.AUTOGENERATED_ID_TYPES.contains(property.getType())) {
throw new InvalidDataAccessApiUsageException(
String.format("Cannot autogenerate id of type %s for entity of type %s!", property.getType().getName(),
String.format("Cannot autogenerate id of type %s for entity of type %s", property.getType().getName(),
entity.getType().getName()));
}
}

View File

@@ -41,7 +41,7 @@ class ExecutableAggregationOperationSupport implements ExecutableAggregationOper
@Override
public <T> ExecutableAggregation<T> aggregateAndReturn(Class<T> domainType) {
Assert.notNull(domainType, "DomainType must not be null!");
Assert.notNull(domainType, "DomainType must not be null");
return new ExecutableAggregationSupport<>(template, domainType, null, null);
}
@@ -69,7 +69,7 @@ class ExecutableAggregationOperationSupport implements ExecutableAggregationOper
@Override
public AggregationWithAggregation<T> inCollection(String collection) {
Assert.hasText(collection, "Collection must not be null nor empty!");
Assert.hasText(collection, "Collection must not be null nor empty");
return new ExecutableAggregationSupport<>(template, domainType, aggregation, collection);
}
@@ -77,7 +77,7 @@ class ExecutableAggregationOperationSupport implements ExecutableAggregationOper
@Override
public TerminatingAggregation<T> by(Aggregation aggregation) {
Assert.notNull(aggregation, "Aggregation must not be null!");
Assert.notNull(aggregation, "Aggregation must not be null");
return new ExecutableAggregationSupport<>(template, domainType, aggregation, collection);
}

View File

@@ -53,7 +53,7 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation {
@Override
public <T> ExecutableFind<T> query(Class<T> domainType) {
Assert.notNull(domainType, "DomainType must not be null!");
Assert.notNull(domainType, "DomainType must not be null");
return new ExecutableFindSupport<>(template, domainType, domainType, null, ALL_QUERY);
}
@@ -84,7 +84,7 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation {
@Override
public FindWithProjection<T> inCollection(String collection) {
Assert.hasText(collection, "Collection name must not be null nor empty!");
Assert.hasText(collection, "Collection name must not be null nor empty");
return new ExecutableFindSupport<>(template, domainType, returnType, collection, query);
}
@@ -92,7 +92,7 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation {
@Override
public <T1> FindWithQuery<T1> as(Class<T1> returnType) {
Assert.notNull(returnType, "ReturnType must not be null!");
Assert.notNull(returnType, "ReturnType must not be null");
return new ExecutableFindSupport<>(template, domainType, returnType, collection, query);
}
@@ -100,7 +100,7 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation {
@Override
public TerminatingFind<T> matching(Query query) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(query, "Query must not be null");
return new ExecutableFindSupport<>(template, domainType, returnType, collection, query);
}
@@ -115,7 +115,7 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation {
}
if (result.size() > 1) {
throw new IncorrectResultSizeDataAccessException("Query " + asString() + " returned non unique result.", 1);
throw new IncorrectResultSizeDataAccessException("Query " + asString() + " returned non unique result", 1);
}
return result.iterator().next();
@@ -158,7 +158,7 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation {
@Override
public TerminatingDistinct<Object> distinct(String field) {
Assert.notNull(field, "Field must not be null!");
Assert.notNull(field, "Field must not be null");
return new DistinctOperationSupport(this, field);
}
@@ -246,7 +246,7 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation {
@SuppressWarnings("unchecked")
public <R> TerminatingDistinct<R> as(Class<R> resultType) {
Assert.notNull(resultType, "ResultType must not be null!");
Assert.notNull(resultType, "ResultType must not be null");
return new DistinctOperationSupport<>((ExecutableFindSupport) delegate.as(resultType), field);
}
@@ -254,7 +254,7 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation {
@Override
public TerminatingDistinct<T> matching(Query query) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(query, "Query must not be null");
return new DistinctOperationSupport<>((ExecutableFindSupport<T>) delegate.matching(query), field);
}

View File

@@ -43,7 +43,7 @@ class ExecutableInsertOperationSupport implements ExecutableInsertOperation {
@Override
public <T> ExecutableInsert<T> insert(Class<T> domainType) {
Assert.notNull(domainType, "DomainType must not be null!");
Assert.notNull(domainType, "DomainType must not be null");
return new ExecutableInsertSupport<>(template, domainType, null, null);
}
@@ -70,7 +70,7 @@ class ExecutableInsertOperationSupport implements ExecutableInsertOperation {
@Override
public T one(T object) {
Assert.notNull(object, "Object must not be null!");
Assert.notNull(object, "Object must not be null");
return template.insert(object, getCollectionName());
}
@@ -78,7 +78,7 @@ class ExecutableInsertOperationSupport implements ExecutableInsertOperation {
@Override
public Collection<T> all(Collection<? extends T> objects) {
Assert.notNull(objects, "Objects must not be null!");
Assert.notNull(objects, "Objects must not be null");
return template.insert(objects, getCollectionName());
}
@@ -86,7 +86,7 @@ class ExecutableInsertOperationSupport implements ExecutableInsertOperation {
@Override
public BulkWriteResult bulk(Collection<? extends T> objects) {
Assert.notNull(objects, "Objects must not be null!");
Assert.notNull(objects, "Objects must not be null");
return template.bulkOps(bulkMode != null ? bulkMode : BulkMode.ORDERED, domainType, getCollectionName())
.insert(new ArrayList<>(objects)).execute();
@@ -95,7 +95,7 @@ class ExecutableInsertOperationSupport implements ExecutableInsertOperation {
@Override
public InsertWithBulkMode<T> inCollection(String collection) {
Assert.hasText(collection, "Collection must not be null nor empty.");
Assert.hasText(collection, "Collection must not be null nor empty");
return new ExecutableInsertSupport<>(template, domainType, collection, bulkMode);
}
@@ -103,7 +103,7 @@ class ExecutableInsertOperationSupport implements ExecutableInsertOperation {
@Override
public TerminatingBulkInsert<T> withBulkMode(BulkMode bulkMode) {
Assert.notNull(bulkMode, "BulkMode must not be null!");
Assert.notNull(bulkMode, "BulkMode must not be null");
return new ExecutableInsertSupport<>(template, domainType, collection, bulkMode);
}

View File

@@ -187,7 +187,9 @@ public interface ExecutableMapReduceOperation {
*
* @author Christoph Strobl
* @since 2.1
* @deprecated since 4.0 in favor of {@link org.springframework.data.mongodb.core.aggregation}.
*/
@Deprecated
interface MapReduceWithOptions<T> {
/**

View File

@@ -37,7 +37,7 @@ class ExecutableMapReduceOperationSupport implements ExecutableMapReduceOperatio
ExecutableMapReduceOperationSupport(MongoTemplate template) {
Assert.notNull(template, "Template must not be null!");
Assert.notNull(template, "Template must not be null");
this.template = template;
}
@@ -48,7 +48,7 @@ class ExecutableMapReduceOperationSupport implements ExecutableMapReduceOperatio
@Override
public <T> ExecutableMapReduceSupport<T> mapReduce(Class<T> domainType) {
Assert.notNull(domainType, "DomainType must not be null!");
Assert.notNull(domainType, "DomainType must not be null");
return new ExecutableMapReduceSupport<>(template, domainType, domainType, null, ALL_QUERY, null, null, null);
}
@@ -101,7 +101,7 @@ class ExecutableMapReduceOperationSupport implements ExecutableMapReduceOperatio
@Override
public MapReduceWithProjection<T> inCollection(String collection) {
Assert.hasText(collection, "Collection name must not be null nor empty!");
Assert.hasText(collection, "Collection name must not be null nor empty");
return new ExecutableMapReduceSupport<>(template, domainType, returnType, collection, query, mapFunction,
reduceFunction, options);
@@ -114,7 +114,7 @@ class ExecutableMapReduceOperationSupport implements ExecutableMapReduceOperatio
@Override
public TerminatingMapReduce<T> matching(Query query) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(query, "Query must not be null");
return new ExecutableMapReduceSupport<>(template, domainType, returnType, collection, query, mapFunction,
reduceFunction, options);
@@ -127,7 +127,7 @@ class ExecutableMapReduceOperationSupport implements ExecutableMapReduceOperatio
@Override
public <R> MapReduceWithQuery<R> as(Class<R> resultType) {
Assert.notNull(resultType, "ResultType must not be null!");
Assert.notNull(resultType, "ResultType must not be null");
return new ExecutableMapReduceSupport<>(template, domainType, resultType, collection, query, mapFunction,
reduceFunction, options);
@@ -140,7 +140,7 @@ class ExecutableMapReduceOperationSupport implements ExecutableMapReduceOperatio
@Override
public ExecutableMapReduce<T> with(MapReduceOptions options) {
Assert.notNull(options, "Options must not be null! Please consider empty MapReduceOptions#options() instead.");
Assert.notNull(options, "Options must not be null Please consider empty MapReduceOptions#options() instead");
return new ExecutableMapReduceSupport<>(template, domainType, returnType, collection, query, mapFunction,
reduceFunction, options);
@@ -153,7 +153,7 @@ class ExecutableMapReduceOperationSupport implements ExecutableMapReduceOperatio
@Override
public MapReduceWithReduceFunction<T> map(String mapFunction) {
Assert.hasText(mapFunction, "MapFunction name must not be null nor empty!");
Assert.hasText(mapFunction, "MapFunction name must not be null nor empty");
return new ExecutableMapReduceSupport<>(template, domainType, returnType, collection, query, mapFunction,
reduceFunction, options);
@@ -166,7 +166,7 @@ class ExecutableMapReduceOperationSupport implements ExecutableMapReduceOperatio
@Override
public ExecutableMapReduce<T> reduce(String reduceFunction) {
Assert.hasText(reduceFunction, "ReduceFunction name must not be null nor empty!");
Assert.hasText(reduceFunction, "ReduceFunction name must not be null nor empty");
return new ExecutableMapReduceSupport<>(template, domainType, returnType, collection, query, mapFunction,
reduceFunction, options);

View File

@@ -44,7 +44,7 @@ class ExecutableRemoveOperationSupport implements ExecutableRemoveOperation {
@Override
public <T> ExecutableRemove<T> remove(Class<T> domainType) {
Assert.notNull(domainType, "DomainType must not be null!");
Assert.notNull(domainType, "DomainType must not be null");
return new ExecutableRemoveSupport<>(tempate, domainType, ALL_QUERY, null);
}
@@ -70,7 +70,7 @@ class ExecutableRemoveOperationSupport implements ExecutableRemoveOperation {
@Override
public RemoveWithQuery<T> inCollection(String collection) {
Assert.hasText(collection, "Collection must not be null nor empty!");
Assert.hasText(collection, "Collection must not be null nor empty");
return new ExecutableRemoveSupport<>(template, domainType, query, collection);
}
@@ -78,7 +78,7 @@ class ExecutableRemoveOperationSupport implements ExecutableRemoveOperation {
@Override
public TerminatingRemove<T> matching(Query query) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(query, "Query must not be null");
return new ExecutableRemoveSupport<>(template, domainType, query, collection);
}

View File

@@ -43,7 +43,7 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
@Override
public <T> ExecutableUpdate<T> update(Class<T> domainType) {
Assert.notNull(domainType, "DomainType must not be null!");
Assert.notNull(domainType, "DomainType must not be null");
return new ExecutableUpdateSupport<>(template, domainType, ALL_QUERY, null, null, null, null, null, domainType);
}
@@ -84,7 +84,7 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
@Override
public TerminatingUpdate<T> apply(UpdateDefinition update) {
Assert.notNull(update, "Update must not be null!");
Assert.notNull(update, "Update must not be null");
return new ExecutableUpdateSupport<>(template, domainType, query, update, collection, findAndModifyOptions,
findAndReplaceOptions, replacement, targetType);
@@ -93,7 +93,7 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
@Override
public UpdateWithQuery<T> inCollection(String collection) {
Assert.hasText(collection, "Collection must not be null nor empty!");
Assert.hasText(collection, "Collection must not be null nor empty");
return new ExecutableUpdateSupport<>(template, domainType, query, update, collection, findAndModifyOptions,
findAndReplaceOptions, replacement, targetType);
@@ -102,7 +102,7 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
@Override
public TerminatingFindAndModify<T> withOptions(FindAndModifyOptions options) {
Assert.notNull(options, "Options must not be null!");
Assert.notNull(options, "Options must not be null");
return new ExecutableUpdateSupport<>(template, domainType, query, update, collection, options,
findAndReplaceOptions, replacement, targetType);
@@ -111,7 +111,7 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
@Override
public FindAndReplaceWithProjection<T> replaceWith(T replacement) {
Assert.notNull(replacement, "Replacement must not be null!");
Assert.notNull(replacement, "Replacement must not be null");
return new ExecutableUpdateSupport<>(template, domainType, query, update, collection, findAndModifyOptions,
findAndReplaceOptions, replacement, targetType);
@@ -120,7 +120,7 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
@Override
public FindAndReplaceWithProjection<T> withOptions(FindAndReplaceOptions options) {
Assert.notNull(options, "Options must not be null!");
Assert.notNull(options, "Options must not be null");
return new ExecutableUpdateSupport<>(template, domainType, query, update, collection, findAndModifyOptions,
options, replacement, targetType);
@@ -129,7 +129,7 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
@Override
public UpdateWithUpdate<T> matching(Query query) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(query, "Query must not be null");
return new ExecutableUpdateSupport<>(template, domainType, query, update, collection, findAndModifyOptions,
findAndReplaceOptions, replacement, targetType);
@@ -138,7 +138,7 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
@Override
public <R> FindAndReplaceWithOptions<R> as(Class<R> resultType) {
Assert.notNull(resultType, "ResultType must not be null!");
Assert.notNull(resultType, "ResultType must not be null");
return new ExecutableUpdateSupport<>(template, domainType, query, update, collection, findAndModifyOptions,
findAndReplaceOptions, replacement, resultType);

View File

@@ -35,7 +35,7 @@ public class FindAndModifyOptions {
private static final FindAndModifyOptions NONE = new FindAndModifyOptions() {
private static final String ERROR_MSG = "FindAndModifyOptions.none() cannot be changed. Please use FindAndModifyOptions.options() instead.";
private static final String ERROR_MSG = "FindAndModifyOptions.none() cannot be changed; Please use FindAndModifyOptions.options() instead";
@Override
public FindAndModifyOptions returnNew(boolean returnNew) {

View File

@@ -38,7 +38,7 @@ public class FindAndReplaceOptions {
private static final FindAndReplaceOptions NONE = new FindAndReplaceOptions() {
private static final String ERROR_MSG = "FindAndReplaceOptions.none() cannot be changed. Please use FindAndReplaceOptions.options() instead.";
private static final String ERROR_MSG = "FindAndReplaceOptions.none() cannot be changed; Please use FindAndReplaceOptions.options() instead";
@Override
public FindAndReplaceOptions returnNew() {

View File

@@ -61,8 +61,8 @@ public interface FindPublisherPreparer extends ReadPreferenceAware {
default FindPublisher<Document> initiateFind(MongoCollection<Document> collection,
Function<MongoCollection<Document>, FindPublisher<Document>> find) {
Assert.notNull(collection, "Collection must not be null!");
Assert.notNull(find, "Find function must not be null!");
Assert.notNull(collection, "Collection must not be null");
Assert.notNull(find, "Find function must not be null");
if (hasReadPreference()) {
collection = collection.withReadPreference(getReadPreference());

View File

@@ -39,7 +39,7 @@ class GeoCommandStatistics {
*/
private GeoCommandStatistics(Document source) {
Assert.notNull(source, "Source document must not be null!");
Assert.notNull(source, "Source document must not be null");
this.source = source;
}
@@ -51,7 +51,7 @@ class GeoCommandStatistics {
*/
public static GeoCommandStatistics from(Document commandResult) {
Assert.notNull(commandResult, "Command result must not be null!");
Assert.notNull(commandResult, "Command result must not be null");
Object stats = commandResult.get("stats");
return stats == null ? NONE : new GeoCommandStatistics((Document) stats);

View File

@@ -97,6 +97,16 @@ public class MappedDocument {
return this.document;
}
/**
* Updates the documents {@link #ID_FIELD}.
*
* @param value the {@literal _id} value to set.
* @since 3.4.3
*/
public void updateId(Object value) {
document.put(ID_FIELD, value);
}
/**
* An {@link UpdateDefinition} that indicates that the {@link #getUpdateObject() update object} has already been
* mapped to the specific domain type.

View File

@@ -40,7 +40,7 @@ import org.springframework.data.mongodb.core.schema.JsonSchemaProperty;
import org.springframework.data.mongodb.core.schema.MongoJsonSchema;
import org.springframework.data.mongodb.core.schema.MongoJsonSchema.MongoJsonSchemaBuilder;
import org.springframework.data.mongodb.core.schema.TypedJsonSchemaObject;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
@@ -81,7 +81,7 @@ class MappingMongoJsonSchemaCreator implements MongoJsonSchemaCreator {
MappingContext<MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext,
Predicate<JsonSchemaPropertyContext> filter, LinkedMultiValueMap<String, Class<?>> mergeProperties) {
Assert.notNull(converter, "Converter must not be null!");
Assert.notNull(converter, "Converter must not be null");
this.converter = converter;
this.mappingContext = mappingContext;
this.filter = filter;
@@ -267,7 +267,7 @@ class MappingMongoJsonSchemaCreator implements MongoJsonSchemaCreator {
}
private boolean isSpecificType(MongoPersistentProperty property) {
return !ClassTypeInformation.OBJECT.equals(property.getTypeInformation().getActualType());
return !TypeInformation.OBJECT.equals(property.getTypeInformation().getActualType());
}
private JsonSchemaProperty applyEncryptionDataIfNecessary(MongoPersistentProperty property,

View File

@@ -57,8 +57,8 @@ public class MongoAction {
public MongoAction(@Nullable WriteConcern defaultWriteConcern, MongoActionOperation mongoActionOperation,
String collectionName, @Nullable Class<?> entityType, @Nullable Document document, @Nullable Document query) {
Assert.hasText(collectionName, "Collection name must not be null or empty!");
Assert.notNull(mongoActionOperation, "MongoActionOperation must not be null!");
Assert.hasText(collectionName, "Collection name must not be null or empty");
Assert.notNull(mongoActionOperation, "MongoActionOperation must not be null");
this.defaultWriteConcern = defaultWriteConcern;
this.mongoActionOperation = mongoActionOperation;

View File

@@ -42,7 +42,7 @@ public class MongoAdmin implements MongoAdminOperations {
*/
public MongoAdmin(MongoClient client) {
Assert.notNull(client, "Client must not be null!");
Assert.notNull(client, "Client must not be null");
this.mongoClient = client;
}

View File

@@ -146,7 +146,7 @@ public class MongoClientFactoryBean extends AbstractFactoryBean<MongoClient> imp
protected MongoClientSettings computeClientSetting() {
if (connectionString != null && (StringUtils.hasText(host) || port != null)) {
throw new IllegalStateException("ConnectionString and host/port configuration exclude one another!");
throw new IllegalStateException("ConnectionString and host/port configuration exclude one another");
}
ConnectionString connectionString = this.connectionString != null ? this.connectionString

View File

@@ -44,8 +44,8 @@ public class MongoDataIntegrityViolationException extends DataIntegrityViolation
super(message);
Assert.notNull(writeResult, "WriteResult must not be null!");
Assert.notNull(actionOperation, "MongoActionOperation must not be null!");
Assert.notNull(writeResult, "WriteResult must not be null");
Assert.notNull(actionOperation, "MongoActionOperation must not be null");
this.writeResult = writeResult;
this.actionOperation = actionOperation;

View File

@@ -64,10 +64,10 @@ public abstract class MongoDatabaseFactorySupport<C> implements MongoDatabaseFac
protected MongoDatabaseFactorySupport(C mongoClient, String databaseName, boolean mongoInstanceCreated,
PersistenceExceptionTranslator exceptionTranslator) {
Assert.notNull(mongoClient, "MongoClient must not be null!");
Assert.hasText(databaseName, "Database name must not be empty!");
Assert.notNull(mongoClient, "MongoClient must not be null");
Assert.hasText(databaseName, "Database name must not be empty");
Assert.isTrue(databaseName.matches("[^/\\\\.$\"\\s]+"),
"Database name must not contain slashes, dots, spaces, quotes, or dollar signs!");
"Database name must not contain slashes, dots, spaces, quotes, or dollar signs");
this.mongoClient = mongoClient;
this.databaseName = databaseName;
@@ -91,7 +91,7 @@ public abstract class MongoDatabaseFactorySupport<C> implements MongoDatabaseFac
@Override
public MongoDatabase getMongoDatabase(String dbName) throws DataAccessException {
Assert.hasText(dbName, "Database name must not be empty!");
Assert.hasText(dbName, "Database name must not be empty");
MongoDatabase db = doGetMongoDatabase(dbName);

View File

@@ -192,7 +192,7 @@ public interface MongoJsonSchemaCreator {
*/
static MongoJsonSchemaCreator create(MongoConverter mongoConverter) {
Assert.notNull(mongoConverter, "MongoConverter must not be null!");
Assert.notNull(mongoConverter, "MongoConverter must not be null");
return new MappingMongoJsonSchemaCreator(mongoConverter);
}

View File

@@ -26,7 +26,9 @@ import org.bson.Document;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.mongodb.core.BulkOperations.BulkMode;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationOptions;
import org.springframework.data.mongodb.core.aggregation.AggregationPipeline;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.AggregationUpdate;
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
@@ -77,6 +79,7 @@ public interface MongoOperations extends FluentMongoOperations {
*
* @param entityClass must not be {@literal null}.
* @return never {@literal null}.
* @throws org.springframework.data.mapping.MappingException if the collection name cannot be derived from the type.
*/
String getCollectionName(Class<?> entityClass);
@@ -178,7 +181,7 @@ public interface MongoOperations extends FluentMongoOperations {
*/
default SessionScoped withSession(Supplier<ClientSession> sessionProvider) {
Assert.notNull(sessionProvider, "SessionProvider must not be null!");
Assert.notNull(sessionProvider, "SessionProvider must not be null");
return new SessionScoped() {
@@ -280,6 +283,56 @@ public interface MongoOperations extends FluentMongoOperations {
*/
MongoCollection<Document> createCollection(String collectionName, @Nullable CollectionOptions collectionOptions);
/**
* Create a view with the provided name. The view content is defined by the {@link AggregationOperation pipeline
* stages} on another collection or view identified by the given {@link #getCollectionName(Class) source type}.
*
* @param name the name of the view to create.
* @param source the type defining the views source collection.
* @param stages the {@link AggregationOperation aggregation pipeline stages} defining the view content.
* @since 4.0
*/
default MongoCollection<Document> createView(String name, Class<?> source, AggregationOperation... stages) {
return createView(name, source, AggregationPipeline.of(stages));
}
/**
* Create a view with the provided name. The view content is defined by the {@link AggregationPipeline pipeline} on
* another collection or view identified by the given {@link #getCollectionName(Class) source type}.
*
* @param name the name of the view to create.
* @param source the type defining the views source collection.
* @param pipeline the {@link AggregationPipeline} defining the view content.
* @since 4.0
*/
default MongoCollection<Document> createView(String name, Class<?> source, AggregationPipeline pipeline) {
return createView(name, source, pipeline, null);
}
/**
* Create a view with the provided name. The view content is defined by the {@link AggregationPipeline pipeline} on
* another collection or view identified by the given {@link #getCollectionName(Class) source type}.
*
* @param name the name of the view to create.
* @param source the type defining the views source collection.
* @param pipeline the {@link AggregationPipeline} defining the view content.
* @param options additional settings to apply when creating the view. Can be {@literal null}.
* @since 4.0
*/
MongoCollection<Document> createView(String name, Class<?> source, AggregationPipeline pipeline, @Nullable ViewOptions options);
/**
* Create a view with the provided name. The view content is defined by the {@link AggregationPipeline pipeline} on
* another collection or view identified by the given source.
*
* @param name the name of the view to create.
* @param source the name of the collection or view defining the to be created views source.
* @param pipeline the {@link AggregationPipeline} defining the view content.
* @param options additional settings to apply when creating the view. Can be {@literal null}.
* @since 4.0
*/
MongoCollection<Document> createView(String name, String source, AggregationPipeline pipeline, @Nullable ViewOptions options);
/**
* A set of collection names.
*
@@ -918,6 +971,8 @@ public interface MongoOperations extends FluentMongoOperations {
* fields specification. Must not be {@literal null}.
* @param replacement the replacement document. Must not be {@literal null}.
* @return the converted object that was updated or {@literal null}, if not found.
* @throws org.springframework.data.mapping.MappingException if the collection name cannot be
* {@link #getCollectionName(Class) derived} from the given replacement value.
* @since 2.1
*/
@Nullable
@@ -959,6 +1014,8 @@ public interface MongoOperations extends FluentMongoOperations {
* @return the converted object that was updated or {@literal null}, if not found. Depending on the value of
* {@link FindAndReplaceOptions#isReturnNew()} this will either be the object as it was before the update or
* as it is after the update.
* @throws org.springframework.data.mapping.MappingException if the collection name cannot be
* {@link #getCollectionName(Class) derived} from the given replacement value.
* @since 2.1
*/
@Nullable
@@ -985,7 +1042,7 @@ public interface MongoOperations extends FluentMongoOperations {
@Nullable
default <T> T findAndReplace(Query query, T replacement, FindAndReplaceOptions options, String collectionName) {
Assert.notNull(replacement, "Replacement must not be null!");
Assert.notNull(replacement, "Replacement must not be null");
return findAndReplace(query, replacement, options, (Class<T>) ClassUtils.getUserClass(replacement), collectionName);
}
@@ -1032,6 +1089,8 @@ public interface MongoOperations extends FluentMongoOperations {
* @return the converted object that was updated or {@literal null}, if not found. Depending on the value of
* {@link FindAndReplaceOptions#isReturnNew()} this will either be the object as it was before the update or
* as it is after the update.
* @throws org.springframework.data.mapping.MappingException if the collection name cannot be
* {@link #getCollectionName(Class) derived} from the given replacement value.
* @since 2.1
*/
@Nullable
@@ -1115,6 +1174,8 @@ public interface MongoOperations extends FluentMongoOperations {
* {@literal null}.
* @param entityClass class that determines the collection to use. Must not be {@literal null}.
* @return the count of matching documents.
* @throws org.springframework.data.mapping.MappingException if the collection name cannot be
* {@link #getCollectionName(Class) derived} from the given type.
* @see #exactCount(Query, Class)
* @see #estimatedCount(Class)
*/
@@ -1170,11 +1231,13 @@ public interface MongoOperations extends FluentMongoOperations {
*
* @param entityClass must not be {@literal null}.
* @return the estimated number of documents.
* @throws org.springframework.data.mapping.MappingException if the collection name cannot be
* {@link #getCollectionName(Class) derived} from the given type.
* @since 3.1
*/
default long estimatedCount(Class<?> entityClass) {
Assert.notNull(entityClass, "Entity class must not be null!");
Assert.notNull(entityClass, "Entity class must not be null");
return estimatedCount(getCollectionName(entityClass));
}
@@ -1206,6 +1269,8 @@ public interface MongoOperations extends FluentMongoOperations {
* {@literal null}.
* @param entityClass class that determines the collection to use. Must not be {@literal null}.
* @return the count of matching documents.
* @throws org.springframework.data.mapping.MappingException if the collection name cannot be
* {@link #getCollectionName(Class) derived} from the given type.
* @since 3.4
*/
default long exactCount(Query query, Class<?> entityClass) {
@@ -1261,9 +1326,10 @@ public interface MongoOperations extends FluentMongoOperations {
/**
* Insert the object into the collection for the entity type of the object to save. <br />
* The object is converted to the MongoDB native representation using an instance of {@see MongoConverter}. <br />
* If your object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property is a
* String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from ObjectId to your
* property type will be handled by Spring's BeanWrapper class that leverages Type Conversion API. See
* If your object has an {@literal Id} property which holds a {@literal null} value, it will be set with the generated
* Id from MongoDB. If your Id property is a String then MongoDB ObjectId will be used to populate that string.
* Otherwise, the conversion from ObjectId to your property type will be handled by Spring's BeanWrapper class that
* leverages Type Conversion API. See
* <a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#validation" > Spring's
* Type Conversion"</a> for more details. <br />
* Insert is used to initially store the object into the database. To update an existing object use the save method.
@@ -1273,6 +1339,8 @@ public interface MongoOperations extends FluentMongoOperations {
* @param objectToSave the object to store in the collection. Must not be {@literal null}.
* @return the inserted object.
* @throws IllegalArgumentException in case the {@code objectToSave} is collection-like.
* @throws org.springframework.data.mapping.MappingException if the target collection name cannot be
* {@link #getCollectionName(Class) derived} from the given object type.
*/
<T> T insert(T objectToSave);
@@ -1297,6 +1365,8 @@ public interface MongoOperations extends FluentMongoOperations {
* @param batchToSave the batch of objects to save. Must not be {@literal null}.
* @param entityClass class that determines the collection to use. Must not be {@literal null}.
* @return the inserted objects that.
* @throws org.springframework.data.mapping.MappingException if the target collection name cannot be
* {@link #getCollectionName(Class) derived} from the given type.
*/
<T> Collection<T> insert(Collection<? extends T> batchToSave, Class<?> entityClass);
@@ -1315,6 +1385,8 @@ public interface MongoOperations extends FluentMongoOperations {
*
* @param objectsToSave the list of objects to save. Must not be {@literal null}.
* @return the inserted objects.
* @throws org.springframework.data.mapping.MappingException if the target collection name cannot be
* {@link #getCollectionName(Class) derived} for the given objects.
*/
<T> Collection<T> insertAll(Collection<? extends T> objectsToSave);
@@ -1333,6 +1405,8 @@ public interface MongoOperations extends FluentMongoOperations {
* @param objectToSave the object to store in the collection. Must not be {@literal null}.
* @return the saved object.
* @throws IllegalArgumentException in case the {@code objectToSave} is collection-like.
* @throws org.springframework.data.mapping.MappingException if the target collection name cannot be
* {@link #getCollectionName(Class) derived} from the given object type.
*/
<T> T save(T objectToSave);
@@ -1367,9 +1441,11 @@ public interface MongoOperations extends FluentMongoOperations {
* the existing object. Must not be {@literal null}.
* @param entityClass class that determines the collection to use. Must not be {@literal null}.
* @return the {@link UpdateResult} which lets you access the results of the previous write.
* @since 3.0
* @see Update
* @see AggregationUpdate
* @throws org.springframework.data.mapping.MappingException if the target collection name cannot be
* {@link #getCollectionName(Class) derived} from the given type.
* @since 3.0
*/
UpdateResult upsert(Query query, UpdateDefinition update, Class<?> entityClass);
@@ -1421,9 +1497,11 @@ public interface MongoOperations extends FluentMongoOperations {
* the existing. Must not be {@literal null}.
* @param entityClass class that determines the collection to use.
* @return the {@link UpdateResult} which lets you access the results of the previous write.
* @since 3.0
* @see Update
* @see AggregationUpdate
* @throws org.springframework.data.mapping.MappingException if the target collection name cannot be
* {@link #getCollectionName(Class) derived} from the given type.
* @since 3.0
*/
UpdateResult updateFirst(Query query, UpdateDefinition update, Class<?> entityClass);
@@ -1475,9 +1553,11 @@ public interface MongoOperations extends FluentMongoOperations {
* the existing. Must not be {@literal null}.
* @param entityClass class of the pojo to be operated on. Must not be {@literal null}.
* @return the {@link UpdateResult} which lets you access the results of the previous write.
* @since 3.0
* @throws org.springframework.data.mapping.MappingException if the target collection name cannot be
* {@link #getCollectionName(Class) derived} from the given type.
* @see Update
* @see AggregationUpdate
* @since 3.0
*/
UpdateResult updateMulti(Query query, UpdateDefinition update, Class<?> entityClass);
@@ -1525,6 +1605,8 @@ public interface MongoOperations extends FluentMongoOperations {
*
* @param object must not be {@literal null}.
* @return the {@link DeleteResult} which lets you access the results of the previous delete.
* @throws org.springframework.data.mapping.MappingException if the target collection name cannot be
* {@link #getCollectionName(Class) derived} from the given object type.
*/
DeleteResult remove(Object object);
@@ -1541,18 +1623,20 @@ public interface MongoOperations extends FluentMongoOperations {
DeleteResult remove(Object object, String collectionName);
/**
* Remove all documents that match the provided query document criteria from the the collection used to store the
* Remove all documents that match the provided query document criteria from the collection used to store the
* entityClass. The Class parameter is also used to help convert the Id of the object if it is present in the query.
*
* @param query the query document that specifies the criteria used to remove a record.
* @param entityClass class that determines the collection to use.
* @return the {@link DeleteResult} which lets you access the results of the previous delete.
* @throws IllegalArgumentException when {@literal query} or {@literal entityClass} is {@literal null}.
* @throws org.springframework.data.mapping.MappingException if the target collection name cannot be
* {@link #getCollectionName(Class) derived} from the given type.
*/
DeleteResult remove(Query query, Class<?> entityClass);
/**
* Remove all documents that match the provided query document criteria from the the collection used to store the
* Remove all documents that match the provided query document criteria from the collection used to store the
* entityClass. The Class parameter is also used to help convert the Id of the object if it is present in the query.
*
* @param query the query document that specifies the criteria used to remove a record.
@@ -1595,14 +1679,16 @@ public interface MongoOperations extends FluentMongoOperations {
* @param query the query document that specifies the criteria used to find and remove documents.
* @param entityClass class of the pojo to be operated on.
* @return the {@link List} converted objects deleted by this operation.
* @throws org.springframework.data.mapping.MappingException if the target collection name cannot be
* {@link #getCollectionName(Class) derived} from the given type.
* @since 1.5
*/
<T> List<T> findAllAndRemove(Query query, Class<T> entityClass);
/**
* Returns and removes all documents that match the provided query document criteria from the the collection used to
* store the entityClass. The Class parameter is also used to help convert the Id of the object if it is present in
* the query.
* Returns and removes all documents that match the provided query document criteria from the collection used to store
* the entityClass. The Class parameter is also used to help convert the Id of the object if it is present in the
* query.
*
* @param query the query document that specifies the criteria used to find and remove documents.
* @param entityClass class of the pojo to be operated on.

View File

@@ -30,6 +30,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
@@ -66,8 +67,8 @@ import org.springframework.data.mongodb.core.QueryOperations.UpdateContext;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext;
import org.springframework.data.mongodb.core.aggregation.AggregationOptions;
import org.springframework.data.mongodb.core.aggregation.AggregationPipeline;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOperationContext;
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
import org.springframework.data.mongodb.core.convert.DbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
@@ -174,6 +175,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
private final EntityOperations operations;
private final PropertyOperations propertyOperations;
private final QueryOperations queryOperations;
private final EntityLifecycleEventDelegate eventDelegate;
private @Nullable WriteConcern writeConcern;
private WriteConcernResolver writeConcernResolver = DefaultWriteConcernResolver.INSTANCE;
@@ -216,7 +218,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
*/
public MongoTemplate(MongoDatabaseFactory mongoDbFactory, @Nullable MongoConverter mongoConverter) {
Assert.notNull(mongoDbFactory, "MongoDbFactory must not be null!");
Assert.notNull(mongoDbFactory, "MongoDbFactory must not be null");
this.mongoDbFactory = mongoDbFactory;
this.exceptionTranslator = mongoDbFactory.getExceptionTranslator();
@@ -228,6 +230,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
this.propertyOperations = new PropertyOperations(this.mongoConverter.getMappingContext());
this.queryOperations = new QueryOperations(queryMapper, updateMapper, operations, propertyOperations,
mongoDbFactory);
this.eventDelegate = new EntityLifecycleEventDelegate();
// We always have a mapping context in the converter, whether it's a simple one or not
mappingContext = this.mongoConverter.getMappingContext();
@@ -266,6 +269,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
this.operations = that.operations;
this.propertyOperations = that.propertyOperations;
this.queryOperations = that.queryOperations;
this.eventDelegate = that.eventDelegate;
}
/**
@@ -308,12 +312,25 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
this.readPreference = readPreference;
}
/**
* Configure whether lifecycle events such as {@link AfterLoadEvent}, {@link BeforeSaveEvent}, etc. should be
* published or whether emission should be suppressed. Enabled by default.
*
* @param enabled {@code true} to enable entity lifecycle events; {@code false} to disable entity lifecycle events.
* @since 4.0
* @see MongoMappingEvent
*/
public void setEntityLifecycleEventsEnabled(boolean enabled) {
this.eventDelegate.setEventsEnabled(enabled);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
prepareIndexCreator(applicationContext);
eventPublisher = applicationContext;
eventDelegate.setPublisher(eventPublisher);
if (entityCallbacks == null) {
setEntityCallbacks(EntityCallbacks.create(applicationContext));
@@ -338,7 +355,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
*/
public void setEntityCallbacks(EntityCallbacks entityCallbacks) {
Assert.notNull(entityCallbacks, "EntityCallbacks must not be null!");
Assert.notNull(entityCallbacks, "EntityCallbacks must not be null");
this.entityCallbacks = entityCallbacks;
}
@@ -430,10 +447,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@SuppressWarnings("ConstantConditions")
protected <T> Stream<T> doStream(Query query, Class<?> entityType, String collectionName, Class<T> returnType) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(entityType, "Entity type must not be null!");
Assert.hasText(collectionName, "Collection name must not be null or empty!");
Assert.notNull(returnType, "ReturnType must not be null!");
Assert.notNull(query, "Query must not be null");
Assert.notNull(entityType, "Entity type must not be null");
Assert.hasText(collectionName, "Collection name must not be null or empty");
Assert.notNull(returnType, "ReturnType must not be null");
return execute(collectionName, (CollectionCallback<Stream<T>>) collection -> {
@@ -462,7 +479,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@SuppressWarnings("ConstantConditions")
public Document executeCommand(String jsonCommand) {
Assert.hasText(jsonCommand, "JsonCommand must not be null nor empty!");
Assert.hasText(jsonCommand, "JsonCommand must not be null nor empty");
return execute(db -> db.runCommand(Document.parse(jsonCommand), Document.class));
}
@@ -471,7 +488,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@SuppressWarnings("ConstantConditions")
public Document executeCommand(Document command) {
Assert.notNull(command, "Command must not be null!");
Assert.notNull(command, "Command must not be null");
return execute(db -> db.runCommand(command, Document.class));
}
@@ -480,7 +497,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@SuppressWarnings("ConstantConditions")
public Document executeCommand(Document command, @Nullable ReadPreference readPreference) {
Assert.notNull(command, "Command must not be null!");
Assert.notNull(command, "Command must not be null");
return execute(db -> readPreference != null //
? db.runCommand(command, readPreference, Document.class) //
@@ -506,9 +523,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
protected void executeQuery(Query query, String collectionName, DocumentCallbackHandler documentCallbackHandler,
@Nullable CursorPreparer preparer) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(collectionName, "CollectionName must not be null!");
Assert.notNull(documentCallbackHandler, "DocumentCallbackHandler must not be null!");
Assert.notNull(query, "Query must not be null");
Assert.notNull(collectionName, "CollectionName must not be null");
Assert.notNull(documentCallbackHandler, "DocumentCallbackHandler must not be null");
Document queryObject = queryMapper.getMappedObject(query.getQueryObject(), Optional.empty());
Document sortObject = query.getSortObject();
@@ -526,7 +543,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@Override
public <T> T execute(DbCallback<T> action) {
Assert.notNull(action, "DbCallback must not be null!");
Assert.notNull(action, "DbCallback must not be null");
try {
MongoDatabase db = prepareDatabase(this.doGetDatabase());
@@ -539,15 +556,15 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@Override
public <T> T execute(Class<?> entityClass, CollectionCallback<T> callback) {
Assert.notNull(entityClass, "EntityClass must not be null!");
Assert.notNull(entityClass, "EntityClass must not be null");
return execute(getCollectionName(entityClass), callback);
}
@Override
public <T> T execute(String collectionName, CollectionCallback<T> callback) {
Assert.notNull(collectionName, "CollectionName must not be null!");
Assert.notNull(callback, "CollectionCallback must not be null!");
Assert.notNull(collectionName, "CollectionName must not be null");
Assert.notNull(callback, "CollectionCallback must not be null");
try {
MongoCollection<Document> collection = getAndPrepareCollection(doGetDatabase(), collectionName);
@@ -560,7 +577,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@Override
public SessionScoped withSession(ClientSessionOptions options) {
Assert.notNull(options, "ClientSessionOptions must not be null!");
Assert.notNull(options, "ClientSessionOptions must not be null");
return withSession(() -> mongoDbFactory.getSession(options));
}
@@ -568,7 +585,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@Override
public MongoTemplate withSession(ClientSession session) {
Assert.notNull(session, "ClientSession must not be null!");
Assert.notNull(session, "ClientSession must not be null");
return new SessionBoundMongoTemplate(session, MongoTemplate.this);
}
@@ -593,7 +610,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
public <T> MongoCollection<Document> createCollection(Class<T> entityClass,
@Nullable CollectionOptions collectionOptions) {
Assert.notNull(entityClass, "EntityClass must not be null!");
Assert.notNull(entityClass, "EntityClass must not be null");
return doCreateCollection(getCollectionName(entityClass),
operations.convertToCreateCollectionOptions(collectionOptions, entityClass));
@@ -602,7 +619,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@Override
public MongoCollection<Document> createCollection(String collectionName) {
Assert.notNull(collectionName, "CollectionName must not be null!");
Assert.notNull(collectionName, "CollectionName must not be null");
return doCreateCollection(collectionName, new Document());
}
@@ -611,16 +628,50 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
public MongoCollection<Document> createCollection(String collectionName,
@Nullable CollectionOptions collectionOptions) {
Assert.notNull(collectionName, "CollectionName must not be null!");
Assert.notNull(collectionName, "CollectionName must not be null");
return doCreateCollection(collectionName,
operations.convertToCreateCollectionOptions(collectionOptions, Object.class));
}
@Override
public MongoCollection<Document> createView(String name, Class<?> source, AggregationPipeline pipeline, @Nullable ViewOptions options) {
return createView(name, getCollectionName(source),
queryOperations.createAggregation(Aggregation.newAggregation(source, pipeline.getOperations()), source),
options);
}
@Override
public MongoCollection<Document> createView(String name, String source, AggregationPipeline pipeline, @Nullable ViewOptions options) {
return createView(name, source,
queryOperations.createAggregation(Aggregation.newAggregation(pipeline.getOperations()), (Class<?>) null),
options);
}
private MongoCollection<Document> createView(String name, String source, AggregationDefinition aggregation,
@Nullable ViewOptions options) {
return doCreateView(name, source, aggregation.getAggregationPipeline(), options);
}
protected MongoCollection<Document> doCreateView(String name, String source, List<Document> pipeline, @Nullable ViewOptions options) {
CreateViewOptions viewOptions = new CreateViewOptions();
if (options != null) {
options.getCollation().map(Collation::toMongoCollation).ifPresent(viewOptions::collation);
}
return execute(db -> {
db.createView(name, source, pipeline, viewOptions);
return db.getCollection(name);
});
}
@Override
@SuppressWarnings("ConstantConditions")
public MongoCollection<Document> getCollection(String collectionName) {
Assert.notNull(collectionName, "CollectionName must not be null!");
Assert.notNull(collectionName, "CollectionName must not be null");
return execute(db -> db.getCollection(collectionName, Document.class));
}
@@ -634,7 +685,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@SuppressWarnings("ConstantConditions")
public boolean collectionExists(String collectionName) {
Assert.notNull(collectionName, "CollectionName must not be null!");
Assert.notNull(collectionName, "CollectionName must not be null");
return execute(db -> {
@@ -655,7 +706,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@Override
public void dropCollection(String collectionName) {
Assert.notNull(collectionName, "CollectionName must not be null!");
Assert.notNull(collectionName, "CollectionName must not be null");
execute(collectionName, (CollectionCallback<Void>) collection -> {
collection.drop();
@@ -695,8 +746,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@Override
public BulkOperations bulkOps(BulkMode mode, @Nullable Class<?> entityType, String collectionName) {
Assert.notNull(mode, "BulkMode must not be null!");
Assert.hasText(collectionName, "Collection name must not be null or empty!");
Assert.notNull(mode, "BulkMode must not be null");
Assert.hasText(collectionName, "Collection name must not be null or empty");
DefaultBulkOperations operations = new DefaultBulkOperations(this, collectionName,
new BulkOperationContext(mode, Optional.ofNullable(getPersistentEntity(entityType)), queryMapper, updateMapper,
@@ -724,9 +775,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@Override
public <T> T findOne(Query query, Class<T> entityClass, String collectionName) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(entityClass, "EntityClass must not be null!");
Assert.notNull(collectionName, "CollectionName must not be null!");
Assert.notNull(query, "Query must not be null");
Assert.notNull(entityClass, "EntityClass must not be null");
Assert.notNull(collectionName, "CollectionName must not be null");
if (ObjectUtils.isEmpty(query.getSortObject())) {
@@ -756,7 +807,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
if (query == null) {
throw new InvalidDataAccessApiUsageException("Query passed in to exist can't be null");
}
Assert.notNull(collectionName, "CollectionName must not be null!");
Assert.notNull(collectionName, "CollectionName must not be null");
QueryContext queryContext = queryOperations.createQueryContext(query);
Document mappedQuery = queryContext.getMappedQuery(entityClass, this::getPersistentEntity);
@@ -775,9 +826,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@Override
public <T> List<T> find(Query query, Class<T> entityClass, String collectionName) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(collectionName, "CollectionName must not be null!");
Assert.notNull(entityClass, "EntityClass must not be null!");
Assert.notNull(query, "Query must not be null");
Assert.notNull(collectionName, "CollectionName must not be null");
Assert.notNull(entityClass, "EntityClass must not be null");
return doFind(collectionName, query.getQueryObject(), query.getFieldsObject(), entityClass,
new QueryCursorPreparer(query, entityClass));
@@ -793,9 +844,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@Override
public <T> T findById(Object id, Class<T> entityClass, String collectionName) {
Assert.notNull(id, "Id must not be null!");
Assert.notNull(entityClass, "EntityClass must not be null!");
Assert.notNull(collectionName, "CollectionName must not be null!");
Assert.notNull(id, "Id must not be null");
Assert.notNull(entityClass, "EntityClass must not be null");
Assert.notNull(collectionName, "CollectionName must not be null");
String idKey = operations.getIdPropertyName(entityClass);
@@ -812,11 +863,11 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
public <T> List<T> findDistinct(Query query, String field, String collectionName, Class<?> entityClass,
Class<T> resultClass) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(field, "Field must not be null!");
Assert.notNull(collectionName, "CollectionName must not be null!");
Assert.notNull(entityClass, "EntityClass must not be null!");
Assert.notNull(resultClass, "ResultClass must not be null!");
Assert.notNull(query, "Query must not be null");
Assert.notNull(field, "Field must not be null");
Assert.notNull(collectionName, "CollectionName must not be null");
Assert.notNull(entityClass, "EntityClass must not be null");
Assert.notNull(resultClass, "ResultClass must not be null");
MongoPersistentEntity<?> entity = entityClass != Object.class ? getPersistentEntity(entityClass) : null;
DistinctQueryContext distinctQueryContext = queryOperations.distinctQueryContext(query, field);
@@ -872,15 +923,15 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
public <T> GeoResults<T> geoNear(NearQuery near, Class<?> domainType, String collectionName, Class<T> returnType) {
if (near == null) {
throw new InvalidDataAccessApiUsageException("NearQuery must not be null!");
throw new InvalidDataAccessApiUsageException("NearQuery must not be null");
}
if (domainType == null) {
throw new InvalidDataAccessApiUsageException("Entity class must not be null!");
throw new InvalidDataAccessApiUsageException("Entity class must not be null");
}
Assert.notNull(collectionName, "CollectionName must not be null!");
Assert.notNull(returnType, "ReturnType must not be null!");
Assert.notNull(collectionName, "CollectionName must not be null");
Assert.notNull(returnType, "ReturnType must not be null");
String collection = StringUtils.hasText(collectionName) ? collectionName : getCollectionName(domainType);
String distanceField = operations.nearQueryDistanceFieldName(domainType);
@@ -894,7 +945,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
DocumentCallback<GeoResult<T>> callback = new GeoNearResultDocumentCallback<>(distanceField,
new ProjectingReadCallback<>(mongoConverter, projection, collection), near.getMetric());
List<GeoResult<T>> result = new ArrayList<>();
List<GeoResult<T>> result = new ArrayList<>(results.getMappedResults().size());
BigDecimal aggregate = BigDecimal.ZERO;
for (Document element : results) {
@@ -934,17 +985,17 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
public <T> T findAndModify(Query query, UpdateDefinition update, FindAndModifyOptions options, Class<T> entityClass,
String collectionName) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(update, "Update must not be null!");
Assert.notNull(options, "Options must not be null!");
Assert.notNull(entityClass, "EntityClass must not be null!");
Assert.notNull(collectionName, "CollectionName must not be null!");
Assert.notNull(query, "Query must not be null");
Assert.notNull(update, "Update must not be null");
Assert.notNull(options, "Options must not be null");
Assert.notNull(entityClass, "EntityClass must not be null");
Assert.notNull(collectionName, "CollectionName must not be null");
FindAndModifyOptions optionsToUse = FindAndModifyOptions.of(options);
Optionals.ifAllPresent(query.getCollation(), optionsToUse.getCollation(), (l, r) -> {
throw new IllegalArgumentException(
"Both Query and FindAndModifyOptions define a collation. Please provide the collation only via one of the two.");
"Both Query and FindAndModifyOptions define a collation; Please provide the collation only via one of the two");
});
if (!options.getCollation().isPresent()) {
@@ -959,15 +1010,15 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
public <S, T> T findAndReplace(Query query, S replacement, FindAndReplaceOptions options, Class<S> entityType,
String collectionName, Class<T> resultType) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(replacement, "Replacement must not be null!");
Assert.notNull(options, "Options must not be null! Use FindAndReplaceOptions#empty() instead.");
Assert.notNull(entityType, "EntityType must not be null!");
Assert.notNull(collectionName, "CollectionName must not be null!");
Assert.notNull(resultType, "ResultType must not be null! Use Object.class instead.");
Assert.notNull(query, "Query must not be null");
Assert.notNull(replacement, "Replacement must not be null");
Assert.notNull(options, "Options must not be null Use FindAndReplaceOptions#empty() instead");
Assert.notNull(entityType, "EntityType must not be null");
Assert.notNull(collectionName, "CollectionName must not be null");
Assert.notNull(resultType, "ResultType must not be null Use Object.class instead");
Assert.isTrue(query.getLimit() <= 1, "Query must not define a limit other than 1 ore none!");
Assert.isTrue(query.getSkip() <= 0, "Query must not define skip.");
Assert.isTrue(query.getLimit() <= 1, "Query must not define a limit other than 1 ore none");
Assert.isTrue(query.getSkip() <= 0, "Query must not define skip");
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityType);
QueryContext queryContext = queryOperations.createQueryContext(query);
@@ -1007,9 +1058,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@Override
public <T> T findAndRemove(Query query, Class<T> entityClass, String collectionName) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(entityClass, "EntityClass must not be null!");
Assert.notNull(collectionName, "CollectionName must not be null!");
Assert.notNull(query, "Query must not be null");
Assert.notNull(entityClass, "EntityClass must not be null");
Assert.notNull(collectionName, "CollectionName must not be null");
return doFindAndRemove(collectionName, query.getQueryObject(), query.getFieldsObject(),
getMappedSortObject(query, entityClass), operations.forType(entityClass).getCollation(query).orElse(null),
@@ -1019,7 +1070,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@Override
public long count(Query query, Class<?> entityClass) {
Assert.notNull(entityClass, "Entity class must not be null!");
Assert.notNull(entityClass, "Entity class must not be null");
return count(query, entityClass, getCollectionName(entityClass));
}
@@ -1035,8 +1086,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@Override
public long count(Query query, @Nullable Class<?> entityClass, String collectionName) {
Assert.notNull(query, "Query must not be null!");
Assert.hasText(collectionName, "Collection name must not be null or empty!");
Assert.notNull(query, "Query must not be null");
Assert.hasText(collectionName, "Collection name must not be null or empty");
CountContext countContext = queryOperations.countQueryContext(query);
@@ -1103,7 +1154,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@Override
public <T> T insert(T objectToSave) {
Assert.notNull(objectToSave, "ObjectToSave must not be null!");
Assert.notNull(objectToSave, "ObjectToSave must not be null");
ensureNotCollectionLike(objectToSave);
return insert(objectToSave, getCollectionName(ClassUtils.getUserClass(objectToSave)));
@@ -1113,8 +1164,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@SuppressWarnings("unchecked")
public <T> T insert(T objectToSave, String collectionName) {
Assert.notNull(objectToSave, "ObjectToSave must not be null!");
Assert.notNull(collectionName, "CollectionName must not be null!");
Assert.notNull(objectToSave, "ObjectToSave must not be null");
Assert.notNull(collectionName, "CollectionName must not be null");
ensureNotCollectionLike(objectToSave);
return (T) doInsert(collectionName, objectToSave, this.mongoConverter);
@@ -1130,7 +1181,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
protected void ensureNotCollectionLike(@Nullable Object source) {
if (EntityOperations.isCollectionLike(source)) {
throw new IllegalArgumentException("Cannot use a collection here.");
throw new IllegalArgumentException("Cannot use a collection here");
}
}
@@ -1202,7 +1253,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@SuppressWarnings("unchecked")
public <T> Collection<T> insert(Collection<? extends T> batchToSave, Class<?> entityClass) {
Assert.notNull(batchToSave, "BatchToSave must not be null!");
Assert.notNull(batchToSave, "BatchToSave must not be null");
return (Collection<T>) doInsertBatch(getCollectionName(entityClass), batchToSave, this.mongoConverter);
}
@@ -1211,8 +1262,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@SuppressWarnings("unchecked")
public <T> Collection<T> insert(Collection<? extends T> batchToSave, String collectionName) {
Assert.notNull(batchToSave, "BatchToSave must not be null!");
Assert.notNull(collectionName, "CollectionName must not be null!");
Assert.notNull(batchToSave, "BatchToSave must not be null");
Assert.notNull(collectionName, "CollectionName must not be null");
return (Collection<T>) doInsertBatch(collectionName, batchToSave, this.mongoConverter);
}
@@ -1221,7 +1272,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@SuppressWarnings("unchecked")
public <T> Collection<T> insertAll(Collection<? extends T> objectsToSave) {
Assert.notNull(objectsToSave, "ObjectsToSave must not be null!");
Assert.notNull(objectsToSave, "ObjectsToSave must not be null");
return (Collection<T>) doInsertAll(objectsToSave, this.mongoConverter);
}
@@ -1258,9 +1309,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
protected <T> Collection<T> doInsertBatch(String collectionName, Collection<? extends T> batchToSave,
MongoWriter<T> writer) {
Assert.notNull(writer, "MongoWriter must not be null!");
Assert.notNull(writer, "MongoWriter must not be null");
List<Document> documentList = new ArrayList<>();
List<Document> documentList = new ArrayList<>(batchToSave.size());
List<T> initializedBatchToSave = new ArrayList<>(batchToSave.size());
for (T uninitialized : batchToSave) {
@@ -1303,7 +1354,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@Override
public <T> T save(T objectToSave) {
Assert.notNull(objectToSave, "Object to save must not be null!");
Assert.notNull(objectToSave, "Object to save must not be null");
return save(objectToSave, getCollectionName(ClassUtils.getUserClass(objectToSave)));
}
@@ -1311,8 +1362,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@SuppressWarnings("unchecked")
public <T> T save(T objectToSave, String collectionName) {
Assert.notNull(objectToSave, "Object to save must not be null!");
Assert.hasText(collectionName, "Collection name must not be null or empty!");
Assert.notNull(objectToSave, "Object to save must not be null");
Assert.hasText(collectionName, "Collection name must not be null or empty");
ensureNotCollectionLike(objectToSave);
AdaptibleEntity<T> source = operations.forEntity(objectToSave, mongoConverter.getConversionService());
@@ -1355,7 +1406,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
if (result.getModifiedCount() == 0) {
throw new OptimisticLockingFailureException(
String.format("Cannot save entity %s with version %s to collection %s. Has it been modified meanwhile?",
String.format("Cannot save entity %s with version %s to collection %s; Has it been modified meanwhile",
source.getId(), source.getVersion(), collectionName));
}
maybeEmitEvent(new AfterSaveEvent<>(toSave, mapped.getDocument(), collectionName));
@@ -1392,18 +1443,21 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
collectionName));
}
MappedDocument mappedDocument = queryOperations.createInsertContext(MappedDocument.of(document))
.prepareId(entityClass);
return execute(collectionName, collection -> {
MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.INSERT, collectionName, entityClass,
document, null);
mappedDocument.getDocument(), null);
WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction);
if (writeConcernToUse == null) {
collection.insertOne(document);
collection.insertOne(mappedDocument.getDocument());
} else {
collection.withWriteConcern(writeConcernToUse).insertOne(document);
collection.withWriteConcern(writeConcernToUse).insertOne(mappedDocument.getDocument());
}
return operations.forEntity(document).getId();
return operations.forEntity(mappedDocument.getDocument()).getId();
});
}
@@ -1454,7 +1508,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
: collection.withWriteConcern(writeConcernToUse);
if (!mapped.hasId()) {
collectionToUse.insertOne(dbDoc);
mapped = queryOperations.createInsertContext(mapped).prepareId(mappingContext.getPersistentEntity(entityClass));
collectionToUse.insertOne(mapped.getDocument());
} else {
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
@@ -1492,7 +1548,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@Override
public UpdateResult upsert(Query query, UpdateDefinition update, Class<?> entityClass, String collectionName) {
Assert.notNull(entityClass, "EntityClass must not be null!");
Assert.notNull(entityClass, "EntityClass must not be null");
return doUpdate(collectionName, query, update, entityClass, true, false);
}
@@ -1510,7 +1566,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@Override
public UpdateResult updateFirst(Query query, UpdateDefinition update, Class<?> entityClass, String collectionName) {
Assert.notNull(entityClass, "EntityClass must not be null!");
Assert.notNull(entityClass, "EntityClass must not be null");
return doUpdate(collectionName, query, update, entityClass, false, false);
}
@@ -1528,7 +1584,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@Override
public UpdateResult updateMulti(Query query, UpdateDefinition update, Class<?> entityClass, String collectionName) {
Assert.notNull(entityClass, "EntityClass must not be null!");
Assert.notNull(entityClass, "EntityClass must not be null");
return doUpdate(collectionName, query, update, entityClass, false, true);
}
@@ -1537,13 +1593,13 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
protected UpdateResult doUpdate(String collectionName, Query query, UpdateDefinition update,
@Nullable Class<?> entityClass, boolean upsert, boolean multi) {
Assert.notNull(collectionName, "CollectionName must not be null!");
Assert.notNull(query, "Query must not be null!");
Assert.notNull(update, "Update must not be null!");
Assert.notNull(collectionName, "CollectionName must not be null");
Assert.notNull(query, "Query must not be null");
Assert.notNull(update, "Update must not be null");
if (query.isSorted() && LOGGER.isWarnEnabled()) {
LOGGER.warn(String.format("%s does not support sort ('%s'). Please use findAndModify() instead.",
LOGGER.warn(String.format("%s does not support sort ('%s'); Please use findAndModify() instead",
upsert ? "Upsert" : "UpdateFirst", serializeToJsonSafely(query.getSortObject())));
}
@@ -1616,7 +1672,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@Override
public DeleteResult remove(Object object) {
Assert.notNull(object, "Object must not be null!");
Assert.notNull(object, "Object must not be null");
return remove(object, getCollectionName(object.getClass()));
}
@@ -1624,8 +1680,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@Override
public DeleteResult remove(Object object, String collectionName) {
Assert.notNull(object, "Object must not be null!");
Assert.hasText(collectionName, "Collection name must not be null or empty!");
Assert.notNull(object, "Object must not be null");
Assert.hasText(collectionName, "Collection name must not be null or empty");
Query query = operations.forEntity(object).getRemoveByQuery();
@@ -1645,7 +1701,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@Override
public DeleteResult remove(Query query, Class<?> entityClass, String collectionName) {
Assert.notNull(entityClass, "EntityClass must not be null!");
Assert.notNull(entityClass, "EntityClass must not be null");
return doRemove(collectionName, query, entityClass, true);
}
@@ -1653,8 +1709,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
protected <T> DeleteResult doRemove(String collectionName, Query query, @Nullable Class<T> entityClass,
boolean multi) {
Assert.notNull(query, "Query must not be null!");
Assert.hasText(collectionName, "Collection name must not be null or empty!");
Assert.notNull(query, "Query must not be null");
Assert.hasText(collectionName, "Collection name must not be null or empty");
MongoPersistentEntity<?> entity = getPersistentEntity(entityClass);
@@ -1764,11 +1820,11 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
public <T> List<T> mapReduce(Query query, Class<?> domainType, String inputCollectionName, String mapFunction,
String reduceFunction, @Nullable MapReduceOptions mapReduceOptions, Class<T> resultType) {
Assert.notNull(domainType, "Domain type must not be null!");
Assert.notNull(inputCollectionName, "Input collection name must not be null!");
Assert.notNull(resultType, "Result type must not be null!");
Assert.notNull(mapFunction, "Map function must not be null!");
Assert.notNull(reduceFunction, "Reduce function must not be null!");
Assert.notNull(domainType, "Domain type must not be null");
Assert.notNull(inputCollectionName, "Input collection name must not be null");
Assert.notNull(resultType, "Result type must not be null");
Assert.notNull(mapFunction, "Map function must not be null");
Assert.notNull(reduceFunction, "Reduce function must not be null");
String mapFunc = replaceWithResourceIfNecessary(mapFunction);
String reduceFunc = replaceWithResourceIfNecessary(reduceFunction);
@@ -1798,7 +1854,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
Optionals.ifAllPresent(collation, mapReduceOptions.getCollation(), (l, r) -> {
throw new IllegalArgumentException(
"Both Query and MapReduceOptions define a collation. Please provide the collation only via one of the two.");
"Both Query and MapReduceOptions define a collation; Please provide the collation only via one of the two.");
});
if (mapReduceOptions.getCollation().isPresent()) {
@@ -1854,21 +1910,21 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@Override
public <O> AggregationResults<O> aggregate(TypedAggregation<?> aggregation, Class<O> outputType) {
Assert.notNull(aggregation, "Aggregation pipeline must not be null");
return aggregate(aggregation, getCollectionName(aggregation.getInputType()), outputType);
}
@Override
public <O> AggregationResults<O> aggregate(TypedAggregation<?> aggregation, String inputCollectionName,
Class<O> outputType) {
Assert.notNull(aggregation, "Aggregation pipeline must not be null!");
return aggregate(aggregation, inputCollectionName, outputType, null);
}
@Override
public <O> AggregationResults<O> aggregate(Aggregation aggregation, Class<?> inputType, Class<O> outputType) {
Assert.notNull(aggregation, "Aggregation pipeline must not be null");
return aggregate(aggregation, getCollectionName(inputType), outputType,
queryOperations.createAggregation(aggregation, inputType).getAggregationOperationContext());
}
@@ -1881,24 +1937,22 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@Override
public <O> Stream<O> aggregateStream(TypedAggregation<?> aggregation, String inputCollectionName,
Class<O> outputType) {
Assert.notNull(aggregation, "Aggregation pipeline must not be null!");
AggregationOperationContext context = new TypeBasedAggregationOperationContext(aggregation.getInputType(),
mappingContext, queryMapper);
return aggregateStream(aggregation, inputCollectionName, outputType, context);
return aggregateStream(aggregation, inputCollectionName, outputType, null);
}
@Override
public <O> Stream<O> aggregateStream(TypedAggregation<?> aggregation, Class<O> outputType) {
Assert.notNull(aggregation, "Aggregation pipeline must not be null");
return aggregateStream(aggregation, getCollectionName(aggregation.getInputType()), outputType);
}
@Override
public <O> Stream<O> aggregateStream(Aggregation aggregation, Class<?> inputType, Class<O> outputType) {
Assert.notNull(aggregation, "Aggregation pipeline must not be null");
return aggregateStream(aggregation, getCollectionName(inputType), outputType,
new TypeBasedAggregationOperationContext(inputType, mappingContext, queryMapper));
queryOperations.createAggregation(aggregation, inputType).getAggregationOperationContext());
}
@Override
@@ -1949,9 +2003,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
protected <O> AggregationResults<O> aggregate(Aggregation aggregation, String collectionName, Class<O> outputType,
@Nullable AggregationOperationContext context) {
Assert.hasText(collectionName, "Collection name must not be null or empty!");
Assert.notNull(aggregation, "Aggregation pipeline must not be null!");
Assert.notNull(outputType, "Output type must not be null!");
Assert.hasText(collectionName, "Collection name must not be null or empty");
Assert.notNull(aggregation, "Aggregation pipeline must not be null");
Assert.notNull(outputType, "Output type must not be null");
return doAggregate(aggregation, collectionName, outputType,
queryOperations.createAggregation(aggregation, context));
@@ -2043,10 +2097,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
protected <O> Stream<O> aggregateStream(Aggregation aggregation, String collectionName, Class<O> outputType,
@Nullable AggregationOperationContext context) {
Assert.hasText(collectionName, "Collection name must not be null or empty!");
Assert.notNull(aggregation, "Aggregation pipeline must not be null!");
Assert.notNull(outputType, "Output type must not be null!");
Assert.isTrue(!aggregation.getOptions().isExplain(), "Can't use explain option with streaming!");
Assert.notNull(aggregation, "Aggregation pipeline must not be null");
Assert.hasText(collectionName, "Collection name must not be null or empty");
Assert.notNull(outputType, "Output type must not be null");
Assert.isTrue(!aggregation.getOptions().isExplain(), "Can't use explain option with streaming");
AggregationDefinition aggregationDefinition = queryOperations.createAggregation(aggregation, context);
@@ -2123,7 +2177,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
Resource functionResource = resourceLoader.getResource(func);
if (!functionResource.exists()) {
throw new InvalidDataAccessApiUsageException(String.format("Resource %s not found!", function));
throw new InvalidDataAccessApiUsageException(String.format("Resource %s not found", function));
}
Scanner scanner = null;
@@ -2132,7 +2186,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
scanner = new Scanner(functionResource.getInputStream());
return scanner.useDelimiter("\\A").next();
} catch (IOException e) {
throw new InvalidDataAccessApiUsageException(String.format("Cannot read map-reduce file %s!", function), e);
throw new InvalidDataAccessApiUsageException(String.format("Cannot read map-reduce file %s", function), e);
} finally {
if (scanner != null) {
scanner.close();
@@ -2168,11 +2222,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
}
protected <E extends MongoMappingEvent<T>, T> E maybeEmitEvent(E event) {
if (eventPublisher != null) {
eventPublisher.publishEvent(event);
}
eventDelegate.publishEvent(event);
return event;
}
@@ -2461,6 +2511,11 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
doc.put("timeseries", timeseries);
});
collectionOptions.getChangeStreamOptions().map(it -> new Document("enabled", it.getPreAndPostImages()))
.ifPresent(it -> {
doc.put("changeStreamPreAndPostImages", it);
});
return doc;
}
@@ -2672,7 +2727,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
.initiateFind(getAndPrepareCollection(doGetDatabase(), collectionName), collectionCallback::doInCollection)
.iterator()) {
List<T> result = new ArrayList<>();
int available = cursor.available();
List<T> result = available > 0 ? new ArrayList<>(available) : new ArrayList<>();
while (cursor.hasNext()) {
Document object = cursor.next();
@@ -2809,8 +2865,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
public FindCallback(Document query, Document fields, @Nullable com.mongodb.client.model.Collation collation) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(fields, "Fields must not be null!");
Assert.notNull(query, "Query must not be null");
Assert.notNull(fields, "Fields must not be null");
this.query = query;
this.fields = fields;
@@ -3197,7 +3253,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
*/
GeoNearResultDocumentCallback(String distanceField, DocumentCallback<T> delegate, Metric metric) {
Assert.notNull(delegate, "DocumentCallback must not be null!");
Assert.notNull(delegate, "DocumentCallback must not be null");
this.distanceField = distanceField;
this.delegate = delegate;

View File

@@ -28,7 +28,7 @@ import java.util.stream.Collectors;
import org.bson.BsonValue;
import org.bson.Document;
import org.bson.codecs.Codec;
import org.bson.types.ObjectId;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.mapping.PropertyReferenceException;
import org.springframework.data.mapping.context.MappingContext;
@@ -46,6 +46,7 @@ import org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOpe
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
import org.springframework.data.mongodb.core.convert.QueryMapper;
import org.springframework.data.mongodb.core.convert.UpdateMapper;
import org.springframework.data.mongodb.core.mapping.MongoId;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.core.mapping.ShardKey;
@@ -107,6 +108,14 @@ class QueryOperations {
this.aggregationUtil = new AggregationUtil(queryMapper, mappingContext);
}
InsertContext createInsertContext(Document source) {
return createInsertContext(MappedDocument.of(source));
}
InsertContext createInsertContext(MappedDocument mappedDocument) {
return new InsertContext(mappedDocument);
}
/**
* Create a new {@link QueryContext} instance.
*
@@ -227,6 +236,57 @@ class QueryOperations {
return new AggregationDefinition(aggregation, aggregationOperationContext);
}
/**
* {@link InsertContext} encapsulates common tasks required to interact with {@link Document} to be inserted.
*
* @since 3.4.3
*/
class InsertContext {
private final MappedDocument source;
private InsertContext(MappedDocument source) {
this.source = source;
}
/**
* Prepare the {@literal _id} field. May generate a new {@literal id} value and convert it to the id properties
* {@link MongoPersistentProperty#getFieldType() target type}.
*
* @param type must not be {@literal null}.
* @param <T>
* @return the {@link MappedDocument} containing the changes.
* @see #prepareId(MongoPersistentEntity)
*/
<T> MappedDocument prepareId(Class<T> type) {
return prepareId(mappingContext.getPersistentEntity(type));
}
/**
* Prepare the {@literal _id} field. May generate a new {@literal id} value and convert it to the id properties
* {@link MongoPersistentProperty#getFieldType() target type}.
*
* @param entity can be {@literal null}.
* @param <T>
* @return the {@link MappedDocument} containing the changes.
*/
<T> MappedDocument prepareId(@Nullable MongoPersistentEntity<T> entity) {
if (entity == null || source.hasId()) {
return source;
}
MongoPersistentProperty idProperty = entity.getIdProperty();
if (idProperty != null
&& (idProperty.hasExplicitWriteTarget() || idProperty.isAnnotationPresent(MongoId.class))) {
if (!ClassUtils.isAssignable(ObjectId.class, idProperty.getFieldType())) {
source.updateId(queryMapper.convertId(new ObjectId(), idProperty.getFieldType()));
}
}
return source;
}
}
/**
* {@link QueryContext} encapsulates common tasks required to convert a {@link Query} into its MongoDB document
* representation, mapping field names, as well as determining and applying {@link Collation collations}.
@@ -288,8 +348,7 @@ class QueryOperations {
return queryMapper.getMappedObject(getQueryObject(), entity);
}
Document getMappedFields(@Nullable MongoPersistentEntity<?> entity,
EntityProjection<?, ?> projection) {
Document getMappedFields(@Nullable MongoPersistentEntity<?> entity, EntityProjection<?, ?> projection) {
Document fields = evaluateFields(entity);
@@ -402,8 +461,7 @@ class QueryOperations {
}
@Override
Document getMappedFields(@Nullable MongoPersistentEntity<?> entity,
EntityProjection<?, ?> projection) {
Document getMappedFields(@Nullable MongoPersistentEntity<?> entity, EntityProjection<?, ?> projection) {
return getMappedFields(entity);
}

View File

@@ -41,7 +41,7 @@ class ReactiveAggregationOperationSupport implements ReactiveAggregationOperatio
*/
ReactiveAggregationOperationSupport(ReactiveMongoTemplate template) {
Assert.notNull(template, "Template must not be null!");
Assert.notNull(template, "Template must not be null");
this.template = template;
}
@@ -49,7 +49,7 @@ class ReactiveAggregationOperationSupport implements ReactiveAggregationOperatio
@Override
public <T> ReactiveAggregation<T> aggregateAndReturn(Class<T> domainType) {
Assert.notNull(domainType, "DomainType must not be null!");
Assert.notNull(domainType, "DomainType must not be null");
return new ReactiveAggregationSupport<>(template, domainType, null, null);
}
@@ -74,7 +74,7 @@ class ReactiveAggregationOperationSupport implements ReactiveAggregationOperatio
@Override
public AggregationOperationWithAggregation<T> inCollection(String collection) {
Assert.hasText(collection, "Collection must not be null nor empty!");
Assert.hasText(collection, "Collection must not be null nor empty");
return new ReactiveAggregationSupport<>(template, domainType, aggregation, collection);
}
@@ -82,7 +82,7 @@ class ReactiveAggregationOperationSupport implements ReactiveAggregationOperatio
@Override
public TerminatingAggregationOperation<T> by(Aggregation aggregation) {
Assert.notNull(aggregation, "Aggregation must not be null!");
Assert.notNull(aggregation, "Aggregation must not be null");
return new ReactiveAggregationSupport<>(template, domainType, aggregation, collection);
}

View File

@@ -49,7 +49,7 @@ class ReactiveChangeStreamOperationSupport implements ReactiveChangeStreamOperat
@Override
public <T> ReactiveChangeStream<T> changeStream(Class<T> domainType) {
Assert.notNull(domainType, "DomainType must not be null!");
Assert.notNull(domainType, "DomainType must not be null");
return new ReactiveChangeStreamSupport<>(template, domainType, domainType, null, null);
}
@@ -75,7 +75,7 @@ class ReactiveChangeStreamOperationSupport implements ReactiveChangeStreamOperat
@Override
public ChangeStreamWithFilterAndProjection<T> watchCollection(String collection) {
Assert.hasText(collection, "Collection name must not be null nor empty!");
Assert.hasText(collection, "Collection name must not be null nor empty");
return new ReactiveChangeStreamSupport<>(template, domainType, returnType, collection, options);
}
@@ -83,7 +83,7 @@ class ReactiveChangeStreamOperationSupport implements ReactiveChangeStreamOperat
@Override
public ChangeStreamWithFilterAndProjection<T> watchCollection(Class<?> entityClass) {
Assert.notNull(entityClass, "Collection type not be null!");
Assert.notNull(entityClass, "Collection type not be null");
return watchCollection(template.getCollectionName(entityClass));
}
@@ -129,7 +129,7 @@ class ReactiveChangeStreamOperationSupport implements ReactiveChangeStreamOperat
@Override
public <R> ChangeStreamWithFilterAndProjection<R> as(Class<R> resultType) {
Assert.notNull(resultType, "ResultType must not be null!");
Assert.notNull(resultType, "ResultType must not be null");
return new ReactiveChangeStreamSupport<>(template, domainType, resultType, collection, options);
}

View File

@@ -47,7 +47,7 @@ class ReactiveFindOperationSupport implements ReactiveFindOperation {
@Override
public <T> ReactiveFind<T> query(Class<T> domainType) {
Assert.notNull(domainType, "DomainType must not be null!");
Assert.notNull(domainType, "DomainType must not be null");
return new ReactiveFindSupport<>(template, domainType, domainType, null, ALL_QUERY);
}
@@ -80,7 +80,7 @@ class ReactiveFindOperationSupport implements ReactiveFindOperation {
@Override
public FindWithProjection<T> inCollection(String collection) {
Assert.hasText(collection, "Collection name must not be null nor empty!");
Assert.hasText(collection, "Collection name must not be null nor empty");
return new ReactiveFindSupport<>(template, domainType, returnType, collection, query);
}
@@ -88,7 +88,7 @@ class ReactiveFindOperationSupport implements ReactiveFindOperation {
@Override
public <T1> FindWithQuery<T1> as(Class<T1> returnType) {
Assert.notNull(returnType, "ReturnType must not be null!");
Assert.notNull(returnType, "ReturnType must not be null");
return new ReactiveFindSupport<>(template, domainType, returnType, collection, query);
}
@@ -96,7 +96,7 @@ class ReactiveFindOperationSupport implements ReactiveFindOperation {
@Override
public TerminatingFind<T> matching(Query query) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(query, "Query must not be null");
return new ReactiveFindSupport<>(template, domainType, returnType, collection, query);
}
@@ -124,7 +124,7 @@ class ReactiveFindOperationSupport implements ReactiveFindOperation {
if (it.size() > 1) {
return Mono.error(
new IncorrectResultSizeDataAccessException("Query " + asString() + " returned non unique result.", 1));
new IncorrectResultSizeDataAccessException("Query " + asString() + " returned non unique result", 1));
}
return Mono.just(it.get(0));
@@ -159,7 +159,7 @@ class ReactiveFindOperationSupport implements ReactiveFindOperation {
@Override
public TerminatingDistinct<Object> distinct(String field) {
Assert.notNull(field, "Field must not be null!");
Assert.notNull(field, "Field must not be null");
return new DistinctOperationSupport<>(this, field);
}
@@ -210,7 +210,7 @@ class ReactiveFindOperationSupport implements ReactiveFindOperation {
@Override
public <R> TerminatingDistinct<R> as(Class<R> resultType) {
Assert.notNull(resultType, "ResultType must not be null!");
Assert.notNull(resultType, "ResultType must not be null");
return new DistinctOperationSupport<>((ReactiveFindSupport) delegate.as(resultType), field);
}
@@ -219,7 +219,7 @@ class ReactiveFindOperationSupport implements ReactiveFindOperation {
@SuppressWarnings("unchecked")
public TerminatingDistinct<T> matching(Query query) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(query, "Query must not be null");
return new DistinctOperationSupport<>((ReactiveFindSupport<T>) delegate.matching(query), field);
}

View File

@@ -41,7 +41,7 @@ class ReactiveInsertOperationSupport implements ReactiveInsertOperation {
@Override
public <T> ReactiveInsert<T> insert(Class<T> domainType) {
Assert.notNull(domainType, "DomainType must not be null!");
Assert.notNull(domainType, "DomainType must not be null");
return new ReactiveInsertSupport<>(template, domainType, null);
}
@@ -62,7 +62,7 @@ class ReactiveInsertOperationSupport implements ReactiveInsertOperation {
@Override
public Mono<T> one(T object) {
Assert.notNull(object, "Object must not be null!");
Assert.notNull(object, "Object must not be null");
return template.insert(object, getCollectionName());
}
@@ -70,7 +70,7 @@ class ReactiveInsertOperationSupport implements ReactiveInsertOperation {
@Override
public Flux<T> all(Collection<? extends T> objects) {
Assert.notNull(objects, "Objects must not be null!");
Assert.notNull(objects, "Objects must not be null");
return template.insert(objects, getCollectionName());
}
@@ -78,7 +78,7 @@ class ReactiveInsertOperationSupport implements ReactiveInsertOperation {
@Override
public ReactiveInsert<T> inCollection(String collection) {
Assert.hasText(collection, "Collection must not be null nor empty.");
Assert.hasText(collection, "Collection must not be null nor empty");
return new ReactiveInsertSupport<>(template, domainType, collection);
}

View File

@@ -46,7 +46,7 @@ class ReactiveMapReduceOperationSupport implements ReactiveMapReduceOperation {
@Override
public <T> ReactiveMapReduceSupport<T> mapReduce(Class<T> domainType) {
Assert.notNull(domainType, "DomainType must not be null!");
Assert.notNull(domainType, "DomainType must not be null");
return new ReactiveMapReduceSupport<>(template, domainType, domainType, null, ALL_QUERY, null, null, null);
}
@@ -100,7 +100,7 @@ class ReactiveMapReduceOperationSupport implements ReactiveMapReduceOperation {
@Override
public MapReduceWithProjection<T> inCollection(String collection) {
Assert.hasText(collection, "Collection name must not be null nor empty!");
Assert.hasText(collection, "Collection name must not be null nor empty");
return new ReactiveMapReduceSupport<>(template, domainType, returnType, collection, query, mapFunction,
reduceFunction, options);
@@ -113,7 +113,7 @@ class ReactiveMapReduceOperationSupport implements ReactiveMapReduceOperation {
@Override
public TerminatingMapReduce<T> matching(Query query) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(query, "Query must not be null");
return new ReactiveMapReduceSupport<>(template, domainType, returnType, collection, query, mapFunction,
reduceFunction, options);
@@ -126,7 +126,7 @@ class ReactiveMapReduceOperationSupport implements ReactiveMapReduceOperation {
@Override
public <R> MapReduceWithQuery<R> as(Class<R> resultType) {
Assert.notNull(resultType, "ResultType must not be null!");
Assert.notNull(resultType, "ResultType must not be null");
return new ReactiveMapReduceSupport<>(template, domainType, resultType, collection, query, mapFunction,
reduceFunction, options);
@@ -139,7 +139,7 @@ class ReactiveMapReduceOperationSupport implements ReactiveMapReduceOperation {
@Override
public ReactiveMapReduce<T> with(MapReduceOptions options) {
Assert.notNull(options, "Options must not be null! Please consider empty MapReduceOptions#options() instead.");
Assert.notNull(options, "Options must not be null Please consider empty MapReduceOptions#options() instead");
return new ReactiveMapReduceSupport<>(template, domainType, returnType, collection, query, mapFunction,
reduceFunction, options);
@@ -152,7 +152,7 @@ class ReactiveMapReduceOperationSupport implements ReactiveMapReduceOperation {
@Override
public MapReduceWithReduceFunction<T> map(String mapFunction) {
Assert.hasText(mapFunction, "MapFunction name must not be null nor empty!");
Assert.hasText(mapFunction, "MapFunction name must not be null nor empty");
return new ReactiveMapReduceSupport<>(template, domainType, returnType, collection, query, mapFunction,
reduceFunction, options);
@@ -165,7 +165,7 @@ class ReactiveMapReduceOperationSupport implements ReactiveMapReduceOperation {
@Override
public ReactiveMapReduce<T> reduce(String reduceFunction) {
Assert.hasText(reduceFunction, "ReduceFunction name must not be null nor empty!");
Assert.hasText(reduceFunction, "ReduceFunction name must not be null nor empty");
return new ReactiveMapReduceSupport<>(template, domainType, returnType, collection, query, mapFunction,
reduceFunction, options);

View File

@@ -115,7 +115,7 @@ public class ReactiveMongoClientFactoryBean extends AbstractFactoryBean<MongoCli
}
throw new IllegalStateException(
"Cannot create MongoClients. One of the following is required: mongoClientSettings, connectionString or host/port");
"Cannot create MongoClients; One of the following is required: mongoClientSettings, connectionString or host/port");
}
@Override

View File

@@ -70,8 +70,8 @@ public class ReactiveMongoContext {
*/
public static Context setSession(Context context, Publisher<ClientSession> session) {
Assert.notNull(context, "Context must not be null!");
Assert.notNull(session, "Session publisher must not be null!");
Assert.notNull(context, "Context must not be null");
Assert.notNull(session, "Session publisher must not be null");
return context.put(SESSION_KEY, Mono.from(session));
}

View File

@@ -25,10 +25,13 @@ import java.util.function.Supplier;
import org.bson.Document;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscription;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.mongodb.ReactiveMongoDatabaseFactory;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationOptions;
import org.springframework.data.mongodb.core.aggregation.AggregationPipeline;
import org.springframework.data.mongodb.core.aggregation.AggregationUpdate;
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
@@ -164,7 +167,7 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
*/
default ReactiveSessionScoped withSession(Supplier<ClientSession> sessionProvider) {
Assert.notNull(sessionProvider, "SessionProvider must not be null!");
Assert.notNull(sessionProvider, "SessionProvider must not be null");
return withSession(Mono.fromSupplier(sessionProvider));
}
@@ -240,6 +243,56 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
*/
Mono<MongoCollection<Document>> createCollection(String collectionName, CollectionOptions collectionOptions);
/**
* Create a view with the provided name. The view content is defined by the {@link AggregationOperation pipeline
* stages} on another collection or view identified by the given {@link #getCollectionName(Class) source type}.
*
* @param name the name of the view to create.
* @param source the type defining the views source collection.
* @param stages the {@link AggregationOperation aggregation pipeline stages} defining the view content.
* @since 4.0
*/
default Mono<MongoCollection<Document>> createView(String name, Class<?> source, AggregationOperation... stages) {
return createView(name, source, AggregationPipeline.of(stages));
}
/**
* Create a view with the provided name. The view content is defined by the {@link AggregationPipeline pipeline} on
* another collection or view identified by the given {@link #getCollectionName(Class) source type}.
*
* @param name the name of the view to create.
* @param source the type defining the views source collection.
* @param pipeline the {@link AggregationPipeline} defining the view content.
* @since 4.0
*/
default Mono<MongoCollection<Document>> createView(String name, Class<?> source, AggregationPipeline pipeline) {
return createView(name, source, pipeline, null);
}
/**
* Create a view with the provided name. The view content is defined by the {@link AggregationPipeline pipeline} on
* another collection or view identified by the given {@link #getCollectionName(Class) source type}.
*
* @param name the name of the view to create.
* @param source the type defining the views source collection.
* @param pipeline the {@link AggregationPipeline} defining the view content.
* @param options additional settings to apply when creating the view. Can be {@literal null}.
* @since 4.0
*/
Mono<MongoCollection<Document>> createView(String name, Class<?> source, AggregationPipeline pipeline, @Nullable ViewOptions options);
/**
* Create a view with the provided name. The view content is defined by the {@link AggregationPipeline pipeline} on
* another collection or view identified by the given source.
*
* @param name the name of the view to create.
* @param source the name of the collection or view defining the to be created views source.
* @param pipeline the {@link AggregationPipeline} defining the view content.
* @param options additional settings to apply when creating the view. Can be {@literal null}.
* @since 4.0
*/
Mono<MongoCollection<Document>> createView(String name, String source, AggregationPipeline pipeline, @Nullable ViewOptions options);
/**
* A set of collection names.
*
@@ -693,6 +746,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
* fields specification. Must not be {@literal null}.
* @param replacement the replacement document. Must not be {@literal null}.
* @return the converted object that was updated or {@link Mono#empty()}, if not found.
* @throws org.springframework.data.mapping.MappingException if the collection name cannot be
* {@link #getCollectionName(Class) derived} from the given replacement value.
* @since 2.1
*/
default <T> Mono<T> findAndReplace(Query query, T replacement) {
@@ -732,6 +787,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
* @return the converted object that was updated or {@link Mono#empty()}, if not found. Depending on the value of
* {@link FindAndReplaceOptions#isReturnNew()} this will either be the object as it was before the update or
* as it is after the update.
* @throws org.springframework.data.mapping.MappingException if the collection name cannot be
* {@link #getCollectionName(Class) derived} from the given replacement value.
* @since 2.1
*/
default <T> Mono<T> findAndReplace(Query query, T replacement, FindAndReplaceOptions options) {
@@ -756,7 +813,7 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
*/
default <T> Mono<T> findAndReplace(Query query, T replacement, FindAndReplaceOptions options, String collectionName) {
Assert.notNull(replacement, "Replacement must not be null!");
Assert.notNull(replacement, "Replacement must not be null");
return findAndReplace(query, replacement, options, (Class<T>) ClassUtils.getUserClass(replacement), collectionName);
}
@@ -802,6 +859,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
* @return the converted object that was updated or {@link Mono#empty()}, if not found. Depending on the value of
* {@link FindAndReplaceOptions#isReturnNew()} this will either be the object as it was before the update or
* as it is after the update.
* @throws org.springframework.data.mapping.MappingException if the collection name cannot be
* {@link #getCollectionName(Class) derived} from the given replacement value.
* @since 2.1
*/
default <S, T> Mono<T> findAndReplace(Query query, S replacement, FindAndReplaceOptions options, Class<S> entityType,
@@ -882,6 +941,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
* {@literal null}.
* @param entityClass class that determines the collection to use. Must not be {@literal null}.
* @return the count of matching documents.
* @throws org.springframework.data.mapping.MappingException if the collection name cannot be
* {@link #getCollectionName(Class) derived} from the given type.
* @see #exactCount(Query, Class)
* @see #estimatedCount(Class)
*/
@@ -937,11 +998,13 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
*
* @param entityClass must not be {@literal null}.
* @return a {@link Mono} emitting the estimated number of documents.
* @throws org.springframework.data.mapping.MappingException if the collection name cannot be
* {@link #getCollectionName(Class) derived} from the given type.
* @since 3.1
*/
default Mono<Long> estimatedCount(Class<?> entityClass) {
Assert.notNull(entityClass, "Entity class must not be null!");
Assert.notNull(entityClass, "Entity class must not be null");
return estimatedCount(getCollectionName(entityClass));
}
@@ -973,6 +1036,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
* {@literal null}.
* @param entityClass class that determines the collection to use. Must not be {@literal null}.
* @return the count of matching documents.
* @throws org.springframework.data.mapping.MappingException if the collection name cannot be
* {@link #getCollectionName(Class) derived} from the given type.
* @since 3.4
*/
default Mono<Long> exactCount(Query query, Class<?> entityClass) {
@@ -1028,9 +1093,10 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
/**
* Insert the object into the collection for the entity type of the object to save. <br />
* The object is converted to the MongoDB native representation using an instance of {@see MongoConverter}. <br />
* If your object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property is a
* String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from ObjectId to your
* property type will be handled by Spring's BeanWrapper class that leverages Type Conversion API. See
* If your object has an {@literal Id} property which holds a {@literal null} value, it will be set with the generated
* Id from MongoDB. If your Id property is a String then MongoDB ObjectId will be used to populate that string.
* Otherwise, the conversion from ObjectId to your property type will be handled by Spring's BeanWrapper class that
* leverages Type Conversion API. See
* <a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#validation" > Spring's
* Type Conversion"</a> for more details. <br />
* Insert is used to initially store the object into the database. To update an existing object use the save method.
@@ -1040,6 +1106,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
* @param objectToSave the object to store in the collection. Must not be {@literal null}.
* @return the inserted object.
* @throws IllegalArgumentException in case the {@code objectToSave} is collection-like.
* @throws org.springframework.data.mapping.MappingException if the target collection name cannot be
* {@link #getCollectionName(Class) derived} from the given object type.
*/
<T> Mono<T> insert(T objectToSave);
@@ -1063,7 +1131,9 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
*
* @param batchToSave the batch of objects to save. Must not be {@literal null}.
* @param entityClass class that determines the collection to use. Must not be {@literal null}.
* @return the inserted objects .
* @return the inserted objects.
* @throws org.springframework.data.mapping.MappingException if the target collection name cannot be
* {@link #getCollectionName(Class) derived} from the given type.
*/
<T> Flux<T> insert(Collection<? extends T> batchToSave, Class<?> entityClass);
@@ -1082,6 +1152,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
*
* @param objectsToSave the list of objects to save. Must not be {@literal null}.
* @return the saved objects.
* @throws org.springframework.data.mapping.MappingException if the target collection name cannot be
* {@link #getCollectionName(Class) derived} for the given objects.
*/
<T> Flux<T> insertAll(Collection<? extends T> objectsToSave);
@@ -1106,6 +1178,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
* @param batchToSave the publisher which provides objects to save. Must not be {@literal null}.
* @param entityClass class that determines the collection to use. Must not be {@literal null}.
* @return the inserted objects.
* @throws org.springframework.data.mapping.MappingException if the target collection name cannot be
* {@link #getCollectionName(Class) derived} for the type.
*/
<T> Flux<T> insertAll(Mono<? extends Collection<? extends T>> batchToSave, Class<?> entityClass);
@@ -1142,6 +1216,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
* @param objectToSave the object to store in the collection. Must not be {@literal null}.
* @return the saved object.
* @throws IllegalArgumentException in case the {@code objectToSave} is collection-like.
* @throws org.springframework.data.mapping.MappingException if the target collection name cannot be
* {@link #getCollectionName(Class) derived} from the given object type.
*/
<T> Mono<T> save(T objectToSave);
@@ -1176,6 +1252,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
*
* @param objectToSave the object to store in the collection. Must not be {@literal null}.
* @return the saved object.
* @throws org.springframework.data.mapping.MappingException if the target collection name cannot be
* {@link #getCollectionName(Class) derived} from the given object type.
*/
<T> Mono<T> save(Mono<? extends T> objectToSave);
@@ -1208,6 +1286,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
* the existing object. Must not be {@literal null}.
* @param entityClass class that determines the collection to use. Must not be {@literal null}.
* @return the {@link UpdateResult} which lets you access the results of the previous write.
* @throws org.springframework.data.mapping.MappingException if the target collection name cannot be
* {@link #getCollectionName(Class) derived} from the given type.
* @since 3.0
* @see Update
* @see AggregationUpdate
@@ -1262,6 +1342,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
* the existing. Must not be {@literal null}.
* @param entityClass class that determines the collection to use.
* @return the {@link UpdateResult} which lets you access the results of the previous write.
* @throws org.springframework.data.mapping.MappingException if the target collection name cannot be
* {@link #getCollectionName(Class) derived} from the given type.
* @since 3.0
* @see Update
* @see AggregationUpdate
@@ -1317,6 +1399,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
* @param entityClass class of the pojo to be operated on. Must not be {@literal null}.
* @return the {@link UpdateResult} which lets you access the results of the previous write.
* @since 3.0
* @throws org.springframework.data.mapping.MappingException if the target collection name cannot be
* {@link #getCollectionName(Class) derived} from the given type.
* @see Update
* @see AggregationUpdate
*/
@@ -1363,6 +1447,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
*
* @param object must not be {@literal null}.
* @return the {@link DeleteResult} which lets you access the results of the previous delete.
* @throws org.springframework.data.mapping.MappingException if the target collection name cannot be
* {@link #getCollectionName(Class) derived} from the given object type.
*/
Mono<DeleteResult> remove(Object object);
@@ -1380,6 +1466,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
*
* @param objectToRemove must not be {@literal null}.
* @return the {@link DeleteResult} which lets you access the results of the previous delete.
* @throws org.springframework.data.mapping.MappingException if the target collection name cannot be
* {@link #getCollectionName(Class) derived} from the given object type.
*/
Mono<DeleteResult> remove(Mono<? extends Object> objectToRemove);
@@ -1393,17 +1481,19 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
Mono<DeleteResult> remove(Mono<? extends Object> objectToRemove, String collectionName);
/**
* Remove all documents that match the provided query document criteria from the the collection used to store the
* Remove all documents that match the provided query document criteria from the collection used to store the
* entityClass. The Class parameter is also used to help convert the Id of the object if it is present in the query.
*
* @param query the query document that specifies the criteria used to remove a record.
* @param entityClass class that determines the collection to use.
* @return the {@link DeleteResult} which lets you access the results of the previous delete.
* @throws org.springframework.data.mapping.MappingException if the target collection name cannot be
* {@link #getCollectionName(Class) derived} from the given type.
*/
Mono<DeleteResult> remove(Query query, Class<?> entityClass);
/**
* Remove all documents that match the provided query document criteria from the the collection used to store the
* Remove all documents that match the provided query document criteria from the collection used to store the
* entityClass. The Class parameter is also used to help convert the Id of the object if it is present in the query.
*
* @param query the query document that specifies the criteria used to remove a record.
@@ -1442,13 +1532,15 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
* @param query the query document that specifies the criteria used to find and remove documents.
* @param entityClass class of the pojo to be operated on.
* @return the {@link Flux} converted objects deleted by this operation.
* @throws org.springframework.data.mapping.MappingException if the target collection name cannot be
* {@link #getCollectionName(Class) derived} from the given type.
*/
<T> Flux<T> findAllAndRemove(Query query, Class<T> entityClass);
/**
* Returns and removes all documents that match the provided query document criteria from the the collection used to
* store the entityClass. The Class parameter is also used to help convert the Id of the object if it is present in
* the query.
* Returns and removes all documents that match the provided query document criteria from the collection used to store
* the entityClass. The Class parameter is also used to help convert the Id of the object if it is present in the
* query.
*
* @param query the query document that specifies the criteria used to find and remove documents.
* @param entityClass class of the pojo to be operated on.
@@ -1471,6 +1563,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
* specification.
* @param entityClass the parametrized type of the returned {@link Flux}.
* @return the {@link Flux} of converted objects.
* @throws org.springframework.data.mapping.MappingException if the target collection name cannot be
* {@link #getCollectionName(Class) derived} from the given type.
*/
<T> Flux<T> tail(Query query, Class<T> entityClass);
@@ -1611,6 +1705,7 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
*
* @param entityClass must not be {@literal null}.
* @return never {@literal null}.
* @throws org.springframework.data.mapping.MappingException if the collection name cannot be derived from the type.
* @since 2.1
*/
String getCollectionName(Class<?> entityClass);

View File

@@ -46,7 +46,6 @@ import org.bson.conversions.Bson;
import org.bson.types.ObjectId;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
@@ -81,6 +80,7 @@ import org.springframework.data.mongodb.core.QueryOperations.UpdateContext;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext;
import org.springframework.data.mongodb.core.aggregation.AggregationOptions;
import org.springframework.data.mongodb.core.aggregation.AggregationPipeline;
import org.springframework.data.mongodb.core.aggregation.PrefixingDelegatingAggregationOperationContext;
import org.springframework.data.mongodb.core.aggregation.RelaxedTypeBasedAggregationOperationContext;
import org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOperationContext;
@@ -127,16 +127,7 @@ import com.mongodb.CursorType;
import com.mongodb.MongoException;
import com.mongodb.ReadPreference;
import com.mongodb.WriteConcern;
import com.mongodb.client.model.CountOptions;
import com.mongodb.client.model.CreateCollectionOptions;
import com.mongodb.client.model.DeleteOptions;
import com.mongodb.client.model.EstimatedDocumentCountOptions;
import com.mongodb.client.model.FindOneAndDeleteOptions;
import com.mongodb.client.model.FindOneAndReplaceOptions;
import com.mongodb.client.model.FindOneAndUpdateOptions;
import com.mongodb.client.model.ReplaceOptions;
import com.mongodb.client.model.ReturnDocument;
import com.mongodb.client.model.UpdateOptions;
import com.mongodb.client.model.*;
import com.mongodb.client.model.changestream.FullDocument;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.InsertOneResult;
@@ -185,6 +176,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
private final EntityOperations operations;
private final PropertyOperations propertyOperations;
private final QueryOperations queryOperations;
private final EntityLifecycleEventDelegate eventDelegate;
private @Nullable WriteConcern writeConcern;
private WriteConcernResolver writeConcernResolver = DefaultWriteConcernResolver.INSTANCE;
@@ -241,7 +233,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
public ReactiveMongoTemplate(ReactiveMongoDatabaseFactory mongoDatabaseFactory,
@Nullable MongoConverter mongoConverter, Consumer<Throwable> subscriptionExceptionHandler) {
Assert.notNull(mongoDatabaseFactory, "ReactiveMongoDatabaseFactory must not be null!");
Assert.notNull(mongoDatabaseFactory, "ReactiveMongoDatabaseFactory must not be null");
this.mongoDatabaseFactory = mongoDatabaseFactory;
this.exceptionTranslator = mongoDatabaseFactory.getExceptionTranslator();
@@ -256,6 +248,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
this.propertyOperations = new PropertyOperations(this.mongoConverter.getMappingContext());
this.queryOperations = new QueryOperations(queryMapper, updateMapper, operations, propertyOperations,
mongoDatabaseFactory);
this.eventDelegate = new EntityLifecycleEventDelegate();
// We create indexes based on mapping events
if (this.mappingContext instanceof MongoMappingContext) {
@@ -287,6 +280,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
this.propertyOperations = that.propertyOperations;
this.sessionSynchronization = that.sessionSynchronization;
this.queryOperations = that.queryOperations;
this.eventDelegate = that.eventDelegate;
}
private void onCheckForIndexes(MongoPersistentEntity<?> entity, Consumer<Throwable> subscriptionExceptionHandler) {
@@ -339,12 +333,25 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
this.readPreference = readPreference;
}
/**
* Configure whether lifecycle events such as {@link AfterLoadEvent}, {@link BeforeSaveEvent}, etc. should be
* published or whether emission should be suppressed. Enabled by default.
*
* @param enabled {@code true} to enable entity lifecycle events; {@code false} to disable entity lifecycle events.
* @since 4.0
* @see MongoMappingEvent
*/
public void setEntityLifecycleEventsEnabled(boolean enabled) {
this.eventDelegate.setEventsEnabled(enabled);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
prepareIndexCreator(applicationContext);
eventPublisher = applicationContext;
eventDelegate.setPublisher(eventPublisher);
if (entityCallbacks == null) {
setEntityCallbacks(ReactiveEntityCallbacks.create(applicationContext));
@@ -367,7 +374,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
*/
public void setEntityCallbacks(ReactiveEntityCallbacks entityCallbacks) {
Assert.notNull(entityCallbacks, "EntityCallbacks must not be null!");
Assert.notNull(entityCallbacks, "EntityCallbacks must not be null");
this.entityCallbacks = entityCallbacks;
}
@@ -468,7 +475,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@Override
public Mono<Document> executeCommand(String jsonCommand) {
Assert.notNull(jsonCommand, "Command must not be empty!");
Assert.notNull(jsonCommand, "Command must not be empty");
return executeCommand(Document.parse(jsonCommand));
}
@@ -481,7 +488,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@Override
public Mono<Document> executeCommand(Document command, @Nullable ReadPreference readPreference) {
Assert.notNull(command, "Command must not be null!");
Assert.notNull(command, "Command must not be null");
return createFlux(db -> readPreference != null ? db.runCommand(command, readPreference, Document.class)
: db.runCommand(command, Document.class)).next();
@@ -500,7 +507,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@Override
public <T> Flux<T> execute(String collectionName, ReactiveCollectionCallback<T> callback) {
Assert.notNull(callback, "ReactiveCollectionCallback must not be null!");
Assert.notNull(callback, "ReactiveCollectionCallback must not be null");
return createFlux(collectionName, callback);
}
@@ -565,7 +572,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
*/
public <T> Flux<T> createFlux(ReactiveDatabaseCallback<T> callback) {
Assert.notNull(callback, "ReactiveDatabaseCallback must not be null!");
Assert.notNull(callback, "ReactiveDatabaseCallback must not be null");
return Mono.defer(this::doGetDatabase).flatMapMany(database -> callback.doInDB(prepareDatabase(database)))
.onErrorMap(translateException());
@@ -580,7 +587,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
*/
public <T> Mono<T> createMono(ReactiveDatabaseCallback<T> callback) {
Assert.notNull(callback, "ReactiveDatabaseCallback must not be null!");
Assert.notNull(callback, "ReactiveDatabaseCallback must not be null");
return Mono.defer(this::doGetDatabase).flatMap(database -> Mono.from(callback.doInDB(prepareDatabase(database))))
.onErrorMap(translateException());
@@ -595,8 +602,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
*/
public <T> Flux<T> createFlux(String collectionName, ReactiveCollectionCallback<T> callback) {
Assert.hasText(collectionName, "Collection name must not be null or empty!");
Assert.notNull(callback, "ReactiveDatabaseCallback must not be null!");
Assert.hasText(collectionName, "Collection name must not be null or empty");
Assert.notNull(callback, "ReactiveDatabaseCallback must not be null");
Mono<MongoCollection<Document>> collectionPublisher = doGetDatabase()
.map(database -> getAndPrepareCollection(database, collectionName));
@@ -614,8 +621,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
*/
public <T> Mono<T> createMono(String collectionName, ReactiveCollectionCallback<T> callback) {
Assert.hasText(collectionName, "Collection name must not be null or empty!");
Assert.notNull(callback, "ReactiveCollectionCallback must not be null!");
Assert.hasText(collectionName, "Collection name must not be null or empty");
Assert.notNull(callback, "ReactiveCollectionCallback must not be null");
Mono<MongoCollection<Document>> collectionPublisher = doGetDatabase()
.map(database -> getAndPrepareCollection(database, collectionName));
@@ -633,7 +640,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
public <T> Mono<MongoCollection<Document>> createCollection(Class<T> entityClass,
@Nullable CollectionOptions collectionOptions) {
Assert.notNull(entityClass, "EntityClass must not be null!");
Assert.notNull(entityClass, "EntityClass must not be null");
CollectionOptions options = collectionOptions != null ? collectionOptions : CollectionOptions.empty();
options = Optionals
@@ -655,10 +662,47 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
return doCreateCollection(collectionName, convertToCreateCollectionOptions(collectionOptions));
}
@Override
public Mono<MongoCollection<Document>> createView(String name, Class<?> source, AggregationPipeline pipeline,
@Nullable ViewOptions options) {
return createView(name, getCollectionName(source),
queryOperations.createAggregation(Aggregation.newAggregation(source, pipeline.getOperations()), source),
options);
}
@Override
public Mono<MongoCollection<Document>> createView(String name, String source, AggregationPipeline pipeline,
@Nullable ViewOptions options) {
return createView(name, source,
queryOperations.createAggregation(Aggregation.newAggregation(pipeline.getOperations()), (Class<?>) null),
options);
}
private Mono<MongoCollection<Document>> createView(String name, String source, AggregationDefinition aggregation,
@Nullable ViewOptions options) {
return doCreateView(name, source, aggregation.getAggregationPipeline(), options);
}
protected Mono<MongoCollection<Document>> doCreateView(String name, String source, List<Document> pipeline,
@Nullable ViewOptions options) {
CreateViewOptions viewOptions = new CreateViewOptions();
if (options != null) {
options.getCollation().map(Collation::toMongoCollation).ifPresent(viewOptions::collation);
}
return execute(db -> {
return Flux.from(db.createView(name, source, pipeline, viewOptions))
.then(Mono.fromSupplier(() -> db.getCollection(name)));
}).next();
}
@Override
public Mono<MongoCollection<Document>> getCollection(String collectionName) {
Assert.notNull(collectionName, "Collection name must not be null!");
Assert.notNull(collectionName, "Collection name must not be null");
return createMono(db -> Mono.just(db.getCollection(collectionName)));
}
@@ -795,11 +839,11 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
public <T> Flux<T> findDistinct(Query query, String field, String collectionName, Class<?> entityClass,
Class<T> resultClass) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(field, "Field must not be null!");
Assert.notNull(collectionName, "CollectionName must not be null!");
Assert.notNull(entityClass, "EntityClass must not be null!");
Assert.notNull(resultClass, "ResultClass must not be null!");
Assert.notNull(query, "Query must not be null");
Assert.notNull(field, "Field must not be null");
Assert.notNull(collectionName, "CollectionName must not be null");
Assert.notNull(entityClass, "EntityClass must not be null");
Assert.notNull(resultClass, "ResultClass must not be null");
MongoPersistentEntity<?> entity = getPersistentEntity(entityClass);
DistinctQueryContext distinctQueryContext = queryOperations.distinctQueryContext(query, field);
@@ -839,13 +883,14 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@Override
public <O> Flux<O> aggregate(TypedAggregation<?> aggregation, String inputCollectionName, Class<O> outputType) {
Assert.notNull(aggregation, "Aggregation pipeline must not be null!");
Assert.notNull(aggregation, "Aggregation pipeline must not be null");
return doAggregate(aggregation, inputCollectionName, aggregation.getInputType(), outputType);
}
@Override
public <O> Flux<O> aggregate(TypedAggregation<?> aggregation, Class<O> outputType) {
Assert.notNull(aggregation, "Aggregation pipeline must not be null");
return aggregate(aggregation, getCollectionName(aggregation.getInputType()), outputType);
}
@@ -862,12 +907,12 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
protected <O> Flux<O> doAggregate(Aggregation aggregation, String collectionName, @Nullable Class<?> inputType,
Class<O> outputType) {
Assert.notNull(aggregation, "Aggregation pipeline must not be null!");
Assert.hasText(collectionName, "Collection name must not be null or empty!");
Assert.notNull(outputType, "Output type must not be null!");
Assert.notNull(aggregation, "Aggregation pipeline must not be null");
Assert.hasText(collectionName, "Collection name must not be null or empty");
Assert.notNull(outputType, "Output type must not be null");
AggregationOptions options = aggregation.getOptions();
Assert.isTrue(!options.isExplain(), "Cannot use explain option with streaming!");
Assert.isTrue(!options.isExplain(), "Cannot use explain option with streaming");
AggregationDefinition ctx = queryOperations.createAggregation(aggregation, inputType);
@@ -925,11 +970,11 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
Class<T> returnType) {
if (near == null) {
throw new InvalidDataAccessApiUsageException("NearQuery must not be null!");
throw new InvalidDataAccessApiUsageException("NearQuery must not be null");
}
if (entityClass == null) {
throw new InvalidDataAccessApiUsageException("Entity class must not be null!");
throw new InvalidDataAccessApiUsageException("Entity class must not be null");
}
String collection = StringUtils.hasText(collectionName) ? collectionName : getCollectionName(entityClass);
@@ -966,14 +1011,14 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
public <T> Mono<T> findAndModify(Query query, UpdateDefinition update, FindAndModifyOptions options,
Class<T> entityClass, String collectionName) {
Assert.notNull(options, "Options must not be null! ");
Assert.notNull(entityClass, "Entity class must not be null!");
Assert.notNull(options, "Options must not be null ");
Assert.notNull(entityClass, "Entity class must not be null");
FindAndModifyOptions optionsToUse = FindAndModifyOptions.of(options);
Optionals.ifAllPresent(query.getCollation(), optionsToUse.getCollation(), (l, r) -> {
throw new IllegalArgumentException(
"Both Query and FindAndModifyOptions define a collation. Please provide the collation only via one of the two.");
"Both Query and FindAndModifyOptions define a collation; Please provide the collation only via one of the two");
});
if (!optionsToUse.getCollation().isPresent()) {
@@ -988,15 +1033,15 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
public <S, T> Mono<T> findAndReplace(Query query, S replacement, FindAndReplaceOptions options, Class<S> entityType,
String collectionName, Class<T> resultType) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(replacement, "Replacement must not be null!");
Assert.notNull(options, "Options must not be null! Use FindAndReplaceOptions#empty() instead.");
Assert.notNull(entityType, "Entity class must not be null!");
Assert.notNull(collectionName, "CollectionName must not be null!");
Assert.notNull(resultType, "ResultType must not be null! Use Object.class instead.");
Assert.notNull(query, "Query must not be null");
Assert.notNull(replacement, "Replacement must not be null");
Assert.notNull(options, "Options must not be null Use FindAndReplaceOptions#empty() instead");
Assert.notNull(entityType, "Entity class must not be null");
Assert.notNull(collectionName, "CollectionName must not be null");
Assert.notNull(resultType, "ResultType must not be null Use Object.class instead");
Assert.isTrue(query.getLimit() <= 1, "Query must not define a limit other than 1 ore none!");
Assert.isTrue(query.getSkip() <= 0, "Query must not define skip.");
Assert.isTrue(query.getLimit() <= 1, "Query must not define a limit other than 1 ore none");
Assert.isTrue(query.getSkip() <= 0, "Query must not define skip");
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityType);
QueryContext queryContext = queryOperations.createQueryContext(query);
@@ -1053,7 +1098,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@Override
public Mono<Long> count(Query query, Class<?> entityClass) {
Assert.notNull(entityClass, "Entity class must not be null!");
Assert.notNull(entityClass, "Entity class must not be null");
return count(query, entityClass, getCollectionName(entityClass));
}
@@ -1066,8 +1111,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@Override
public Mono<Long> count(Query query, @Nullable Class<?> entityClass, String collectionName) {
Assert.notNull(query, "Query must not be null!");
Assert.hasText(collectionName, "Collection name must not be null or empty!");
Assert.notNull(query, "Query must not be null");
Assert.hasText(collectionName, "Collection name must not be null or empty");
return createMono(collectionName, collection -> {
@@ -1152,7 +1197,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@Override
public <T> Mono<T> insert(Mono<? extends T> objectToSave) {
Assert.notNull(objectToSave, "Mono to insert must not be null!");
Assert.notNull(objectToSave, "Mono to insert must not be null");
return objectToSave.flatMap(this::insert);
}
@@ -1165,7 +1210,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@Override
public <T> Flux<T> insertAll(Mono<? extends Collection<? extends T>> batchToSave, String collectionName) {
Assert.notNull(batchToSave, "Batch to insert must not be null!");
Assert.notNull(batchToSave, "Batch to insert must not be null");
return Flux.from(batchToSave).flatMap(collection -> insert(collection, collectionName));
}
@@ -1173,7 +1218,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@Override
public <T> Mono<T> insert(T objectToSave) {
Assert.notNull(objectToSave, "Object to insert must not be null!");
Assert.notNull(objectToSave, "Object to insert must not be null");
ensureNotCollectionLike(objectToSave);
return insert(objectToSave, getCollectionName(ClassUtils.getUserClass(objectToSave)));
@@ -1182,7 +1227,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@Override
public <T> Mono<T> insert(T objectToSave, String collectionName) {
Assert.notNull(objectToSave, "Object to insert must not be null!");
Assert.notNull(objectToSave, "Object to insert must not be null");
ensureNotCollectionLike(objectToSave);
return doInsert(collectionName, objectToSave, this.mongoConverter);
@@ -1257,7 +1302,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
protected <T> Flux<T> doInsertBatch(String collectionName, Collection<? extends T> batchToSave,
MongoWriter<Object> writer) {
Assert.notNull(writer, "MongoWriter must not be null!");
Assert.notNull(writer, "MongoWriter must not be null");
Mono<List<Tuple2<AdaptibleEntity<T>, Document>>> prepareDocuments = Flux.fromIterable(batchToSave)
.flatMap(uninitialized -> {
@@ -1300,7 +1345,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@Override
public <T> Mono<T> save(Mono<? extends T> objectToSave) {
Assert.notNull(objectToSave, "Mono to save must not be null!");
Assert.notNull(objectToSave, "Mono to save must not be null");
return objectToSave.flatMap(this::save);
}
@@ -1308,7 +1353,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@Override
public <T> Mono<T> save(Mono<? extends T> objectToSave, String collectionName) {
Assert.notNull(objectToSave, "Mono to save must not be null!");
Assert.notNull(objectToSave, "Mono to save must not be null");
return objectToSave.flatMap(o -> save(o, collectionName));
}
@@ -1316,15 +1361,15 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@Override
public <T> Mono<T> save(T objectToSave) {
Assert.notNull(objectToSave, "Object to save must not be null!");
Assert.notNull(objectToSave, "Object to save must not be null");
return save(objectToSave, getCollectionName(ClassUtils.getUserClass(objectToSave)));
}
@Override
public <T> Mono<T> save(T objectToSave, String collectionName) {
Assert.notNull(objectToSave, "Object to save must not be null!");
Assert.hasText(collectionName, "Collection name must not be null or empty!");
Assert.notNull(objectToSave, "Object to save must not be null");
Assert.hasText(collectionName, "Collection name must not be null or empty");
AdaptibleEntity<T> source = operations.forEntity(objectToSave, mongoConverter.getConversionService());
@@ -1403,7 +1448,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
.format("Inserting Document containing fields: " + dbDoc.keySet() + " in collection: " + collectionName));
}
Document document = new Document(dbDoc);
MappedDocument document = MappedDocument.of(dbDoc);
queryOperations.createInsertContext(document).prepareId(entityClass);
Flux<InsertOneResult> execute = execute(collectionName, collection -> {
@@ -1413,10 +1459,10 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
MongoCollection<Document> collectionToUse = prepareCollection(collection, writeConcernToUse);
return collectionToUse.insertOne(document);
return collectionToUse.insertOne(document.getDocument());
});
return Flux.from(execute).last().map(success -> MappedDocument.of(document).getId());
return Flux.from(execute).last().map(success -> document.getId());
}
protected Flux<ObjectId> insertDocumentList(String collectionName, List<Document> dbDocList) {
@@ -1429,7 +1475,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
LOGGER.debug(String.format("Inserting list of Documents containing %d items", dbDocList.size()));
}
List<Document> documents = new ArrayList<>();
List<Document> documents = new ArrayList<>(dbDocList.size());
return execute(collectionName, collection -> {
@@ -1480,7 +1526,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
Publisher<?> publisher;
if (!mapped.hasId()) {
publisher = collectionToUse.insertOne(document);
publisher = collectionToUse.insertOne(queryOperations.createInsertContext(mapped).prepareId(entityClass).getDocument());
} else {
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
@@ -1568,7 +1614,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
if (query.isSorted() && LOGGER.isWarnEnabled()) {
LOGGER.warn(String.format("%s does not support sort ('%s'). Please use findAndModify() instead.",
LOGGER.warn(String.format("%s does not support sort ('%s'); Please use findAndModify() instead",
upsert ? "Upsert" : "UpdateFirst", serializeToJsonSafely(query.getSortObject())));
}
@@ -1682,7 +1728,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@Override
public Mono<DeleteResult> remove(Object object) {
Assert.notNull(object, "Object must not be null!");
Assert.notNull(object, "Object must not be null");
return remove(operations.forEntity(object).getRemoveByQuery(), object.getClass());
}
@@ -1690,8 +1736,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@Override
public Mono<DeleteResult> remove(Object object, String collectionName) {
Assert.notNull(object, "Object must not be null!");
Assert.hasText(collectionName, "Collection name must not be null or empty!");
Assert.notNull(object, "Object must not be null");
Assert.hasText(collectionName, "Collection name must not be null or empty");
return doRemove(collectionName, operations.forEntity(object).getRemoveByQuery(), object.getClass());
}
@@ -1711,7 +1757,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
if (!MongoSimpleTypes.AUTOGENERATED_ID_TYPES.contains(property.getType())) {
throw new InvalidDataAccessApiUsageException(
String.format("Cannot autogenerate id of type %s for entity of type %s!", property.getType().getName(),
String.format("Cannot autogenerate id of type %s for entity of type %s", property.getType().getName(),
value.getClass().getName()));
}
}
@@ -1735,10 +1781,10 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
protected <T> Mono<DeleteResult> doRemove(String collectionName, Query query, @Nullable Class<T> entityClass) {
if (query == null) {
throw new InvalidDataAccessApiUsageException("Query passed in to remove can't be null!");
throw new InvalidDataAccessApiUsageException("Query passed in to remove can't be null");
}
Assert.hasText(collectionName, "Collection name must not be null or empty!");
Assert.hasText(collectionName, "Collection name must not be null or empty");
MongoPersistentEntity<?> entity = getPersistentEntity(entityClass);
@@ -1850,7 +1896,13 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
publisher = filter.isEmpty() ? db.watch(Document.class) : db.watch(filter, Document.class);
}
publisher = options.getResumeToken().map(BsonValue::asDocument).map(publisher::resumeAfter).orElse(publisher);
if (options.isResumeAfter()) {
publisher = options.getResumeToken().map(BsonValue::asDocument).map(publisher::resumeAfter)
.orElse(publisher);
} else if (options.isStartAfter()) {
publisher = options.getResumeToken().map(BsonValue::asDocument).map(publisher::startAfter)
.orElse(publisher);
}
publisher = options.getCollation().map(Collation::toMongoCollation).map(publisher::collation)
.orElse(publisher);
publisher = options.getResumeBsonTimestamp().map(publisher::startAtOperationTime).orElse(publisher);
@@ -1895,13 +1947,13 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
public <T> Flux<T> mapReduce(Query filterQuery, Class<?> domainType, String inputCollectionName, Class<T> resultType,
String mapFunction, String reduceFunction, MapReduceOptions options) {
Assert.notNull(filterQuery, "Filter query must not be null!");
Assert.notNull(domainType, "Domain type must not be null!");
Assert.hasText(inputCollectionName, "Input collection name must not be null or empty!");
Assert.notNull(resultType, "Result type must not be null!");
Assert.notNull(mapFunction, "Map function must not be null!");
Assert.notNull(reduceFunction, "Reduce function must not be null!");
Assert.notNull(options, "MapReduceOptions must not be null!");
Assert.notNull(filterQuery, "Filter query must not be null");
Assert.notNull(domainType, "Domain type must not be null");
Assert.hasText(inputCollectionName, "Input collection name must not be null or empty");
Assert.notNull(resultType, "Result type must not be null");
Assert.notNull(mapFunction, "Map function must not be null");
Assert.notNull(reduceFunction, "Reduce function must not be null");
Assert.notNull(options, "MapReduceOptions must not be null");
assertLocalFunctionNames(mapFunction, reduceFunction);
@@ -1927,7 +1979,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
if (filterQuery.getLimit() > 0 && (options.getLimit() != null)) {
throw new IllegalArgumentException(
"Both Query and MapReduceOptions define a limit. Please provide the limit only via one of the two.");
"Both Query and MapReduceOptions define a limit; Please provide the limit only via one of the two.");
}
if (filterQuery.getLimit() > 0) {
@@ -1943,7 +1995,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
Optionals.ifAllPresent(filterQuery.getCollation(), options.getCollation(), (l, r) -> {
throw new IllegalArgumentException(
"Both Query and MapReduceOptions define a collation. Please provide the collation only via one of the two.");
"Both Query and MapReduceOptions define a collation; Please provide the collation only via one of the two.");
});
if (options.getCollation().isPresent()) {
@@ -1992,7 +2044,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
if (ResourceUtils.isUrl(function)) {
throw new IllegalArgumentException(String.format(
"Blocking accessing to resource %s is not allowed using reactive infrastructure. You may load the resource at startup and cache its value.",
"Blocking accessing to resource %s is not allowed using reactive infrastructure; You may load the resource at startup and cache its value.",
function));
}
}
@@ -2324,11 +2376,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
}
protected <E extends MongoMappingEvent<T>, T> E maybeEmitEvent(E event) {
if (eventPublisher != null) {
eventPublisher.publishEvent(event);
}
eventDelegate.publishEvent(event);
return event;
}
@@ -2850,8 +2898,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
ReadDocumentCallback(EntityReader<? super T, Bson> reader, Class<T> type, String collectionName) {
Assert.notNull(reader, "EntityReader must not be null!");
Assert.notNull(type, "Entity type must not be null!");
Assert.notNull(reader, "EntityReader must not be null");
Assert.notNull(type, "Entity type must not be null");
this.reader = reader;
this.type = type;
@@ -2939,7 +2987,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
*/
GeoNearResultDocumentCallback(String distanceField, DocumentCallback<T> delegate, Metric metric) {
Assert.notNull(delegate, "DocumentCallback must not be null!");
Assert.notNull(delegate, "DocumentCallback must not be null");
this.distanceField = distanceField;
this.delegate = delegate;

View File

@@ -44,7 +44,7 @@ class ReactiveRemoveOperationSupport implements ReactiveRemoveOperation {
@Override
public <T> ReactiveRemove<T> remove(Class<T> domainType) {
Assert.notNull(domainType, "DomainType must not be null!");
Assert.notNull(domainType, "DomainType must not be null");
return new ReactiveRemoveSupport<>(tempate, domainType, ALL_QUERY, null);
}
@@ -67,7 +67,7 @@ class ReactiveRemoveOperationSupport implements ReactiveRemoveOperation {
@Override
public RemoveWithQuery<T> inCollection(String collection) {
Assert.hasText(collection, "Collection must not be null nor empty!");
Assert.hasText(collection, "Collection must not be null nor empty");
return new ReactiveRemoveSupport<>(template, domainType, query, collection);
}
@@ -75,7 +75,7 @@ class ReactiveRemoveOperationSupport implements ReactiveRemoveOperation {
@Override
public TerminatingRemove<T> matching(Query query) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(query, "Query must not be null");
return new ReactiveRemoveSupport<>(template, domainType, query, collection);
}

View File

@@ -45,7 +45,7 @@ class ReactiveUpdateOperationSupport implements ReactiveUpdateOperation {
@Override
public <T> ReactiveUpdate<T> update(Class<T> domainType) {
Assert.notNull(domainType, "DomainType must not be null!");
Assert.notNull(domainType, "DomainType must not be null");
return new ReactiveUpdateSupport<>(template, domainType, ALL_QUERY, null, null, null, null, null, domainType);
}
@@ -82,7 +82,7 @@ class ReactiveUpdateOperationSupport implements ReactiveUpdateOperation {
@Override
public TerminatingUpdate<T> apply(org.springframework.data.mongodb.core.query.UpdateDefinition update) {
Assert.notNull(update, "Update must not be null!");
Assert.notNull(update, "Update must not be null");
return new ReactiveUpdateSupport<>(template, domainType, query, update, collection, findAndModifyOptions,
findAndReplaceOptions, replacement, targetType);
@@ -91,7 +91,7 @@ class ReactiveUpdateOperationSupport implements ReactiveUpdateOperation {
@Override
public UpdateWithQuery<T> inCollection(String collection) {
Assert.hasText(collection, "Collection must not be null nor empty!");
Assert.hasText(collection, "Collection must not be null nor empty");
return new ReactiveUpdateSupport<>(template, domainType, query, update, collection, findAndModifyOptions,
findAndReplaceOptions, replacement, targetType);
@@ -127,7 +127,7 @@ class ReactiveUpdateOperationSupport implements ReactiveUpdateOperation {
@Override
public UpdateWithUpdate<T> matching(Query query) {
Assert.notNull(query, "Query must not be null!");
Assert.notNull(query, "Query must not be null");
return new ReactiveUpdateSupport<>(template, domainType, query, update, collection, findAndModifyOptions,
findAndReplaceOptions, replacement, targetType);
@@ -141,7 +141,7 @@ class ReactiveUpdateOperationSupport implements ReactiveUpdateOperation {
@Override
public TerminatingFindAndModify<T> withOptions(FindAndModifyOptions options) {
Assert.notNull(options, "Options must not be null!");
Assert.notNull(options, "Options must not be null");
return new ReactiveUpdateSupport<>(template, domainType, query, update, collection, options,
findAndReplaceOptions, replacement, targetType);
@@ -150,7 +150,7 @@ class ReactiveUpdateOperationSupport implements ReactiveUpdateOperation {
@Override
public FindAndReplaceWithProjection<T> replaceWith(T replacement) {
Assert.notNull(replacement, "Replacement must not be null!");
Assert.notNull(replacement, "Replacement must not be null");
return new ReactiveUpdateSupport<>(template, domainType, query, update, collection, findAndModifyOptions,
findAndReplaceOptions, replacement, targetType);
@@ -159,7 +159,7 @@ class ReactiveUpdateOperationSupport implements ReactiveUpdateOperation {
@Override
public FindAndReplaceWithProjection<T> withOptions(FindAndReplaceOptions options) {
Assert.notNull(options, "Options must not be null!");
Assert.notNull(options, "Options must not be null");
return new ReactiveUpdateSupport<>(template, domainType, query, update, collection, findAndModifyOptions, options,
replacement, targetType);
@@ -168,7 +168,7 @@ class ReactiveUpdateOperationSupport implements ReactiveUpdateOperation {
@Override
public <R> FindAndReplaceWithOptions<R> as(Class<R> resultType) {
Assert.notNull(resultType, "ResultType must not be null!");
Assert.notNull(resultType, "ResultType must not be null");
return new ReactiveUpdateSupport<>(template, domainType, query, update, collection, findAndModifyOptions,
findAndReplaceOptions, replacement, resultType);

View File

@@ -77,10 +77,10 @@ public class SimpleReactiveMongoDatabaseFactory implements DisposableBean, React
private SimpleReactiveMongoDatabaseFactory(MongoClient client, String databaseName, boolean mongoInstanceCreated) {
Assert.notNull(client, "MongoClient must not be null!");
Assert.hasText(databaseName, "Database name must not be empty!");
Assert.notNull(client, "MongoClient must not be null");
Assert.hasText(databaseName, "Database name must not be empty");
Assert.isTrue(databaseName.matches("[^/\\\\.$\"\\s]+"),
"Database name must not contain slashes, dots, spaces, quotes, or dollar signs!");
"Database name must not contain slashes, dots, spaces, quotes, or dollar signs");
this.mongo = client;
this.databaseName = databaseName;
@@ -103,7 +103,7 @@ public class SimpleReactiveMongoDatabaseFactory implements DisposableBean, React
public Mono<MongoDatabase> getMongoDatabase(String dbName) throws DataAccessException {
Assert.hasText(dbName, "Database name must not be empty.");
Assert.hasText(dbName, "Database name must not be empty");
return Mono.fromSupplier(() -> {

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2022 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 java.util.Optional;
import org.springframework.data.mongodb.core.query.Collation;
import org.springframework.lang.Nullable;
/**
* Immutable object holding additional options to be applied when creating a MongoDB
* <a href="https://www.mongodb.com/docs/manual/core/views/">views</a>.
*
* @author Christoph Strobl
* @since 4.0
*/
public class ViewOptions {
private final @Nullable Collation collation;
static ViewOptions none() {
return new ViewOptions();
}
/**
* Creates new instance of {@link ViewOptions}.
*/
public ViewOptions() {
this(null);
}
private ViewOptions(@Nullable Collation collation) {
this.collation = collation;
}
/**
* Get the {@link Collation} to be set.
*
* @return {@link Optional#empty()} if not set.
*/
public Optional<Collation> getCollation() {
return Optional.ofNullable(collation);
}
/**
* @param collation the {@link Collation} to use for language-specific string comparison.
* @return new instance of {@link ViewOptions}.
*/
public ViewOptions collation(Collation collation) {
return new ViewOptions(collation);
}
}

View File

@@ -19,12 +19,16 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.bson.Document;
import org.springframework.data.mongodb.core.aggregation.Aggregation.SystemVariable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
@@ -69,8 +73,31 @@ abstract class AbstractAggregationExpression implements AggregationExpression {
return ((AggregationExpression) value).toDocument(context);
}
if (value instanceof Field) {
return context.getReference((Field) value).toString();
if (value instanceof Field field) {
return context.getReference(field).toString();
}
if (value instanceof Fields fields) {
List<Object> mapped = new ArrayList<>(fields.size());
for (Field field : fields) {
mapped.add(unpack(field, context));
}
return mapped;
}
if (value instanceof Sort sort) {
Document sortDoc = new Document();
for (Order order : sort) {
// Check reference
FieldReference reference = context.getReference(order.getProperty());
sortDoc.put(reference.getRaw(), order.isAscending() ? 1 : -1);
}
return sortDoc;
}
if (value instanceof List) {
@@ -78,7 +105,9 @@ abstract class AbstractAggregationExpression implements AggregationExpression {
List<Object> sourceList = (List<Object>) value;
List<Object> mappedList = new ArrayList<>(sourceList.size());
sourceList.stream().map((item) -> unpack(item, context)).forEach(mappedList::add);
for (Object o : sourceList) {
mappedList.add(unpack(o, context));
}
return mappedList;
}
@@ -130,21 +159,53 @@ abstract class AbstractAggregationExpression implements AggregationExpression {
return append(value, Expand.EXPAND_VALUES);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@SuppressWarnings({ "unchecked" })
protected Map<String, Object> append(String key, Object value) {
Assert.isInstanceOf(Map.class, this.value, "Value must be a type of Map!");
Assert.isInstanceOf(Map.class, this.value, "Value must be a type of Map");
Map<String, Object> clone = new LinkedHashMap<>((java.util.Map) this.value);
return append((Map<String, Object>) this.value, key, value);
}
private Map<String, Object> append(Map<String, Object> existing, String key, Object value) {
Map<String, Object> clone = new LinkedHashMap<>(existing);
clone.put(key, value);
return clone;
}
@SuppressWarnings("rawtypes")
protected Map<String, Object> appendTo(String key, Object value) {
Assert.isInstanceOf(Map.class, this.value, "Value must be a type of Map");
if (this.value instanceof Map map) {
Map<String, Object> target = new HashMap<>(map);
if (!target.containsKey(key)) {
target.put(key, value);
return target;
}
target.computeIfPresent(key, (k, v) -> {
if (v instanceof List<?> list) {
List<Object> targetList = new ArrayList<>(list);
targetList.add(value);
return targetList;
}
return Arrays.asList(v, value);
});
return target;
}
throw new IllegalStateException(
String.format("Cannot append value to %s type", ObjectUtils.nullSafeClassName(this.value)));
}
@SuppressWarnings({ "unchecked", "rawtypes" })
protected Map<String, Object> remove(String key) {
Assert.isInstanceOf(Map.class, this.value, "Value must be a type of Map!");
Assert.isInstanceOf(Map.class, this.value, "Value must be a type of Map");
Map<String, Object> clone = new LinkedHashMap<>((java.util.Map) this.value);
clone.remove(key);
@@ -163,7 +224,7 @@ abstract class AbstractAggregationExpression implements AggregationExpression {
@SuppressWarnings({ "unchecked" })
protected Map<String, Object> appendAt(int index, String key, Object value) {
Assert.isInstanceOf(Map.class, this.value, "Value must be a type of Map!");
Assert.isInstanceOf(Map.class, this.value, "Value must be a type of Map");
Map<String, Object> clone = new LinkedHashMap<>();
@@ -223,11 +284,15 @@ abstract class AbstractAggregationExpression implements AggregationExpression {
@SuppressWarnings("unchecked")
protected <T> T get(Object key) {
Assert.isInstanceOf(Map.class, this.value, "Value must be a type of Map!");
Assert.isInstanceOf(Map.class, this.value, "Value must be a type of Map");
return (T) ((Map<String, Object>) this.value).get(key);
}
protected boolean isArgumentMap() {
return this.value instanceof Map;
}
/**
* Get the argument map.
*
@@ -237,7 +302,7 @@ abstract class AbstractAggregationExpression implements AggregationExpression {
@SuppressWarnings("unchecked")
protected Map<String, Object> argumentMap() {
Assert.isInstanceOf(Map.class, this.value, "Value must be a type of Map!");
Assert.isInstanceOf(Map.class, this.value, "Value must be a type of Map");
return Collections.unmodifiableMap((java.util.Map<String, Object>) value);
}

View File

@@ -65,7 +65,7 @@ public class AccumulatorOperators {
*/
public AccumulatorOperatorFactory(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
this.fieldReference = fieldReference;
this.expression = null;
}
@@ -77,7 +77,7 @@ public class AccumulatorOperators {
*/
public AccumulatorOperatorFactory(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
this.fieldReference = null;
this.expression = expression;
}
@@ -112,6 +112,17 @@ public class AccumulatorOperators {
return usesFieldRef() ? Max.maxOf(fieldReference) : Max.maxOf(expression);
}
/**
* Creates new {@link AggregationExpression} that takes the associated numeric value expression and returns the
* requested number of maximum values.
*
* @return new instance of {@link Max}.
* @since 4.0
*/
public Max max(int numberOfResults) {
return max().limit(numberOfResults);
}
/**
* Creates new {@link AggregationExpression} that takes the associated numeric value expression and returns the
* minimum value.
@@ -122,6 +133,17 @@ public class AccumulatorOperators {
return usesFieldRef() ? Min.minOf(fieldReference) : Min.minOf(expression);
}
/**
* Creates new {@link AggregationExpression} that takes the associated numeric value expression and returns the
* requested number of maximum values.
*
* @return new instance of {@link Max}.
* @since 4.0
*/
public Min min(int numberOfResults) {
return min().limit(numberOfResults);
}
/**
* Creates new {@link AggregationExpression} that takes the associated numeric value expression and calculates the
* population standard deviation of the input values.
@@ -278,7 +300,7 @@ public class AccumulatorOperators {
*/
public static Sum sumOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Sum(asFields(fieldReference));
}
@@ -290,7 +312,7 @@ public class AccumulatorOperators {
*/
public static Sum sumOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Sum(Collections.singletonList(expression));
}
@@ -303,7 +325,7 @@ public class AccumulatorOperators {
*/
public Sum and(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Sum(append(Fields.field(fieldReference)));
}
@@ -316,7 +338,7 @@ public class AccumulatorOperators {
*/
public Sum and(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Sum(append(expression));
}
@@ -330,7 +352,7 @@ public class AccumulatorOperators {
*/
public Sum and(Number value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return new Sum(append(value));
}
@@ -372,7 +394,7 @@ public class AccumulatorOperators {
*/
public static Avg avgOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Avg(asFields(fieldReference));
}
@@ -384,7 +406,7 @@ public class AccumulatorOperators {
*/
public static Avg avgOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Avg(Collections.singletonList(expression));
}
@@ -397,7 +419,7 @@ public class AccumulatorOperators {
*/
public Avg and(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Avg(append(Fields.field(fieldReference)));
}
@@ -410,7 +432,7 @@ public class AccumulatorOperators {
*/
public Avg and(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Avg(append(expression));
}
@@ -441,7 +463,7 @@ public class AccumulatorOperators {
@Override
protected String getMongoMethod() {
return "$max";
return contains("n") ? "$maxN" : "$max";
}
/**
@@ -452,8 +474,8 @@ public class AccumulatorOperators {
*/
public static Max maxOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Max(asFields(fieldReference));
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Max(Collections.singletonMap("input", Fields.field(fieldReference)));
}
/**
@@ -464,8 +486,8 @@ public class AccumulatorOperators {
*/
public static Max maxOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Max(Collections.singletonList(expression));
Assert.notNull(expression, "Expression must not be null");
return new Max(Collections.singletonMap("input", expression));
}
/**
@@ -477,8 +499,8 @@ public class AccumulatorOperators {
*/
public Max and(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Max(append(Fields.field(fieldReference)));
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Max(appendTo("input", Fields.field(fieldReference)));
}
/**
@@ -490,8 +512,27 @@ public class AccumulatorOperators {
*/
public Max and(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Max(append(expression));
Assert.notNull(expression, "Expression must not be null");
return new Max(appendTo("input", expression));
}
/**
* Creates new {@link Max} that returns the given number of maxmimum values ({@literal $maxN}).
* <strong>NOTE</strong>: Cannot be used with more than one {@literal input} value.
*
* @param numberOfResults
* @return new instance of {@link Max}.
*/
public Max limit(int numberOfResults) {
return new Max(append("n", numberOfResults));
}
@Override
public Document toDocument(AggregationOperationContext context) {
if (get("n") == null) {
return toDocument(get("input"), context);
}
return super.toDocument(context);
}
@Override
@@ -521,7 +562,7 @@ public class AccumulatorOperators {
@Override
protected String getMongoMethod() {
return "$min";
return contains("n") ? "$minN" : "$min";
}
/**
@@ -532,8 +573,8 @@ public class AccumulatorOperators {
*/
public static Min minOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Min(asFields(fieldReference));
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Min(Collections.singletonMap("input", Fields.field(fieldReference)));
}
/**
@@ -544,8 +585,8 @@ public class AccumulatorOperators {
*/
public static Min minOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Min(Collections.singletonList(expression));
Assert.notNull(expression, "Expression must not be null");
return new Min(Collections.singletonMap("input", expression));
}
/**
@@ -557,8 +598,8 @@ public class AccumulatorOperators {
*/
public Min and(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Min(append(Fields.field(fieldReference)));
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Min(appendTo("input", Fields.field(fieldReference)));
}
/**
@@ -570,8 +611,28 @@ public class AccumulatorOperators {
*/
public Min and(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Min(append(expression));
Assert.notNull(expression, "Expression must not be null");
return new Min(appendTo("input", expression));
}
/**
* Creates new {@link Min} that returns the given number of minimum values ({@literal $minN}).
* <strong>NOTE</strong>: Cannot be used with more than one {@literal input} value.
*
* @param numberOfResults
* @return new instance of {@link Min}.
*/
public Min limit(int numberOfResults) {
return new Min(append("n", numberOfResults));
}
@Override
public Document toDocument(AggregationOperationContext context) {
if (get("n") == null) {
return toDocument(get("input"), context);
}
return super.toDocument(context);
}
@Override
@@ -612,7 +673,7 @@ public class AccumulatorOperators {
*/
public static StdDevPop stdDevPopOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new StdDevPop(asFields(fieldReference));
}
@@ -624,7 +685,7 @@ public class AccumulatorOperators {
*/
public static StdDevPop stdDevPopOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new StdDevPop(Collections.singletonList(expression));
}
@@ -637,7 +698,7 @@ public class AccumulatorOperators {
*/
public StdDevPop and(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new StdDevPop(append(Fields.field(fieldReference)));
}
@@ -650,7 +711,7 @@ public class AccumulatorOperators {
*/
public StdDevPop and(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new StdDevPop(append(expression));
}
@@ -692,7 +753,7 @@ public class AccumulatorOperators {
*/
public static StdDevSamp stdDevSampOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new StdDevSamp(asFields(fieldReference));
}
@@ -704,7 +765,7 @@ public class AccumulatorOperators {
*/
public static StdDevSamp stdDevSampOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new StdDevSamp(Collections.singletonList(expression));
}
@@ -717,7 +778,7 @@ public class AccumulatorOperators {
*/
public StdDevSamp and(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new StdDevSamp(append(Fields.field(fieldReference)));
}
@@ -730,7 +791,7 @@ public class AccumulatorOperators {
*/
public StdDevSamp and(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new StdDevSamp(append(expression));
}
@@ -768,7 +829,7 @@ public class AccumulatorOperators {
*/
public static CovariancePop covariancePopOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new CovariancePop(asFields(fieldReference));
}
@@ -828,7 +889,7 @@ public class AccumulatorOperators {
*/
public static CovarianceSamp covarianceSampOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new CovarianceSamp(asFields(fieldReference));
}

View File

@@ -21,6 +21,7 @@ import java.util.Arrays;
import java.util.List;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mongodb.core.aggregation.AddFieldsOperation.AddFieldsOperationBuilder;
@@ -34,7 +35,6 @@ import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.SerializationUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -138,7 +138,7 @@ public class Aggregation {
*/
public Aggregation withOptions(AggregationOptions options) {
Assert.notNull(options, "AggregationOptions must not be null.");
Assert.notNull(options, "AggregationOptions must not be null");
return new Aggregation(this.pipeline.getOperations(), options);
}
@@ -177,7 +177,7 @@ public class Aggregation {
*/
protected static List<AggregationOperation> asAggregationList(AggregationOperation... aggregationOperations) {
Assert.notEmpty(aggregationOperations, "AggregationOperations must not be null or empty!");
Assert.notEmpty(aggregationOperations, "AggregationOperations must not be null or empty");
return Arrays.asList(aggregationOperations);
}
@@ -199,8 +199,8 @@ public class Aggregation {
*/
protected Aggregation(List<AggregationOperation> aggregationOperations, AggregationOptions options) {
Assert.notNull(aggregationOperations, "AggregationOperations must not be null!");
Assert.notNull(options, "AggregationOptions must not be null!");
Assert.notNull(aggregationOperations, "AggregationOperations must not be null");
Assert.notNull(options, "AggregationOptions must not be null");
this.pipeline = new AggregationPipeline(aggregationOperations);
this.options = options;
@@ -238,6 +238,40 @@ public class Aggregation {
return AddFieldsOperation.builder();
}
/**
* Creates a new {@link AggregationOperation} taking the given {@link Bson bson value} as is. <br />
*
* <pre class="code">
* Aggregation.stage(Aggregates.search(exists(fieldPath("..."))));
* </pre>
*
* Field mapping against a potential domain type or previous aggregation stages will not happen.
*
* @param aggregationOperation the must not be {@literal null}.
* @return new instance of {@link AggregationOperation}.
* @since 4.0
*/
public static AggregationOperation stage(Bson aggregationOperation) {
return new BasicAggregationOperation(aggregationOperation);
}
/**
* Creates a new {@link AggregationOperation} taking the given {@link String json value} as is. <br />
*
* <pre class="code">
* Aggregation.stage("{ $search : { near : { path : 'released' , origin : ... } } }");
* </pre>
*
* Field mapping against a potential domain type or previous aggregation stages will not happen.
*
* @param json the JSON representation of the pipeline stage. Must not be {@literal null}.
* @return new instance of {@link AggregationOperation}.
* @since 4.0
*/
public static AggregationOperation stage(String json) {
return new BasicAggregationOperation(json);
}
/**
* Creates a new {@link ProjectionOperation} including the given fields.
*
@@ -267,7 +301,7 @@ public class Aggregation {
*/
public static ProjectionOperation project(Class<?> type) {
Assert.notNull(type, "Type must not be null!");
Assert.notNull(type, "Type must not be null");
return new ProjectionOperation(type);
}
@@ -731,48 +765,4 @@ public class Aggregation {
public String toString() {
return SerializationUtils.serializeToJsonSafely(toDocument("__collection__", DEFAULT_CONTEXT));
}
/**
* Describes the system variables available in MongoDB aggregation framework pipeline expressions.
*
* @author Thomas Darimont
* @author Christoph Strobl
* @see <a href="https://docs.mongodb.com/manual/reference/aggregation-variables">Aggregation Variables</a>.
*/
enum SystemVariable {
ROOT, CURRENT, REMOVE;
private static final String PREFIX = "$$";
/**
* Return {@literal true} if the given {@code fieldRef} denotes a well-known system variable, {@literal false}
* otherwise.
*
* @param fieldRef may be {@literal null}.
* @return {@literal true} if the given field refers to a {@link SystemVariable}.
*/
public static boolean isReferingToSystemVariable(@Nullable String fieldRef) {
if (fieldRef == null || !fieldRef.startsWith(PREFIX) || fieldRef.length() <= 2) {
return false;
}
int indexOfFirstDot = fieldRef.indexOf('.');
String candidate = fieldRef.substring(2, indexOfFirstDot == -1 ? fieldRef.length() : indexOfFirstDot);
for (SystemVariable value : values()) {
if (value.name().equals(candidate)) {
return true;
}
}
return false;
}
@Override
public String toString() {
return PREFIX.concat(name());
}
}
}

View File

@@ -60,7 +60,7 @@ interface AggregationExpressionTransformer
super(currentNode, parentNode, previousOperationObject);
Assert.notNull(context, "AggregationOperationContext must not be null!");
Assert.notNull(context, "AggregationOperationContext must not be null");
this.aggregationContext = context;
}

View File

@@ -20,12 +20,16 @@ import java.lang.reflect.Method;
import java.util.Arrays;
import org.bson.Document;
import org.bson.codecs.configuration.CodecRegistry;
import org.springframework.beans.BeanUtils;
import org.springframework.data.mongodb.CodecRegistryProvider;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import com.mongodb.MongoClientSettings;
/**
* The context for an {@link AggregationOperation}.
*
@@ -33,7 +37,7 @@ import org.springframework.util.ReflectionUtils;
* @author Christoph Strobl
* @since 1.3
*/
public interface AggregationOperationContext {
public interface AggregationOperationContext extends CodecRegistryProvider {
/**
* Returns the mapped {@link Document}, potentially converting the source considering mapping metadata etc.
@@ -86,7 +90,7 @@ public interface AggregationOperationContext {
*/
default Fields getFields(Class<?> type) {
Assert.notNull(type, "Type must not be null!");
Assert.notNull(type, "Type must not be null");
return Fields.fields(Arrays.stream(BeanUtils.getPropertyDescriptors(type)) //
.filter(it -> { // object and default methods
@@ -114,4 +118,9 @@ public interface AggregationOperationContext {
default AggregationOperationContext continueOnMissingFieldReference() {
return this;
}
@Override
default CodecRegistry getCodecRegistry() {
return MongoClientSettings.getDefaultCodecRegistry();
}
}

View File

@@ -144,7 +144,7 @@ public class AggregationOptions {
*/
public static AggregationOptions fromDocument(Document document) {
Assert.notNull(document, "Document must not be null!");
Assert.notNull(document, "Document must not be null");
boolean allowDiskUse = document.getBoolean(ALLOW_DISK_USE, false);
boolean explain = document.getBoolean(EXPLAIN, false);

View File

@@ -16,6 +16,7 @@
package org.springframework.data.mongodb.core.aggregation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
@@ -34,6 +35,10 @@ public class AggregationPipeline {
private final List<AggregationOperation> pipeline;
public static AggregationPipeline of(AggregationOperation... stages) {
return new AggregationPipeline(Arrays.asList(stages));
}
/**
* Create an empty pipeline
*/
@@ -48,7 +53,7 @@ public class AggregationPipeline {
*/
public AggregationPipeline(List<AggregationOperation> aggregationOperations) {
Assert.notNull(aggregationOperations, "AggregationOperations must not be null!");
Assert.notNull(aggregationOperations, "AggregationOperations must not be null");
pipeline = new ArrayList<>(aggregationOperations);
}
@@ -60,7 +65,7 @@ public class AggregationPipeline {
*/
public AggregationPipeline add(AggregationOperation aggregationOperation) {
Assert.notNull(aggregationOperation, "AggregationOperation must not be null!");
Assert.notNull(aggregationOperation, "AggregationOperation must not be null");
pipeline.add(aggregationOperation);
return this;
@@ -100,11 +105,11 @@ public class AggregationPipeline {
for (AggregationOperation operation : pipeline) {
if (isOut(operation) && !isLast(operation)) {
throw new IllegalArgumentException("The $out operator must be the last stage in the pipeline.");
throw new IllegalArgumentException("The $out operator must be the last stage in the pipeline");
}
if (isMerge(operation) && !isLast(operation)) {
throw new IllegalArgumentException("The $merge operator must be the last stage in the pipeline.");
throw new IllegalArgumentException("The $merge operator must be the last stage in the pipeline");
}
}
}

View File

@@ -48,8 +48,8 @@ public class AggregationResults<T> implements Iterable<T> {
*/
public AggregationResults(List<T> mappedResults, Document rawResults) {
Assert.notNull(mappedResults, "List of mapped results must not be null!");
Assert.notNull(rawResults, "Raw results must not be null!");
Assert.notNull(mappedResults, "List of mapped results must not be null");
Assert.notNull(rawResults, "Raw results must not be null");
this.mappedResults = Collections.unmodifiableList(mappedResults);
this.rawResults = rawResults;
@@ -73,7 +73,7 @@ public class AggregationResults<T> implements Iterable<T> {
*/
@Nullable
public T getUniqueMappedResult() {
Assert.isTrue(mappedResults.size() < 2, "Expected unique result or null, but got more than one!");
Assert.isTrue(mappedResults.size() < 2, "Expected unique result or null, but got more than one");
return mappedResults.size() == 1 ? mappedResults.get(0) : null;
}

View File

@@ -60,7 +60,7 @@ public class AggregationSpELExpression implements AggregationExpression {
*/
public static AggregationSpELExpression expressionOf(String expressionString, Object... parameters) {
Assert.notNull(expressionString, "ExpressionString must not be null!");
Assert.notNull(expressionString, "ExpressionString must not be null");
return new AggregationSpELExpression(expressionString, parameters);
}

View File

@@ -133,7 +133,7 @@ public class AggregationUpdate extends Aggregation implements UpdateDefinition {
*/
public AggregationUpdate set(SetOperation setOperation) {
Assert.notNull(setOperation, "SetOperation must not be null!");
Assert.notNull(setOperation, "SetOperation must not be null");
setOperation.getFields().forEach(it -> {
keysTouched.add(it.getName());
@@ -152,7 +152,7 @@ public class AggregationUpdate extends Aggregation implements UpdateDefinition {
*/
public AggregationUpdate unset(UnsetOperation unsetOperation) {
Assert.notNull(unsetOperation, "UnsetOperation must not be null!");
Assert.notNull(unsetOperation, "UnsetOperation must not be null");
pipeline.add(unsetOperation);
keysTouched.addAll(unsetOperation.removedFieldNames());
@@ -170,7 +170,7 @@ public class AggregationUpdate extends Aggregation implements UpdateDefinition {
*/
public AggregationUpdate replaceWith(ReplaceWithOperation replaceWithOperation) {
Assert.notNull(replaceWithOperation, "ReplaceWithOperation must not be null!");
Assert.notNull(replaceWithOperation, "ReplaceWithOperation must not be null");
pipeline.add(replaceWithOperation);
return this;
}
@@ -183,7 +183,7 @@ public class AggregationUpdate extends Aggregation implements UpdateDefinition {
*/
public AggregationUpdate replaceWith(Object value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return replaceWith(ReplaceWithOperation.replaceWithValue(value));
}
@@ -197,7 +197,7 @@ public class AggregationUpdate extends Aggregation implements UpdateDefinition {
*/
public SetValueAppender set(String key) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(key, "Key must not be null");
return new SetValueAppender() {
@@ -209,7 +209,7 @@ public class AggregationUpdate extends Aggregation implements UpdateDefinition {
@Override
public AggregationUpdate toValueOf(Object value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return set(SetOperation.builder().set(key).toValueOf(value));
}
};
@@ -223,8 +223,8 @@ public class AggregationUpdate extends Aggregation implements UpdateDefinition {
*/
public AggregationUpdate unset(String... keys) {
Assert.notNull(keys, "Keys must not be null!");
Assert.noNullElements(keys, "Keys must not contain null elements.");
Assert.notNull(keys, "Keys must not be null");
Assert.noNullElements(keys, "Keys must not contain null elements");
return unset(new UnsetOperation(Arrays.stream(keys).map(Fields::field).collect(Collectors.toList())));
}

View File

@@ -36,11 +36,11 @@ interface AggregationUtils {
*/
static List<Long> toRangeValues(Range<Long> range) {
Assert.notNull(range, "Range must not be null!");
Assert.notNull(range, "Range must not be null");
List<Long> result = new ArrayList<Long>(2);
result.add(range.getLowerBound().getValue()
.orElseThrow(() -> new IllegalArgumentException("Lower bound of range must be bounded!")));
.orElseThrow(() -> new IllegalArgumentException("Lower bound of range must be bounded")));
range.getUpperBound().getValue().ifPresent(it -> result.add(it));
return result;

View File

@@ -91,7 +91,7 @@ public class ArithmeticOperators {
*/
public ArithmeticOperatorFactory(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
this.fieldReference = fieldReference;
this.expression = null;
}
@@ -103,7 +103,7 @@ public class ArithmeticOperators {
*/
public ArithmeticOperatorFactory(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
this.fieldReference = null;
this.expression = expression;
}
@@ -126,7 +126,7 @@ public class ArithmeticOperators {
*/
public Add add(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return createAdd().add(fieldReference);
}
@@ -139,7 +139,7 @@ public class ArithmeticOperators {
*/
public Add add(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return createAdd().add(expression);
}
@@ -151,7 +151,7 @@ public class ArithmeticOperators {
*/
public Add add(Number value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return createAdd().add(value);
}
@@ -218,7 +218,7 @@ public class ArithmeticOperators {
*/
public Divide divideBy(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return createDivide().divideBy(fieldReference);
}
@@ -231,7 +231,7 @@ public class ArithmeticOperators {
*/
public Divide divideBy(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return createDivide().divideBy(expression);
}
@@ -243,7 +243,7 @@ public class ArithmeticOperators {
*/
public Divide divideBy(Number value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return createDivide().divideBy(value);
}
@@ -304,7 +304,7 @@ public class ArithmeticOperators {
*/
public Integral integral(String unit) {
Assert.hasText(unit, "Unit must not be empty!");
Assert.hasText(unit, "Unit must not be empty");
return integral().unit(unit);
}
@@ -328,7 +328,7 @@ public class ArithmeticOperators {
*/
public Log log(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return createLog().log(fieldReference);
}
@@ -341,7 +341,7 @@ public class ArithmeticOperators {
*/
public Log log(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return createLog().log(fieldReference);
}
@@ -354,7 +354,7 @@ public class ArithmeticOperators {
*/
public Log log(Number base) {
Assert.notNull(base, "Base must not be null!");
Assert.notNull(base, "Base must not be null");
return createLog().log(base);
}
@@ -380,7 +380,7 @@ public class ArithmeticOperators {
*/
public Mod mod(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return createMod().mod(fieldReference);
}
@@ -393,7 +393,7 @@ public class ArithmeticOperators {
*/
public Mod mod(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return createMod().mod(expression);
}
@@ -406,7 +406,7 @@ public class ArithmeticOperators {
*/
public Mod mod(Number value) {
Assert.notNull(value, "Base must not be null!");
Assert.notNull(value, "Base must not be null");
return createMod().mod(value);
}
@@ -422,7 +422,7 @@ public class ArithmeticOperators {
*/
public Multiply multiplyBy(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return createMultiply().multiplyBy(fieldReference);
}
@@ -434,7 +434,7 @@ public class ArithmeticOperators {
*/
public Multiply multiplyBy(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return createMultiply().multiplyBy(expression);
}
@@ -446,7 +446,7 @@ public class ArithmeticOperators {
*/
public Multiply multiplyBy(Number value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return createMultiply().multiplyBy(value);
}
@@ -462,7 +462,7 @@ public class ArithmeticOperators {
*/
public Pow pow(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return createPow().pow(fieldReference);
}
@@ -474,7 +474,7 @@ public class ArithmeticOperators {
*/
public Pow pow(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return createPow().pow(expression);
}
@@ -486,7 +486,7 @@ public class ArithmeticOperators {
*/
public Pow pow(Number value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return createPow().pow(value);
}
@@ -511,7 +511,7 @@ public class ArithmeticOperators {
*/
public Subtract subtract(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return createSubtract().subtract(fieldReference);
}
@@ -523,7 +523,7 @@ public class ArithmeticOperators {
*/
public Subtract subtract(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return createSubtract().subtract(expression);
}
@@ -535,7 +535,7 @@ public class ArithmeticOperators {
*/
public Subtract subtract(Number value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return createSubtract().subtract(value);
}
@@ -851,7 +851,7 @@ public class ArithmeticOperators {
*/
public ATan2 atan2(Number value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return createATan2().atan2of(value);
}
@@ -865,7 +865,7 @@ public class ArithmeticOperators {
*/
public ATan2 atan2(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return createATan2().atan2of(fieldReference);
}
@@ -879,7 +879,7 @@ public class ArithmeticOperators {
*/
public ATan2 atan2(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return createATan2().atan2of(expression);
}
@@ -961,7 +961,7 @@ public class ArithmeticOperators {
*/
public static Abs absoluteValueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Abs(Fields.field(fieldReference));
}
@@ -973,7 +973,7 @@ public class ArithmeticOperators {
*/
public static Abs absoluteValueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Abs(expression);
}
@@ -985,7 +985,7 @@ public class ArithmeticOperators {
*/
public static Abs absoluteValueOf(Number value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return new Abs(value);
}
}
@@ -1014,7 +1014,7 @@ public class ArithmeticOperators {
*/
public static Add valueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Add(asFields(fieldReference));
}
@@ -1026,7 +1026,7 @@ public class ArithmeticOperators {
*/
public static Add valueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Add(Collections.singletonList(expression));
}
@@ -1038,7 +1038,7 @@ public class ArithmeticOperators {
*/
public static Add valueOf(Number value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return new Add(Collections.singletonList(value));
}
@@ -1050,7 +1050,7 @@ public class ArithmeticOperators {
*/
public Add add(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Add(append(Fields.field(fieldReference)));
}
@@ -1062,7 +1062,7 @@ public class ArithmeticOperators {
*/
public Add add(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Add(append(expression));
}
@@ -1101,7 +1101,7 @@ public class ArithmeticOperators {
*/
public static Ceil ceilValueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Ceil(Fields.field(fieldReference));
}
@@ -1113,7 +1113,7 @@ public class ArithmeticOperators {
*/
public static Ceil ceilValueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Ceil(expression);
}
@@ -1125,7 +1125,7 @@ public class ArithmeticOperators {
*/
public static Ceil ceilValueOf(Number value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return new Ceil(value);
}
}
@@ -1154,7 +1154,7 @@ public class ArithmeticOperators {
*/
public static Divide valueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Divide(asFields(fieldReference));
}
@@ -1166,7 +1166,7 @@ public class ArithmeticOperators {
*/
public static Divide valueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Divide(Collections.singletonList(expression));
}
@@ -1178,7 +1178,7 @@ public class ArithmeticOperators {
*/
public static Divide valueOf(Number value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return new Divide(Collections.singletonList(value));
}
@@ -1190,7 +1190,7 @@ public class ArithmeticOperators {
*/
public Divide divideBy(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Divide(append(Fields.field(fieldReference)));
}
@@ -1202,7 +1202,7 @@ public class ArithmeticOperators {
*/
public Divide divideBy(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Divide(append(expression));
}
@@ -1241,7 +1241,7 @@ public class ArithmeticOperators {
*/
public static Exp expValueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Exp(Fields.field(fieldReference));
}
@@ -1253,7 +1253,7 @@ public class ArithmeticOperators {
*/
public static Exp expValueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Exp(expression);
}
@@ -1265,7 +1265,7 @@ public class ArithmeticOperators {
*/
public static Exp expValueOf(Number value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return new Exp(value);
}
}
@@ -1294,7 +1294,7 @@ public class ArithmeticOperators {
*/
public static Floor floorValueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Floor(Fields.field(fieldReference));
}
@@ -1306,7 +1306,7 @@ public class ArithmeticOperators {
*/
public static Floor floorValueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Floor(expression);
}
@@ -1318,7 +1318,7 @@ public class ArithmeticOperators {
*/
public static Floor floorValueOf(Number value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return new Floor(value);
}
}
@@ -1347,7 +1347,7 @@ public class ArithmeticOperators {
*/
public static Ln lnValueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Ln(Fields.field(fieldReference));
}
@@ -1359,7 +1359,7 @@ public class ArithmeticOperators {
*/
public static Ln lnValueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Ln(expression);
}
@@ -1371,7 +1371,7 @@ public class ArithmeticOperators {
*/
public static Ln lnValueOf(Number value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return new Ln(value);
}
}
@@ -1400,7 +1400,7 @@ public class ArithmeticOperators {
*/
public static Log valueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Log(asFields(fieldReference));
}
@@ -1412,7 +1412,7 @@ public class ArithmeticOperators {
*/
public static Log valueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Log(Collections.singletonList(expression));
}
@@ -1424,7 +1424,7 @@ public class ArithmeticOperators {
*/
public static Log valueOf(Number value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return new Log(Collections.singletonList(value));
}
@@ -1436,7 +1436,7 @@ public class ArithmeticOperators {
*/
public Log log(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Log(append(Fields.field(fieldReference)));
}
@@ -1448,7 +1448,7 @@ public class ArithmeticOperators {
*/
public Log log(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Log(append(expression));
}
@@ -1487,7 +1487,7 @@ public class ArithmeticOperators {
*/
public static Log10 log10ValueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Log10(Fields.field(fieldReference));
}
@@ -1499,7 +1499,7 @@ public class ArithmeticOperators {
*/
public static Log10 log10ValueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Log10(expression);
}
@@ -1511,7 +1511,7 @@ public class ArithmeticOperators {
*/
public static Log10 log10ValueOf(Number value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return new Log10(value);
}
}
@@ -1540,7 +1540,7 @@ public class ArithmeticOperators {
*/
public static Mod valueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Mod(asFields(fieldReference));
}
@@ -1552,7 +1552,7 @@ public class ArithmeticOperators {
*/
public static Mod valueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Mod(Collections.singletonList(expression));
}
@@ -1564,7 +1564,7 @@ public class ArithmeticOperators {
*/
public static Mod valueOf(Number value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return new Mod(Collections.singletonList(value));
}
@@ -1576,7 +1576,7 @@ public class ArithmeticOperators {
*/
public Mod mod(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Mod(append(Fields.field(fieldReference)));
}
@@ -1588,7 +1588,7 @@ public class ArithmeticOperators {
*/
public Mod mod(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Mod(append(expression));
}
@@ -1627,7 +1627,7 @@ public class ArithmeticOperators {
*/
public static Multiply valueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Multiply(asFields(fieldReference));
}
@@ -1639,7 +1639,7 @@ public class ArithmeticOperators {
*/
public static Multiply valueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Multiply(Collections.singletonList(expression));
}
@@ -1651,7 +1651,7 @@ public class ArithmeticOperators {
*/
public static Multiply valueOf(Number value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return new Multiply(Collections.singletonList(value));
}
@@ -1663,7 +1663,7 @@ public class ArithmeticOperators {
*/
public Multiply multiplyBy(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Multiply(append(Fields.field(fieldReference)));
}
@@ -1675,7 +1675,7 @@ public class ArithmeticOperators {
*/
public Multiply multiplyBy(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Multiply(append(expression));
}
@@ -1714,7 +1714,7 @@ public class ArithmeticOperators {
*/
public static Pow valueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Pow(asFields(fieldReference));
}
@@ -1726,7 +1726,7 @@ public class ArithmeticOperators {
*/
public static Pow valueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Pow(Collections.singletonList(expression));
}
@@ -1738,7 +1738,7 @@ public class ArithmeticOperators {
*/
public static Pow valueOf(Number value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return new Pow(Collections.singletonList(value));
}
@@ -1750,7 +1750,7 @@ public class ArithmeticOperators {
*/
public Pow pow(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Pow(append(Fields.field(fieldReference)));
}
@@ -1762,7 +1762,7 @@ public class ArithmeticOperators {
*/
public Pow pow(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Pow(append(expression));
}
@@ -1801,7 +1801,7 @@ public class ArithmeticOperators {
*/
public static Sqrt sqrtOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Sqrt(Fields.field(fieldReference));
}
@@ -1813,7 +1813,7 @@ public class ArithmeticOperators {
*/
public static Sqrt sqrtOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Sqrt(expression);
}
@@ -1825,7 +1825,7 @@ public class ArithmeticOperators {
*/
public static Sqrt sqrtOf(Number value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return new Sqrt(value);
}
}
@@ -1854,7 +1854,7 @@ public class ArithmeticOperators {
*/
public static Subtract valueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Subtract(asFields(fieldReference));
}
@@ -1866,7 +1866,7 @@ public class ArithmeticOperators {
*/
public static Subtract valueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Subtract(Collections.singletonList(expression));
}
@@ -1878,7 +1878,7 @@ public class ArithmeticOperators {
*/
public static Subtract valueOf(Number value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return new Subtract(Collections.singletonList(value));
}
@@ -1890,7 +1890,7 @@ public class ArithmeticOperators {
*/
public Subtract subtract(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Subtract(append(Fields.field(fieldReference)));
}
@@ -1902,7 +1902,7 @@ public class ArithmeticOperators {
*/
public Subtract subtract(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Subtract(append(expression));
}
@@ -1941,7 +1941,7 @@ public class ArithmeticOperators {
*/
public static Trunc truncValueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Trunc(Fields.field(fieldReference));
}
@@ -1953,7 +1953,7 @@ public class ArithmeticOperators {
*/
public static Trunc truncValueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Trunc(expression);
}
@@ -1965,7 +1965,7 @@ public class ArithmeticOperators {
*/
public static Trunc truncValueOf(Number value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return new Trunc(value);
}
}
@@ -1997,7 +1997,7 @@ public class ArithmeticOperators {
*/
public static Round roundValueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Round(Collections.singletonList(Fields.field(fieldReference)));
}
@@ -2009,7 +2009,7 @@ public class ArithmeticOperators {
*/
public static Round roundValueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Round(Collections.singletonList(expression));
}
@@ -2021,7 +2021,7 @@ public class ArithmeticOperators {
*/
public static Round round(Number value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return new Round(Collections.singletonList(value));
}
@@ -2043,7 +2043,7 @@ public class ArithmeticOperators {
*/
public Round placeOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Round(append(expression));
}
@@ -2056,7 +2056,7 @@ public class ArithmeticOperators {
*/
public Round placeOf(String fieldReference) {
Assert.notNull(fieldReference, "fieldReference must not be null!");
Assert.notNull(fieldReference, "fieldReference must not be null");
return new Round(append(Fields.field(fieldReference)));
}
@@ -2400,7 +2400,7 @@ public class ArithmeticOperators {
*/
public static ASin asinOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new ASin(Fields.field(fieldReference));
}
@@ -2704,7 +2704,7 @@ public class ArithmeticOperators {
*/
public static ACos acosOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new ACos(Fields.field(fieldReference));
}
@@ -2905,7 +2905,7 @@ public class ArithmeticOperators {
*/
public static ATan atanOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new ATan(Fields.field(fieldReference));
}
@@ -2958,7 +2958,7 @@ public class ArithmeticOperators {
*/
public static ATan2 valueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new ATan2(asFields(fieldReference));
}
@@ -2971,7 +2971,7 @@ public class ArithmeticOperators {
*/
public static ATan2 valueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new ATan2((Collections.singletonList(expression)));
}
@@ -2985,7 +2985,7 @@ public class ArithmeticOperators {
*/
public ATan2 atan2of(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new ATan2(append(Fields.field(fieldReference)));
}
@@ -2999,7 +2999,7 @@ public class ArithmeticOperators {
*/
public ATan2 atan2of(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new ATan2(append(expression));
}

View File

@@ -23,6 +23,7 @@ import java.util.List;
import org.bson.Document;
import org.springframework.data.domain.Range;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.aggregation.ArrayOperators.Filter.AsBuilder;
import org.springframework.data.mongodb.core.aggregation.ArrayOperators.Reduce.PropertyExpression;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
@@ -87,7 +88,7 @@ public class ArrayOperators {
*/
public ArrayOperatorFactory(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
this.fieldReference = fieldReference;
this.expression = null;
this.values = null;
@@ -100,7 +101,7 @@ public class ArrayOperators {
*/
public ArrayOperatorFactory(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
this.fieldReference = null;
this.expression = expression;
this.values = null;
@@ -114,7 +115,7 @@ public class ArrayOperators {
*/
public ArrayOperatorFactory(Collection<?> values) {
Assert.notNull(values, "Values must not be null!");
Assert.notNull(values, "Values must not be null");
this.fieldReference = null;
this.expression = null;
this.values = values;
@@ -140,7 +141,7 @@ public class ArrayOperators {
*/
public ArrayElemAt elementAt(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return createArrayElemAt().elementAt(expression);
}
@@ -153,7 +154,7 @@ public class ArrayOperators {
*/
public ArrayElemAt elementAt(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return createArrayElemAt().elementAt(fieldReference);
}
@@ -175,7 +176,7 @@ public class ArrayOperators {
*/
public ConcatArrays concat(String arrayFieldReference) {
Assert.notNull(arrayFieldReference, "ArrayFieldReference must not be null!");
Assert.notNull(arrayFieldReference, "ArrayFieldReference must not be null");
return createConcatArrays().concat(arrayFieldReference);
}
@@ -188,7 +189,7 @@ public class ArrayOperators {
*/
public ConcatArrays concat(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return createConcatArrays().concat(expression);
}
@@ -213,7 +214,7 @@ public class ArrayOperators {
return Filter.filter(fieldReference);
}
Assert.state(values != null, "Values must not be null!");
Assert.state(values != null, "Values must not be null");
return Filter.filter(new ArrayList<>(values));
}
@@ -224,7 +225,7 @@ public class ArrayOperators {
*/
public IsArray isArray() {
Assert.state(values == null, "Does it make sense to call isArray on an array? Maybe just skip it?");
Assert.state(values == null, "Does it make sense to call isArray on an array; Maybe just skip it");
return usesFieldRef() ? IsArray.isArray(fieldReference) : IsArray.isArray(expression);
}
@@ -315,6 +316,21 @@ public class ArrayOperators {
.withInitialValue(initialValue).reduce(expressions);
}
/**
* Creates new {@link AggregationExpression} that takes the associated array and sorts it by the given {@link Sort order}.
*
* @return new instance of {@link SortArray}.
* @since 4.0
*/
public SortArray sort(Sort sort) {
if (usesFieldRef()) {
return SortArray.sortArrayOf(fieldReference).by(sort);
}
return (usesExpression() ? SortArray.sortArrayOf(expression) : SortArray.sortArray(values)).by(sort);
}
/**
* Creates new {@link AggregationExpression} that transposes an array of input arrays so that the first element of
* the output array would be an array containing, the first element of the first input array, the first element of
@@ -363,7 +379,7 @@ public class ArrayOperators {
return usesExpression() ? ArrayToObject.arrayValueOfToObject(expression) : ArrayToObject.arrayToObject(values);
}
/**
* Creates new {@link AggregationExpression} that return the first element in the associated array.
* <strong>NOTE:</strong> Requires MongoDB 4.4 or later.
@@ -379,7 +395,7 @@ public class ArrayOperators {
return usesExpression() ? First.firstOf(expression) : First.first(values);
}
/**
* Creates new {@link AggregationExpression} that return the last element in the given array.
* <strong>NOTE:</strong> Requires MongoDB 4.4 or later.
@@ -450,7 +466,7 @@ public class ArrayOperators {
*/
public static ArrayElemAt arrayOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new ArrayElemAt(asFields(fieldReference));
}
@@ -462,7 +478,7 @@ public class ArrayOperators {
*/
public static ArrayElemAt arrayOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new ArrayElemAt(Collections.singletonList(expression));
}
@@ -475,7 +491,7 @@ public class ArrayOperators {
*/
public static ArrayElemAt arrayOf(Collection<?> values) {
Assert.notNull(values, "Values must not be null!");
Assert.notNull(values, "Values must not be null");
return new ArrayElemAt(Collections.singletonList(values));
}
@@ -497,7 +513,7 @@ public class ArrayOperators {
*/
public ArrayElemAt elementAt(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new ArrayElemAt(append(expression));
}
@@ -509,7 +525,7 @@ public class ArrayOperators {
*/
public ArrayElemAt elementAt(String arrayFieldReference) {
Assert.notNull(arrayFieldReference, "ArrayReference must not be null!");
Assert.notNull(arrayFieldReference, "ArrayReference must not be null");
return new ArrayElemAt(append(Fields.field(arrayFieldReference)));
}
}
@@ -538,7 +554,7 @@ public class ArrayOperators {
*/
public static ConcatArrays arrayOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new ConcatArrays(asFields(fieldReference));
}
@@ -550,7 +566,7 @@ public class ArrayOperators {
*/
public static ConcatArrays arrayOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new ConcatArrays(Collections.singletonList(expression));
}
@@ -563,7 +579,7 @@ public class ArrayOperators {
*/
public static ConcatArrays arrayOf(Collection<?> values) {
Assert.notNull(values, "Values must not be null!");
Assert.notNull(values, "Values must not be null");
return new ConcatArrays(Collections.singletonList(values));
}
@@ -575,7 +591,7 @@ public class ArrayOperators {
*/
public ConcatArrays concat(String arrayFieldReference) {
Assert.notNull(arrayFieldReference, "ArrayFieldReference must not be null!");
Assert.notNull(arrayFieldReference, "ArrayFieldReference must not be null");
return new ConcatArrays(append(Fields.field(arrayFieldReference)));
}
@@ -587,7 +603,7 @@ public class ArrayOperators {
*/
public ConcatArrays concat(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new ConcatArrays(append(expression));
}
}
@@ -617,7 +633,7 @@ public class ArrayOperators {
*/
public static AsBuilder filter(String field) {
Assert.notNull(field, "Field must not be null!");
Assert.notNull(field, "Field must not be null");
return filter(Fields.field(field));
}
@@ -629,7 +645,7 @@ public class ArrayOperators {
*/
public static AsBuilder filter(Field field) {
Assert.notNull(field, "Field must not be null!");
Assert.notNull(field, "Field must not be null");
return new FilterExpressionBuilder().filter(field);
}
@@ -641,7 +657,7 @@ public class ArrayOperators {
*/
public static AsBuilder filter(List<?> values) {
Assert.notNull(values, "Values must not be null!");
Assert.notNull(values, "Values must not be null");
return new FilterExpressionBuilder().filter(values);
}
@@ -768,7 +784,7 @@ public class ArrayOperators {
@Override
public AsBuilder filter(List<?> array) {
Assert.notNull(array, "Array must not be null!");
Assert.notNull(array, "Array must not be null");
filter.input = new ArrayList<Object>(array);
return this;
}
@@ -776,7 +792,7 @@ public class ArrayOperators {
@Override
public AsBuilder filter(Field field) {
Assert.notNull(field, "Field must not be null!");
Assert.notNull(field, "Field must not be null");
filter.input = field;
return this;
}
@@ -784,7 +800,7 @@ public class ArrayOperators {
@Override
public ConditionBuilder as(String variableName) {
Assert.notNull(variableName, "Variable name must not be null!");
Assert.notNull(variableName, "Variable name must not be null");
filter.as = new ExposedField(variableName, true);
return this;
}
@@ -792,7 +808,7 @@ public class ArrayOperators {
@Override
public Filter by(AggregationExpression condition) {
Assert.notNull(condition, "Condition must not be null!");
Assert.notNull(condition, "Condition must not be null");
filter.condition = condition;
return filter;
}
@@ -800,7 +816,7 @@ public class ArrayOperators {
@Override
public Filter by(String expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
filter.condition = expression;
return filter;
}
@@ -808,7 +824,7 @@ public class ArrayOperators {
@Override
public Filter by(Document expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
filter.condition = expression;
return filter;
}
@@ -839,7 +855,7 @@ public class ArrayOperators {
*/
public static IsArray isArray(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new IsArray(Fields.field(fieldReference));
}
@@ -851,7 +867,7 @@ public class ArrayOperators {
*/
public static IsArray isArray(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new IsArray(expression);
}
}
@@ -880,7 +896,7 @@ public class ArrayOperators {
*/
public static Size lengthOfArray(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Size(Fields.field(fieldReference));
}
@@ -892,7 +908,7 @@ public class ArrayOperators {
*/
public static Size lengthOfArray(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Size(expression);
}
@@ -905,7 +921,7 @@ public class ArrayOperators {
*/
public static Size lengthOfArray(Collection<?> values) {
Assert.notNull(values, "Values must not be null!");
Assert.notNull(values, "Values must not be null");
return new Size(Collections.singletonList(values));
}
}
@@ -934,7 +950,7 @@ public class ArrayOperators {
*/
public static Slice sliceArrayOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Slice(asFields(fieldReference));
}
@@ -946,7 +962,7 @@ public class ArrayOperators {
*/
public static Slice sliceArrayOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Slice(Collections.singletonList(expression));
}
@@ -959,7 +975,7 @@ public class ArrayOperators {
*/
public static Slice sliceArrayOf(Collection<?> values) {
Assert.notNull(values, "Values must not be null!");
Assert.notNull(values, "Values must not be null");
return new Slice(Collections.singletonList(values));
}
@@ -1029,7 +1045,7 @@ public class ArrayOperators {
*/
public static IndexOfArrayBuilder arrayOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new IndexOfArrayBuilder(Fields.field(fieldReference));
}
@@ -1041,7 +1057,7 @@ public class ArrayOperators {
*/
public static IndexOfArrayBuilder arrayOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new IndexOfArrayBuilder(expression);
}
@@ -1054,7 +1070,7 @@ public class ArrayOperators {
*/
public static IndexOfArrayBuilder arrayOf(Collection<?> values) {
Assert.notNull(values, "Values must not be null!");
Assert.notNull(values, "Values must not be null");
return new IndexOfArrayBuilder(values);
}
@@ -1087,7 +1103,7 @@ public class ArrayOperators {
*/
public IndexOfArray indexOf(Object value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return new IndexOfArray(Arrays.asList(targetArray, value));
}
}
@@ -1411,8 +1427,8 @@ public class ArrayOperators {
protected PropertyExpression(String propertyName, AggregationExpression aggregationExpression) {
Assert.notNull(propertyName, "Property name must not be null!");
Assert.notNull(aggregationExpression, "AggregationExpression must not be null!");
Assert.notNull(propertyName, "Property name must not be null");
Assert.notNull(aggregationExpression, "AggregationExpression must not be null");
this.propertyName = propertyName;
this.aggregationExpression = aggregationExpression;
@@ -1559,7 +1575,7 @@ public class ArrayOperators {
*/
public static ZipBuilder arrayOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new ZipBuilder(Fields.field(fieldReference));
}
@@ -1571,7 +1587,7 @@ public class ArrayOperators {
*/
public static ZipBuilder arrayOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new ZipBuilder(expression);
}
@@ -1584,7 +1600,7 @@ public class ArrayOperators {
*/
public static ZipBuilder arrayOf(Collection<?> values) {
Assert.notNull(values, "Expression must not be null!");
Assert.notNull(values, "Expression must not be null");
return new ZipBuilder(values);
}
@@ -1605,7 +1621,7 @@ public class ArrayOperators {
*/
public Zip defaultTo(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Zip(append("defaults", Fields.field(fieldReference)));
}
@@ -1617,7 +1633,7 @@ public class ArrayOperators {
*/
public Zip defaultTo(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Zip(append("defaults", expression));
}
@@ -1629,7 +1645,7 @@ public class ArrayOperators {
*/
public Zip defaultTo(Object[] array) {
Assert.notNull(array, "Array must not be null!");
Assert.notNull(array, "Array must not be null");
return new Zip(append("defaults", Arrays.asList(array)));
}
@@ -1653,7 +1669,7 @@ public class ArrayOperators {
*/
public Zip zip(Object... arrays) {
Assert.notNull(arrays, "Arrays must not be null!");
Assert.notNull(arrays, "Arrays must not be null");
for (Object value : arrays) {
if (value instanceof String) {
@@ -1696,11 +1712,11 @@ public class ArrayOperators {
*/
public static InBuilder arrayOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return value -> {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return new In(Arrays.asList(value, Fields.field(fieldReference)));
};
}
@@ -1713,11 +1729,11 @@ public class ArrayOperators {
*/
public static InBuilder arrayOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return value -> {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return new In(Arrays.asList(value, expression));
};
@@ -1732,11 +1748,11 @@ public class ArrayOperators {
*/
public static InBuilder arrayOf(Collection<?> values) {
Assert.notNull(values, "Values must not be null!");
Assert.notNull(values, "Values must not be null");
return value -> {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return new In(Arrays.asList(value, values));
};
@@ -1807,7 +1823,7 @@ public class ArrayOperators {
return "$arrayToObject";
}
}
/**
* {@link AggregationExpression} for {@code $first} that returns the first element in an array. <br />
* <strong>NOTE:</strong> Requires MongoDB 4.4 or later.
@@ -1861,7 +1877,7 @@ public class ArrayOperators {
return "$first";
}
}
/**
* {@link AggregationExpression} for {@code $last} that returns the last element in an array. <br />
* <strong>NOTE:</strong> Requires MongoDB 4.4 or later.
@@ -1915,4 +1931,66 @@ public class ArrayOperators {
return "$last";
}
}
/**
* {@link AggregationExpression} for {@code $sortArray} that sorts elements in an array. <br />
*
* @author Christoph Strobl
* @since 4.0
*/
public static class SortArray extends AbstractAggregationExpression {
private SortArray(Object value) {
super(value);
}
/**
* Returns the given array.
*
* @param array must not be {@literal null}.
* @return new instance of {@link SortArray}.
*/
public static SortArray sortArray(Object array) {
return new SortArray(Collections.singletonMap("input", array));
}
/**
* Sorts the elements in the array pointed to by the given {@link Field field reference}.
*
* @param fieldReference must not be {@literal null}.
* @return new instance of {@link SortArray}.
*/
public static SortArray sortArrayOf(String fieldReference) {
return sortArray(Fields.field(fieldReference));
}
/**
* Sorts the elements of the array computed buy the given {@link AggregationExpression expression}.
*
* @param expression must not be {@literal null}.
* @return new instance of {@link SortArray}.
*/
public static SortArray sortArrayOf(AggregationExpression expression) {
return sortArray(expression);
}
/**
* Set the order to put elements in.
*
* @param sort must not be {@literal null}.
* @return new instance of {@link SortArray}.
*/
public SortArray by(Sort sort) {
return new SortArray(append("sortBy", sort));
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AbstractAggregationExpression#getMongoMethod()
*/
@Override
protected String getMongoMethod() {
return "$sortArray";
}
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2022 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.aggregation;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.data.mongodb.util.BsonUtils;
import org.springframework.util.ObjectUtils;
/**
* {@link AggregationOperation} implementation that can return a {@link Document} from a {@link Bson} or {@link String}
* document.
*
* @author Christoph Strobl
* @since 4.0
*/
record BasicAggregationOperation(Object value) implements AggregationOperation {
@Override
public Document toDocument(AggregationOperationContext context) {
if (value instanceof Bson bson) {
return BsonUtils.asDocument(bson, context.getCodecRegistry());
}
if (value instanceof String json && BsonUtils.isJsonDocument(json)) {
return BsonUtils.parse(json, context);
}
throw new IllegalStateException(
String.format("%s cannot be converted to org.bson.Document", ObjectUtils.nullSafeClassName(value)));
}
}

View File

@@ -87,7 +87,7 @@ public class BooleanOperators {
*/
public BooleanOperatorFactory(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
this.fieldReference = fieldReference;
this.expression = null;
}
@@ -99,7 +99,7 @@ public class BooleanOperators {
*/
public BooleanOperatorFactory(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
this.fieldReference = null;
this.expression = expression;
}
@@ -113,7 +113,7 @@ public class BooleanOperators {
*/
public And and(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return createAnd().andExpression(expression);
}
@@ -126,7 +126,7 @@ public class BooleanOperators {
*/
public And and(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return createAnd().andField(fieldReference);
}
@@ -143,7 +143,7 @@ public class BooleanOperators {
*/
public Or or(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return createOr().orExpression(expression);
}
@@ -156,7 +156,7 @@ public class BooleanOperators {
*/
public Or or(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return createOr().orField(fieldReference);
}
@@ -213,7 +213,7 @@ public class BooleanOperators {
*/
public And andExpression(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new And(append(expression));
}
@@ -225,7 +225,7 @@ public class BooleanOperators {
*/
public And andField(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new And(append(Fields.field(fieldReference)));
}
@@ -237,7 +237,7 @@ public class BooleanOperators {
*/
public And andValue(Object value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return new And(append(value));
}
}
@@ -267,7 +267,7 @@ public class BooleanOperators {
*/
public static Or or(Object... expressions) {
Assert.notNull(expressions, "Expressions must not be null!");
Assert.notNull(expressions, "Expressions must not be null");
return new Or(Arrays.asList(expressions));
}
@@ -279,7 +279,7 @@ public class BooleanOperators {
*/
public Or orExpression(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Or(append(expression));
}
@@ -291,7 +291,7 @@ public class BooleanOperators {
*/
public Or orField(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Or(append(Fields.field(fieldReference)));
}
@@ -303,7 +303,7 @@ public class BooleanOperators {
*/
public Or orValue(Object value) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(value, "Value must not be null");
return new Or(append(value));
}
}
@@ -333,7 +333,7 @@ public class BooleanOperators {
*/
public static Not not(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
Assert.notNull(fieldReference, "FieldReference must not be null");
return new Not(asFields(fieldReference));
}
@@ -346,7 +346,7 @@ public class BooleanOperators {
*/
public static Not not(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
Assert.notNull(expression, "Expression must not be null");
return new Not(Collections.singletonList(expression));
}
}

View File

@@ -50,7 +50,7 @@ public class BucketAutoOperation extends BucketOperationSupport<BucketAutoOperat
super(groupByField);
Assert.isTrue(buckets > 0, "Number of buckets must be greater 0!");
Assert.isTrue(buckets > 0, "Number of buckets must be greater 0");
this.buckets = buckets;
this.granularity = null;
@@ -66,7 +66,7 @@ public class BucketAutoOperation extends BucketOperationSupport<BucketAutoOperat
super(groupByExpression);
Assert.isTrue(buckets > 0, "Number of buckets must be greater 0!");
Assert.isTrue(buckets > 0, "Number of buckets must be greater 0");
this.buckets = buckets;
this.granularity = null;
@@ -117,7 +117,7 @@ public class BucketAutoOperation extends BucketOperationSupport<BucketAutoOperat
*/
public BucketAutoOperation withBuckets(int buckets) {
Assert.isTrue(buckets > 0, "Number of buckets must be greater 0!");
Assert.isTrue(buckets > 0, "Number of buckets must be greater 0");
return new BucketAutoOperation(this, buckets, granularity);
}
@@ -132,7 +132,7 @@ public class BucketAutoOperation extends BucketOperationSupport<BucketAutoOperat
*/
public BucketAutoOperation withGranularity(Granularity granularity) {
Assert.notNull(granularity, "Granularity must not be null!");
Assert.notNull(granularity, "Granularity must not be null");
return new BucketAutoOperation(this, buckets, granularity.getMongoRepresentation());
}

View File

@@ -113,7 +113,7 @@ public class BucketOperation extends BucketOperationSupport<BucketOperation, Buc
*/
public BucketOperation withDefaultBucket(Object literal) {
Assert.notNull(literal, "Default bucket literal must not be null!");
Assert.notNull(literal, "Default bucket literal must not be null");
return new BucketOperation(this, boundaries, literal);
}
@@ -126,8 +126,8 @@ public class BucketOperation extends BucketOperationSupport<BucketOperation, Buc
*/
public BucketOperation withBoundaries(Object... boundaries) {
Assert.notNull(boundaries, "Boundaries must not be null!");
Assert.noNullElements(boundaries, "Boundaries must not contain null values!");
Assert.notNull(boundaries, "Boundaries must not be null");
Assert.noNullElements(boundaries, "Boundaries must not contain null values");
List<Object> newBoundaries = new ArrayList<Object>(this.boundaries.size() + boundaries.length);
newBoundaries.addAll(this.boundaries);

View File

@@ -51,7 +51,7 @@ public abstract class BucketOperationSupport<T extends BucketOperationSupport<T,
*/
protected BucketOperationSupport(Field groupByField) {
Assert.notNull(groupByField, "Group by field must not be null!");
Assert.notNull(groupByField, "Group by field must not be null");
this.groupByField = groupByField;
this.groupByExpression = null;
@@ -65,7 +65,7 @@ public abstract class BucketOperationSupport<T extends BucketOperationSupport<T,
*/
protected BucketOperationSupport(AggregationExpression groupByExpression) {
Assert.notNull(groupByExpression, "Group by AggregationExpression must not be null!");
Assert.notNull(groupByExpression, "Group by AggregationExpression must not be null");
this.groupByExpression = groupByExpression;
this.groupByField = null;
@@ -89,8 +89,8 @@ public abstract class BucketOperationSupport<T extends BucketOperationSupport<T,
*/
protected BucketOperationSupport(BucketOperationSupport<?, ?> operationSupport, Outputs outputs) {
Assert.notNull(operationSupport, "BucketOperationSupport must not be null!");
Assert.notNull(outputs, "Outputs must not be null!");
Assert.notNull(operationSupport, "BucketOperationSupport must not be null");
Assert.notNull(outputs, "Outputs must not be null");
this.groupByField = operationSupport.groupByField;
this.groupByExpression = operationSupport.groupByExpression;
@@ -213,8 +213,8 @@ public abstract class BucketOperationSupport<T extends BucketOperationSupport<T,
*/
protected OutputBuilder(Object value, T operation) {
Assert.notNull(value, "Value must not be null or empty!");
Assert.notNull(operation, "ProjectionOperation must not be null!");
Assert.notNull(value, "Value must not be null or empty");
Assert.notNull(operation, "ProjectionOperation must not be null");
this.value = value;
this.operation = operation;
@@ -321,8 +321,8 @@ public abstract class BucketOperationSupport<T extends BucketOperationSupport<T,
*/
public B apply(String operation, Object... values) {
Assert.hasText(operation, "Operation must not be empty or null!");
Assert.notNull(value, "Values must not be null!");
Assert.hasText(operation, "Operation must not be empty or null");
Assert.notNull(value, "Values must not be null");
List<Object> objects = new ArrayList<Object>(values.length + 1);
objects.add(value);
@@ -355,7 +355,7 @@ public abstract class BucketOperationSupport<T extends BucketOperationSupport<T,
}
if (value instanceof Field) {
throw new IllegalStateException("Cannot add a field as top-level output. Use accumulator expressions.");
throw new IllegalStateException("Cannot add a field as top-level output; Use accumulator expressions");
}
return this.operation
@@ -437,7 +437,7 @@ public abstract class BucketOperationSupport<T extends BucketOperationSupport<T,
*/
protected Outputs and(Output output) {
Assert.notNull(output, "BucketOutput must not be null!");
Assert.notNull(output, "BucketOutput must not be null");
return new Outputs(this.outputs, output);
}
@@ -480,7 +480,7 @@ public abstract class BucketOperationSupport<T extends BucketOperationSupport<T,
*/
protected Output(Field field) {
Assert.notNull(field, "Field must not be null!");
Assert.notNull(field, "Field must not be null");
this.field = new ExposedField(field, true);
}
@@ -516,8 +516,8 @@ public abstract class BucketOperationSupport<T extends BucketOperationSupport<T,
super(Fields.field(operation));
Assert.hasText(operation, "Operation must not be null or empty!");
Assert.notNull(values, "Values must not be null!");
Assert.hasText(operation, "Operation must not be null or empty");
Assert.notNull(values, "Values must not be null");
this.operation = operation;
this.values = new ArrayList<Object>(values);
@@ -616,8 +616,8 @@ public abstract class BucketOperationSupport<T extends BucketOperationSupport<T,
super(Fields.field(expression));
Assert.hasText(expression, "Expression must not be null!");
Assert.notNull(parameters, "Parameters must not be null!");
Assert.hasText(expression, "Expression must not be null");
Assert.notNull(parameters, "Parameters must not be null");
this.expression = expression;
this.params = parameters.clone();

Some files were not shown because too many files have changed in this diff Show More