Compare commits

...

736 Commits

Author SHA1 Message Date
Mark Paluch
2a81dc75a8 DATAMONGO-1816 - Release version 2.0.2 (Kay SR2). 2017-11-27 16:12:34 +01:00
Mark Paluch
58cd4c08ca DATAMONGO-1816 - Prepare 2.0.2 (Kay SR2). 2017-11-27 16:11:21 +01:00
Mark Paluch
344e019143 DATAMONGO-1816 - Updated changelog. 2017-11-27 16:11:15 +01:00
Mark Paluch
918b7e96bb DATAMONGO-1799 - Updated changelog. 2017-11-27 15:58:45 +01:00
Christoph Strobl
fce7a5c1cb DATAMONGO-1818 - Polishing.
Move overlapping/duplicate documentation into one place.

Original Pull Request: #512
2017-11-27 07:53:22 +01:00
Mark Paluch
dbd2de8e0f DATAMONGO-1818 - Reword tailable cursors documentation.
Fix reference to @Tailable annotation. Slightly reword documentation.

Original Pull Request: #512
2017-11-27 07:53:08 +01:00
Mark Paluch
0dbe331ab0 DATAMONGO-1823 - Polishing.
Replace constructor with lombok's RequiredArgsConstructor. Add Nullable annotation. Tiny reformatting. Align license header. Migrate test to AssertJ.

Original pull request: #517.
2017-11-22 14:33:20 +01:00
Christoph Strobl
846ebcd91d DATAMONGO-1823 - Emit ApplicationEvents using projecting find methods.
We now again emit application events when using finder methods that apply projection.

Original pull request: #517.
2017-11-22 14:33:20 +01:00
Oliver Gierke
9e0b5caeac DATAMONGO-1737 - BasicMongoPersistentEntity now correctly initializes comparator.
In BasicMongoPersistentEntity.verify() we now properly call the super method to make sure the comparators that honor the @Field's order value are initialized properly.
2017-11-17 14:55:00 +01:00
Mark Paluch
cf70f5e5eb DATAMONGO-1819 - Polishing.
Use native field names for NamedMongoScript query instead of relying on metadata-based mapping as NamedMongoScript is considered a simple top-level type.

Related pull request: #513.
2017-11-17 13:49:06 +01:00
Mark Paluch
331dc6df6f DATAMONGO-1821 - Fix method ambiguity in tests when compiling against MongoDB 3.6 2017-11-07 12:47:51 +01:00
Mark Paluch
a51dce2c90 DATAMONGO-1820 - Set Mongo's Feature Compatibility flag for TravisCI build to 3.4.
Apply setFeatureCompatibilityVersion to upgrade MongoDB to 3.4 features.
2017-11-06 10:28:10 +01:00
Mark Paluch
c0cf1aa95b DATAMONGO-1817 - Polishing.
Remove blank line.

Original pull request: #510.
2017-11-06 10:02:35 +01:00
Sola
7104ffa543 DATAMONGO-1817 - Align nullability in Kotlin MongoOperationsExtensions with Java API.
Return types in MongoOperationsExtensions are now aligned to the nullability of MongoOperations.

Original pull request: #510.
2017-11-06 10:02:35 +01:00
Oliver Gierke
28d2fb6680 DATAMONGO-1793 - After release cleanups. 2017-10-27 15:50:48 +02:00
Oliver Gierke
140e26946f DATAMONGO-1793 - Prepare next development iteration. 2017-10-27 15:50:45 +02:00
Oliver Gierke
f4e730ce87 DATAMONGO-1793 - Release version 2.0.1 (Kay SR1). 2017-10-27 15:25:11 +02:00
Oliver Gierke
e3a83ebc42 DATAMONGO-1793 - Prepare 2.0.1 (Kay SR1). 2017-10-27 15:24:24 +02:00
Oliver Gierke
f65c1e324e DATAMONGO-1793 - Updated changelog. 2017-10-27 15:24:14 +02:00
Oliver Gierke
1dd0061f03 DATAMONGO-1815 - Adapt API changes in Property in test cases. 2017-10-27 11:13:31 +02:00
Mark Paluch
5ea860700c DATAMONGO-1814 - Update reference documentation for faceted classification.
Original pull request: #426.
Original ticket: DATAMONGO-1552.
2017-10-26 09:44:50 +02:00
Christoph Strobl
3dd653a702 DATAMONGO-1811 - Update documentation of MongoOperations.executeCommand.
Update Javadoc and reference documentation.
2017-10-24 14:59:47 +02:00
Christoph Strobl
f87847407b DATAMONGO-1805 - Update GridFsOperations documentation.
Fix return type in reference documentation and update Javadoc.
2017-10-24 14:59:40 +02:00
Christoph Strobl
433a125c9e DATAMONGO-1806 - Polishing.
Remove unused import, trailing whitespaces and update Javadoc.

Original Pull Request: #506
2017-10-24 14:59:33 +02:00
hartmut
5827cb0971 DATAMONGO-1806 - Fix Javadoc for GridFsResource.
Original Pull Request: #506
2017-10-24 14:59:24 +02:00
Mark Paluch
0109bf6858 DATAMONGO-1809 - Introduce AssertJ assertions for Document.
Original pull request: #508.
2017-10-24 14:45:03 +02:00
Christoph Strobl
49d1555576 DATAMONGO-1809 - Polishing.
Move tests to AssertJ.

Original pull request: #508.
2017-10-24 14:45:03 +02:00
Christoph Strobl
fdbb305b8e DATAMONGO-1809 - Fix positional parameter detection for PropertyPaths.
We now make sure to capture all digits for positional parameters.

Original pull request: #508.
2017-10-24 14:45:03 +02:00
Mark Paluch
49dd03311a DATAMONGO-1696 - Mention appropriate EnableMongoAuditing annotation in reference documentation. 2017-10-20 08:45:33 +02:00
Mark Paluch
a86a3210e1 DATAMONGO-1802 - Polishing.
Reduce converter visibility to MongoConverters's package-scope visibility. Tiny alignment in Javadoc wording. Copyright year, create empty byte array with element count instead initializer.

Original pull request: #505.
2017-10-17 14:52:11 +02:00
Christoph Strobl
4b655abfb6 DATAMONGO-1802 - Add Binary to byte array converter.
We now provide and register a Binary to byte[] converter to provide conversion of binary data to a byte array. MongoDB deserializes binary data using the document API to its Binary type. With this converter, we reinstantiated the previous capability to use byte arrays for binary data within domain types.

Original pull request: #505.
2017-10-17 14:52:11 +02:00
Oliver Gierke
0963e6cf77 DATAMONGO-1775 - Updated changelog. 2017-10-11 19:03:29 +02:00
Oliver Gierke
3e1b2c4bdb DATAMONGO-1795 - Removed obsolete Kotlin build setup. 2017-10-04 11:05:27 +02:00
Mark Paluch
03e0e0c431 DATAMONGO-1776 - After release cleanups. 2017-10-02 11:38:04 +02:00
Mark Paluch
51900021a1 DATAMONGO-1776 - Prepare next development iteration. 2017-10-02 11:38:03 +02:00
Mark Paluch
e5e8fa45c2 DATAMONGO-1776 - Release version 2.0 GA (Kay). 2017-10-02 11:10:22 +02:00
Mark Paluch
f5ad4e42f9 DATAMONGO-1776 - Prepare 2.0 GA (Kay). 2017-10-02 11:09:17 +02:00
Mark Paluch
e6b7d2ffd0 DATAMONGO-1776 - Updated changelog. 2017-10-02 11:09:09 +02:00
Mark Paluch
5b24d3fd0b DATAMONGO-1778 - Polishing.
Javadoc, modifiers.

Original pull request: #503.
2017-10-02 10:38:20 +02:00
Christoph Strobl
10f13c8f37 DATAMONGO-1778 - Polishing.
Migrate UpdateTests to AssertJ and adjust constructor visibility.

Original pull request: #503.
2017-10-02 10:38:20 +02:00
Christoph Strobl
c05f8f056c DATAMONGO-1778 - Fix equals() and hashCode() for Update.
We now include the entire update document with its modifiers and the isolation flag when computing the hash code and comparing for object equality.

Original pull request: #503.
2017-10-02 10:37:34 +02:00
Mark Paluch
dbd38a8e82 DATAMONGO-1791 - Polishing.
Replace RxJava 1 repositories with RxJava 2 repositories. Fix broken links. Fix duplicate section ids.
2017-09-27 12:19:11 +02:00
Mark Paluch
77b1f3cb37 DATAMONGO-1791 - Adapt to changed Spring Framework 5 documentation structure.
Update links in the reference docs to their new locations.
2017-09-27 12:13:51 +02:00
Mark Paluch
5444ac39b5 DATAMONGO-1785 - Downgrade to CDI 1.0.
We now build against CDI 1.0 again while using CDI 2.0 for testing.
2017-09-21 13:50:39 +02:00
Mark Paluch
cf476b9bc8 DATAMONGO-1787 - Added explicit automatic module name for JDK 9. 2017-09-21 13:50:39 +02:00
Christoph Strobl
f28d47b01b DATAMONGO-1777 - Polishing. 2017-09-21 11:32:52 +02:00
Christoph Strobl
5bf03cfa70 DATAMONGO-1777 - Pretty print Modifiers when calling Update.toString().
We now make sure to pretty print Update modifiers by safely rendering to a json representation including an optional $isolated opereator if applicable.
Along the way we also fix a flaw in PushOperationBuilder ignoring eg. $position when pushing single values.
2017-09-21 11:32:50 +02:00
Oliver Gierke
98e893636b DATAMONGO-1779 - Polishing.
Fixed imports.
2017-09-21 11:31:45 +02:00
Oliver Gierke
4b552b051e DATAMONGO-1779 - Fixed handling of empty queries in MongoTemplate.find(…).
Calls to MongoTemplate.find(…) were routed to ….findAll(…) in case no criteria definition or sort was defined on the query. This however neglected that cursor preparation aspects (limits, skips) are defined on the query as well which cause them not to be applied correctly. Removed the over-optimistic re-routing so that normal query execution now always gets applied.
2017-09-21 11:31:44 +02:00
Mark Paluch
1c295b62c6 DATAMONGO-1786 - Adapt tests to nullability validation in Spring Data Commons.
Related issue: DATACMNS-1157.
2017-09-21 11:27:41 +02:00
Christoph Strobl
0a8458a045 DATAMONGO-1784 - Polishing.
Update JavaDoc, enforce nullability constraints and add tests.

Original Pull Request: #501
2017-09-20 12:47:29 +02:00
Sergey Shcherbakov
a3b9fb33ea DATAMONGO-1784 - Add expression support to GroupOperation#sum().
We now allow passing an AggregationExpression to GroupOperation.sum which allows construction of more complex expressions.

Original Pull Request: #501
2017-09-20 12:46:14 +02:00
Christoph Strobl
3d651b72ad DATAMONGO-1782 - Polishing.
toCyclePath now returns an empty String when Path does not cycle.
Also split and add tests and move code to Java8.

Original Pull Request: #500
2017-09-19 11:07:04 +02:00
Mark Paluch
187c25bcc0 DATAMONGO-1782 - Detect type cycles using PersistentProperty paths.
We now rely on PersistentProperty paths to detect cycles between types. Cycles are detected when building up the path object and traversing PersistentProperty stops after the cycle was hit for the second time to generated indexes for at least one hierarchy level.

Previously, we used String-based property dot paths and compared whether paths to a particular property was already found by a substring search which caused false positives if a property was reachable via multiple paths.

Original Pull Request: #500
2017-09-19 10:03:40 +02:00
Mark Paluch
087482d82e DATAMONGO-1785 - Upgrade to OpenWebBeans 2.0.1
Upgrade also to Equalsverifier 1.7.8 to resolve ASM version conflict.
2017-09-18 15:21:57 +02:00
Mark Paluch
e80d1df571 DATAMONGO-1781 - Update what's new in reference documentation. 2017-09-14 14:09:08 +02:00
Oliver Gierke
a9b1b640c0 DATAMONGO-1754 - After release cleanups. 2017-09-11 17:40:21 +02:00
Oliver Gierke
b888864407 DATAMONGO-1754 - Prepare next development iteration. 2017-09-11 17:40:18 +02:00
Oliver Gierke
3e672e4563 DATAMONGO-1754 - Release version 2.0 RC3 (Kay). 2017-09-11 17:24:45 +02:00
Oliver Gierke
0fecd8bed9 DATAMONGO-1754 - Prepare 2.0 RC3 (Kay). 2017-09-11 17:23:51 +02:00
Oliver Gierke
4b6ff36724 DATAMONGO-1754 - Updated changelog. 2017-09-11 17:23:43 +02:00
Mark Paluch
ab31b24f99 DATAMONGO-1755 - Updated changelog. 2017-09-11 12:43:54 +02:00
Christoph Strobl
ba81caffe4 DATAMONGO-1631 - Polishing
Update Javadoc and test classes.

Original Pull Request: #490
2017-09-08 20:01:28 +02:00
Mark Paluch
3ab3dab2b4 DATAMONGO-1631 - Better method names for reactive configuration support.
This commit renames methods in AbstractReactiveMongoConfiguration for methods exposing MongoClient and ReactiveMongoDatabaseFactory instances. Renaming prevents possible clashes with beans created via AbstractMongoConfiguration (blocking driver) as bean names default to the producing method name.

Original Pull Request: #490
2017-09-08 20:00:42 +02:00
Mark Paluch
2d21b04a12 DATAMONGO-1774 - Polishing.
Synchronize javadoc between reactive and imperative operations interfaces. Add trailing punctuation. Consistent naming for collection name parameter.

Use Object.class instead of null in ReactiveMongoTemplate.findAllAndRemove to prevent null-pointer exceptions.

Original pull request: #498.
2017-09-06 11:47:23 +02:00
Christoph Strobl
301dd51560 DATAMONGO-1774 - Enforce null constraint checks.
And remove code paths returning null where a reactive wrapper type would be expected.

Original pull request: #498.
2017-09-06 11:44:36 +02:00
Christoph Strobl
d3d6242a16 DATAMONGO-1774 - Fix infinite loop in ReactiveMongoOperations#remove(Mono, String).
Original pull request: #498.
2017-09-06 11:44:20 +02:00
Christoph Strobl
7cf69c5b1a DATAMONGO-1772 - Fix UpdateMapper type key rendering for abstract list elements contained in concrete typed ones.
Original pull request: #497.
2017-09-05 10:59:02 +02:00
Christoph Strobl
995e5bf830 DATAMONGO-1770 - Upgrade to MongoDB Java driver 3.5 and reactive driver 1.6.
Fix test failures do to changed Json rendering.
2017-08-31 09:00:05 +02:00
Christoph Strobl
f281ab6c56 DATAMONGO-1771 - Fix Travis CI setup. 2017-08-29 15:19:23 +02:00
Mark Paluch
3012bcd575 DATAMONGO-1762 - Fix line endings.
Convert line endings from CRLF to LF.
2017-08-29 14:51:59 +02:00
Mark Paluch
0be4d1345e DATAMONGO-1762 - Polishing.
Add missing Nullable annotations. Provide getRequired…() methods for values known to exist. Update javadoc according to null-allowance/non-null requirements. Remove superfluous null-checks for values known to be non-null. Remove license from package Javadoc. Update license headers, remove trailing whitespaces.
2017-08-29 14:51:39 +02:00
Christoph Strobl
bdd5c9dec7 DATAMONGO-1762 - Add @Nullable and @NonNullApi annotations.
Marked all packages with Spring Frameworks @NonNullApi. Added Spring's @Nullable to methods, parameters and fields that take or produce null values. Adapted using code to make sure the IDE can evaluate the null flow properly. Fixed Javadoc in places where an invalid null handling policy was advertised. Strengthened null requirements for types that expose null-instances.
2017-08-29 14:48:15 +02:00
Mark Paluch
e28bede416 DATAMONGO-1768 - Polishing.
Use Lombok to generate constructors. Extend javadocs. Make methods static/reorder methods where possible. Use diamond syntax where possible. Formatting.

Original pull request: #496.
2017-08-25 10:47:57 +02:00
Christoph Strobl
2d825bed41 DATAMONGO-1768 - Introduce UntypedExampleMatcher.
Introducing UntypedExampleMatcher allows creation of QBE criteria that does not infer a strict type match.

Original pull request: #496.
2017-08-25 10:45:58 +02:00
Christoph Strobl
5fedbe9598 DATAMONGO-1768 - Allow ignoring type restriction when issuing QBE.
We now allow to remove the type restriction inferred by the QBE mapping via an ignored path expression on the ExampleMatcher. This allows to create untyped QBE expressions returning all entities matching the query without limiting the result to types assignable to the probe itself.

Original pull request: #496.
2017-08-25 10:45:38 +02:00
Oliver Gierke
faf7e36311 DATAMONGO-1765 - Polishing.
Lambdas and AssertJ in test cases.
2017-08-07 18:23:10 +02:00
Oliver Gierke
a95f77245e DATAMONGO-1765 - DefaultDbRefResolver now maps duplicate references correctly.
On bulk resolution of a DBRef array we now map the resulting documents back to their ids to make sure that reoccurring identifiers are mapped to the corresponding documents.
2017-08-07 17:48:36 +02:00
Mark Paluch
d956c8cbf2 DATAMONGO-1756 - Polishing.
Remove redundant casts. Add author tag.

Original pull request: #491.
2017-08-02 08:39:36 +02:00
Christoph Strobl
e8ae928e74 DATAMONGO-1756 - Fix nested field name resolution for arithmetic aggregation ops.
Original pull request: #491.
2017-08-02 08:39:23 +02:00
Oliver Gierke
f2e72fe931 DATAMONGO-1757 - Polishing.
Formatting.
2017-07-27 18:09:47 +02:00
Oliver Gierke
c35ea14c4f DATAMONGO-1757 - Improved exception being thrown if Document is supposed to be read into unsuitable type.
In case we run into a situation that we're supposed to read a Document into a type that's not a PersistentEntity, we previously only exposed the latter in an exception. This is now changed to add more context to the exception, incl. the source value to be read and the target type that we were supposed to read into.

This should leave the users with a better clue where the problem is.
2017-07-27 18:09:47 +02:00
Christoph Strobl
fc65bffc21 DATAMONGO-1758 - Remove spring-data-mongodb-log4j module from benchmarks profile. 2017-07-27 14:06:39 +02:00
Oliver Gierke
190f21fe46 DATAMONGO-1750 - Updated changelog. 2017-07-27 00:48:58 +02:00
Mark Paluch
5245cd4b55 DATAMONGO-1706 - Adapt to deprecated RxJava 1 CRUD repositories.
Move off RxJava1CrudRepository as base repository in tests by extending just Repository and declaring query methods/overloads using RxJava1 types.
2017-07-26 14:18:17 +02:00
Oliver Gierke
b72b8c5e09 DATAMONGO-1751 - After release cleanups. 2017-07-25 16:10:38 +02:00
Oliver Gierke
6652279189 DATAMONGO-1751 - Prepare next development iteration. 2017-07-25 16:10:34 +02:00
Oliver Gierke
0f5b9d5c4b DATAMONGO-1751 - Release version 2.0 RC2 (Kay). 2017-07-25 15:34:23 +02:00
Oliver Gierke
197e0bbb66 DATAMONGO-1751 - Prepare 2.0 RC2 (Kay). 2017-07-25 15:33:33 +02:00
Oliver Gierke
0e56ad40d8 DATAMONGO-1751 - Updated changelog. 2017-07-25 15:33:24 +02:00
Oliver Gierke
97a0f3b635 DATAMONGO-1752 - Fixed execution of repository query methods with closed projections.
We now skip the explicit definition of which type to read in case a closed projection is defined as return type.
2017-07-25 14:02:14 +02:00
Oliver Gierke
3d2c5a9235 DATAMONGO-1753 - IndexEnsuringQueryCreationListener now skips query methods without a predicate. 2017-07-25 14:02:14 +02:00
Oliver Gierke
489f3bb0ee DATAMONGO-1717 - After release cleanups. 2017-07-25 10:00:08 +02:00
Oliver Gierke
5cc78fa16b DATAMONGO-1717 - Prepare next development iteration. 2017-07-25 10:00:04 +02:00
Oliver Gierke
f4db26ffd1 DATAMONGO-1717 - Release version 2.0 RC1 (Kay). 2017-07-25 09:48:49 +02:00
Oliver Gierke
b14a3166e3 DATAMONGO-1717 - Prepare 2.0 RC1 (Kay). 2017-07-25 09:48:01 +02:00
Oliver Gierke
bd7af4c55b DATAMONGO-1717 - Updated changelog. 2017-07-25 09:47:53 +02:00
Oliver Gierke
491304f2c7 DATAMONGO-1711 - Updated changelog. 2017-07-24 22:20:42 +02:00
Oliver Gierke
51d5a3b61a DATAMONGO-1720 - Make sure benchmark module is not included by default.
The benchmarks module does not produce a JAR by default which let's our Maven Central deployment fail as a module has to produce one according to their rules. We're now only including the benchmark module when the benchmarks profile is active.
2017-07-24 18:39:56 +02:00
Sebastien Deleuze
2c193ec325 DATAMONGO-1748 - Removed placeholder for Kotlin version as the build parent already has it.
Original pull request: #489.
2017-07-24 14:52:42 +02:00
Sebastien Deleuze
427d4f5bd5 DATAMONGO-1748 - Tweaked Kotlin extensions to add Collection variant of Criteria.inValues(…) alias.
Original pull request: #489.
2017-07-24 14:52:32 +02:00
Sebastien Deleuze
8f8d792b61 DATAMONGO-1748 - Fine-tuning of nullability expressions in Kotlin extension for Criteria.
The Kotlin extensions introduced for Criteria now define relaxed null requirements for both isEqualTo(…) and the elements of the varargs handed to inValues(…).

Original pull request: #488.
2017-07-24 11:07:29 +02:00
Oliver Gierke
f16809a363 DATAMONGO-1519 - Method signature change for MongoTemplate.insertDocumentList(…).
Implemented return type change for protected method insertDocumentList(String, List<Document>).

Related ticket: DATAMONGO-1513.
2017-07-24 10:12:58 +02:00
Christoph Strobl
58b33e949b DATAMONGO-1719 - Add support for open/closed interface projections to fluent reactive API.
Original Pull Request: #487
2017-07-24 09:03:00 +02:00
Christoph Strobl
47481c4597 DATAMONGO-1719 - Polishing.
Use empty query where possible to avoid null values and introduce non optional findAndModify alternative for imperative api.
Add missing ExecutableUpdateOperation Kotlin extension.
Update Javadoc and add non-Javadoc comments.

Original Pull Request: #487
2017-07-24 09:02:23 +02:00
Mark Paluch
1475cde337 DATAMONGO-1719 - Polishing.
Use mockito extensions to mimic static imports.
Use Lombok's FieldDefaults and NonNull in operations support.

Original Pull Request: #487
2017-07-24 09:01:48 +02:00
Mark Paluch
4734a2925c DATAMONGO-1719 - Rename blocking fluent entry interfaces from …Operation to Executable… and remove Operation from intermediate interfaces.
Original Pull Request: #487
2017-07-24 08:45:35 +02:00
Mark Paluch
a6a0bde6f2 DATAMONGO-1719 - Add fluent reactive operations.
We now provide a fluent API for find, insert, update, aggregate and delete operations that can be used as an alternative for their counterparts in ReactiveMongoOperations.

Original Pull Request: #487
2017-07-24 08:44:39 +02:00
Mark Paluch
30a8608135 DATAMONGO-1746 - Inherit Project Reactor version from dependency management.
Adapt to BOM import in Spring Data Build pom.
2017-07-20 15:48:37 +02:00
Oliver Gierke
c77facda90 DATAMONGO-1733 - Polishing.
Tiny improvements to the ProjectingReadCallback as we now skip null values completely. Made the ProjectionFactory an instance variable to make sure we propagate the BeanFactory and BeanClassLoader in setApplicationContext(…). Added unit test to verify instances aren't proxied unnecessarily if the interface asked for is already implemented by the target.

Original pull request: #486.
Related tickets: DATACMNS-1121.
2017-07-20 14:53:06 +02:00
Christoph Strobl
b4c213b8c2 DATAMONGO-1733 - Added benchmark for projections in FluentMongoOperations.
Original pull request: #486.
2017-07-20 14:53:03 +02:00
Christoph Strobl
2230b51a79 DATAMONGO-1733 - Added support for projections on FluentMongoOperations.
Interfaces based projections handed to queries built using the FluentMongoOperations APIs now get projected as expected and also apply querying optimizations so that only fields needed in the projection are read in the first place.

Original pull request: #486.
2017-07-20 14:52:35 +02:00
Oliver Gierke
7258cb8d1d DATAMONGO-1748 - Polishing.
Added missing license headers, formatting.

Original pull request: #473.
2017-07-20 13:28:28 +02:00
Sebastien Deleuze
e6bae5d124 DATAMONGO-1748 - Add Kotlin extensions for Criteria API.
This commit introduces two Criteria method aliases because in and is are reserved keywords in Kotlin:

 - isEqualTo(…) alias for is(…)
 - inValues(…) alias for in(…)

Original pull request: #473.
2017-07-20 13:28:28 +02:00
Christoph Strobl
41bb619dc7 DATAMONGO-1646 - Polishing.
Remove ReactiveMongoDbUtils, update JavaDoc and add missing tests.

Original Pull Request: #481
2017-07-20 09:37:10 +02:00
Mark Paluch
6c42c4c828 DATAMONGO-1646 - Polishing.
Add missing license header.

Original Pull Request: #481
2017-07-20 09:32:58 +02:00
Mark Paluch
58050405a3 DATAMONGO-1646 - Support reactive aggregation execution.
We now support reactive aggregation execution via ReactiveMongoOperations.aggregate(…).

Original Pull Request: #481
2017-07-20 09:32:16 +02:00
Oliver Gierke
8834c5e97d DATAMONGO-1702 - Polishing.
Removed obsolete constants from MongoRepositoryFactory.

Original pull request: #480.
2017-07-19 15:56:07 +02:00
Mark Paluch
7526f3bd2e DATAMONGO-1702 - Adopt to composable repositories.
Deprecate QuerydslMongoRepository, introduce QuerydslMongoPredicateExecutor instead without extending SimpleMongoRepository. Use RepositoryFragments to mix in requested repository aspects.

Original pull request: #480.
2017-07-19 15:56:03 +02:00
Oliver Gierke
3d623d8181 DATAMONGO-1744 - Improved setup of default MongoMappingContext instances created.
We now make sure that the SimpleTypeHolder produced by MongoCustomConversions is used to set up default MongoMappingContext instances in (Reactive)MongoTemplate and unit tests.
2017-07-19 15:04:24 +02:00
Mark Paluch
ada8c4ec8d DATAMONGO-1738 - Polishing.
Adapt stream execution to changes in fluent API. Use fluent API for GeoNear executions. Remove unused code, update JavaDoc. Remove superfluous exception declaration in tests.

Original pull request: #484.
2017-07-18 11:13:19 +02:00
Oliver Gierke
dd8fc1a591 DATAMONGO-1738 - Move repository query execution to fluent operations API.
We now use the fluent FindOperations API in AbstractMongoQuery and MongoQueryExecution instead of the MongoOperations. This allows us to eagerly resolve some general execution coordinates (which collection to query etc.) and thus simplify the eventual execution.

Got rid of a couple of very simple QueryExecution implementations that can be replace by a simple lambda. Removed the need to read into a partially filled domain object and then map to the projection DTO as we can now tell the operations to read into the DTO directly.

Adapted unit tests.

Original pull request: #484.
2017-07-18 11:13:05 +02:00
Oliver Gierke
e1f19f69bd DATAMONGO-1739 - Changed TerminatingFindOperation.stream() to return Stream.
TerminatingFindOperation.stream() now returns a Stream directly, leveraging Spring Data Commons' StreamUtils.createStreamFromIterator(…) to create a Stream and register a callback to forward calls to Stream.close() to the iterator.

Original pull request: #485.
2017-07-18 09:50:07 +02:00
Mark Paluch
566e69a825 DATAMONGO-1703 - Polishing.
Use lombok's Value for ObjectPathItem. Make methods accessible in DefaultDbRefResolver before calling. Use class.cast to avoid warnings. Update Javadoc.

Original pull request: #478.
2017-07-14 11:36:29 +02:00
Christoph Strobl
6342ef1806 DATAMONGO-1703 - Convert resolved DBRef's from source that do not match the requested property type.
We now check if already resolved DBRef's are assignable to the target property type. If not, we perform conversion again to prevent ClassCastException when trying to assign non matching types.

Remove non applicable public modifiers in ObjectPath.

Original pull request: #478.
2017-07-14 11:36:14 +02:00
Mark Paluch
9d4d47f503 DATAMONGO-1721 - Move ReactiveIndexOperations to core.index package.
Align with synchronous IndexOperations.

Related pull request: #470.
2017-07-14 09:49:13 +02:00
Mark Paluch
f22036851e DATAMONGO-1682 - Polishing.
Require non-null arguments in DefaultReactiveIndexOperations constructor. Remove superfluous publisher creation indirections. Use StepVerifier.verifyComplete() to verify the step sequence.

Use provided entity type in template API to construct index operations.

Original pull request: #474.
2017-07-13 16:11:00 +02:00
Christoph Strobl
d5006bb693 DATAMONGO-1682 - Add support partialFilterExpression for reactive index creation.
We now support partial filter expression on indexes via Index.partial(…) on the reactive API. This allows to create partial indexes that only index the documents in a collection that meet a specified filter expression.

Original pull request: #474.
2017-07-13 16:01:00 +02:00
Mark Paluch
82fdbe8cc2 DATAMONGO-1720 - Polishing.
Enhance benchmark statistics with Git/working tree details. Specify byte encoding for JSON to byte encoder.
Add status code check to HttpResultsWriter to verify that the results were accepted. Convert spaces to tabs in pom.xml.

Original pull request: #483.
2017-07-13 15:16:32 +02:00
Christoph Strobl
747625b5c3 DATAMONGO-1720 - Add JMH based benchmarks for MappingMongoConverter.
Run the benchmark via the maven profile "benchmarks":

    mvn -P benchmarks clean test

Or run them customized:

    mvn -P benchmarks -DwarmupIterations=2 -DmeasurementIterations=5 -Dforks=1 clean test

Origin pull request: #483.
2017-07-13 15:16:28 +02:00
Oliver Gierke
3dee8de66d DATAMONGO-1371 - Polishing.
Removed console output from unit tests.
2017-07-13 14:37:09 +02:00
Oliver Gierke
e3b98693d4 DATAMONGO-1721 - Polishing.
Removed deprecated types and adapt dependency tests accordingly.

Refactored MongoExampleMapper to revert to use StringMatcher from Spring Data Commons' ExampleMatcher. Introduced MongoRegexCreator specific MatchMode, which is basically a copy of StringMatcher. Adapted MongoExampleMapper and MongoQueryCreator to translate from StringMatcher and Part.Type to MatchMode.

Turned unit tests for MongoRegexCreator into parameterized ones.

Original pull request: #470.
2017-07-13 14:37:07 +02:00
Jens Schauder
80ff3760ef DATAMONGO-1721 - Fixed package dependencies.
Added a Degraph based tests to identify package cycles and violations in layering.

Moved Collation to the core.query package, fixing dependency cycles. Moved IndexOperations and IndexOperationsProvider to the core.index package. fixing dependency cycles. Moved GeoJsonConfiguration to config package. Replaced the original version of these interfaces/classes with a deprecated version extending the new one, in order to not break the existing API.

Removed all references to Part.Type, except for those to maintain the existing API. API using Part.Type is marked as deprecated. It violates the layering, because nothing but "config" should access "repository". Tests added to MongoRegexCreator in order to facilitate the removal of Part.Type dependencies. Using the moved/new ExampleMatcherAccessor.

Related Tickets: DATACMNS-1097.
Original pull request: #470.
2017-07-13 14:36:57 +02:00
Mark Paluch
d19ea88670 DATAMONGO-1735 - Query sort and field documents no longer allow null.
We now require Sort and Fields (Projection) documents in Query. Absent sorting and projection uses empty documents.

Original pull request: #479.
2017-07-07 14:23:21 +02:00
Christoph Strobl
d3b9f91478 DATAMONGO-1734 - Polish MongoTemplate.exists execution.
Optimize execution by using count() limited to 1 element.

Original pull request: #479.
2017-07-07 14:23:14 +02:00
Christoph Strobl
7fb5c7d97c DATAMONGO-1734 - Add exists() and count() to fluent API.
Original pull request: #479.
2017-07-07 14:22:53 +02:00
Mark Paluch
18487ef252 DATAMONGO-1713 - Polishing.
Fix typos. Migrate to diamond syntax where applicable. Use Arrays.stream(…) instead of Arrays.asList(…).stream(). Mention percent sign as required char for URL encoding and reference RFC 3986 in documentation.

Original pull request: #477.
2017-07-06 14:21:34 +02:00
Christoph Strobl
1aa2ee5f54 DATAMONGO-1713 - Allow using URL encoded username/password for <mongo-client credentials=… />.
We now URL decode username & password before creating MongoCredentials. This allows usage of reserved characters in the credentials string.

Original pull request: #477.
2017-07-06 14:21:12 +02:00
Christoph Strobl
b9282c8d32 DATAMONGO-1726 - Add oneValue() and firstValue() to FluentMongoOperations returning nullable types.
We leave the choice of using Optional open by also providing terminating find operation methods that return null instead of Optional.

Original pull request: #475.
2017-07-06 11:29:08 +02:00
Oliver Gierke
3ac379a4b8 DATAMONGO-1725 - Polishing. 2017-07-05 13:16:21 +02:00
Oliver Gierke
0470dd6268 DATAMONGO-1725 - Prevent NullPointerException in CloseableIterableCursorAdapter.close(). 2017-07-05 13:06:33 +02:00
Christoph Strobl
270d373083 DATAMONGO-1728 - Fix NPE in ExecutableFindOperation.first().
Original pull request: #476.
2017-07-05 09:50:52 +02:00
Mark Paluch
697f5ad7c6 DATAMONGO-1730 - Adapt to API changes in mapping subsystem. 2017-07-04 14:36:58 +02:00
Oliver Gierke
028aeb327f DATAMONGO-1729 - Open projections don't get field restrictions applied.
We now only apply a field restriction if the projection used for a query is closed.
2017-07-03 22:04:16 +02:00
Oliver Gierke
6568fa2d2e DATAMONGO-1723 - ConfigurationExtensionUnitTests now need to provide a BeanDefinitionRegistry. 2017-06-26 16:55:27 +02:00
Mark Paluch
34986df70b DATAMONGO-1678 - Polishing.
Use Lombok's Value annotation for immutable value objects. Use IllegalArgumentException for NonNull validation exceptions. Introduce missing generics. Use static methods where possible. Remove unused WriteConcernResolver. Trim whitespaces, formatting.

Original pull request: #472.
2017-06-26 13:23:30 +02:00
Christoph Strobl
c3383432f7 DATAMONGO-1678 - Run bulk update / remove documents through type mappers.
We now make sure to run any query / update object through the Query- / UpdateMapper. This ensures @Field annotations and potential custom conversions get processed correctly for update / remove operations.

Original pull request: #472.
2017-06-26 13:23:25 +02:00
Christoph Strobl
e9498c86ca DATAMONGO-1705 - Deprecate cross-store support.
We deprecate cross-store support to remove cross-store with a future release.

Original pull request: #471.
2017-06-26 10:34:37 +02:00
Christoph Strobl
09f8dc6843 DATAMONGO-1715 - Remove spring-data-mongodb-log4j module.
We no longer support spring-data-mongodb-log4j hence removing the code entirely.

Original pull request: #471.
2017-06-26 10:34:11 +02:00
Christoph Strobl
9f22195330 DATAMONGO-1697 - Update MongoOperations JavaDoc regarding mapping limitations.
We now explicitly mention mapping/support limitations for API variants like count(Query, String) not having domain type specific information that allows field specific mapping.
2017-06-19 10:40:19 +02:00
Christoph Strobl
dd944b0881 DATAMONGO-1718 - Polishing.
Add test and hand over Object.class as placeholder for required domain type.

Original Pull Request: #469
2017-06-16 13:25:19 +02:00
Borislav Rangelov
cf0f891c8b DATAMONGO-1718 - Fix MongoTemplate::findAllAndRemove(Query,String) delegating to wrong overload.
Original Pull Request: #469 (by Borislav Rangelov).
2017-06-16 13:25:11 +02:00
Mark Paluch
fbf84fed0e DATAMONGO-1688 - After release cleanups. 2017-06-14 17:14:08 +02:00
Mark Paluch
251a953957 DATAMONGO-1688 - Prepare next development iteration. 2017-06-14 17:14:07 +02:00
Mark Paluch
cdc78592ee DATAMONGO-1688 - Release version 2.0 M4 (Kay). 2017-06-14 17:03:48 +02:00
Mark Paluch
ab97e58793 DATAMONGO-1688 - Prepare 2.0 M4 (Kay). 2017-06-14 17:03:00 +02:00
Mark Paluch
a4eeb9f305 DATAMONGO-1688 - Updated changelog. 2017-06-14 17:02:58 +02:00
Oliver Gierke
de6c649c83 DATAMONGO-1689 - Polish compiler configuration in POM.
Original pull request: #463.
2017-06-14 16:43:20 +02:00
Sebastien Deleuze
e90c6b0790 DATAMONGO-1689 - Add Kotlin extensions for new fluent API.
Original pull request: #463.
2017-06-14 16:38:18 +02:00
Sebastien Deleuze
d2e68cd925 DATAMONGO-1689 - Polishing.
Improve Maven Kotlin configuration for now + documentation fixes.

Original pull request: #463.
2017-06-14 16:37:52 +02:00
Christoph Strobl
7ed48f5e76 DATAMONGO-1689 - Polishing.
Additionally format code, update license header, update JavaDoc and add issue reference to tests.

Original pull request: #463.
2017-06-14 16:37:47 +02:00
Sebastien Deleuze
2359357977 DATAMONGO-1689 - Add Kotlin extensions for [Reactive]MongoOperations.
We now offer dedicated Kotlin extensions for MongoOperations and ReactiveMongoOperations.

Original pull request: #463.
2017-06-14 16:37:40 +02:00
Mark Paluch
a90f238574 DATAMONGO-1716 - Upgrade to Reactive Streams driver 1.5.0. 2017-06-14 11:53:23 +02:00
Christoph Strobl
1c9188f7e1 DATAMONGO-1712 - Polishing.
Follow ReactiveCrudRepository contract, fix spelling, update issue references and add deleteById(Publisher).

Related ticket: DATACMNS-1063.

Original Pull Request: #467
2017-06-13 19:46:27 +02:00
Mark Paluch
a2f7c3f482 DATAMONGO-1712 - Adopt to ReactiveCrudRepository.findById(Publisher) and existsById(Publisher).
Related ticket: DATACMNS-1063.

Original Pull Request: #467
2017-06-13 19:45:30 +02:00
Christoph Strobl
3440bf6c4d DATAMONGO-1714 - Deprecate MongoLog4jAppender. 2017-06-13 19:24:52 +02:00
Mark Paluch
deed19187f DATAMONGO-1563 - Polishing.
Rename TerminatingAggregationOperation.get() to TerminatingAggregationOperation.all() to name methods consistently. Extract collection name retrieval to method. Javadoc, formatting, add generics where required/use diamond syntax where applicable.

Original pull request: #466.
2017-06-13 10:39:40 +02:00
Christoph Strobl
c5f2abe037 DATAMONGO-1563 - Add fluent alternative for MongoOperations.
We now provide an alternative API for MongoOperations that allows defining operations in a fluent way. FluentMongoOperations reduces the number of methods and strips down the interface to a minimum while offering a more readable API.

// find all with filter query and projecting return type
template.query(Person.class)
    .matching(query(where("firstname").is("luke")))
    .as(Jedi.class)
    .all();

// insert
template.insert(Person.class)
    .inCollection(STAR_WARS)
    .one(luke);

// update with filter & upsert
template.update(Person.class)
    .apply(new Update().set("firstname", "Han"))
    .matching(query(where("id").is("han-solo")))
    .upsert();

// remove all matching
template.remove(Jedi.class)
    .inCollection(STAR_WARS)
    .matching(query(where("name").is("luke")))
    .all();

// aggregate
template.aggregateAndReturn(Jedi.class)
    .inCollection("star-wars)
    .by(newAggregation(project("name")))
    .all();

Original pull request: #466.
2017-06-13 10:39:10 +02:00
Mark Paluch
6cce16414e DATAMONGO-1672 - Updated changelog. 2017-06-08 11:56:20 +02:00
Mark Paluch
a85855a307 DATAMONGO-1710 - Adopt to changed AnnotationUtils.getValue(…) and OperatorNode.getRightOperand() behavior.
Related ticket: SPR-15540.
2017-06-07 17:20:58 +02:00
Mark Paluch
31390d41e0 DATAMONGO-1671 - Updated changelog. 2017-06-07 12:23:35 +02:00
Mark Paluch
117ab7c033 DATAMONGO-1707 - Polishing.
Fix typo in test method names.
2017-06-01 10:08:52 +02:00
Mark Paluch
73fbaaf3bd DATAMONGO-1707 - Upgrade to Reactor 3.1 M2.
Adopt to API change from Publisher.subscribe() to Publisher.toProcessor(). Adopt to changed reactor-test groupId. Provide mocks for calls that allowed previously null Publishers.
2017-06-01 10:08:52 +02:00
Christoph Strobl
17937b0475 DATAMONGO-1699 - Upgrade travis-ci build to use MongoDB 3.4 server.
We now do it explicitly as there seems to be almost no movement getting the alias on the whitelist.
2017-05-24 12:56:57 +02:00
Mark Paluch
46943716ee DATAMONGO-1693 - Support collation in ReactiveMongoTemplate.createCollection.
We now consider Collation via CollectionOptions when creating collections using ReactiveMongoTemplate.createCollection.

Original Pull Request: #462.
2017-05-24 11:03:54 +02:00
Christoph Strobl
25af5b5f79 DATAMONGO-1687 - Polishing.
CollectionOptions is now immutable and returns Optional#empty for values not set. Some minor changes to JavaDoc and required updates for tests involved.

Original Pull Request: #462.
2017-05-24 11:01:00 +02:00
Mark Paluch
a5a4c6d8c4 DATAMONGO-1687 - Initialize collation in CollectionOptions eagerly.
CollectionOptions.collation is initialized with Optional.empty() to guard collection creation against null dereference.

Original Pull Request: #462
2017-05-24 10:58:41 +02:00
Christoph Strobl
5885d084be DATAMONGO-1619 - Polishing.
Align to changes in DATACMNS-995 and emit Exception if findOne yields more than one result.

Original Pull Request: #444
2017-05-22 15:18:06 +02:00
Mark Paluch
d8fdc18265 DATAMONGO-1619 - Use ReactiveQueryByExampleExecutor in ReactiveMongoRepository.
Add ReactiveQueryByExampleExecutor to ReactiveMongoRepository and check by providing tests for the execution invocation.
Move methods into order and add some missing @Override annotations along the way.

Related ticket: DATACMNS-995 via (spring-projects/spring-data-commons#197)

Original Pull Request: #444
2017-05-22 15:16:44 +02:00
Christoph Strobl
840bde65e8 DATAMONGO-1686 - Upgrade to mongodb-driver-reactivestreams 1.4.0. 2017-05-22 14:32:54 +02:00
Christoph Strobl
f2ee7d90c4 DATAMONGO-1690 - Polishing.
Rename QueryDslMongoRepository -> QuerydslMongoRepository. Migrate assertions to AssertJ.

Original pull request #461.
Related ticket: DATACMNS-1059.
2017-05-19 09:38:15 +02:00
Christoph Strobl
898489fecf DATAMONGO-1690 - Adapt to QuerydslPredicateExecutor API changes.
We now return Optional<T> for QuerydslPredicateExecutor.findOne(Predicate).

Original pull request #461.
Related ticket: DATACMNS-1059.
2017-05-19 09:36:44 +02:00
Oliver Gierke
3575d5461e DATAMONGO-1695 - Polishing.
Javadoc. Variable names. Move off deprecated methods. Removed obsolete private method.
2017-05-18 13:27:46 +02:00
Oliver Gierke
4fa09d80db DATAMONGO-1695 - Make sure we read GridFs content type from the same field we write it to.
We now consistently store the content type of a file in _contentType in the metadata document. On the lookup side we still fall back to the deprecated file.getContentType().
2017-05-18 13:27:10 +02:00
Christoph Strobl
bb84b92d1d DATAMONGO-1685 - Polishing.
Migrate assertions to AssertJ. Fix Javadoc.

Original pull request: #460.
2017-05-11 09:51:58 +02:00
Christoph Strobl
af85b46e7d DATAMONGO-1685 - Adapt to QueryByExampleExecutor API changes.
Use Optional as return type for findOne(Example example).

Related ticket: DATACMNS-1058.

Original pull request: #460.
2017-05-11 09:51:33 +02:00
Mark Paluch
96fbe49cdb DATAMONGO-1664 - After release cleanups. 2017-05-09 11:34:42 +02:00
Mark Paluch
6b36c792b9 DATAMONGO-1664 - Prepare next development iteration. 2017-05-09 11:34:41 +02:00
Mark Paluch
006c8cfae2 DATAMONGO-1664 - Release version 2.0 M3 (Kay). 2017-05-09 11:23:00 +02:00
Mark Paluch
14aed4c348 DATAMONGO-1664 - Prepare 2.0 M3 (Kay). 2017-05-09 11:22:12 +02:00
Mark Paluch
37165dd76d DATAMONGO-1664 - Updated changelog. 2017-05-09 11:22:07 +02:00
Mark Paluch
b22fd056aa DATAMONGO-1667 - Rename @InfiniteStream to @Tailable.
Rename InfiniteStream annotation to Tailable to reflect the related MongoDB approach used for repository query methods returning an infinite stream. InfiniteStream is the high-level concept that is achieved by using tailable cursors.

Original Pull Request: #458
2017-05-04 15:17:14 +02:00
Mark Paluch
42672a6df9 DATAMONGO-1518 - Polishing.
Rename ICULocale to CollationLocale. Introduce interface for ComparisonLevel construction and let ICUComparisonLevel types implement that interface. Make value types immutable where possible. Provide static instances for default comparison level instances.

Replace collation conversion IndexConverters with Collation.from(…).toMongoCollation() converter. Introduce missing generic types. Replace Optional.get() with Optional.map(…).orElse(…).

Update reference documentation.

Original pull request: #459.
2017-05-04 11:36:05 +02:00
Christoph Strobl
0b169d5341 DATAMONGO-1518 - Add support for collations.
We now support collations for collections, indexes, queries, findAndModify, delete, geo, bulk and aggregation operations in both the imperative and reactive implementations on template level.

Collation collation = Collation.of("fr")
  .strength(ComparisonLevel.secondary()
    .includeCase())
  .numericOrderingEnabled()
  .alternate(Alternate.shifted().punct())
  .forwardDiacriticSort()
  .normalizationEnabled();

template.createCollection(Person.class, CollectionOptions.just(collation));

Query query = new Query(Criteria.where("firstName").is("Amél")).collation(collation);

Original pull request: #459.
2017-05-04 11:33:44 +02:00
Oliver Gierke
b9d301e525 DATAMONGO-1679 - Further removal of Serializable as requirement for identifiers. 2017-05-03 18:23:31 +02:00
Oliver Gierke
e3238593ce DATAMONGO-1679 - Adapt to API changes in repository interfaces. 2017-05-03 17:51:45 +02:00
Mark Paluch
5d8370fa90 DATAMONGO-1684 - Adopt documentation to removed JodaTime DateMidnight support.
Related ticket: DATACMNS-1014.
2017-05-03 08:34:56 +02:00
Oliver Gierke
e01c745884 DATAMONGO-1674 - Adapted to Range API changes. 2017-04-26 18:02:29 +02:00
Mark Paluch
9ae3a29103 DATAMONGO-1660 - Adapt to moved CustomConversions to Spring Data Commons.
Introduce MongoCustomConversions extending o.s.d.convert.CustomConversions.

Remove o.s.d.mongo.core.convert.CustomConversions implementation code and utility classes and let it extend MongoCustomConversions. Replace references to o.s.d.m.c.c.CustomConversions with o.s.d.convert.CustomConversions. Adapt tests and MappingMongoConverter to MongoCustomConversions.

Related ticket: DATACMNS-1035.
2017-04-24 13:20:11 +02:00
Mark Paluch
6a446cbc7f DATAMONGO-1325 - Polishing.
Add since tag to new method. Set year of inception in copyright header. Add ticket reference to test. Minor code reformatting. Add integration test.

Change query keyword for query-by-example from $sample to $example to prevent accidental collisions.

Remove Mongo 3.4-next build profile due to removed Mongo 3.4 driver snapshots.

Original pull request: #452.
2017-04-20 10:55:49 +02:00
Gustavo de Geus
d40084f78e DATAMONGO-1325 - Add $sample aggregation stage.
We now support the $sample aggregation pipeline stage via Aggregation to select a random subset of result documents.

TypedAggregation<Employee> agg = Aggregation.newAggregation(Employee.class,
		sample(5));

Original pull request: #452.
2017-04-20 10:42:50 +02:00
Mark Paluch
7bfbff0602 DATAMONGO-1205 - Polishing.
Add author tag. Extend year range in copyright header.

Original pull request: #397.
2017-04-20 08:41:22 +02:00
Martin Macko
fc377cf0f9 DATAMONGO-1205 - Log only CyclicPropertyReferenceException message.
We log CyclicPropertyReferenceException with its message only and removed the stack trace from the log. The stacktrace points to a verifier location and is not particularly useful in finding the offending code. This change creates consistency over how CyclicPropertyReferenceException is logged.

Original pull request: #397.
2017-04-20 08:41:00 +02:00
Oliver Gierke
d594afb5bb DATAMONGO-1670 - Updated changelog. 2017-04-19 21:04:19 +02:00
Oliver Gierke
3012e228c5 DATAMONGO-1669 - Updated changelog. 2017-04-19 20:01:47 +02:00
Mark Paluch
0a947da7e4 DATAMONGO-1668 - Polishing.
Replace new Sort(…) with Sort.by(…) and new PageRequest(…) with PageRequest.of(…).
2017-04-19 15:11:19 +02:00
Mark Paluch
eb85fb3a14 DATAMONGO-1668 - Adopt changed Mono and Flux error handling API.
Replace Flux/Mono.onErrorResumeWith(…) with Flux/Mono.onErrorMap(…) and turn translateException into a method returning a mapping function instead of a reactive type emitting the mapped exception.
2017-04-19 14:54:14 +02:00
Oliver Gierke
ebc8c5df3a DATAMONGO-1634 - Updated changelog. 2017-04-19 13:04:08 +02:00
Oliver Gierke
5b52af4efe DATAMONGO-1633 - Updated changelog. 2017-04-19 11:50:47 +02:00
Christoph Strobl
74161162b4 DATAMONGO-1666 - Polishing.
Some minor language level cleanups and removal of deprecated API usage.

Original Pull Request: #457
2017-04-13 11:26:18 +02:00
Mark Paluch
bcba123e32 DATAMONGO-1666 - Consider collection type in bulk DBRef fetching.
We now consider the property's collection type after bulk-fetching DBRefs before returning the actual result value. The issue got only visible if bulk fetching is possible and constructor creation is used. Setting the property value on through an property accessor works fine because the property accessor checks all values for assignability and potentially converts values to their target type. That's different for constructor creation.

Original Pull Request: #457
2017-04-13 11:25:47 +02:00
Sebastien Deleuze
935db07511 DATAMONGO-1665 - Upgraded to Reactor 3.1.0.BUILD-SNAPSHOT.
Original pull request: #456.
Related ticket: spring-projects/spring-data-build#333
2017-04-12 07:20:55 +02:00
Oliver Gierke
314b95370f DATAMONGO-1597 - Updated changelog. 2017-04-10 13:41:25 +02:00
Michael J. Simons
20929b34f1 DATAMONGO-1662 - Fix classname in reference docs about projections in aggregations.
Original pull request: #455.
2017-04-10 09:13:12 +02:00
Oliver Gierke
782bcd4d5f DATAMONGO-1535 - After release cleanups. 2017-04-04 22:08:18 +02:00
Oliver Gierke
33fb40c872 DATAMONGO-1535 - Prepare next development iteration. 2017-04-04 22:08:15 +02:00
Oliver Gierke
bf61c5782e DATAMONGO-1535 - Release version 2.0 M2 (Kay). 2017-04-04 21:12:35 +02:00
Oliver Gierke
431e71f4a0 DATAMONGO-1535 - Prepare 2.0 M2 (Kay). 2017-04-04 21:12:02 +02:00
Oliver Gierke
3192d7dd78 DATAMONGO-1535 - Updated changelog. 2017-04-04 21:11:53 +02:00
Christoph Strobl
d7a6594933 DATAMONGO-1655 - Remove obsolete build profiles.
And add snapshot profile for 3.5.0.
2017-04-03 18:37:19 +02:00
Christoph Strobl
609d6d5a19 DATAMONGO-1656 - Upgrade to MongoDB Driver 3.4.2 and Reactive Streams Driver 1.3.0.
Prepare issue branch.
2017-04-03 18:37:06 +02:00
Mark Paluch
19c8788376 DATAMONGO-1643 - Polishing.
Fix documentation for namespace types. Remove unused ReflectiveDBCollectionInvoker. Simplify tests, align bean name to mongoClient. Remove injection of Mongo in favor of injecting MongoTemplate.

Remove throws declaration from AbstractMongoConfiguration.mongoClient(). MongoClient creation does not throw checked exceptions so throwing an Exception is no longer required. Replace Mongo by MongoClient in reference documentation.

Original pull request: #451.
2017-04-03 15:36:58 +02:00
Christoph Strobl
db9934c7d8 DATAMONGO-1643 - Replace references to Mongo by MongoClient.
Remove and replace usage of "mongo" by "mongoClient". This involves xsd schema, bean names, constructor and parameter types. This required some API changes as some server commands are no longer directly available through the api, but have to be invoked via runCommand.

Also remove references to outdated API using Credentials and an authentication DB instead of MongoCredentials for authentication.

Updated and removed (unused) tests; Altered documentation.

Original pull request: #451.
2017-04-03 15:35:43 +02:00
Christoph Strobl
b5679744e7 DATAMONGO-1643 - Add and use 2.0 namespace xsd.
Original pull request: #451.
2017-04-03 15:35:27 +02:00
Mark Paluch
b1acda4188 DATAMONGO-1610 - Support RxJava 2 repositories.
Add RxJava 2 dependency. Add test to verify RxJava 2 interoperability.

Original Pull Request: #440
2017-04-03 14:57:11 +02:00
Christoph Strobl
2ab466eb35 DATAMONGO-1447 - Add support for isolations on Update.
We now allow usage of the $isolated update operator via Update.isolated().
In case isolated is set the query involved in MongoOperations.updateMulti will be enhanced by '$isolated' : 1 in case the isolation level has not already been set explicitly via eg. new BasicQuery("{'$isolated' : 0}").

Original pull request: #371.
2017-04-03 13:53:00 +02:00
Mark Paluch
e9da449667 DATAMONGO-1559 - Drop collections used in ReactiveMongoTemplateExecuteTests before tests.
We now drop the collections used in ReactiveMongoTemplateExecuteTests on test start to create a clean state for the tests. Previously, collections were dropped after the tests only so existing data in the collections could interfere with the tests themselves.
2017-03-27 08:40:10 +02:00
John Blum
6bc72a654f DATAMONGO-1648 - Rename getRepositoryFactoryClassName to getRepositoryFactoryBeanClassName. 2017-03-24 13:36:11 -07:00
Mark Paluch
4fd9edf585 DATAMONGO-1559 - Polishing.
Migrate off deprecated Cancellation API to Disposable.
2017-03-24 17:46:41 +01:00
Mark Paluch
955597bb54 DATAMONGO-1559 - Migrate reactive tests from TestSubscriber to StepVerifier. 2017-03-24 17:42:31 +01:00
Oliver Gierke
f59bbd351d DATAMONGO-1647 - Polishing. 2017-03-24 12:25:21 +01:00
Oliver Gierke
43ab3cad13 DATAMONGO-1647 - Switched to use IdentifierAccessor.getRequiredIdentifier() in MongoTemplate.doSaveVersioned(…). 2017-03-24 12:24:57 +01:00
Oliver Gierke
5ba46dadb8 DATAMONGO-1609 - Switched to Mockito from parent POM.
Moved of deprecated runner declarations.
2017-03-24 08:54:29 +01:00
Oliver Gierke
a245c0f280 DATAMONGO-1609 - Adapt to API changes in Spring Data Commons. 2017-03-24 08:54:29 +01:00
Christoph Strobl
288f244c34 DATAMONGO-1609 - Fix failing tests.
Fix issues pointed out by failing tests. Main focus was to restore functionality and not a Java 8 code cleanup. So, this one still needs some love and polishing.
2017-03-24 08:54:29 +01:00
Christoph Strobl
90bb6262f9 DATAMONGO-1609 - Fix compile errors.
Still way to go:
  - Failures: 113, Errors: 836, Skipped: 16
2017-03-24 08:54:29 +01:00
Oliver Gierke
826d00afa7 DATAMONGO-1609 - Hacking. 2017-03-24 08:54:29 +01:00
Mark Paluch
ac3f7dbf99 DATAMONGO-1645 - Polishing.
Clean up appender and log level after test run. Suppress log output during tests.

Original pull request: #450.
2017-03-21 10:52:14 +01:00
Christoph Strobl
f70e1fa291 DATAMONGO-1645 - Safely serialize JSON output for log message in LoggingEventListener.
We now make sure to safely serialize JSON output for mapped documents. This prevents the logger from rendering false exception messages to log appender.

Original pull request: #450.
2017-03-21 10:45:13 +01:00
Mark Paluch
a84c4b064d DATAMONGO-1637 - Polishing.
Move aggregation options conversion to AggregationOptions.getMongoAggregationOptions(). Allow cursor options to control cursor batch size. Add command logging to stream execution. Rearrange method order. Close cursor in tests. Change author name from user name to full name.

Original pull request: #447.
2017-03-21 09:57:25 +01:00
Mainder Singh
1a65828365 DATAMONGO-1637 - Add support for aggregation result streaming.
We now support aggregation result streaming backed by a MongoDB cursor. Result streaming fetches aggregation results in batches from MongoDB and converts results as they are retrieved through the iterator.

Aggregation aggregation = …

CloseableIterator<TagCount> results = mongoOperations.aggregateStream(aggregation, "inputCollection", TagCount.class);

List<TagCount> tagCount = new ArrayList<TagCount>();
while (results.hasNext()) {
	tagCount.add(results.next());
}

results.close();

Original pull request: #447.
2017-03-21 09:56:53 +01:00
Mark Paluch
f4f5e02e66 DATAMONGO-1620 - Polishing.
Fix test method name. Add JavaDoc.

Original pull request: #449.
2017-03-13 16:28:54 +01:00
Christoph Strobl
4b8d35262f DATAMONGO-1620 - Add server-selection-timeout to XML MongoClientOptions config.
We now allow server-selection-timeout attribute on MongoClientOptions XML configuration for a MongoDB 3.x client.

Original pull request: #449.
2017-03-13 16:28:49 +01:00
Mark Paluch
b486fec048 DATAMONGO-1641 - Remove formatting config from the repository.
See https://github.com/spring-projects/spring-data-build/tree/master/etc/ide for most recent IDE settings.
2017-03-08 11:45:42 +01:00
Mark Paluch
50fcbd18f2 DATAMONGO-1421 - Polishing.
Remove trailing whitespaces. Construct exception message with String.format(…).

Original pull request: #448.
2017-03-08 08:56:03 +01:00
Christoph Strobl
c37dfd9688 DATAMONGO-1421 - Fix serialization in error message causing error itself.
We now make sure to safely serialize the criteria object used for creating the error message when raising an `InvalidMongoDbApiUsageException` in cases where `addCriteria` is used to add multiple entries for the same property.

Original pull request: #448.
2017-03-08 08:55:43 +01:00
Oliver Gierke
98d655f4e2 DATAMONGO-1639 - Make sure BeforeConvertEvent sees new version for updates.
The changes for DATAMONGO-1617 subtley changed the behavior for entity updates in terms of the version value they see for entities using optimistic locking. Previously the updates already saw the new version value, where after the fix for DATAMONGO-1617 it saw the old one. That caused BeforeConvertEvent listeners not being able to distinguish between an original insert and the first update anymore.

This change is now rolled back and we introduced a test case that encodes this expectation explicitly.
2017-03-06 16:32:19 +01:00
Oliver Gierke
98a9b66e6b DATAMONGO-1617 - Reinstantiate version property initialization before BeforeConvertEvent publication.
Related pull request: #443.
2017-03-03 08:46:28 +01:00
Oliver Gierke
827b6204a9 DATAMONGO-1617 - Polishing.
Some cleanups in MongoTemplateTests. Removed manual ID assignment in general id handling test to make sure we use the id generation. Removed unneccessary code from domain type in favor of Lombok.

Original pull request: #443.
2017-03-03 08:36:21 +01:00
Laszlo Csontos
781717faa8 DATAMONGO-1617 - BeforeConvertEvent is now emitted before updatable idendifier assertion.
We now make sure the BeforeConvertEvent is published before we check for identifier types that can potentially be auto-generated. That allows the event listeners to populate identifiers. Previously the identifier check kicked in before that and thus caused the listener not being able to populate the property.

Original pull request: #443.
2017-03-03 08:36:05 +01:00
Oliver Gierke
084a167e20 DATAMONGO-1598 - Updated changelog. 2017-03-02 11:11:03 +01:00
Mark Paluch
456ae2459f DATAMONGO-1605 - Polishing.
Remove additional quoting around JSON serialization because JSON serialization adds quotes to a string. Reformat code.
2017-03-01 16:14:03 +01:00
Christoph Strobl
d079edb92c DATAMONGO-1605 - Retain type of SpEL expression result when used in @Query.
Fix issue where any result of a SpEL expression had been treated as quoted String within the resulting MongoDB query.
2017-03-01 16:14:00 +01:00
Mark Paluch
eb97944fd4 DATAMONGO-1600 - Make GraphLookupOperationBuilder public.
Make GraphLookupOperationBuilder public so it can be used in types outside the aggregation package.

Original Pull Request: #437
2017-03-01 12:55:39 +01:00
Mark Paluch
e2d6f187c2 DATAMONGO-1603 - Polishing.
Remove code that became unused. Reformat code. Extend years in copyright header.

Original pull request: #441.
2017-03-01 08:54:32 +01:00
Christoph Strobl
8068e36679 DATAMONGO-1603 - Fix Placeholder not replaced correctly in @Query.
Fix issues when placeholders are appended with other chars eg. '?0xyz' or have been reused multiple times within the query. Additional tests and fixes for complex quoted replacements eg. in regex query. Rely on placeholder quotation indication instead of binding one. Might be misleading when placeholder is used more than once.

Original pull request: #441.
2017-03-01 08:52:18 +01:00
Christoph Strobl
c62d13154f DATAMONGO-1608 - Polishing.
Throw an IllegalArgumentException when trying to create a query using 'null' as an argument for queries resulting in a $regex query operator.

Original Pull Request: #439
2017-02-13 08:33:12 +01:00
Edward Prentice
7d53f21d58 DATAMONGO-1608 - Add guard against NPE in MongoQueryCreator when using IgnoreCase.
Original Pull Request: #439
2017-02-13 08:28:26 +01:00
Christoph Strobl
0000a8fd11 DATAMONGO-1607 - Polishing.
Move coordinate conversion to dedicated method. Additionally fix issue with assertions applied to late in the chain and added some tests.

Original Pull Request: #438
2017-02-10 14:24:37 +01:00
Thiago Diniz da Silveira
fad9756a93 DATAMONGO-1607 - Fix ClassCastException in Circle, Point and Sphere when coordinates are not Double.
Original Pull Request: #438
2017-02-10 14:19:06 +01:00
Mark Paluch
54acc4934c DATAMONGO-1602 - Remove references to Assert single-arg methods.
Replace references to Assert single-arg methods with references to methods accepting the test object and message.

Related ticket: SPR-15196.
2017-02-01 11:08:11 +01:00
Oliver Gierke
2e593bb9b2 DATAMONGO-1573 - Updated changelog. 2017-01-26 12:12:37 +01:00
Oliver Gierke
2bf32a25be DATAMONGO-1574 - Updated changelog. 2017-01-26 12:12:07 +01:00
Christoph Strobl
148c4f9e24 DATAMONGO-1517 - Polishing.
Remove ReflectiveSimpleTypes in favor of MongoSimpleTypes.
Add add integration test.
2017-01-25 17:12:31 +01:00
Mark Paluch
ae6171802e DATAMONGO-1517 - Add support for Decimal128 BSON type.
Support Decimal128 as Mongo simple type if present. Decimal128 is stored as NumberDecimal.

class Person {

  String id;
  Decimal128 decimal128;

  Person(String id, Decimal128 decimal128) {
    this.id = id;
    this.decimal128 = decimal128;
  }
}

mongoTemplate.save(new Person("foo", new Decimal128(new BigDecimal("123.456"))));

is represented as:

{ "_id" : "foo", "decimal128" : NumberDecimal("123.456") }
2017-01-25 17:12:31 +01:00
Mark Paluch
1b97d1d1d0 DATAMONGO-1596 - Fix typo in JavaDoc.
Use correct @RelatedDocument annotation in MongoDB cross store reference documentation.
2017-01-25 16:53:41 +01:00
Mark Paluch
91495825a5 DATAMONGO-1575 - Polishing.
Extend year range in license headers. Use MongoDB JSON serializer for String escaping. Move unquoting/quote checking to inner QuotedString utility class. Reformat code.
2017-01-25 11:44:12 +01:00
Christoph Strobl
18e6b9cfa7 DATAMONGO-1575 - Escape Strings correctly.
Use regex groups and parameter index values for replacement in string based queries.
2017-01-25 11:44:09 +01:00
Christoph Strobl
0e0b8d5f79 DATAMONGO-1594 - Update "what’s new" section in reference documentation. 2017-01-23 08:23:51 +01:00
Oliver Gierke
11882724fa DATAMONGO-1592 - Adapt AuditingEventListenerUnitTests to changes in core auditing.
The core auditing implementation now skips the invocation of auditing in case the candidate aggregate doesn't need any auditing in the first place. We needed to adapt the sample class we use to actually carry the necessary auditing annotations.

Related ticket: DATACMNS-957.
2017-01-20 16:36:45 +01:00
Oliver Gierke
eb2a58cdbe DATAMONGO-1590 - Polishing.
Removed some compiler warnings. Hide newly introduced class in package scope and made use of Lombok annotations to avoid boilerplate code.

Original pull request: #436.
2017-01-18 19:42:46 +01:00
Christoph Strobl
8c9bbf7f91 DATAMONGO-1590 - EntityInformation selected now correctly considers Persistable.
We now wrap the MappingMongoEntityInformation into one that delegates the methods implemented by Persistable to the actual entity in case it implements said interface.

Original pull request: #436.
2017-01-18 19:42:42 +01:00
Mark Paluch
63fc047160 DATAMONGO-1581 - Expose ReactiveMongoRepositoryConfigurationExtension as public type.
Expose ReactiveMongoRepositoryConfigurationExtension so configuration extensions such as Spring Boot's ReactiveMongoRepositoriesAutoConfigureRegistrar can pick it up and reuse the repository configuration extension.
2017-01-17 14:14:08 +01:00
Mark Paluch
44e872c7df DATAMONGO-1588 - Polishing.
Remove unused fields. Fix typo in method name. Reformat inner class to align formatting.

Original pull request: #435.
2017-01-16 09:29:10 +01:00
Christoph Strobl
1135e90be0 DATAMONGO-1588 - Fix derived finder not accepting subclass of parameter type.
We now allow using sub types as arguments for derived queries. This makes it possible to use eg. a GeoJsonPoint for querying while the declared property type in the domain object remains a regular (legacy) Point.

Original pull request: #435.
2017-01-16 09:29:06 +01:00
Mark Paluch
65da90afd8 DATAMONGO-1589 - Update project documentation with the CLA tool integration. 2017-01-13 11:46:58 +01:00
Mark Paluch
4856c9b4f5 DATAMONGO-1587 - Polishing.
Convert @see http://… links to valid format using @see <a href=…>…</a>
2017-01-12 17:24:03 +01:00
Mark Paluch
644c1a2c89 DATAMONGO-1587 - Migrate ticket references in test code to Spring Framework style. 2017-01-12 16:51:57 +01:00
Mark Paluch
8df9d30d2e DATAMONGO-1586 - Consider field name in TypeBasedAggregationOperationContext.getReferenceFor(…).
We now consider the provided field name (alias) in mapped fields with which it is exposed. The field name applies to the exposed field after property path resolution in TypeBasedAggregationOperationContext. Previously, the field reference used the property name which caused fields to be considered non-aliased, so aggregation projection operations dropped the alias and exposed the field with its leaf property name.

Original Pull Request: #434
2017-01-12 10:34:02 +01:00
Christoph Strobl
90ae6d1805 DATAMONGO-1585 - Polishing.
Update documentation for better readability in html and pdf format.

Original Pull Request: #433
2017-01-12 10:19:55 +01:00
Mark Paluch
1fe79f1194 DATAMONGO-1585 - Expose synthetic fields in $project aggregation stage.
Field projections now expose their fields as synthetic simple fields. Projection aggregation stage redefines the available field set available for later aggregation stages entirely so projected fields are considered synthetic. A simple synthetic field has no target field which causes later aggregation stages to not pick up the underlying target but the exposed field name when rendering aggregation operations to Mongo documents.

The change is motivated by a bug where previously an aggregation consisting of projection of an aliased field and sort caused the sort projection stage to render with the original field name instead of the aliased field. The sort did not apply any sorting since projection redefines the available field set entirely and the original field is no longer accessible.

Original Pull Request: #433
2017-01-12 10:19:10 +01:00
Christoph Strobl
2c6bd6ecea DATAMONGO-1576 - Update lifecycle event documentation.
Add note on lifecycle event handling for property types.
2017-01-11 13:10:25 +01:00
Mark Paluch
fc5bb3f1d3 DATAMONGO-1578 - Polishing.
Add ticket references to test methods. Extend license years in copyright header.

Original pull request: #398.
2017-01-02 11:46:57 +01:00
Martin Macko
d4d9c7673a DATAMONGO-1578 - Add missing @Test annotation to ProjectionOperationUnitTests.
Original pull request: #398.
2017-01-02 11:45:04 +01:00
Mark Paluch
20e2cfb273 DATAMONGO-1508 - Improve reference documentation.
Replace Spring Data Document with Spring Data MongoDB. Extend copyright year range. Replace static Spring version leftover with variable. Fix typos.
2017-01-02 11:19:59 +01:00
Lukasz Kryger
634f618eb1 DATAMONGO-1577 - Fix wording repetition in MongoRepository JavaDoc.
Original pull request: #407.
2017-01-02 11:19:59 +01:00
Ken Dombeck
c6e2662151 DATAMONGO-1577 - Fix Reference and JavaDoc spelling issues.
Replaced invalid class name MongoMappingConverter with actual class name of MappingMongoConverter. Fix typos.

Original pull request: #425.
2017-01-02 11:19:56 +01:00
Mark Paluch
51ae618585 DATAMONGO-1508 - Polishing.
Highlight attribute name. Replace tabs with spaces.

Original pull request: #399.
2017-01-02 11:14:25 +01:00
John Lilley
b584f04a41 DATAMONGO-1508 - Document authentication-dbname attribute in db-factory.
Original pull request: #399.
2017-01-02 11:14:25 +01:00
Oliver Gierke
6e1e9967af DATAMONGO-1522 - Updated changelog. 2016-12-21 19:35:37 +01:00
Oliver Gierke
af49230093 DATAMONGO-1469 - Updated changelog. 2016-12-21 18:43:02 +01:00
Oliver Gierke
3355a436c8 DATAMONGO-1467 - Polishing.
Original pull request: #431.
2016-12-20 14:26:40 +01:00
Christoph Strobl
9a0241992e DATAMONGO-1467 - Add support for MongoDB 3.2 partialFilterExpression for index creation.
We now support partial filter expression on indexes via Index.partial(…). This allows to create partial indexes that only index the documents in a collection that meet a specified filter expression.

new Index().named("idx").on("k3y", ASC).partial(filter(where("age").gte(10)))

The filter expression can be set via a plain DBObject or a CriteriaDefinition and is mapped against the associated domain type.

Original pull request: #431.
2016-12-20 14:19:28 +01:00
Oliver Gierke
779145645d DATAMONGO-1565 - Polishing.
Formatting in ExpressionEvaluatingParameterBinder and StringBasedMongoQueryUnitTests. Turned Placeholder into value object.
2016-12-20 11:37:28 +01:00
Mark Paluch
c0f3255e26 DATAMONGO-1565 - Polishing.
Consider quoted/unquoted parameter use with the same parameter reference. Extend date range in license headers.
2016-12-20 11:37:05 +01:00
Christoph Strobl
b1de52f05a DATAMONGO-1565 - Ignore placeholder pattern in replacement values for annotated queries.
We now make sure to quote single and double ticks in the replacement values before actually appending them to the query. We also replace single ticks around parameters in the actual raw annotated query by double quotes to make sure they are treated as a single string parameter.
2016-12-20 11:30:02 +01:00
Mark Paluch
646b525d86 DATAMONGO-1564 - Polishing.
Fix JavaDoc references and minor a import formatting issue.

Original pull request: #429.
2016-12-16 14:10:15 +01:00
Christoph Strobl
2c29f204c3 DATAMONGO-1564 - Split up AggregationExpressions.
Refactored to multiple smaller Aggregation Operator classes reflecting the grouping (array operators, string operators,…) predefined by MongoDB.

Original pull request: #429.
2016-12-16 14:00:22 +01:00
Mark Paluch
9cd44faeb7 DATAMONGO-1567 - Use newer Java 8 on Travis CI. 2016-12-16 10:31:22 +01:00
Mark Paluch
362de45664 DATAMONGO-1533 - Polishing.
Extend JavaDoc. Minor reformatting.

Original pull request: #428.
2016-12-16 09:24:42 +01:00
Christoph Strobl
b7317892a2 DATAMONGO-1533 - Add AggregationExpression derived from SpEL AST.
We added an AggregationExpression that renders a MongoDB Aggregation Framework expression from the AST of a SpEL expression. This allows usage with various stages (eg. $project, $group) throughout the aggregation support.

  // { $and: [ { $gt: [ "$qty", 100 ] }, { $lt: [ "$qty", 250 ] } ] }
  expressionOf("qty > 100 && qty < 250);

  // { $cond : { if : { $gte : [ "$a", 42 ]}, then : "answer", else : "no-answer" } }
  expressionOf("cond(a >= 42, 'answer', 'no-answer')");

Original pull request: #428.
2016-12-16 09:21:27 +01:00
Mark Paluch
35f43e9ab8 DATAMONGO-1566 - Adapt API in ReactiveMongoRepositoryFactoryBean.
Related tickets: DATACMNS-891.
2016-12-16 09:21:27 +01:00
Oliver Gierke
a77c5b6e1d DATAMONGO-1566 - Adapt API in MongoRepositoryFactoryBean.
Related tickets: DATACMNS-891.
2016-12-15 16:17:54 +01:00
Christoph Strobl
5cf8ec3e55 DATAMONGO-1552 - Polishing.
Updated doc, removed whitespaces, minor method wording changes.

Original Pull Request: #426
2016-12-14 13:09:06 +01:00
Mark Paluch
450549150d DATAMONGO-1552 - Add $facet aggregation stage.
Original Pull Request: #426
2016-12-14 12:00:30 +01:00
Mark Paluch
b7a0b1d523 DATAMONGO-1552 - Add $bucketAuto aggregation stage.
Original Pull Request: #426
2016-12-14 11:46:54 +01:00
Mark Paluch
5c5c616be9 DATAMONGO-1552 - Add $bucket aggregation stage.
Original Pull Request: #426
2016-12-14 11:32:50 +01:00
Mark Paluch
0bd98d67c8 DATAMONGO-442 - Polishing.
Reformat code according to Spring Data style. Add test for authenticated use. Add JavaDoc to newly introduced methods. Allow configuration of an authentication database. Update reference documentation.

Original pull request: #419.
2016-12-13 16:51:02 +01:00
Ricardo Espirito Santo
8302727b23 DATAMONGO-442 - Support username/password authentication with MongoLog4jAppender.
Added optional username and password for authentication support on Log4jAppender.

Original pull request: #419.
2016-12-13 16:48:02 +01:00
Christoph Strobl
86dbd95220 DATAMONGO-1551 - Polishing.
Add startWith overload allowing to mix expressions, removed white spaces, updated doc.

Original Pull Request: #424
2016-12-13 15:15:00 +01:00
Mark Paluch
3d0750afc5 DATAMONGO-1551 - Add $graphLookup aggregation stage.
We now support the $graphLookup aggregation pipeline stage via Aggregation to perform recursive lookup adding the lookup result as array to documents entering $graphLookup.

TypedAggregation<Employee> agg = Aggregation.newAggregation(Employee.class,
		graphLookup("employee")
			.startWith("reportsTo")
			.connectFrom("reportsTo")
			.connectTo("name")
			.depthField("depth")
			.maxDepth(5)
			.as("reportingHierarchy"));

Original Pull Request: #424
2016-12-13 14:44:53 +01:00
Christoph Strobl
1bf8eb09ca DATAMONGO-1550 - Polishing $replaceRoot (aggregation stage).
Original Pull Request: #422.
2016-12-13 08:18:40 +01:00
Mark Paluch
ae4cfaa58c DATAMONGO-1550 - Add $replaceRoot aggregation stage.
We now support the $replaceRoot stage in aggregation pipelines. $replaceRoot can reference either a field, an aggregation expression or it can be used to compose a replacement document.

newAggregation(
	replaceRoot().withDocument()
		.andValue("value").as("field")
		.and(MULTIPLY.of(field("total"), field("discounted")))
);

newAggregation(
	replaceRoot("item")));

Original Pull Request: #422
2016-12-13 08:18:40 +01:00
Christoph Strobl
1dea009e32 DATAMONGO-1549 - Polishing $count (aggregation stage).
Original Pull Request: #422
2016-12-13 08:18:27 +01:00
Mark Paluch
4c07235107 DATAMONGO-1549 - Add $count aggregation stage.
We now support the $count stage in aggregation pipelines.

newAggregation(
	match(where("hotelCode").is("0360")),
	count().as("documents"));

Original Pull Request: #422
2016-12-13 08:18:10 +01:00
Christoph Strobl
5ebbf93cf9 DATAMONGO-1558 - Upgrade MongoDB server version to, and add build profile for MongoDB 3.4.
Added MongoDB 3.4 profile to pom.xml and upgraded to MongoDB 3.4 on travis-ci.
Delete assertion checking property that has been removed in MongoDB 3.4 (see: https://jira.mongodb.org/browse/SERVER-24928)
2016-12-13 08:18:10 +01:00
Mark Paluch
794756d055 DATAMONGO-1548 - Polishing.
Enhance JavaDoc. Minor formatting. Fix typos.

Original pull request: #423.
2016-12-12 12:58:36 +01:00
Christoph Strobl
4fcc09c6c1 DATAMONGO-1548 - Add support for MongoDB 3.4 aggregation operators.
We now support the following MongoDB 3.4 aggregation operators:

$indexOfBytes, $indexOfCP, $split, $strLenBytes, $strLenCP, $substrCP, $indexOfArray, $range, $reverseArray, $reduce, $zip, $in, $isoDayOfWeek, $isoWeek, $isoWeekYear, $switch and $type.

Original pull request: #423.
2016-12-12 12:58:32 +01:00
Mark Paluch
d297f5a253 DATAMONGO-1538 - Polishing.
Use InheritingExposedFieldsAggregationOperationContext instead of anonymous context class for condition mapping. Drop aggregation input collections before tests. Minor reformatting.

Original pull request: #417.
2016-12-07 10:01:20 +01:00
Christoph Strobl
696e53ff60 DATAMONGO-1538 - Add support for $let to aggregation.
We now support $let in aggregation $project stage.

ExpressionVariable total = newExpressionVariable("total").forExpression(ADD.of(field("price"), field("tax")));
ExpressionVariable discounted = newExpressionVariable("discounted").forExpression(Cond.when("applyDiscount").then(0.9D).otherwise(1.0D));

newAggregation(Sales.class,
	project()
		.and(define(total, discounted)
			.andApply(MULTIPLY.of(field("total"), field("discounted"))))
		.as("finalTotal"));

Original pull request: #417.
2016-12-07 10:01:17 +01:00
Christoph Strobl
f512d8cb16 DATAMONGO-1542 - Polishing.
Added some static entry points for better readability.

Original Pull Request: #421
2016-12-06 10:08:05 +01:00
Mark Paluch
b98bc0e2bf DATAMONGO-1542 - Refactor CondOperator and IfNullOperator to children of AggregationExpressions.
Renamed CondOperator to Cond and IfNullOperator to IfNull. Both conditional operations are now available from ConditionalOperators.when and ConditionalOperators.ifNull and accept AggregationExpressions for conditions and values.

Original Pull Request: #421
2016-12-06 10:06:58 +01:00
Christoph Strobl
f64d205522 DATAMONGO-1520 - Add overload for aggregation $match accepting CriteriaDefinition.
We now also accept CriteriaDefinition next to Criteria for Aggregation.match. The existing match(Criteria) method remains to preserve binary compatibility.
2016-12-06 09:05:39 +01:00
Mark Paluch
853b2b2d5c DATAMONGO-1540 - Polishing.
Reduce Map aggregation expression builder entrypoint. Fix JavaDoc.

Original pull request: #420.
2016-12-05 16:46:50 +01:00
Christoph Strobl
c3f9af01e6 DATAMONGO-1540 - Add support for $map (aggregation).
We now support $map operator in aggregation.

Original pull request: #420.
2016-12-05 16:46:41 +01:00
Oliver Gierke
655a1e0351 DATAMONGO-1547 - Register MongoRepositoryFactory in spring.factories.
This is required for the switch in support for multi-store detection.

Related ticket: DATACMNS-952.
2016-12-05 14:28:26 +01:00
Oliver Gierke
26395f1b78 DATAMONGO-1546 - Register GeoJsonConfiguration via spring.factories.
Related tickets: DATACMNS-952.
2016-12-05 14:24:18 +01:00
Oliver Gierke
ecd8dae876 DATAMONGO-1141 - Polishing.
Aligned assertion messages for consistency. Fixed imports in  UpdateMapperUnitTests.

Original pull request: #405.
2016-12-02 18:33:08 +01:00
Mark Paluch
4b59736f82 DATAMONGO-1141 - Polishing.
Add property to field name mapping for Sort orders by moving Sort mapping to UpdateMapper. Fix typo. Add JavaDoc. Reformat code. Remove trailing whitespaces.

Original pull request: #405.
2016-12-02 18:32:50 +01:00
Pavel Vodrážka
31d4434562 DATAMONGO-1141 - Add support for $push $sort in Update.
Sorting update modifier added. Supports sorting arrays by document fields and element values.

Original pull request: #405.
2016-12-02 18:26:09 +01:00
Oliver Gierke
f5a339bfe4 DATAMONGO-1454 - Polishing.
Formatting in test case.

Original pull request: #381.
2016-12-02 16:46:06 +01:00
Mark Paluch
5e60867750 DATAMONGO-1454 - Add support for exists projection in repository query methods.
We now support exists projections for query methods in query methods for derived and string queries.

public PersonRepository extends Repository<Person, String> {

  boolean existsByFirstname(String firstname);

  @ExistsQuery(value = "{ 'lastname' : ?0 }")
  boolean someExistQuery(String lastname);

  @Query(value = "{ 'lastname' : ?0 }", exists = true)
  boolean anotherExistQuery(String lastname);
}

Original pull request: #381.
2016-12-02 16:45:58 +01:00
Mark Paluch
8a5da0e737 DATAMONGO-1536 - Polishing.
Add JavaDoc. Change visibility of AbstractAggregationExpression.getMongoMethod() to protected.

Original pull request: #418.
2016-12-02 15:43:11 +01:00
Christoph Strobl
e01ebcf605 DATAMONGO-1536 - Add aggregation operators for array, arithmetic, date and set operations.
We now support the following aggregation framework operators:

- setEquals, setIntersection, setUnion, setDifference, setIsSubset, anyElementTrue, allElementsTrue
- stdDevPop, stdDevSamp
- abs, ceil, exp, floor, ln, log, log10, pow, sqrt, trunc
- arrayElementAt, concatArrays, isArray
- literal
- dayOfYear, dayOfMonth, dayOfWeek, year, month, week, hour, minute, second, millisecond, dateToString

Original pull request: #418.
2016-12-02 15:43:05 +01:00
Oliver Gierke
b01a34b2b1 DATAMONGO-1539 - Polishing.
Renamed @Count and @Delete to @CountQuery and @DeleteQuery. Minor polishing in test cases and test repository methods. JavaDoc, formatting.

Original pull request: #416.
2016-12-02 11:59:10 +01:00
Fırat KÜÇÜK
5650e35eb6 DATAMONGO-1539 - Introduce @CountQuery and @DeleteQuery.
Introducing dedicated annotations for manually defined count and delete queries to avoid misconfiguration and generally simplifying the declaration.

Original pull request: 416.
2016-12-02 11:59:10 +01:00
Christoph Strobl
e5a41ad7f9 DATAMONGO-1534 - Fix bulk operations missing to write type info.
We now correctly convert entities into their MongoDB representation including type information via _class property.

Original pull request: #415.
2016-11-28 09:13:57 +01:00
Christoph Strobl
dd7d25cdb3 DATAMONGO-1530 - Polishing.
Add missing transformations for ConstructorReference, OperatorNot, OpNE, OpEQ, OpGT, OpGE, OpLT, OpLE, OperatorPower, OpOr and OpAnd. This allows usage of logical operators &, || and ! as part of the expression, while ConstructorReference allows instantiating eg. arrays via an expression `new int[]{4,5,6}`. This can be useful eg. comparing arrays using $setEquals.

More complex aggregation operators like $filter can be created by defining the variable references as string inside the expression like filter(a, 'num', '$$num' > 10).
Commands like $let requires usage of InlineMap to pass in required arguments like eg. let({low:1, high:'$$low'}, gt('$$low', '$$high')).

Original Pull Request: #410
2016-11-25 17:14:17 +01:00
Sebastien Gerard
0ddd7e3afd DATAMONGO-1530 - Add support for missing MongoDB 3.2 aggregation pipeline operators.
Original Pull Request: #410
2016-11-25 15:46:49 +01:00
Mark Paluch
81c501dea3 DATAMONGO-784 - Polishing.
Add JavaDoc for compareValue.

Original pull request: #414.
2016-11-24 13:49:12 +01:00
Christoph Strobl
b1cd7cfa53 DATAMONGO-784 - Add support for comparison aggregation operators to group & project.
We now directly support comparison aggregation operators ($cmp, $eq, $gt, $gte, $lt, $lte and $ne) on both group and project stages.

Original pull request: #414.
2016-11-24 13:49:09 +01:00
Mark Paluch
2ffac0a74e DATAMONGO-1491 - Polishing.
Remove variable before returning value. Add generics for list creation.

Original pull request: #412.
2016-11-24 12:49:30 +01:00
Christoph Strobl
ded99a74a3 DATAMONGO-1491 - Add support for $filter (aggregation).
We new support $filter in aggregation pipeline.

Aggregation.newAggregation(Sales.class,
	Aggregation.project()
		.and(filter("items").as("item").by(GTE.of(field("item.price"), 100)))
		.as("items"))

Original pull request: #412.
2016-11-24 12:45:56 +01:00
Christoph Strobl
f275aaad7f DATAMONGO-1327 - Polishing.
Just added overloads for stdDevSamp and stdDevPop taking AggregationExpression and updated the doc.
Also replaced String operation based MongoDB operation building by using operators directly.

Original Pull Request: #360
2016-11-24 07:57:17 +01:00
gustavodegeus
5d2faef072 DATAMONGO-1327 - Added support for $stdDevSamp and $stdDevPop to aggregation $group stage.
Original Pull Request: #360
CLA: 171720160409030719 (Gustavo de Geus)
2016-11-24 07:56:33 +01:00
Oliver Gierke
2c3cbb3613 DATAMONGO-1527 - After release cleanups. 2016-11-23 10:59:11 +01:00
Oliver Gierke
2b635fa151 DATAMONGO-1527 - Prepare next development iteration. 2016-11-23 10:59:08 +01:00
Oliver Gierke
909fda2076 DATAMONGO-1527 - Release version 2.0 M1 (Kay). 2016-11-23 10:35:48 +01:00
Oliver Gierke
3b5d231529 DATAMONGO-1527 - Prepare 2.0 M1 (Kay). 2016-11-23 10:35:08 +01:00
Oliver Gierke
e90fe70ae1 DATAMONGO-1527 - Updated changelog. 2016-11-23 10:35:01 +01:00
Oliver Gierke
27d379ba71 DATAMONGO-1527 - Removed explicit reference to Spring Framework 5 snapshots. 2016-11-19 15:30:23 +01:00
Mark Paluch
e987a853ac DATAMONGO-1509 - Polishing.
Adopt type hint assertion for existing _class field checks. Simplify test code to use Collections.singletonList instead of Arrays.asList. Replace BasicDBList with List in JavaDoc. Use type inference for DocumentTestUtils.getAsDBList to avoid casts in test code. Extend documentation.

Original pull request: #411.
2016-11-17 15:54:10 +01:00
Christoph Strobl
3c16b4db7f DATAMONGO-1509 - Write type hint as last element of a Document.
Always add type hint as last property of a Document.
This is necessary to assure document equality within MongoDB in cases where the query contains full document comparisons. Unfortunately this also might break existing stuff since the order of properties within a Document is changed with this commit.

Original pull request: #411.
2016-11-17 15:12:36 +01:00
Mark Paluch
070d784be3 DATAMONGO-1176 - Exclude null id fields in bulk insert.
We no longer map _id fields into Document that are null to enforce MongoDB ObjectId generation on batch insert like insertAll.
2016-11-17 13:56:45 +01:00
Mark Paluch
af4f0e0913 DATAMONGO-1444 - Accept Collection and subtypes in ReactiveMongoOperations.insertAll(…). 2016-11-14 18:13:35 +01:00
Oliver Gierke
474af92075 DATAMONGO-1444 - Moved to new base class for reactive repository factories. 2016-11-14 18:13:34 +01:00
Oliver Gierke
99838c02fd DATAMONGO-1444 - Adapt to new changes in reactive repository configuration.
We now use the newly introduced ….useRepositoryConfiguration(…) in the module specific RepositoryConfigurationExtension implementations to distinguish between reactive and non-reactive repositories.

Removed RepositoryType class as it was only used by the previous repository typ detection.
2016-11-14 18:13:34 +01:00
Oliver Gierke
8060ebae6a DATAMONGO-1444 - Polishing.
Removed unused references to ConversionService from repository query implementations.
2016-11-14 18:13:34 +01:00
Mark Paluch
9e9495ee54 DATAMONGO-1444 - Make Project Reactor dependency no longer required for blocking repository usage.
Use ReactiveWrapperConverters for reactive wrapper type conversion to not require Project Reactor for blocking repository usage.
2016-11-14 18:13:34 +01:00
Christoph Strobl
098aae41b7 DATAMONGO-1444 - Update bulk insert operations.
Accept Mono<Collection<T>> instead of Publisher<T> to get rid of hidden buffer call inside of MongoTemplate.
2016-11-14 18:13:28 +01:00
Christoph Strobl
df859d0f3a DATAMONGO-1444 - Adopt changes in Spring Data Commons.
- Adopt RxJava to RxJava1 repository interface renaming.
- Remove ReactiveChunk, Slice and Page.
- Update documentation.
- Prevent sliced/paged query execution.
2016-11-14 18:13:25 +01:00
Christoph Strobl
e0f371f648 DATAMONGO-1444 - Polishing.
- Update Javadoc comments and reference documentation.
- Introduce Adapter for blocking IndexOperations.
- Remove transaction synchronization.
- Remove unused types.
- Remove dropDupos options from indexes.
- Prevent usage of Querydsl along with reactive repository.
- Use ReactiveQueryMethod in ReactiveMongoQuery.
2016-11-14 18:13:25 +01:00
Mark Paluch
2145e212ca DATAMONGO-1444 - Add support for RxJava wrapper types and slice queries.
Reactive MongoDB repository can now be composed from Project Reactor and RxJava types for method arguments and return types. Query methods and methods from the base/implementation classes can be invoked with a conversion of input/output types.
2016-11-14 18:13:25 +01:00
Mark Paluch
c814073441 DATAMONGO-1176 - Test code cleanup.
Replace DbObject in documentation with Document. Fix typos. Change dbObject variable names to document.
2016-11-14 18:13:24 +01:00
Mark Paluch
59573b10e6 DATAMONGO-1176 - Cleanup.
Replace DbObject in documentation with Document. Fix typos. Change dbObject variable names to document. Improve error messages. Remove unused code.
2016-11-14 18:13:24 +01:00
Christoph Strobl
054274392e DATAMONGO-1176 - Cleanup.
- Update licenses headers.
- Renname variables and methods from dbo -> document.
- Remove deprecations.
- Remove unused code blocks.
- Upgrade to MongoDB Java Driver 3.3
2016-11-14 18:13:24 +01:00
Mark Paluch
2d3efdc0b4 DATAMONGO-1176 - Polishing.
- Remove dropDups assertion as the MongoDB 3 driver does no longer provide dropDups even if running agains a MongoDB v2.6.7.
- Remove mongo-next build profile as we're based on the Mongo 3 driver now.
- Map update object and merge set operations.
2016-11-14 18:13:23 +01:00
Christoph Strobl
2461575c52 DATAMONGO-1176 - Switch to Document API.
We use the Document API when interacting with the MongoDB Java Driver. This allows us to make use of new features and enables us to use the Codec API and prepares the project for future enhancements concerning the drivers the reactive API.
2016-11-14 18:13:23 +01:00
Mark Paluch
4371760272 DATAMONGO-1461 - Upgrade Hibernate/Validator/JPA dependencies to match Spring 5 baseline.
Upgrade:
* Hibernate Validator to 5.2.4.Final
* JPA API to 2.1.1
* Hibernate Core to 5.2.1.Final
2016-11-14 17:49:48 +01:00
Mark Paluch
da5289fc18 DATAMONGO-1448 - Prepare 2.0 development.
Upgraded to Spring Data Build parent 2.0 snapshots and Spring Data Commons 2.0 snapshots. Removed obsolete distribution key property. Removed obsolete template.mf.
2016-11-14 17:49:48 +01:00
Oliver Gierke
ea9b402547 DATAMONGO-1525 - Improved creation of empty collections, esp. EnumSet.
We now use more type information to create a better empty collection in the first place. The previous algorithm always used an empty HashSet plus a subsequent conversion using the raw collection type. Especially the latter caused problems for EnumSets as the conversion into one requires the presence of component type information.

We now use Spring's collection factory and more available type information to create a proper collection in the first place and only rely on a subsequent conversion for arrays.
2016-11-13 18:33:45 +01:00
Oliver Gierke
255d32513c DATAMONGO-1502 - Updated changelog. 2016-11-03 18:56:45 +01:00
Oliver Gierke
6a9823fd24 DATAMONGO-1521 - Added Aggregation.skip(…) overload to support longs.
Deprecated the one taking an int.
2016-11-03 15:00:20 +01:00
Christoph Strobl
2ae75a4ff9 DATAMONGO-1500 - Fix JSON serialization error in derived queries with field spec.
We now make sure not to eagerly attempt to convert given query parameters into a mongo specific format by calling toString() the query object, but rather delegate this to another step later in the chain.

Original pull request: #404.
2016-11-03 09:36:42 +01:00
Christoph Strobl
9c20da3e8f DATAMONGO-1504 - Assert compatibility with MongoDB 3.4.
We now make sure to comply to the API requirements of mongo-java-driver 3.4 (in current beta1) by using empty DBObjects instead of null, ignoring non appropriate replication settings and cleaning up tests after execution.

Original pull request: #394.
2016-11-03 09:32:56 +01:00
Oliver Gierke
f782338581 DATAMONGO-1513 - Fixed identifier population for event listener generated, non-ObjectId on batch inserts.
The methods in MongoTemplate inserting a batch of documents previously only returned database generated identifiers, more especially ObjectId ones. This caused non-ObjectId identifiers potentially generated by other parties — i.e. an event listener reacting to a BeforeSaveEvent — not being considered for source object identifier population.

This commit adds a workaround augmenting the list of database generated identifiers with the ones actually present in the documents to be inserted. A follow-up ticket DATAMONGO-1519 was created to track the removal of the workaround in favor of a proper fix unfortunately requiring a change in public API (so a 2.0 candidate only).

Related tickets: DATAMONGO-1519.
2016-11-02 09:52:47 +01:00
Oliver Gierke
cb90bfc6a6 DATAMONGO-1514 - Polishing.
Extended license years in copyright header.

Original pull request: #401.
2016-10-27 14:32:37 +02:00
Martin Macko
189d4dd1b7 DATAMONGO-1514 - SpringDataMongodbQuery needs to be public.
SpringDataMongodbQuery is exposed publicly in QuerydslRepositorySupport, that's we've got to make it public to make sure class to the exposed methods from outside the package actually compile.

Original pull request: #401.
2016-10-27 14:31:46 +02:00
Christoph Strobl
10208001f8 DATAMONGO-1480 - Polishing.
Opened up Meta attributes to now allowing usage of more than one cursor option via dedicated enum.

new Query().noCursorTimeout();

and

interface PersonRepository extends CrudRepository<Person, String> {

    @Meta(flags = {CursorOptions.NO_TIMEOUT})
    Iterable<Person> findBy();
}

Original Pull Request: #390
2016-10-24 18:44:35 +02:00
Mark Paluch
98dca5a65e DATAMONGO-1480 - Add support for noCursorTimeout in Query.
We now allow setting noCursorTimeout for queries using `Query` and `@Meta`.

Query query = new Query().noCursorTimeout();

and

interface PersonRepository extends CrudRepository<Person, String> {

    @Meta(noCursorTimeout = true)
    Iterable<Person> findBy();

    @Meta(noCursorTimeout = true)
    Stream<Person> streamBy();
}

Original Pull Request: #390
2016-10-24 18:43:40 +02:00
Christoph Strobl
b6bc0ea316 DATAMONGO-1490 - Polishing.
Restore 1.8.xsd and create new 1.10 one reflecting the changes made.

Original Pull Request: #389
2016-10-24 13:26:51 +02:00
Mark Paluch
b67c551e19 DATAMONGO-1490 - Replace space indentation by tabs.
Original Pull Request: #389
2016-10-24 13:26:51 +02:00
Mark Paluch
e0bc1e0f20 DATAMONGO-1490 - Change the XML data type of boolean flags to String.
We now accept String data types for boolean flags in XML configurations. Boolean data types in the XSD don't allows use of property placeholders even if the resolved value could be converted to boolean. Affected fields by this change are:

* `<mongo:repositories create-query-indexes=… />`
* `<mongo:options ssl=…/>`
* `<mongo:client-options ssl=… />`

Original Pull Request: #389
2016-10-24 13:26:40 +02:00
Oliver Gierke
fcb436dd30 DATAMONGO-1495 - Updated changelog. 2016-09-29 14:42:09 +02:00
Oliver Gierke
0e57dd473c DATAMONGO-1499 - Updated changelog. 2016-09-29 11:42:09 +02:00
Oliver Gierke
8d36e42b1b DATAMONGO-1498 - Removed defaulting of MongoMappingContext for repositories and auditing.
Previously we created a default bean definition for MongoMappingContext if none was present in the application context. That lookup for an existing one unfortunately comes too early, especially with Spring Boot in place. This then caused the MappingContext not being aware of the custom conversions and simply types registered by Boot.

We now removed the defaulting relying on a MappingMongoConverter being present in the Application context (which usually is the case for the usage with AbstractMongoConfiguration or the XML <mongo:mapping-converter /> alternative. We use that bean to lookup the MappingContext.
2016-09-28 16:22:20 +02:00
Oliver Gierke
b66bfae105 DATAMONGO-1497 - MappingMongoConverter now consistently uses DbObjectAccessor.
We now use DbObjectAccessor also for preliminary inspections of the source DBObject (e.g. whether a value is present at all). Previously we operated on the DBObject directly which caused issues with properties mapped to nested fields as the keys weren't exploded correctly and thus the check always failed.
2016-09-22 17:55:50 +02:00
Oliver Gierke
eb3d55e0bd DATAMONGO-1494 - Updated changelog. 2016-09-21 08:04:20 +02:00
Oliver Gierke
84dbfdfd5e DATAMONGO-1450 - Updated changelog. 2016-09-21 08:04:14 +02:00
Mark Paluch
1813b1aea0 DATAMONGO-1493 - Fix minor typo in reference documentation.
Related pull request: #391.
2016-09-19 17:03:29 +02:00
Jordan Jennings
69241737b7 DATAMONGO-1493 - Fix minor typo in docs.
Original pull request: #391.
2016-09-19 16:21:12 +02:00
Christoph Strobl
f053bed447 DATAMONGO-1492 - Make o.s.d.m.core.aggregation.AggregationExpression public.
By turning `AggregationExpression` public we allow adding custom expressions without workarounds. It is now possible to create eg. `ProjectionOperation` like:

ProjectionOperation agg = Aggregation.project()
      .and(new AggregationExpression() {

        @Override
        public DBObject toDbObject(AggregationOperationContext context) {

          DBObject filterExpression = new BasicDBObject();
          filterExpression.put("input", "$x");
          filterExpression.put("as", "y");
          filterExpression.put("cond", new BasicDBObject("$eq", Arrays.<Object> asList("$$y.z", 2)));

          return new BasicDBObject("$filter", filterExpression);
        }
      }).as("profile");

Original pull request: #392.
2016-09-19 16:02:44 +02:00
Christoph Strobl
1a1cd9ef14 DATAMONGO-1485 - Consider potential custom conversion for enums in Querydsl paths.
We now take potential registered converters for enums into account when serializing path expressions via SpringDataMongodbSerializer.

Original pull request: #388.
2016-09-19 07:00:21 +02:00
Oliver Gierke
7effc0e10f DATAMONGO-1468 - Polishing.
Slightly touched test case.

Original pull request: #387
2016-09-08 10:29:23 +02:00
Christoph Strobl
395bb1faa4 DATAMONGO-1486 - Fix ClassCastException when mapping non-String Map key for updates.
We now make sure to convert Map keys into Strings when mapping update values for Map properties.

Original pull request: #387.
2016-09-08 10:29:22 +02:00
Christoph Strobl
eb1392cc1a DATAMONGO-861 - Polishing.
Favor usage of List over BasicDBList.
Rename ProjectionOperation.transform to applyCondition.
Add missing author and since tags, remove trailing white spaces and fix reference documentation headline clash.

Original Pull Request: #385
2016-08-30 14:40:24 +02:00
Mark Paluch
ace01e4e6d DATAMONGO-861 - Add support for $cond and $ifNull operators in aggregation operations.
We now support $cond and $ifNull operators for projection and grouping operations. ConditionalOperator and IfNullOperators are AggregationExpressions that can be applied to transform or generate values during aggregation.

TypedAggregation<InventoryItem> agg = newAggregation(InventoryItem.class,
  project().and("discount")
    .transform(ConditionalOperator.newBuilder().when(Criteria.where("qty").gte(250))
      .then(30)
      .otherwise(20))
    .and(ifNull("description", "Unspecified")).as("description")
);

corresponds to

{ "$project": { "discount": { "$cond": { "if": { "$gte": [ "$qty", 250 ] },
        "then": 30, "else": 20 } },
    "description": { "$ifNull": [ "$description", "Unspecified"] }
  }
}

Original Pull Request: #385
2016-08-30 14:39:43 +02:00
Mark Paluch
116dda63c2 DATAMONGO-1406 - Propagate PersistentEntity when mapping query criteria for nested keywords.
We now propagate the PersistentEntity when mapping nested keywords so that the criteria mapping chain for nested keywords and properties has now access to the PersistentEntity and can use configured field names.

Previously the plain property names have been used as field names and potential customizations via @Field have been ignored.

Original Pull Request: #384
2016-08-25 13:09:04 +02:00
Mark Paluch
4649872394 DATAMONGO-1465 - Polishing.
Replace boolean flag in convertAndJoinScriptArgs with literal. Joined args are rendered to JavaScript and require always string quotation.

Original pull request: #383.
2016-08-23 14:59:43 +02:00
Christoph Strobl
ecc6f3fc4e DATAMONGO-1465 - Fix String quotation in DefaultScriptOperations.execute().
This change prevents Strings from being quoted prior to sending them as args of a script.

Original pull request: #383.
2016-08-23 14:57:10 +02:00
Mark Paluch
512f68a611 DATAMONGO-1476 - Polishing.
Extend year range in license header. Use the specified collection name in doRemove.

Original pull request: #382.
2016-08-23 10:06:53 +02:00
Niko Schmuck
fbcd4ba367 DATAMONGO-1476 - Consistently use specified collection name in MongoTemplate.stream().
We now use the specified argument name instead of DBCollection.getName() when invoking ReadDbObjectCallback.

Original pull request: #382.
2016-08-23 10:01:59 +02:00
Oliver Gierke
760d7d6a32 DATAMONGO-1471 - Converter only applies identifier values if actually available.
Setting the value for the identifier property is an explicit step in MappingMongoConverter and always executed if the type to be created has an identifier property. If the source document doesn't contain an _id field (e.g. because it has been excluded explicitly) that previously caused null to be set on the identifier. This caused an exception if the identifier property is a primitive type.

We now explicitly check whether the field backing the identifier property is actually present in the source document and only explicitly set the value if so.
2016-08-17 16:54:10 +02:00
Oliver Gierke
29a6688e8c DATAMONGO-1470 - AbstractMongoConfiguration now supports multiple base packages for @Document scanning.
Introduced AbstractMongoConfiguration.getMappingBasePackages() to return multiple ones over the previously existing ….getMappingBasePackage(). The former is now used by the code triggering the scanning using what the latter returns by default.
2016-07-28 13:10:48 +02:00
Oliver Gierke
b6e7683202 DATAMONGO-1409 - After release cleanups. 2016-07-27 14:32:37 +02:00
Oliver Gierke
286a977575 DATAMONGO-1409 - Prepare next development iteration. 2016-07-27 14:32:35 +02:00
Oliver Gierke
d7f70e219b DATAMONGO-1409 - Release version 1.10 M1 (Ingalls). 2016-07-27 13:52:12 +02:00
Oliver Gierke
728cc390f6 DATAMONGO-1409 - Prepare 1.10 M1 (Ingalls). 2016-07-27 13:51:38 +02:00
Oliver Gierke
ddcc3914ff DATAMONGO-1409 - Updated changelog. 2016-07-27 13:51:32 +02:00
Oliver Gierke
9a385599af DATAMONGO-1394 - Polishing.
Some internal refactorings to avoid deeply nested if-clauses.

Original pull request: #373.
2016-07-27 10:54:21 +02:00
Christoph Strobl
c14c42fb0c DATAMONGO-1394 - Support identifier references on Querydsl expressions for DBRefs.
We now allow direct usage path.eq(…) on id properties of db referenced objects. This allows to write the query as person.coworker.id.eq(coworker.getId()) instead of person.coworker.eq(coworker). This helps building the query using just the plain id not having to actually create new object wrapping it.

Original pull request: #373.
2016-07-27 10:54:21 +02:00
Oliver Gierke
5a8e4f3dae DATAMONGO-1194 - Polishing.
Some missing JavaDoc and slight code polish.

Original pull request: #377.
2016-07-26 15:30:31 +02:00
Christoph Strobl
5d50155d81 DATAMONGO-1194 - Improve DBRef resolution for maps.
We bulk load maps of referenced objects as long as they are stored in the same collection. This reduces database roundtrips and network traffic.

Original pull request: #377.
2016-07-26 15:30:31 +02:00
Christoph Strobl
babab54ffd DATAMONGO-1194 - Improve DBRef resolution for collections.
We now bulk load collections of referenced objects as long as they are stored in the same collection. This reduces database roundtrips and network traffic.

Original pull request: #377.
2016-07-26 15:30:30 +02:00
Mark Paluch
1ba137b98a DATAMONGO-1464 - Polishing.
Added JavaDoc. Simplified if-check in MongoQueryExecution.isListOfGeoResult(…).

Original pull request: #379.
2016-07-26 14:51:55 +02:00
Mark Paluch
353b836a77 DATAMONGO-1464 - Optimize query execution for pagination queries.
We execute paged queries now in an optimized way. The data is obtained for each paged execution but the count query is deferred. We determine the total from the pageable and the results in which we don't hit the page size bounds (i.e. results are less than a full page without offset or results are greater 0 and less than a full page with offset). In all other cases we issue an additional count query.

Original pull request: #379.
2016-07-26 14:51:29 +02:00
Oliver Gierke
325bcd11b9 DATAMONGO-1431 - Added MongoOperations.stream(…) with explicit collection. 2016-07-20 15:59:52 +02:00
Mark Paluch
9db2dde19b DATAMONGO-1463 - Upgrade to mongo-java-driver 2.14.3.
Upgrade mongo-java-driver 2.14.3 and upgrade the mongo33 profile to use 3.3.0 (release).
2016-07-20 10:33:23 +02:00
Mark Paluch
318ba53e2f DATAMONGO-1462 - Integrate version badge from spring.io.
Add version badge from spring.io and replace fixed version numbers with a placeholder.
2016-07-20 08:43:37 +02:00
Mark Paluch
3db30bd4a6 DATAMONGO-1460 - User placeholder property for JSR-303 API. 2016-07-15 12:48:37 +02:00
Oliver Gierke
dd1fbfeb66 DATAMONGO-1459 - Polishing.
Added missing @Overrides to MongoRepository interface and polished non-JavaDoc references.
2016-07-14 15:52:32 +02:00
Oliver Gierke
3fa17272bb DATAMONGO-1459 - Added support for any-match mode in Query-by-example.
MongoExampleMapper now $or-concatenates the predicates derived from the example in case the ExampleMatcher expresses any-match binding to be desired.

Moved integration tests for Query-by-example to the appropriate package and polished the code a little.

Related ticket: DATACMNS-879.
2016-07-14 15:52:32 +02:00
Christoph Strobl
9361fc3c71 DATAMONGO-1455, DATAMONGO-1456 - Polishing.
Use static imports for org.junit.Assert and org.hamcrest.core. Fix spelling.

Original pull request: #375.
2016-07-12 15:25:49 +02:00
Christoph Strobl
ac55f5e77f DATAMONGO-1455, DATAMONGO-1456 - Add support for $caseSensitive and $diacriticSensitive to $text.
We added methods to set values for $caseSensitive and $diacriticSensitive when using TextCriteria. Both operators are optional and will not be used until explicitly set.

    // { "$text" : { "$search" : "coffee" , "$caseSensitive" : true } }
    TextCriteria.forDefaultLanguage().matching("coffee").caseSensitive(true);

    // { "$text" : { "$search" : "coffee" , "$diacriticSensitive" : true } }
    TextCriteria.forDefaultLanguage().matching("coffee").diacriticSensitive(true);

Original pull request: #375.
2016-07-12 15:25:49 +02:00
Christoph Strobl
116baf9a92 DATAMONGO-832 - Polishing
Moved newly introduced types into order. Added missing @since tag and additional test.
Updated reference documentation for update operators and added $slice operator to "what’s new" section.

Original Pull Request: #374
2016-07-11 10:02:22 +02:00
Mark Paluch
026dce2612 DATAMONGO-832 - Add support for $slice in Update.push.
We now support $slice in Update operations via the PushOperatorBuilder.

    new Update().push("key").slice(5).each(Arrays.asList("one", "two", "three"));

Original Pull Request: #374
2016-07-11 09:49:45 +02:00
Mark Paluch
eae32be568 DATAMONGO-1457 - Polishing.
Add missing Javadoc to size operator. Mention Array Aggregation Operators in reference docs. Fix typos in reference docs.

Original pull request: #372.
2016-07-08 10:34:08 +02:00
Christoph Strobl
9d51ea4c01 DATAMONGO-1457 - Add support for $slice in aggregation.
We now support $slice in aggregation projections via the ProjectionOperationBuilder.

    Aggregation.project().and("field").slice(10, 20)

Original pull request: #372.
2016-07-08 10:08:29 +02:00
Mark Paluch
f4a5482005 DATAMONGO-1418 - Polishing.
Added ticket references. Simplified code.

 Original pull request: #361.
2016-06-24 15:32:58 +02:00
Nikolai Bogdanov
0db36aff8f DATAMONGO-1418 - Add support for $out operator in aggregations.
We now support the $out operator via Aggregation.out(…) to store aggregation results in a collection. Using the $out operator returns an empty list in AggregationResults.

Original pull request: #361.
CLA: 172720160413124705 (Nikolai Bogdanov)
2016-06-24 15:28:45 +02:00
Christoph Strobl
ba8ece334a DATAMONGO-1453 - Fix GeoJson conversion when coordinates are Integers.
We now use Number instead of Double for reading "coordinates" from GeoJSON representations.

Original pull request: #369.
2016-06-24 14:04:58 +02:00
Oliver Gierke
a5394074c5 DATAMONGO-1410 - Updated changelog. 2016-06-15 14:31:49 +02:00
Kevin Dosey
fe5bb515b7 DATAMONGO-1449 - Switched to foreach loop in collection handling of MappingMongoConverter.
This should result in minor to moderate performance improvement for iteration on Collections/Arrays during DBObject to object mapping.

Original pull request: #368.
2016-06-11 18:29:32 +02:00
Mark Paluch
c84bfbccf4 DATAMONGO-1437 - Polishing.
Renamed test. Added JavaDoc. Simplify throws declaration.

Original pull request: #367.
2016-06-02 08:55:09 +02:00
Christoph Strobl
d147f80a39 DATAMONGO-1437 - Preserve non translatable Exception cause when lazily resolving DBRef.
We now preserve the cause of Exceptions that cannot be translated into DataAccessExceptions when an error occurs during lazily loading DBRefs.

Original pull request: #367.
2016-06-02 08:52:53 +02:00
Christoph Strobl
7b8dadeb74 DATAMONGO-1271 - Polishing.
Removed non Java 6 language features, reworked and added a few tests.

Original Pull Request: #322
2016-05-27 07:53:53 +02:00
Jordi Llach Fernandez
d1251c42ca DATAMONGO-1271 - Provide lifecycle events for DBRefs.
We now publish livecycle events when loading DBRefs.

Original Pull Request: #322
CLA: 121620150519031801 (Jordi Llach Fernandez)
2016-05-27 07:53:45 +02:00
Oliver Gierke
4140dd573f DATAMONGO-1423 - Polishing.
Orignal pull request: #365.
2016-05-25 17:26:31 +02:00
Christoph Strobl
0e60630393 DATAMONGO-1423 - Map keys now get registered conversions applied for Updates.
We now pipe map keys through the potentially registered conversions when mapping Updates.

Orignal pull request: #365.
2016-05-25 17:26:30 +02:00
Oliver Gierke
9bc35512fd DATAMONGO-1416 - Polishing.
Just use instanceOf(…) from Hamcrest's Matchers class instead of dedicated class.

Original pull request: #362.
2016-05-24 15:57:21 +02:00
Christoph Strobl
b626c2f82b DATAMONGO-1416 - Get rid of the warnings for Atomic… type conversions.
We now use explicit converters instead of a ConverterFactory. This reduces noise in log when registering converters.

Original pull request: #362.
2016-05-24 15:57:21 +02:00
Mark Paluch
c3e894ee8d DATAMONGO-1424 - Polishing.
Remove EndingWith from NotLike. Remove superfluous white-spaces. Split combined highlighted keywords to individual highlighting.

Original pull request: #364.
2016-05-09 11:06:44 +02:00
Christoph Strobl
2f713bede5 DATAMONGO-1424 - Add support for NOT_LIKE.
We now support `notLike` and `isNotLike` in query derivation.

Original pull request: #364.
2016-05-09 11:05:44 +02:00
Mark Paluch
e03520d2fb DATAMONGO-1425 - Polishing.
Add NotContaining to documentation. Add integration test for Containing/NotContaining on collection properties.

Original pull request: #363.
2016-05-09 10:42:19 +02:00
Christoph Strobl
3829d58dc2 DATAMONGO-1425 - Fix query derivation for notContaining on String properties.
We now correctly build up the criteria for derived queries using notContaining keyword on String properties.

Original pull request: #363.
2016-05-09 10:42:15 +02:00
Mark Paluch
7b87fa9509 DATAMONGO-1412 - Fix backticks and code element highlighting.
Fixed broken highlighting using backticks followed by chars/single quotes. Convert single quote emphasis of id to backtick code fences. Add missing spaces between words and backticks.

Original Pull Request: #359
2016-05-02 13:20:29 +02:00
Mark Paluch
b2b9f3406a DATAMONGO-1412 - Document mapping rules for Java types to MongoDB representation.
Original Pull Request: #359
Related pull request: #353
Related ticket: DATAMONGO-1404
2016-05-02 13:20:22 +02:00
Mark Paluch
d610761019 DATAMONGO-1404 - Polishing.
Add author and since tags. Update license headers. Reformat code. Replace FQCN with import and simple class name. Remove final keyword in test methods. Add tests for numeric values. Update documentation.

Original pull request: #353.
2016-05-02 13:20:10 +02:00
Alexey Plotnik
8983bd26ce DATAMONGO-1404 - Add support for $min and $max update operators.
Original pull request: #353.
CLA: 169820160330091912 (Alexey Plotnik)
2016-05-02 13:19:31 +02:00
Christoph Strobl
5485f2fcd4 DATAMONGO-1391 - Polishing.
Removed white spaces, updated Javadoc and return early when using non 3.2 $unwind options.

Original Pull Request: #355
2016-05-02 12:56:38 +02:00
Mark Paluch
f8681fec66 DATAMONGO-1391 - Support Mongo 3.2 syntax for $unwind in aggregation.
We now support both, the simple {$unwind: path} and the MongoDB 3.2 {$unwind: {…}} syntax.

Original Pull Request: #355
2016-05-02 12:52:39 +02:00
Mark Paluch
0dd904894d DATAMONGO-1399 - Polishing.
Update since version to 1.10. Remove trailing whitespaces.

Original pull request: #352.
2016-05-02 09:44:37 +02:00
Christoph Strobl
7d70a8677e DATAMONGO-1399 - Allow adding hole to GeoJSON Polygon.
We now allow creation of GeoJsonPolygon having an outer and multiple inner rings.

Original pull request: #352.
2016-05-02 09:40:44 +02:00
Mark Paluch
13a52b5ac9 DATAMONGO-1403 - Add maxExecutionTimeMs alias for @Meta(maxExcecutionTime).
We added maxExecutionTimeMs as an alias for maxExcecutionTime which has been deprecated due to spelling issues.

Original pull request: #356.
2016-04-26 12:43:37 +02:00
Mark Paluch
f5cfcda673 DATAMONGO-1411 - Enable build on TravisCI.
We now start MongoDB server via apt-get instead of relying on the TravisCI managed 2.4.2 installation.
Doing this we altered tests to just check on the port and not the host part of the URIs.

Additionally we upgraded build profiles, removed promoted snapshot-versions, renamed mongo32-next to mongo32  and added mongo33-next build profile.

Original pull request: #358
2016-04-26 10:40:29 +02:00
Raja Dilip Kolli
cf44a7105f DATAMONGO-1420 - Update version numbers in Github readme.
Bumped to latest versions available

Original pull request: #354
2016-04-15 08:30:32 +02:00
Oliver Gierke
0228255d2b DATAMONGO-1356 - AuditingEventListener now has an explicit order.
AuditingEventListener now has a fixed ordering of 100. This allows other listeners to be registered to be executed before or after it.
2016-04-14 22:27:46 +02:00
Oliver Gierke
50e37355d4 DATAMONGO-1419 - Removed deprecated methods of AbstractMongoEventListener. 2016-04-14 22:27:42 +02:00
Oliver Gierke
a15dababfa DATAMONGO-1408 - Updated changelog. 2016-04-06 23:14:25 +02:00
Oliver Gierke
9942451017 DATAMONGO-1405 - After release cleanups. 2016-04-06 16:37:03 +02:00
Oliver Gierke
e144c29316 DATAMONGO-1405 - Prepare next development iteration. 2016-04-06 16:36:59 +02:00
Oliver Gierke
64d4880983 DATAMONGO-1405 - Release version 1.9 GA (Hopper). 2016-04-06 16:35:59 +02:00
Oliver Gierke
47c348e03a DATAMONGO-1405 - Prepare 1.9 GA (Hopper). 2016-04-06 16:34:45 +02:00
Oliver Gierke
dea86535c1 DATAMONGO-1405 - Updated changelog. 2016-04-06 16:34:39 +02:00
Artur Konczak
eee6b62589 DATAMONGO-1407 - updated jira link to point to correct project on jira.
Original pull request: #357.
2016-04-05 14:13:28 +02:00
Mark Paluch
771ca8d84c DATAMONGO-1407 - Add pull request template. 2016-04-05 09:50:18 +02:00
Christoph Strobl
8f5b334951 DATAMONGO-1398 - Mention QBE and add links.
Original Pull Request: #349
2016-03-31 21:00:27 +02:00
Mark Paluch
0dc6169282 DATAMONGO-1398, DATAMONGO-1395 - Update Lifecycle Events examples in Reference Documentation.
Replace deprecated methods by the supported API.

Original Pull Request: #349
2016-03-31 20:59:53 +02:00
Mark Paluch
abe78f0428 DATAMONGO-1398 - Updated what's new section and general improvements.
Update Spring Framework documentation links to point always to the Spring Framework version specified in the pom, where possible. Mention $lookup in aggregation.

Original Pull Request: #349
2016-03-31 20:59:16 +02:00
Christoph Strobl
9930ec2d19 DATAMONGO-1401 - Fix error when updating entity with both GeoJsonPoint and Version property.
We now ignore property reference exceptions when resolving field values that have already been mapped. Eg. in case of an already mapped update extracted from an actual domain type instance.

Original pull request: #351.
2016-03-31 09:15:29 +02:00
Oliver Gierke
83d7f4477e DATAMONGO-1392 - After release cleanups. 2016-03-18 11:16:07 +01:00
Oliver Gierke
18c3704c2e DATAMONGO-1392 - Prepare next development iteration. 2016-03-18 11:15:51 +01:00
Oliver Gierke
bef581caa5 DATAMONGO-1392 - Release version 1.9 RC1 (Hopper). 2016-03-18 11:15:00 +01:00
Oliver Gierke
2f0abe0604 DATAMONGO-1392 - Prepare 1.9 RC1 (Hopper). 2016-03-18 11:06:57 +01:00
Oliver Gierke
4235b44c47 DATAMONGO-1392 - Updated changelog. 2016-03-18 11:06:52 +01:00
Oliver Gierke
f318185ad0 DATAMONGO-1400 - Adapt to rename of Tuple to Pair in Spring Data Commons.
Related tickets: DATACMNS-818.
2016-03-18 09:59:06 +01:00
Oliver Gierke
43b496287c DATAMONGO-1245 - Final tweaks to Query by Example documentation.
Tweaked section anchor to match conventions. Use level offsets to accommodate changes in Spring Data Commons.
2016-03-18 09:29:46 +01:00
Oliver Gierke
9d0c8ecdc3 DATAMONGO-1245 - Polishing.
Adapt to API changes in Spring Data Commons.

Related tickets: DATACMNS-810.
Original pull request: #341.
2016-03-17 18:39:18 +01:00
Mark Paluch
5a78d99af0 DATAMONGO-1245 - Initial documentation for Query by Example.
Adopt changes from query by example API refactoring.

Related tickets: DATACMNS-810.
Original pull request: #341.
2016-03-17 18:39:18 +01:00
Christoph Strobl
693f5ddf6e DATAMONGO-1245 - Add support for Query By Example.
An explorative approach to QBE trying find possibilities and limitations. We now support querying documents by providing a sample of the given object holding compare values. For the sake of partial matching we flatten out nested structures so we can create different queries for matching like:

{ _id : 1, nested : { value : "conflux" } }
{ _id : 1, nested.value : { "conflux" } }

This is useful when you want so search using a only partially filled nested document. String matching can be configured to wrap strings with $regex which creates { firstname : { $regex : "^foo", $options: "i" } } when using StringMatchMode.STARTING along with the ignoreCaseOption. DBRefs and geo structures such as Point or GeoJsonPoint is converted to their according structure.

Related tickets: DATACMNS-810.
Original pull request: #341.
2016-03-17 18:39:18 +01:00
Christoph Strobl
ece655f67d DATAMONGO-1387 - Polishing.
Added a few more tests and append values if present on Query.

Original Pull Request: #345
2016-03-17 13:10:51 +01:00
John Willemin
119692c979 DATAMONGO-1387 - Fix BasicQuery getFieldsObject() inconsistency.
We changed BasicQuery to consider its parent getFieldsObject() when not given an explicit fields DBObject.

Original Pull Request: #345
CLA: 165520160303021604 (John Willemin)
2016-03-17 13:09:58 +01:00
Oliver Gierke
6068f3243a DATAMONGO-1397 - Polishing.
Switched to Slf4J-native placeholder replacement in debug logging for MongoTemplate.

Original pull request: #348.
2016-03-16 17:28:04 +01:00
Mark Paluch
a7cda2e793 DATAMONGO-1397 - Log command, entity and collection name in MongoTemplate.geoNear(…).
Original pull request: #348.
2016-03-16 17:28:03 +01:00
Oliver Gierke
2687cb85f0 DATAMONGO-1373 - Polishing.
Added method, field and annotation target to @Field annotation explicitly. Fixed copyright date ranges where needed.

Tweaked formatting in test cases.

Original pull request: #347.
Related ticket: DATACMNS-825.
2016-03-15 15:35:10 +01:00
Mark Paluch
b2ce1700d2 DATAMONGO-1373 - Allow usage of @AliasFor with mapping and indexing annotations.
We now support @AliasFor to build composed annotations with: @Document, @Id, @Field, @Indexed, @CompoundIndex, @GeoSpatialIndexed, @TextIndexed, @Query, and @Meta. Added missing license header to @Field.

Original pull request: #347.
Related tickets: DATACMNS-825.
2016-03-15 15:20:45 +01:00
Christoph Strobl
0b634f8340 DATAMONGO-1373 - Allow usage of @AliasFor for composed @Document annotation.
We now resolve aliased attribute values when reading @Document on entity types. This allows creation of composed annotations like:

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
@Document
static @interface ComposedDocumentAnnotation {

  @AliasFor(annotation = Document.class, attribute = "collection")
  String name() default "custom-collection-name";
}

Original pull request: #347.
Related issue: DATACMNS-825.
2016-03-15 15:20:22 +01:00
Mark Paluch
9a078b743f DATAMONGO-1326 - Support field inheritance for $lookup aggregation operator.
We now distinguish between aggregation operations that replace fields in the aggregation pipeline and those which inherit fields from previous operations. InheritsFieldsAggregationOperation is a nested interface of FieldsExposingAggregationOperation is a marker to lookup fields along the aggregation context chain. Added unit and integration tests. Mention lookup operator in docs.

Original pull request: #344.
2016-03-08 09:00:55 +01:00
Christoph Strobl
65b6576cfc DATAMONGO-1326 - Add Builder, update javadoc and remove additional interface.
Updated javadoc and formatting. Added tests and removed marker interface.

Original Pull Request: #344
2016-03-08 08:59:54 +01:00
Alessio Fachechi
78e99e6df2 DATAMONGO-1326 - Add support for $lookup to aggregation.
Original Pull Request: #344
CLA: 164120160221125037 (Alessio Fachechi)
2016-03-07 14:20:14 +01:00
Oliver Gierke
bb0a42733d DATAMONGO-1389 - Fixed test case to verify type predicting bean registration.
Related ticket: DATACMNS-821.
2016-03-01 15:02:18 +01:00
Oliver Gierke
a2ae08e263 DATAMONGO-1381 - Updated changelog. 2016-02-23 14:27:23 +01:00
Oliver Gierke
eaa9d6c7e6 DATAMONGO-1366 - After release cleanups. 2016-02-12 15:43:57 +01:00
Oliver Gierke
8900695153 DATAMONGO-1366 - Prepare next development iteration. 2016-02-12 15:43:39 +01:00
Oliver Gierke
bfe548d573 DATAMONGO-1366 - Release version 1.9 M1 (Hopper). 2016-02-12 15:42:47 +01:00
Oliver Gierke
7ab4002771 DATAMONGO-1366 - Prepare 1.9 M1 (Hopper). 2016-02-12 15:36:19 +01:00
Oliver Gierke
6eace856aa DATAMONGO-1366 - Updated changelog. 2016-02-12 15:36:11 +01:00
Oliver Gierke
f10e5a19c5 DATAMONGO-1345 - Finalized application of projections in query methods.
Refactored the query execution out of AbstractMongoQuery into MongoQueryExecution. Made sure the streaming execution lazily applies the projections, too.

Added a DtoInstantiatingConverter to be able to copy data from created entities into DTOs as we cannot hand the DTO type into the MongoTemplate execution in the first place as it's going to be used for the query mapping currently.
2016-02-12 14:14:54 +01:00
Uxío Fuentefría
90a4a63776 DATAMONGO-1378 - Update reference documentation: Change Query.sort() to Query.with(Sort sort).
sort() is not a method of Query, to sort a query you have to use with().

Original pull request: #320.
CLA: 162620160211060822 (Uxío Fuentefría)
2016-02-11 20:22:36 +01:00
Oliver Gierke
0f14e35ba3 DATAMONGO-1288 - Polishing.
Some JavaDoc here and there. Moved converter factory registration into MongoConverters.getConvertersToRegister() for consistency with others.

Original pull request: #331.
2016-02-11 14:08:31 +01:00
Christoph Strobl
ad0c4207d6 DATAMONGO-1288 - Add conversion for AtomicInteger & AtomicLong.
We now convert AtomicInteger and AtomicLong to the required Number target type by calling get() followed by the actual conversion. This allows to directly use these types e.g. as part of an Update: new Update().set("intValue", new AtomicInteger(10));

Original pull request: #331.
2016-02-11 14:08:19 +01:00
Mark Paluch
97da43645a DATAMONGO-1380 - Polishing.
Add credits, use message formatting instead string concatenation.

Original pull request: #317.
2016-02-11 12:02:09 +01:00
Alex Vengrovsk
42b7c42617 DATAMONGO-1380 - Improve logging in MongoChangeSetPersister.
Add checking for debug enabling in the getPersistentId method

Original pull request: #317.
2016-02-11 11:53:15 +01:00
Timo Kockert
bd81e25e6b DATAMONGO-1270 - Update documentation to reflect deprecation of MongoFactoryBean.
Original pull request: #315.
2016-02-10 15:57:15 +01:00
Thomas Dudouet
debe6aa649 DATAMONGO-1377 - Update JavaDoc: Use @EnableMongoRepositories instead of @EnableJpaRepositories.
The JavaDoc description references the EnableJpaRepositories annotation instead of the EnableMongoRepositories annotation.

Original pull request: #340.
2016-02-10 15:13:24 +01:00
Oliver Gierke
6f433902f0 DATAMONGO-1376 - Moved away from SimpleTypeInformationMapper.INSTANCE.
Related tickets: DATACMNS-815.
2016-02-09 14:31:05 +01:00
Martin Macko
ba902e7f8e DATAMONGO-1375 - Fix typo in MongoOperations JavaDoc.
Original pull request: #343.
2016-02-09 11:29:30 +01:00
Oliver Gierke
7e8ec21684 DATAMONGO-1372 - Polishing.
Tiny formattings, collapsed if-clause into ternary operation.

Original pull request: #342.
2016-02-04 15:19:51 +01:00
Christoph Strobl
b7131b7efc DATAMONGO-1372 - Add and register Converters for java.util.Currency.
We now support conversion from currency into ISO 4217 String and back.

Original pull request: #342.
2016-02-04 15:19:48 +01:00
Oliver Gierke
ace99c3464 DATAMONGO-1371 - Added code of conduct.
Moved to Asciidoctor for the CONTRIBUTING file.
2016-02-02 09:42:48 +01:00
Oliver Gierke
83fc5bc113 DATAMONGO-1366 - Declare Artifactory Maven plugin to be able to distribute build artifacts. 2016-01-28 14:51:55 +01:00
Oliver Gierke
160de0adf6 DATAMONGO-1361 - Guard command result statistics evaluation against changes in MongoDB 3.2.
MongoDB 3.2 RC1 decided to remove fields from statistics JSON documents returned in case no result was found for a geo near query. The avgDistance field is unfortunately missing as of that version.

Introduced a value object to encapsulate the mitigation behavior and make client code unaware of that.
2016-01-21 12:45:10 +01:00
Oliver Gierke
b4753f3a83 DATAMONGO-1360 - Query instances contained in a Near Query now get mapped during geoNear(…) execution.
A Query instance which might be part of a NearQuery definition is now passed through the QueryMapper to make sure complex types contained in it or even in more general types that have custom conversions registered are mapped correctly before the near command is actually executed.
2016-01-20 13:10:50 +01:00
Oliver Gierke
bce6e2c78c DATAMONGO-1163 - Polishing.
Fixed indentation changes in IndexingIntegrationTests. Separated test cases from each other.

Original pull request: #325.
2015-12-27 12:05:19 +01:00
Jordi Llach
b5ea0eccd2 DATAMONGO-1163 - Allow usage of @Indexed as meta-annotation.
@Indexed can now be used as meta-annotation so that user annotations can be annotated with it and the index creation facilities still pick up the configuration information.

Original pull request: #325.
2015-12-27 12:05:17 +01:00
Oliver Gierke
87865b9761 DATAMONGO-1355 - Updated changelog. 2015-12-18 10:55:56 +01:00
Christoph Strobl
13fa4703c0 DATAMONGO-1334 - Map-reduce operations now honor MapReduceOptions.limit.
We now also consider the limit set via MapReduceOptions when executing mapReduce operations via MongoTemplate.mapReduce(…).

MapReduceOptions.limit(…) supersedes a potential limit set via the Query itself. This change also allows to define a limit even when no explicit Query is used.

Original pull request: #338.
2015-12-16 11:57:44 +01:00
Christoph Strobl
5a21e00322 DATAMONGO-1317 - Assert compatibility with mongo-java-driver 3.2.
We now do a defensive check against the actual WObject of WriteConcern to avoid the IllegalStateException raised by the new java-driver in case _w is null or not an Integer. This allows us to run against recent 2.13, 2.14, 3.0, 3.1 and the latest 3.2.0.

Original pull request: #337.
2015-12-16 11:49:01 +01:00
Oliver Gierke
3feed2bc5a DATAMONGO-1289 - Polishing.
Some additional JavaDoc and comment removal.

Original pull request: #333.
2015-12-16 11:38:31 +01:00
Christoph Strobl
501b9501e0 DATAMONGO-1289 - MappingMongoEntityInformation no uses fallback identifier type derived from repository declaration.
We now use RepositoryMetdata.getIdType() to provide a fallback identifier type in case the entity information does not hold an id property which is perfectly valid for MongoDB.

Original pull request: #333.
2015-12-16 11:37:51 +01:00
Oliver Gierke
727271e68c DATAMONGO-1345 - Added support for projections on repository methods.
Related tickets: DATACMNS-89.
2015-12-14 19:56:42 +01:00
Christoph Strobl
63a619dddf DATAMONGO-1349 - Upgrade to mongo-java-driver 2.14.0. 2015-12-11 10:38:36 +01:00
Oliver Gierke
113566a6ab DATAMONGO-1346 - Update.pullAll(…) now registers multiple invocations correctly.
Previously calling the method multiple times overrode the result of previous calls. We now use addMultiFieldOperation(…) to make sure already existing values are kept.
2015-12-10 15:38:40 +01:00
Oliver Gierke
7862841b48 DATAMONGO-934 - Polishing.
Polished JavaDoc and implementation as well as tests. Extracted Tuple to Spring Data Commons. Moved exception translation into MongoExceptionTranslator.

Changed implementation of DefaultBulkOperations to consider the WriteConcernResolver of the underlying MongoTemplate to avoid exposing the WriteConcern on execution.

Original pull request: #327.
Related tickets: DATACMNS-790.
2015-11-26 17:56:39 +01:00
Tobias Trelle
fe6cbaa03d DATAMONGO-934 - Added support for bulk operations.
Introduced BulkOperations that can be obtained via MongoOperations, register operations to be eventually executed in a bulk.

Original pull request: #327.
2015-11-26 17:56:35 +01:00
Oliver Gierke
9ef1fc7304 DATAMONGO-1337 - Another round of polishes on SonarQuber complaints. 2015-11-26 12:27:22 +01:00
Oliver Gierke
cf3a9d3ced DATAMONGO-1337 - Reverted making some of the loggers static.
The logger instance in AbstractMonitor is supposed to pick up the type of the actual implementation class and thus cannot be static.

Related pull request: #336.
2015-11-26 12:00:40 +01:00
Christian Ivan
1d1c80db7b DATAMONGO-1337 - General code quality improvements.
A round of code polish regarding the PMD and Squid rules referred to in the ticket.

Original pull request: #336.
2015-11-26 11:53:06 +01:00
Oliver Gierke
eeb37e9104 DATAMONGO-1342 - Fixed potential NullPointerException in MongoQueryCreator.
MongoQueryCreator.nextAsArray(…) now returns a single element object array in case null is handed to the method. It previously failed with a NullPointerException.
2015-11-25 17:23:15 +01:00
Oliver Gierke
18bf0daee7 DATAMONGO-1335 - DBObjectAccessor now writes all nested fields correctly.
Previously, DBObjectAccessor has always reset the in-between values when traversing nested properties. This caused previously written values to be erased if subsequent values are written. We now reuse an already existing BasicDBObject if present.
2015-11-25 16:06:52 +01:00
Oliver Gierke
1e9189aee7 DATAMONGO-1341 - Moved MongoDbErrorCodes into utility package.
This resolves a package cycle introduced by MongoPersistentEntityIndexCreator referring to error codes now.

Updated Sonargraph architecture description along the way.
2015-11-25 15:36:22 +01:00
Oliver Gierke
95f6dfafdd DATAMONGO-1287 - Optimizations in reading associations as constructor arguments.
As per discussion on the ticket we now omit looking up the value for an association being used as constructor argument as the simple check whether the currently handled property is a constructor argument is sufficient to potentially skip handling the value.

Related pull requests: #335, #322.
2015-11-23 11:13:07 +01:00
Christoph Strobl
bedaae8a90 DATAMONGO-1287 - Fix double fetching for lazy DbRefs used in entity constructor.
We now check properties for their usage as constructor arguments, that might already have been resolved, before setting the actual value. This prevents turning already eagerly fetched DBRefs back into LazyLoadingProxies.

Original pull request: #335.
Related pull request: #322.
2015-11-20 13:39:00 +01:00
Oliver Gierke
7bfa3fe7fd DATAMONGO-1290 - Polishing.
Removed a level of indentation from ExpressionEvaluationParameterBinder.replacePlaceholders(…). Polished JavaDoc.

Original pull request: #332.
2015-11-20 13:20:11 +01:00
Christoph Strobl
143b0b73b9 DATAMONGO-1290 - Move parameter binding for String based queries.
Moved parameter binding for string based queries into separate class.

Original pull request: #332.
2015-11-20 13:20:09 +01:00
Christoph Strobl
cbfc46270e DATAMONGO-1290 - Convert byte[] parameter in @Query to $binary representation.
We now convert non quoted binary parameters to the $binary format. This allows using them along with the @Query annotation.

Original pull request: #332.
2015-11-20 13:06:22 +01:00
Christoph Strobl
b31efb46ec DATAMONGO-1204 - ObjectPath now uses raw id values to track resolved objects.
We now use the native id within ObjectPath for checking if a DBref has already been resolved. This is required as MongoDB Java driver 3 generation changed ObjectId.equals(…) which now performs a type check.

Original pull request: #334.
Related pull request: #288.
2015-11-20 12:47:52 +01:00
Oliver Gierke
ef3477098f DATAMONGO-1324 - Register ObjectId converters unconditionally to make sure they really get used.
The presence of ObjectToObjectConverter in a DefaultConversionService causes the guard trying to register converters for ObjectIds in AbstractMongoConverter to not trigger the registration. This in turn caused ObjectId conversions to be executed via reflection instead of the straight forward method calls and thus a drop in performance for such operations.

We no unconditionally register the converters to make sure they really get applied.

Related tickets: SPR-13703.
2015-11-19 12:02:41 +01:00
Oliver Gierke
9dce117555 DATAMONGO-1238 - Upgraded to Querydsl 4. 2015-11-17 13:42:38 +01:00
Oliver Gierke
e66e1e0502 DATAMONGO-1316 - Updated changelog. 2015-11-16 08:31:45 +01:00
Christoph Strobl
19e1e9daeb DATAMONGO-1297 - Allow @Indexed annotation on DBRef.
We now also treat references as source of a potential index. This enforces index creation for Objects like:

@Document
class WithDbRef {

  @Indexed
  @DBRef
  ReferencedObject reference;
}

Combining @TextIndexed or @GeoSpatialIndexed with a DBRef will lead to a MappingException.

Original pull request: #329.
2015-11-13 17:54:42 +01:00
Christoph Strobl
ec8a948f3f DATAMONGO-1302 - Allow ConverterFactory to be registered in CustomConversions.
We now allow registration of ConverterFactory within CustomConversions by inspecting the generic type arguments for determining the conversion source and target types.

Original pull request: #330.
2015-11-10 14:37:02 +01:00
Ilho Ahn
38fc7641a0 DATAMONGO-1314 - Fix typo in Exception message.
Original Pull Request: #265
2015-11-09 20:37:26 +01:00
Christoph Strobl
ddc3925659 DATAMONGO-1291 - Made @Document usable as meta-annotation.
We now use Spring's AnnotationUtils.findAnnotation(…) for @Document lookup which enables the full power of Spring 4.2's composable annotations.

Original pull request: #326.
2015-11-06 14:34:43 +01:00
Christoph Strobl
f8416edf8f DATAMONGO-1293 - Polishing.
Move configuration parsing error into method actually responsible for reading uri/client-uri attributes.

Original Pull Request: #328
2015-10-29 12:47:16 +01:00
Viktor Khoroshko
4f94f37ce8 DATAMONGO-1293 - Allowed id attribute in addition to client-uri attribute in MongoDbFactoryParser.
We now allow write-concern and id to be configured along with the uri or client-uri attribute of <mongo:db-factory.

Original Pull Request: #328
CLA: 140120150929074128 (Viktor Khoroshko)
2015-10-29 12:47:08 +01:00
Oliver Gierke
528de58418 DATAMONGO-1276 - Fixed potential NullPointerExceptions in MongoTemplate.
Triggering data access exception translation could lead to NullPointerException in cases where PersistenceExceptionTranslator returned null because the original exception couldn't be translated and the result was directly used from a throw clause.

This is now fixed by consistently the potentiallyConvertRuntimeException(…) method, which was made static to be able to refer to it from nested static classes.

Refactored Scanner usage to actually close the Scanner instance to prevent a resource leak.
2015-10-21 15:04:12 +02:00
Oliver Gierke
e6ea34aed8 DATAMONGO-1304 - Updated changelog. 2015-10-14 13:46:21 +02:00
Oliver Gierke
f171938b00 DATAMONGO-1303 - Added build profiles for MongoDB Java driver 3.1 and 3.2 snapshots.
Added new build profiles mongod31 and mongo32-next to build the project against the latest MongoDB 3.1 driver as well as upcoming snapshots of the 3.2 generation.
2015-10-12 15:41:30 +02:00
Oliver Gierke
7b27368d2d DATAMONGO-1282 - After release cleanups. 2015-09-01 12:11:02 +02:00
Spring Buildmaster
f754df51bc DATAMONGO-1282 - Prepare next development iteration. 2015-09-01 02:12:29 -07:00
Spring Buildmaster
77dce53c7a DATAMONGO-1282 - Release version 1.8.0.RELEASE (Gosling GA). 2015-09-01 02:12:26 -07:00
Oliver Gierke
73f268e7c4 DATAMONGO-1282 - Prepare 1.8.0.RELEASE (Gosling GA). 2015-09-01 09:44:21 +02:00
Oliver Gierke
075d7d8131 DATAMONGO-1282 - Updated changelog. 2015-09-01 09:44:11 +02:00
Christoph Strobl
206337044a DATAMONGO-1280 - Updated "What’s new" section in reference documentation.
Original pull request: #319.
2015-08-31 12:55:30 +02:00
Christoph Strobl
55b44ff7aa DATAMONGO-1275 - Fixed broken links in reference documentation.
Original pull request: #318.
2015-08-22 13:16:49 +02:00
Christoph Strobl
ae48639ae9 DATAMONGO-1275 - Added documentation for optimistic locking.
Original pull request: #318.
2015-08-22 13:16:45 +02:00
Oliver Gierke
6b5e78f810 DATAMONGO-1256 - Polishing.
Minor Javadoc polishing.

Original pull request: #316.
2015-08-07 14:04:49 +02:00
Christoph Strobl
3e485e0a88 DATAMONGO-1256 - MongoMappingEvents now expose the collection name they're issued for.
We now directly expose the collection name via MongoMappingEvent.getCollectionName(). Therefore we added new constructors to all the events, deprecating the previous ones. 

Several overloads have been added to MongoEventListener, deprecating previous API. We’ll call the deprecated from the new ones until their removal.

Original pull request: #316.
2015-08-07 14:04:47 +02:00
Oliver Gierke
335c78f908 DATAMONGO-1269 - Polishing.
Original pull request: #314.
2015-08-06 11:00:36 +02:00
Christoph Strobl
b103e4eaf6 DATAMONGO-1269 - Retain position parameter in property path.
We now retain position parameters in paths used in queries when mapping the field name. This allows to map "list.1.name" to the name property of the first element in the list.

The change also fixes a glitch in mapping java.util.Map like structures having numeric keys.

Original pull request: #314.
2015-08-06 11:00:36 +02:00
Oliver Gierke
c4a6c63d23 DATAMONGO-1268 - After release cleanups. 2015-08-04 14:09:20 +02:00
Spring Buildmaster
4a4f10f97b DATAMONGO-1268 - Prepare next development iteration. 2015-08-04 04:37:14 -07:00
Spring Buildmaster
a5712daab7 DATAMONGO-1268 - Release version 1.8.0.RC1 (Gosling RC1). 2015-08-04 04:37:12 -07:00
Oliver Gierke
28cb1ef106 DATAMONGO-1268 - Prepare 1.8.0.RC1 (Gosling RC1). 2015-08-04 13:08:49 +02:00
Oliver Gierke
0d99a3e527 DATAMONGO-1268 - Updated changelog. 2015-08-04 13:08:49 +02:00
Christoph Strobl
9da43263ce DATAMONGO-1263 - Index resolver considers generic type argument of collection elements.
We now consider the potential generic type argument of collection elements. 
Prior to this change an index within List<GenericWrapper<ConcreteWithIndex>> would not have been resolved.

Original pull request: #312.
2015-08-04 08:48:57 +02:00
Oliver Gierke
784e199068 DATAMONGO-1266 - Fixed domain type lookup for methods returning primitves.
If a repository query method returned a primitive, that primitive was exposed as domain type which e.g. caused deleteBy…(…) methods to fail that returned a void.

We now shortcut the MongoEntityMetadata lookup in MongoQueryMethod to use the repository's domain type if a primitive or wrapper is returned.
2015-08-03 11:53:10 +02:00
Oliver Gierke
1ffee802c0 DATAMONGO-1261 - Updated changelog. 2015-07-28 16:42:58 +02:00
Christoph Strobl
6f0ac7f0c2 DATAMONGO-1254 - Grouping after projection in aggregation now uses correct aliased field name.
We now push the aliased field name down the aggregation pipeline for projections including operations. This allows to reference them in a later stage. Prior to this change the field reference was potentially resolved to the target field of the operation which did not result in an error but lead to false results.

Original pull request: #311.
2015-07-27 14:15:33 +02:00
Christoph Strobl
941d4d8985 DATAMONGO-1260 - Prevent accidental authentication misconfiguration on SimpleMongoDbFactory.
We now reject configuration using MongoClient along with UserCredentials in SimpleMongoDbFactory. This move favors the native authentication mechanism provided via MongoCredential.

<mongo:mongo-client id="mongo-client-with-credentials" credentials="jon:warg@snow?uri.authMechanism=PLAIN" />

Original pull request: #309.
2015-07-27 14:08:42 +02:00
Oliver Gierke
44c76d8ffb DATAMONGO-1257 - We now hint to credential quoting from the XSD.
The namespace XSD now mentions the capability of quoting more complex credentials in case they validly contain a comma.
2015-07-27 13:47:11 +02:00
Oliver Gierke
df9a9f5fb6 DATAMONGO-1257 - Polishing.
Made internal helper methods in MongoCredentialPropertyEditor static where possible.

Original pull request: #310.
2015-07-24 18:40:57 +02:00
Christoph Strobl
bebd0fa0e6 DATAMONGO-1257 - <mongo:mongo-client /> element now supports usernames with a comma.
We now allow grouping credentials by enclosing them in single quotes like this:

credentials='CN=myName,OU=myOrgUnit,O=myOrg,L=myLocality,ST=myState,C=myCountry?uri.authMechanism=MONGODB-X509'

We also changed the required argument checks to be more authentication mechanism specific which means the pattern is now username[:password@database][?options].

Original pull request: #310.
2015-07-24 18:40:56 +02:00
Oliver Gierke
594e90789d DATAMONGO-1244 - Polishing.
Minor reformattings and extracted a method to improve digestability.

Original pull request: #306.
2015-07-08 10:18:35 +02:00
Thomas Darimont
f2ab42cb80 DATAMONGO-1244 - Improved handling of expression parameters in StringBasedMongoQuery.
Replaced regex based parsing of dynamic expression based parameters with custom parsing to make sure we also support complex nested expression objects.
Previously we only supported simple named or positional expressions. Since MongoDBs JSON based query language uses deeply nested objects to express queries, we needed to improve the handling here.

Manual parsing is tedious and more verbose than regex based parsing but it gives us more control over the whole parsing process.

We also dynamically adjust  the quoting so that we only output quoted parameters if necessary.

This enables to express complex filtering queries the use Spring Security constructors like:
```
@Query("{id: ?#{ hasRole('ROLE_ADMIN') ? {$exists:true} : principal.id}}")
List<User> findAllForCurrentUserById();
```

Original pull request: #306.
2015-07-08 10:18:27 +02:00
Christoph Strobl
3224fa8ce7 DATAMONGO-1251 - Fixed potential NullPointerException in UpdateMapper.
We now explicitly handle the possibility of the source object a type hint needs to be calculated for being null.
2015-07-07 09:57:46 +02:00
Oliver Gierke
ce156c1344 DATAMONGO-1250 - Fixed inline code formatting in reference docs. 2015-07-04 19:07:09 +02:00
Oliver Gierke
434e553022 DATAMONGO-1250 - Fixed accidental duplicate invocation of value conversion in UpdateMapper.
UpdateMapper.getMappedObjectForField(…) invokes the very same method of the super class but handed in an already mapped value so that value conversion was invoked twice.

This was especially problematic in cases a dedicated converter had been registered for an object that is already a Mongo-storable one (e.g. an enum-to-string converter and back) without indicating which of the tow converter is the reading or the writing one. This basically caused the source value converted back and forth during the update mapping creating the impression the value wasn't converted at all.

This is now fixed by removing the superfluous mapping.
2015-07-04 19:00:21 +02:00
Oliver Gierke
de5b5ee4b0 DATAMONGO-1246 - Updated changelog. 2015-07-01 10:00:16 +02:00
Oliver Gierke
60636bf56d DATAMONGO-1247 - Updated changelog. 2015-07-01 07:48:31 +02:00
Oliver Gierke
1ca71f93e9 DATAMONGO-1248 - Updated changelog. 2015-06-30 13:58:37 +02:00
Oliver Gierke
63ff39bed6 DATAMONGO-1236 - Polishing.
Removed the creation of a BasicMongoPersistentEntity in favor of always handing ClassTypeInformation.OBJECT into the converter in case not entity can be found.

This makes sure type information is written for updates on properties of type Object (which essentially leads to no PersistentEntity being available).

Original pull request: #301.
2015-06-30 09:54:53 +02:00
Christoph Strobl
cb0b9604d4 DATAMONGO-1236 - Update now include type hint correctly.
We now use property type information when mapping fields affected by an update in case we do not have proper entity information within the context. This allows more precise type resolution required for determining the need to write type hints for a given property.

Original pull request: #301.
2015-06-30 09:54:53 +02:00
Christoph Strobl
1dbe3b62d7 DATAMONGO-1125 - Improve exception message for index creation errors.
We now use MongoExceptionTranslator to potentially convert exceptions during index creation into Springs DataAccessException hierarchy. In case we encounter an error code indicating DataIntegrityViolation we try to fetch existing index data and append it to the exceptions message.

Original pull request: #302.
2015-06-24 20:28:23 +02:00
Christoph Strobl
5c0707d221 DATAMONGO-1232 - IngoreCase in criteria now escapes query.
We now quote the original criteria before actually wrapping it inside of an regular expression for case insensitive search. This happens not only to case insensitive is, startsWith, endsWith criteria but also to those using like. In that case we quote the part between leading and trailing wildcard if required.

Original pull request: #301.
2015-06-22 12:50:05 +02:00
Christoph Strobl
c4ffc37dd5 DATAMONGO-1166 - ReadPreference is now be used for aggregations.
We now use MongoTemplate.readPreference(…) when executing commands such as geoNear(…) and aggregate(…).

Original pull request: #303.
2015-06-22 08:21:23 +02:00
Christoph Strobl
aaf93b0f6f DATAMONGO-1157 - Throw meaningful exception when @DbRef is used with unsupported types.
We now eagerly check DBRef properties for invalid definitions such as final class or array. In that case we throw a MappingException when verify is called.
2015-06-19 15:54:19 +02:00
Thomas Darimont
23eab1e84f DATAMONGO-1242 - Update MongoDB Java driver to 3.0.2 in mongo3 profile.
Update mongo driver.

Original pull request: #304.
2015-06-19 15:37:47 +02:00
Oliver Gierke
218f32e552 DATAMONGO-1229 - Fixed application of ignore case flag on nested properties.
Previously we tried to apply the ignore case settings found in the PartTree to the root PropertyPath we handle in MongoQueryCreator.create(). This is now changed to work on the leaf property of the PropertyPath.
2015-06-05 06:49:03 +02:00
Eddú Meléndez
62fbe4d08c DATAMONGO-1234 - Fix typos in JavaDoc. 2015-06-05 06:37:22 +02:00
Oliver Gierke
41ffd00619 DATAMONGO-1228 - After release cleanups. 2015-06-02 11:58:11 +02:00
Spring Buildmaster
98b9a604cf DATAMONGO-1228 - Prepare next development iteration. 2015-06-02 01:29:04 -07:00
Spring Buildmaster
01468b640a DATAMONGO-1228 - Release version 1.8.0.M1 (Gosling M1). 2015-06-02 01:29:01 -07:00
Oliver Gierke
4d96b036a2 DATAMONGO-1228 - Prepare 1.8.0.M1 (Gosling M1). 2015-06-02 09:29:53 +02:00
Oliver Gierke
2d1ac15e24 DATAMONGO-1228 - Updated changelog. 2015-06-02 08:24:47 +02:00
Oliver Gierke
2c27e8576f DATAMONGO-990 - Polishing.
Removed EvaluationExpressionContext from all AbstractMongoQuery implementations that don't actually need it and from AbstractMongoQuery itself, too. Cleaned up test cases after that.

Moved SpEL related tests into AbstractPersonRepositoryIntegrationTests to make sure they're executed for all sub-types. JavaDoc and assertion polishes.

Original pull request: #285.
2015-06-01 17:27:58 +02:00
Thomas Darimont
67f638d953 DATAMONGO-990 - Add support for SpEL expressions in @Query.
Ported and adapted support for SpEL expressions @Query annotations from Spring Data JPA. StringBasedMongoQuery can now evaluate SpEL fragments in queries with the help of the given EvaluationContextProvider. Introduced EvaluationContextProvider to AbstractMongoQuery. Exposed access to actual parameter values in MongoParameterAccessor.

Original pull request: #285.
2015-06-01 17:27:58 +02:00
Oliver Gierke
ea5bd5f7d3 DATAMONGO-1210 - Polishing.
Moved getTypeHint(…) method to Field class.

Original pull request: #292.
2015-06-01 13:21:07 +02:00
Christoph Strobl
394f695416 DATAMONGO-1210 - Fixed type hints for usage with findAndModify(…).
We now inspect the actual field type during update mapping and provide a type hint accordingly. Simple, non interface and non abstract types will no longer be decorated with the _class attribute. We now honor positional parameters when trying to map paths to properties. This allows more decent type mapping since we have now access to the meta model which allows us to check if presence of type hint (aka _class) is required.

We now add a special type hint indicating nested types to the converter. This allows more fine grained removal of _class property without the need to break the contract of MongoWriter.convertToMongoType(…).

Original pull request: #292.
2015-06-01 13:21:07 +02:00
Stefan Ganzer
e4db466ab9 DATAMONGO-1210 - Add breaking test case for findAndModify/addToSet/each.
The problem stems from the inconsistent handling of type hints such as MongoTemplate.save(…) does not add a type hint, but findAndModify(…) does. The same values are then treated differently by MongoDB, depending on whether they have a type hint or not. To verify this behavior, you can manually add the (superfluous) type hint to the saved object - findAndModify will then work as expected.

Additional tests demonstrate that findAndModify(…) removes type hints from complex documents in collections that are either nested in another collection or in a document, or doesn't add them in the first place.

Original pull requests: #290, #291.
Related pull request: #292.
CLA: 119820150506013701 (Stefan Ganzer)
2015-06-01 13:21:01 +02:00
Christoph Strobl
ee04c014c9 DATAMONGO-1134 - Add support for $geoIntersects.
We now support $geoIntersects via Criteria.intersects(…) using GeoJSON types.

Original pull request: #295.
2015-06-01 12:36:20 +02:00
Christoph Strobl
ea84f08de8 DATAMONGO-1216 - Skip authentication via AuthDB for MongoClient.
We now skip authentication via an explicit AuthDB when requesting a DB via a MongoClient instance.

Related ticket: DATACMNS-1218
Original pull request: #296.
2015-06-01 12:10:14 +02:00
Christoph Strobl
7d8a2b2d56 DATAMONGO-1218 - Deprecate non-MongoClient related configuration options in XML namespace.
We added deprecation hints to the description sections of elements and attributes within the spring-mongo.xsd of 1.7. Also we’ve added (for 1.8) a configuration attribute to db-factory allowing to set a client-uri creating a MongoClientURI instead of a MongoURI that will be passed on to MongoDbFactory. Just as 'uri', 'client-uri' will not allow additional configuration options like username, password next to it.

Original pull request: #296
2015-06-01 12:10:14 +02:00
Christoph Strobl
995d1e5aac DATAMONGO-1202 - Polishing.
Moved and renamed types into test class.
Added collection cleanup and missing author information.

Original pull request: #293.
2015-06-01 09:23:35 +02:00
Thomas Darimont
3b918492ae DATAMONGO-1202 - More robust type inspection for @Indexed properties.
We now use TypeInformation in IndexResolver to lookup the root PersistentEntity for resolving @Indexed properties to ensure that we retrieve the same PersistentEntity that was stored. Previously we used the Class to lookup up the PersistentEntity which yielded a partially processed result.

Original pull request: #293.
2015-06-01 09:08:31 +02:00
Christoph Strobl
66b419163c DATAMONGO-1193 - Prevent unnecessary database lookups when resolving DBRefs on 2.x driver.
We now check against the used driver version before requesting db instance from factory. Potential improvements on fetch strategy for MongoDB Java Driver 3 will be handled in DATAMONGO-1194.

Related tickets: DATAMONGO-1194.
Original pull request: #286.
2015-06-01 08:09:50 +02:00
Oliver Gierke
52bff39c22 DATAMONGO-1224 - Ensure Spring Framework 4.2 compatibility.
Removed obsolete generics in MongoPersistentEntityIndexCreator to make sure MappingContextEvents are delivered to the listener on Spring 4.2 which applies more strict generics handling to ApplicationEvents.

Tweaked PersonBeforeSaveListener in test code to actually reflect how an ApplicationEventListener for MongoDB would be implemented.

Removed deprecated (and now removed) usage of ConversionServiceFactory in AbstractMongoConverter. Added MongoMappingEventPublisher.publishEvent(Object) as NoOp.
2015-05-25 13:12:47 +02:00
Domenique Tilleuil
d151a13e87 DATAMONGO-1208 - Use QueryCursorPreparer for streaming in MongoTemplate.
We now use the QueryCursorPreparer honor skip, limit, sort, etc. for streaming.

Original pull request: #297.
Polishing pull request: #298.
2015-05-21 09:00:33 +02:00
Oliver Gierke
5e7e7d3598 DATAMONGO-1221 - Removed <relativePath /> element from parent POM declaration. 2015-05-15 15:07:30 +02:00
Oliver Gierke
356248bd05 DATAMONGO-1213 - Included section on dependency management in reference documentation.
Related ticket: DATACMNS-687.
2015-05-04 14:51:34 +02:00
Oliver Gierke
73a60153f6 DATAMONGO-1211 - Adapt to changes in Spring Data Commons.
Tweaked method signatures in MongoRepositoryFactory after some signature changes in Spring Data Commons. Use newly introduced getTragetRepositoryViaReflection(…) to obtain the repository instance via the super class.

Added repositoryBaseClass() attribute to @EnableMongoRepositories.

Related tickets: DATACMNS-542.
2015-05-02 14:49:31 +02:00
Oliver Gierke
67cf0e62a7 DATAMONGO-1207 - Fixed potential NPE in MongoTemplate.doInsertAll(…).
If a collection containing null values is handed to MongoTempalte.insertAll(…), a NullPointerException was caused by the unguarded attempt to lookup the class of the element. We now explicitly handle this case and skip the element.

Some code cleanups in MongoTemplate.doInsertAll(…).
2015-05-02 14:49:31 +02:00
Oliver Gierke
21fbcc3e67 DATAMONGO-1196 - Upgraded build profiles after MongoDB 3.0 Java driver GA release. 2015-04-01 17:11:55 +02:00
Oliver Gierke
0d63ff92a0 DATAMONGO-1192 - Switched to Spring 4.1's CollectionFactory. 2015-03-31 17:16:44 +02:00
Oliver Gierke
983645e222 DATAMONGO-1189 - After release cleanups. 2015-03-23 14:00:52 +01:00
Spring Buildmaster
d2805bfa47 DATAMONGO-1189 - Prepare next development iteration. 2015-03-23 13:03:26 +01:00
Spring Buildmaster
3f16b30631 DATAMONGO-1189 - Release version 1.7.0.RELEASE (Fowler GA). 2015-03-23 13:03:07 +01:00
Oliver Gierke
8ebcbe3c5c DATAMONGO-1189 - Prepare 1.7.0.RELEASE (Fowler GA). 2015-03-23 12:34:49 +01:00
Oliver Gierke
363bed5c37 DATAMONGO-1189 - Updated changelog. 2015-03-23 12:03:56 +01:00
Christoph Strobl
1547a646dd DATAMONGO-1189 - DATAJPA-692 - Polish reference docs before release.
Add repository query return types to reference doc.
Fall back to locally available Spring Data Commons reference docs as the remote variant doesn't seem to work currently
2015-03-23 11:17:25 +01:00
Oliver Gierke
1408d51065 DATAMONGO-979 - Polishing.
Minor JavaDoc and code style polishes.

Original pull request: #272.
2015-03-23 09:32:52 +01:00
Thomas Darimont
f5c319f18f DATAMONGO-979 - Add support for $size expression in project and group aggregation pipeline.
Introduced AggregationExpression interface to be able to represent arbitrary MongoDB expressions that can be used in projection and group operations. Supported function expressions are provided via the AggregationFunctionExpressions enum.

Original pull request: #272.
2015-03-23 09:32:26 +01:00
Christoph Strobl
a3c29054d0 DATAMONGO-1124 - Switch log level for cyclic reference index warnings to INFO.
Reduce log level from warn to info to avoid noise during application startup.

Original pull request: #282.
2015-03-23 09:00:24 +01:00
Oliver Gierke
01533ca34c DATAMONGO-1181 - Register GeoJsonModule with @EnableSpringDataWebSupport.
Added the necessary configuration infrastructure to automatically register the GeoJsonModule as Spring bean when @EnableSpringDataWebSupport is used. This is implemented by exposing a configuration class annotated with @SpringDataWebConfigurationMixin.

Added Spring WebMVC as test dependency to be able to write an integration test. Polished GeoJsonModule to hide the actual serializers.

Original pull request: #283.
Related ticket: DATACMNS-660.
2015-03-17 19:40:57 +01:00
Christoph Strobl
a1f6dc6db4 DATAMONGO-1181 - Add Jackson Module for GeoJSON types.
Added GeoJsonModule providing JsonDeserializers for GeoJsonPoint, GeoJsonMultiPoint, GeoJsonLineString, GeoJsonMultiLineString, GeoJsonPolygon and GeoJsonMultiPolygon.

Original pull request: #283.
2015-03-17 19:40:57 +01:00
Oliver Gierke
37d53d936d DATAMONGO-1179 - Polishing. 2015-03-10 14:29:22 +01:00
Christoph Strobl
bc0a2df653 DATAMONGO-1179 - Update reference documentation.
Added new-features section. Updated links and requirements. Added section for GeoJSON support. Updated Script Operations section. Added return type Stream to repositories section. Updated keyword list.

Original pull request: #281.
2015-03-10 14:29:22 +01:00
Oliver Gierke
7e50fd8273 DATAMONGO-1180 - Polishing.
Fixed copyright ranges in license headers. Added unit test to PartTreeMongoQueryUnitTests to verify the root exception being propagated correctly.

Original pull request: #280.
Related pull request: #259.
2015-03-10 12:20:53 +01:00
Thomas Darimont
ba560ffbad DATAMONGO-1180 - Fixed incorrect exception message creation in PartTreeMongoQuery.
The JSONParseException caught in PartTreeMongoQuery is now passed to the IllegalStateException we throw from the method. Previously it was passed to the String.format(…) varargs. Verified by manually throwing a JSONParseException in the debugger.

Original pull request: #280.
Related pull request: #259.
2015-03-10 12:20:53 +01:00
Oliver Gierke
50ca32c8b9 DATAMONGO-1173 - After release cleanups. 2015-03-05 19:41:05 +01:00
Spring Buildmaster
bdfe3af505 DATAMONGO-1173 - Prepare next development iteration. 2015-03-05 07:47:13 -08:00
Spring Buildmaster
798b56055d DATAMONGO-1173 - Release version 1.7.0.RC1. 2015-03-05 07:47:11 -08:00
Oliver Gierke
ce68e4a070 DATAMONGO-1173 - Prepare 1.7.0.RC1 (Fowler RC1). 2015-03-05 16:31:00 +01:00
Oliver Gierke
5da3130d26 DATAMONGO-1173 - Updated changelog. 2015-03-05 15:54:23 +01:00
Oliver Gierke
6687cdc101 DATAMONGO-1110 - Polishing.
Moved to newly introduced Range type in Spring Data Commons to more safely bind minimum and maximum distances. Changed internal APIs to always use a Range<Distance> which gets populated based on the method signature's characteristics: if only one Distance parameter is found it's interpreted as a range with upper bound only.

Removed invalid testcase for minDistance on 2D index.

Original pull request: #277.
2015-03-05 15:35:42 +01:00
Christoph Strobl
7e74ec6b62 DATAMONGO-1110 - Add support for $minDistance.
We now support $minDistance for NearQuery and Criteria. Please keep in mind that minDistance is only available for MongoDB 2.6 and better and can only be combined with $near or $nearSphere operator depending on the defined index type. Usage of $minDistance with NearQuery is only possible when a 2dsphere index is present. We also make sure $minDistance operator gets correctly nested when using GeoJSON types.

It is now possible to use a Range<Distance> parameter within the repository queries. This allows to define near queries like:

findByLocationNear(Point point, Range<Distance> distances);

The lower bound of the range is treated as the minimum distance while the upper one defines the maximum distance from the given point. In case a Distance parameter is provided it will serve as maxDistance.

Original pull request: #277.
2015-03-05 15:34:45 +01:00
Thomas Darimont
b887fa70a5 DATAMONGO-1133 - Fixed broken tests,
AggregationTests.shouldHonorFieldAliasesForFieldReferences() now correctly sets up 3 different instances of MeterData and correctly calculates the aggreated counter values.

Original pull request: #279.
2015-03-05 15:30:35 +01:00
Oliver Gierke
1c6ab25253 DATAMONGO-1135 - Polishing.
A few polishing changes to the GeoConverters.
2015-03-05 14:28:11 +01:00
Christoph Strobl
1c43a3d1ee DATAMONGO-1135 - Add support for GeoJson.
We’ve added special types representing GeoJson structures. This allows to use those within both queries and domain types.

GeoJson types should only be used in combination with a 2dsphere index as 2d index is not able to handle the structure. Though legacy coordinate pairs and GeoJson types can be mixed inside MongoDB, we currently do not support conversion of legacy coordinates to GeoJson types.
2015-03-05 14:28:11 +01:00
Thomas Darimont
60ca1b3509 DATAMONGO-1133 - Assert that field aliasing is honored in aggregation operations.
Added some test to show that field aliases are honored during object rendering in aggregation operations.

Original pull request: #279.
2015-03-05 12:21:12 +01:00
Oliver Gierke
39d9312005 DATAMONGO-479 - Polishing.
Removed ServersideJavaScript abstraction as we still had to resort on instanceof checks and it created more ambiguities than it helped (e.g. in a script with name and code, which of the two get's executed?). We now have an ExecutableMongoScript which is code only and a NamedMongoScript, which basically is the former assigned to a name. Execution can be triggered on the former or a name.

ScriptOperations.exists(…) now returns a primitive boolean to avoid null checks. JavaDoc.

Original pull request: #254.
2015-03-04 15:18:46 +01:00
Christoph Strobl
a0e42f5dfe DATAMONGO-479 - Add support for calling functions.
We added ScriptOperations to MongoTemplate. Those allow storage and execution of java script function directly on the MongoDB server instance. Having ScriptOperations in place builds the foundation for annotation driver support in repository layer.

Original pull request: #254.
2015-03-04 15:18:40 +01:00
Oliver Gierke
7a3aff12a5 DATAMONGO-1165 - Polishing.
Renamed MongoOperations executeAsStream(…) to stream(…). Make use of Spring Data Commons StreamUtils in AbstractMongoQuery's StreamExecution. Moved test case from PersonRepositoryIntegrationTests to AbstractPersonRepositoryIntegrationTests to make sure they're executed for all sub-types.

Original pull request: #274.
2015-03-03 22:33:33 +01:00
Thomas Darimont
d4f1ef8704 DATAMONGO-1165 - Add support for Java 8 Stream as return type for repository methods.
Added support for a MongoDB Cursor backed Iterator that allows the usage of a Java 8 Stream at the repository level.

Original pull request: #274.
2015-03-03 20:56:47 +01:00
Oliver Gierke
a86d704bec DATAMONGO-1158 - Polishing.
MongoFactoryBean, MongoOptionsFactoryBean, MongoClientFactoryBean and MongoClientOptionsFactoryBean now extend AbstractFactoryBean to get a lot of the lifecycle callbacks without further code.

Added non-null assertions to newly introduced methods on MongoOperations/MongoTemplate.

Moved MongoClientVersion into util package. Introduced static imports for ReflectionUtils and MongoClientVersion for all references in the newly introduced Invoker types.

Some formatting, JavaDoc polishes, suppress deprecation warnings. Added build profile for MongoDB Java driver 3.0 as well as the following snapshot.

Original pull request: #273.
2015-03-02 21:50:27 +01:00
Christoph Strobl
57ab27aa5b DATAMONGO-1158 - Add Support for MongoDB Java driver 3.0.
We now support mongo-java-driver version 2.x and 3.0 along with MongoDB Server 2.6.7 and 3.0.0.

Please note that some of the configurations options might no longer be valid when used with version 3 of the MongoDB Java driver. Have a look at the table below so see some of the major differences in using version 2.x or 3.0

                      | 2.x                  | 3.0
----------------------+----------------------+-----------------------------------------------
default WriteConcern  | NONE                 | UNACKNOWLEDGED
----------------------+----------------------+-----------------------------------------------
option for slaveOk    | available            | ignored
----------------------+----------------------+-----------------------------------------------
option for autoConnect| available            | ignored
----------------------+----------------------+-----------------------------------------------
write result checking | available            | ignored (errors are exceptions anyway)
----------------------+----------------------+-----------------------------------------------
rest index cache      | available            | throws UnsupportedOperationException
----------------------+----------------------+-----------------------------------------------
DBRef resolution      | via DBRef.fetch      | via collection.findOne
----------------------+----------------------+-----------------------------------------------
MapReduce Options     | applied              | ignored
----------------------+----------------------+-----------------------------------------------
authentication        | via UserCredentials  | via MongoClient
----------------------+----------------------+-----------------------------------------------
WriteConcernException | not available        | translated to DataIntegretyViolationException
----------------------+----------------------+-----------------------------------------------
executeInSession      | available            | requestStart/requestDone commands ignored.
----------------------+----------------------+-----------------------------------------------
index creation        | via createIndex      | via createIndex
----------------------+----------------------+-----------------------------------------------

We need to soften the exception validation a bit since the message is slightly different when using different storage engines in a MongoDB 3.0 environment.

Added an explicit <mongo-client /> element and <client-options /> to the configuration schema. These elements will replace existing <mongo /> and <options /> elements in a subsequent release. Added credentials attribute to <mongo-client /> which allows to define a set of credentials used for setting up the MongoClient correctly using authentication data. We now reject <mongo-options /> configuration when using MongoDB Java driver generation 3.0 and above.

Original pull request: #273.
2015-03-02 20:26:50 +01:00
Thomas Darimont
909cc8b5d3 DATAMONGO-1081 - Improve documentation on field mapping semantics.
Added table with examples to identifier field mapping section.

Original pull request: #276.
2015-03-02 18:15:18 +01:00
Thomas Darimont
b7acbc4347 DATAMONGO-1167 - Added QueryDslPredicateExecutor.findAll(Predicate, Sort).
We now support findAll on QueryDslMongoRepository that accepts a Querydsl Predicate and a Sort and returns a List<T>.

Original pull request: #275.
2015-02-24 09:51:39 +01:00
Oliver Gierke
d276306ddc DATAMONGO-1162 - Adapt to API changes in Spring Data Commons. 2015-02-06 12:48:26 +01:00
Oliver Gierke
25b98b7ad2 DATAMONGO-1154 - Upgraded to MongoDB Java driver 2.13.0. 2015-01-29 20:54:39 +01:00
Oliver Gierke
819b424142 DATAMONGO-1153 - Fix documentation build.
Movend jconsole.png to the images folder. Extracted MongoDB-specific auditing documentation into separate file for inclusion after the general auditing docs.
2015-01-29 14:04:16 +01:00
Oliver Gierke
5d0328ba4b DATAMONGO-1144 - Updated changelog. 2015-01-28 20:46:19 +01:00
Oliver Gierke
b219cff29c DATAMONGO-1143 - Updated changelog. 2015-01-28 10:00:59 +01:00
Oliver Gierke
409eeaf962 DATAMONGO-1148 - Favor EclipseLink’s JPA over the Hibernate one. 2015-01-27 21:43:46 +01:00
Oliver Gierke
4e5e8bd026 DATAMONGO-1146 - Polishing.
Added missing @Override annotations to QueryDslMongoRepository methods.

Related tickets: DATACMNS-636.
Original pull request: #270.
2015-01-26 11:52:14 +01:00
Thomas Darimont
b91ec53ae0 DATAMONGO-1146 - Added QueryDslMongoRepository.exists(…) which accepts a Querydsl predicate.
Added explicit test case for QueryDslMongoRepository.

Related tickets: DATACMNS-636.
Original pull request: #270.
2015-01-26 11:52:06 +01:00
Oliver Gierke
ce0624b8b0 DATAMONGO-712 - Another round of performance improvements.
Refactored CustomConversions to unify locked access to the cached types. Added a cache for raw-write-targets so that they’re cached, too.

DBObjectAccessor now avoids expensive code paths for both reads and writes in case of simple field names.

MappingMongoConverter now eagerly skips conversions of simple types in case the value is already assignable to the target type.

QueryMapper now checks the ConversionService and only triggers a conversion if it’s actually capable of doing so instead of catching a more expensive exception.

CachingMongoPersistentProperty now also caches usePropertyAccess() and isTransient() as they’re used quite frequently.

Related ticket: DATACMNS-637.
2015-01-25 18:57:56 +01:00
alex-on-java
b4de2769cf DATAMONGO-1147 - Remove manual array copy.
Remove manual array coping by using Arrays.copyOf(values, values.length).

Original pull request: #258.
2015-01-23 17:51:44 +01:00
Thomas Darimont
3f7b0f1eb6 DATAMONGO-1082 - Improved documentation of alias usage in aggregation framework.
Added missing JavaDoc and added short note to the reference documentation.

Original pull request: #268.
2015-01-22 08:47:15 +01:00
Thomas Darimont
4055365c57 DATAMONGO-1127 - Add support for geoNear queries with distance information.
Made unit tests more robust to small differences in distance calculations between MongoDB versions.
2015-01-20 19:04:01 +01:00
Thomas Darimont
db7f782ca6 DATAMONGO-1127 - Add support for geoNear queries with distance information.
We now support geoNear queries in Aggregations. Exposed GeoNearOperation factory method in Aggregation. Introduced new distanceField property to NearQuery since it is required for geoNear queries in Aggregations.

Original pull request: #261.
2015-01-20 18:16:12 +01:00
Christoph Strobl
cde9d8d23a DATAMONGO-1121 - Fix false positive when checking for potential cycles.
We now only check for cycles on entity types and explicitly exclude simple types.

Original pull request: #267.
2015-01-20 12:17:13 +01:00
Oliver Gierke
3dd9b0a2b6 DATAMONGO-1136 - Polishing.
Polished equals(…) / hashCode() methods in GeoCommand.

Original pull request: #263.
2015-01-12 19:42:50 +01:00
Christoph Strobl
59e54cecd2 DATAMONGO-1136 - Use $geoWithin instead of $within for geo queries.
We now use the $geoWithin operator for geospatial criteria which requires to run on  at least MongoDB 2.4.

Original pull request: #263.
2015-01-12 19:42:15 +01:00
Oliver Gierke
5ed7e8efc2 DATAMONGO-1139 - MongoQueryCreator now only uses $nearSpherical if non-neutral Metric is used.
Fixed the evaluation of the Distance for a near clause handed into a query method. Previously we evaluated against null, which will never result in true as Distance returns Metrics.NEUTRAL by default.
2015-01-12 19:10:10 +01:00
Oliver Gierke
fa85adfe0b DATAMONGO-1123 - Improve JavaDoc of MongoOperations.geoNear(…).
The JavaDoc of the geoNear(…) methods in MongoOperations now contain a hint to MongoDB limiting the number of results by default and an explicit limit on the NearQuery can be used to disable that.
2015-01-07 15:02:32 +01:00
Oliver Gierke
a3e4f44a64 DATAMONGO-1118 - Polishing.
Created dedicated prepareMapKey(…) method to chain calls to potentiallyConvertMapKey(…) and potentiallyEscapeMapKey(…) and make sure they always get applied in combination.

Fixed initial map creation for DBRefs to apply the fixed behavior, too.

Original pull request: #260.
2015-01-06 15:45:30 +01:00
Thomas Darimont
4a7a485e62 DATAMONGO-1118 - Simplified potentiallyConvertMapKey in MappingMongoConverter.
Fixed typos in CustomConversions.

Original pull request: #260.
2015-01-06 15:45:30 +01:00
Christoph Strobl
c353e02b3e DATAMONGO-1118 - MappingMongoConverter now uses custom conversions for Map keys, too.
We now allow conversions of map keys using custom Converter implementations if the conversion target type is a String.

Original pull request: #260.
2015-01-06 15:45:26 +01:00
Christophe Fargette
1c2964cab4 DATACMNS-1132 - Fixed keyword translation table in the reference documentation.
Original pull request: #262.
2015-01-06 13:29:37 +01:00
Oliver Gierke
47e083280a DATACMNS-1131 - We now register the ThreeTen back port converters by default.
Related ticket: DATACMNS-628.
2015-01-05 19:11:54 +01:00
Oliver Gierke
7db003100b DATAMONGO-1129 - Upgraded to MongoDB Java driver 2.12.4.
Added Travis build configuration, too.
2014-12-31 14:20:52 +01:00
Oliver Gierke
f814b1ef47 DATAMONGO-1128 - Added test cases to validate Optional mapping.
Added test cases to make sure Optional instances are handled correctly and the converters are actually applied to the nested value.
2014-12-31 13:59:43 +01:00
Oliver Gierke
f3d2ae366e DATAMONGO-1120 - Fix execution of query methods using pagination and field mapping customizations.
Repository queries that used pagination and referred to a field that was customized were failing as the count query executed was not mapped correctly in MongoOperations.

This result from the fix for DATAMONGO-1080 which removed the premature field name translation from AbstractMongoQuery and thus lead to unmapped field names being used for the count query.

We now expose the previously existing, but not public count(…) method on MongoOperations that takes both an entity type as well as an explicit collection name to be able to count-query a dedicated collection but still get the query mapping applied for a certain type.

Related ticket: DATAMONGO-1080.
2014-12-18 15:47:54 +01:00
Oliver Gierke
b6ecce3aa2 DATAMONGO-1096 - Polishing.
Fixed formatting for changes introduced with DATAMONGO-1096.
2014-12-17 18:37:33 +01:00
Oliver Gierke
c5235be9a7 DATAMONGO-1106 - After release cleanups. 2014-12-01 13:44:58 +01:00
Spring Buildmaster
23300de9d4 DATAMONGO-1106 - Prepare next development iteration. 2014-12-01 13:36:36 +01:00
Spring Buildmaster
41dc57c84f DATAMONGO-1106 - Release version 1.7.0.M1 (Fowler M1). 2014-12-01 13:36:32 +01:00
Oliver Gierke
85d1fe1ce6 DATAMONGO-1106 - Prepare 1.7.0.M1 (Fowler M1). 2014-12-01 12:26:52 +01:00
Oliver Gierke
ac6067ad53 DATAMONGO-1106 - Updated changelog. 2014-12-01 12:25:53 +01:00
Thomas Darimont
173a62b5ce DATAMONGO-1085 - Fixed sorting with Querydsl in QueryDslMongoRepository.
We now translate QSort's OrderSpecifiers into appropriate sort criteria.
Previously the OrderSpecifiers were not correctly translated to appropriate property path expressions.

We're now overriding support for findAll(Pageable) and findAll(Sort) to QueryDslMongoRepository to apply special QSort handling.

Original pull request: #236.
2014-12-01 12:09:14 +01:00
Oliver Gierke
cbbafce73d DATAMONGO-1043 - Make sure we dynamically lookup SpEL based collection names for query execution.
Changed SimpleMongoEntityMetadata to keep a reference to the collection entity instead of the eagerly resolved collection name. This is to make sure the name gets re-evaluated for every query execution to support dynamically changing collections defined via SpEL expressions.

Related pull request: #238.
2014-11-28 20:26:23 +01:00
Oliver Gierke
2e74c19995 DATAMONGO-1054 - Polishing.
Tweaked JavaDoc of the APIs to be less specific about implementation internals and rather point to the save(…) methods. Changed SimpleMongoRepository.save(…) methods to inspect the given entity/entities and use the optimized insert(All)-calls if all entities are considered new.

Original pull request: #253.
2014-11-28 18:33:19 +01:00
Thomas Darimont
a212b7566c DATAMONGO-1054 - Add support for fast insertion via MongoRepository.insert(..).
Introduced new insert(..) method variants on MongoRepositories that delegates to MongoTemplate.insert(..). This bypasses ID-population, save event generation and version checking and allows for fast insertion of bulk data.

Original pull request: #253.
2014-11-28 18:33:18 +01:00
Oliver Gierke
08faa52ef4 DATAMONGO-1108 - Performance improvements in BasicMongoPersistentEntity.
BasicMongoPersistentEntity.getCollection() now avoids repeated SpEL-parsing and evaluating in case no SpEL expression is used. Parsing is happening at most once now. Evaluation is skipped entirely if the configured collection String is not or does not contain an expression.
2014-11-28 16:24:25 +01:00
Oliver Gierke
33bc4fffd9 DATAMONGO-1079 - Updated changelog. 2014-11-28 12:06:05 +01:00
Christoph Strobl
eca2108e15 DATAMONGO-1087 - Fix index resolver detecting cycles for partial match.
We now check for presence of a dot path to verify that we’ve detected a cycle.

Original pull request: #240.
2014-11-28 12:03:38 +01:00
Christoph Strobl
dab6034eb9 DATAMONGO-943 - Add support for $position to Update $push $each.
We now support $position on update.push.

Original pull request: #248.
2014-11-28 11:41:51 +01:00
Christoph Strobl
461e7d05d7 DATAMONGO-1092 - Ensure compatibility with MongoDB 2.8.0.rc0 and java driver 2.13.0-rc0.
We updated GroupByResults to allow working with changed data types returned for count and keys and fixed assertion on error message for duplicate keys.
Using java-driver 2.12.x when connecting to an 2.8.0.rc-0 instance is likely to cause trouble with authentication. This is the intended behavior.

2.8.0-rc0 throws error when removing elements from a collection that does not yet exist, which is different to what 2.6.x does.

The java-driver 2.13.0-rc0 works perfectly fine with a 2.6.x Server instance.
We deprecated Index.Duplicates#DROP since it has been removed in MongoDB 2.8

Original pull request: #246.
2014-11-28 11:33:12 +01:00
Oliver Gierke
10c37b101d DATAMONGO-1105 - Added implementation of QueryDslPredicateExecutor.findAll(OrderSpecifier<?>... orders).
Renamed QuerydslRepositorySupportUnitTests to QuerydslRepositorySupportTests as it's an integration test.
2014-11-28 10:37:21 +01:00
Christoph Strobl
81f2c910f7 DATAMONGO-1075 - Containing keyword is now correctly translated for collection properties.
We now inspect the properties type when creating criteria for CONTAINS keyword so that, if the target property is of type String, we use an expression, and if the property is collection like we try to finds an exact match within the collection using $in.

Added support for NotContaining along the way.

Original pull request: #241.
2014-11-27 17:06:39 +01:00
Thomas Darimont
1fd97713c1 DATAMONGO-1093 - Added hashCode() and equals(…) in BasicQuery.
We now have equals(…) and hashCode(…) methods on BasicQuery. Previously we solely relied on Query.hashCode()/equals(…) which didn't consider the fields of BasicQuery.

Introduced equals verifier library to automatically test equals contracts.
Added some additional test cases to BasicQueryUnitTests.

Original pull request: #252.
2014-11-27 16:45:35 +01:00
Oliver Gierke
2d3eeed9ec DATAMONGO-1102 - Added support for Java 8 date/time types.
We're now able to persist and read non-time-zoned JDK 8 date/time types (LocalDate, LocalTime, LocalDateTime) to and from Date instances.
2014-11-27 16:28:36 +01:00
Christoph Strobl
b22eb6f12f DATAMONGO-1101 - Add support for $bit to Update.
We now support bitwise and/or/xor operations for Update.
2014-11-26 11:26:56 +01:00
Mikhail Mikhaylenko
dfb0a2a368 DATAMONGO-1096 - Use null-safe toString representation of query for debug logging.
We now use the null-safe serailizeToJsonSafely to avoid potential RuntimeExceptions during debug query printing in MongoTemplate.

Based on original PR: #247.

Original pull request: #251.
2014-11-26 09:40:30 +01:00
Thomas Darimont
03bcc56429 DATAMONGO-1094 - Fixed ambiguous field mapping error message in BasicMongoPersistentEntity.
Original pull request: #245.
2014-11-25 17:32:16 +01:00
Christoph Strobl
457fda3fc3 DATAMONGO-1097 - Add support for $mul to Update.
We now support multiply on Update allowing to multiply the value of the given key by a multiplier.
2014-11-24 20:38:44 +01:00
Oliver Gierke
54cee64610 DATAMONGO-1100 - Upgrade to new PersistentPropertyAccessor API. 2014-11-20 15:12:25 +01:00
Christoph Strobl
477499248a DATAMONGO-1086 - Mapping fails for collection with two embbeded types that extend a generic abstract.
We now use the type information of the raw property type to check if we need to include _class.
2014-11-20 15:12:25 +01:00
Oliver Gierke
3b70b6aeee DATAMONGO-1078 - Polishing.
Polished test cases. Simplified equals(…)/hashCode() for sample entity and its identifier type.

Original pull request: #239.
2014-11-10 16:38:03 +01:00
Christoph Strobl
163762e99e DATAMONGO-1078 - @Query annotated repository method fails for complex Id when used with Collection type.
Remove object type hint defaulting.
2014-11-10 16:37:56 +01:00
Oliver Gierke
b99833df75 DATAMONGO-1080 - AbstractMongoQuery now refrains from eagerly post-processing the query execution results.
To properly support general post processing of query execution results (in QueryExecutorMethodInterceptor) we need to remove the eager post-processing of query execution results in AbstractMongoQuery.

Removed the usage of the local ConversionService all together.
2014-10-30 11:35:51 +01:00
Thomas Darimont
4be6231426 DATAMONGO-1076 - Avoid resolving lazy-loading proxy for DBRefs during finalize.
We now handle intercepted finalize method invocations by not resolving the proxy. Previously the LazyLoadingProxy tried to resolve the proxy during finalization which could lead to unnecessary database accesses.

Original pull request: #234.
2014-10-29 10:16:12 +01:00
Christoph Strobl
4673e3d511 DATAMONGO-1077 - Fix Update removing $ operator for DBRef.
We now retain the positional parameter "$" when mapping field names for associations.

Orignal pull request: #235.
2014-10-28 14:28:22 +01:00
Christoph Strobl
00e48cc424 DATAMONGO-1050 - Explicitly annotated Field should not be considered Id.
We changed the id resolution to skip properties having an explicit name set via @Field unless they are marked with @Id. This means that

@Field(“id”) String id;

will be stored as “id” within mongodb. Prior to this change the fieldname would have been changed to “_id”.
Added tests to ensure proper field mapping for various "id" field variants.

Original pull request: #225.
2014-10-23 11:39:17 +02:00
Christoph Strobl
f8453825fb DATAMONGO-1072 - Fix annotated query placeholders not replaced correctly.
We now also check field names for potential placeholder matches to ensure those are registered for binding parameters.

Original pull request: #233.
2014-10-22 13:55:50 +02:00
Christoph Strobl
6cda9ab939 DATAMONGO-1068 - Fix getCritieriaObject returns empty DBO when no key defined.
We now check for the presence of a Critieria key.

Original pull request: #232.
2014-10-21 11:36:15 +02:00
Oliver Gierke
831d667896 DATAMONGO-1070 - Fixed a few glitches in DBRef binding for repository query methods.
The QueryMapping for derived repository queries pointing to the identifier of the referenced document. We now reduce the query field's key from reference.id to reference so that the generated DBRef is applied correctly and also take care that the id's are potentially converted to ObjectIds. This is mainly achieved by using the AssociationConverter pulled up from UpdateMapper in ObjectMapper.getMappedKey().

MongoQueryCreator now refrains from translating the field keys as that will fail the QueryMapper to correctly detect id properties.

Fixed DBRef handling for StringBasedMongoQuery which previously didn't parse the DBRef instance created after JSON parsing for placeholders.
2014-10-15 10:13:53 +02:00
Christoph Strobl
17c342895a DATAMONGO-1063 - Fix application of Querydsl'S any().in() throwing Exception.
We now only convert paths that point to either a property or variable.

Original pull request: #230.
2014-10-10 11:35:45 +02:00
Christoph Strobl
6ef518e6a0 DATAMONGO-1053 - Type check is now only performed on explicit language properties.
We now only perform a type check on via @Language explicitly defined language properties. Prior to this change non-String properties named language caused errors on entity validation.

Original pull request: #228.
2014-10-10 11:31:30 +02:00
Oliver Gierke
ddee2fbb12 DATAMONGO-1057 - Polishing.
Slightly tweaked the changes in SlicedExecution to simplify the implementation. We now apply the given pageable but tweak the limit the query uses to peek into the next page.

Original pull request: #226.
2014-10-08 07:06:18 +02:00
Christoph Strobl
6512c2cdfb DATAMONGO-1057 - Fix SliceExecution skipping elements.
We now directly set the offset to use instead of reading it from the used pageable. This asserts that every single element is read from the store.
Prior to this change the altered pageSize lead to an unintended increase of the number of elements to skip.

Original pull request: #226.
2014-10-08 07:06:14 +02:00
Oliver Gierke
0eee05adaa DATAMONGO-1062 - Polishing.
Removed exploded static imports. Updated copyright header.

Original pull request: #229.
2014-10-07 15:32:18 +02:00
Christoph Strobl
17e0154ff3 DATAMONGO-1058 - DBRef should respect explicit field name.
We now use property.getFieldName() for mapping DbRefs. This assures we also capture explicitly defined names set via @Field.

Original pull request: #227.
2014-10-01 10:06:22 +02:00
Thomas Darimont
2780f60c65 DATAMONGO-1062 - Fix failing test in ServerAddressPropertyEditorUnitTests.
The test rejectsAddressConfigWithoutASingleParsableServerAddress fails because the supposedly non-existing hostname "bar" "now" resolves to a real host-address.

The addresses "gugu.nonexistant.example.org, gaga.nonexistant.example.org" shouldn't be resolvable TM.

Original pull request: #229.
2014-09-30 12:55:24 +02:00
Christoph Strobl
7dd3450362 DATAMONGO-1049 - Check for explicitly declared language field.
We now check for an explicitly declared language field for setting language_override within a text index. Therefore the attribute (even if named with the reserved keyword language) has to be explicitly marked with @Language. Prior to this change having:

@Language String lang;
String language;

would have caused trouble when trying to resolve index structures as one cannot set language override to more than one property.

Original pull request: #224.
2014-09-25 12:40:26 +02:00
Oliver Gierke
ca4b2a61b8 DATAMONGO-1046 - After release cleanups. 2014-09-15 14:30:23 +02:00
Oliver Gierke
d2ecd65ca5 DATAMONGO-1046 - After release cleanups. 2014-09-05 14:27:21 +02:00
Spring Buildmaster
03bd49f6c8 DATAMONGO-1046 - Prepare next development iteration. 2014-09-05 03:12:04 -07:00
Spring Buildmaster
51607c5ed8 DATAMONGO-1046 - Release version 1.6.0.RELEASE (Evans GA). 2014-09-05 03:12:02 -07:00
Oliver Gierke
e2cbd3ee28 DATAMONGO-1046 - Prepare 1.6.0.RELEASE (Evans GA). 2014-09-05 11:43:58 +02:00
Oliver Gierke
5944e6b57e DATAMONGO-1046 - Updated changelog. 2014-09-05 09:23:31 +02:00
Oliver Gierke
efd46498ef DATAMONGO-1033 - Updated changelog. 2014-09-05 07:31:54 +02:00
Christoph Strobl
3d705a737f DATAMONGO-1040 - Derived delete should respect collection name.
Adding collection metadata allows to fine grained remove entities from specific collections using derived delete queries.

Original pull request: #223.
2014-09-04 15:47:13 +02:00
Christoph Strobl
996c57bccf DATAMONGO-1039 - Polish db clean hook implementation.
- Refactored internal structure.
- Updated documentation.
- Added some tests

Original pull request: #222.
2014-09-04 11:21:55 +02:00
Oliver Gierke
a31e72ff06 DATAMONGO-1045 - Tweak AspectJ setup in cross-store module to be able to build against Spring 4.1.
Added an aop.xml to only compile explicitly listed aspects in the cross-store module. This is needed as Spring 4.1 includes a new aspect for JavaEE 7 JCache support that has optional dependencies which we don't have in the classpath. Trying to compile all aspects contained in spring-aspects will result in ClassNotFoundExceptions for the aspects with missing dependencies.
2014-09-04 08:51:31 +02:00
Mark Paluch
f07d8fca8c DATAMONGO-1036 - Improved detection of custom implementations for CDI repositories.
Adapted to API changes in CDI extension.

Related ticket: DATACMNS-565.
2014-09-01 13:51:20 +02:00
Christoph Strobl
69dbdee01f DATAMONGO-1038 - Assert Mongo instances cleaned up properly after test runs.
Add JUnit rule and RunListener taking care of clean up task.

Original pull request: #221.
2014-08-27 11:12:39 +02:00
Oliver Gierke
dedb9f3dc0 DATAMONGO-1034 - Explicitly reject incompatible types in MappingMongoConverter.
Improved the exception message that is occurs if the source document contains a BasicDBList but has to be converted into a complex object. We now explicitly hint to use a custom Converter to manually.

Improved toString() method on ObjectPath to create more helpful output.
2014-08-26 20:07:46 +02:00
Oliver Gierke
7d69b840fe DATAMONGO-1030 - Projections now work on single-entity query method executions.
We now correctly forward the domain type collection to the query executing a query for a projection type.
2014-08-26 15:16:18 +02:00
Christoph Strobl
4eaef300cb DATAMONGO-1025 - Fix creation of nested named index.
Deprecated collection attribute for @Indexed, @CompoundIndex, @GeoSpatialIndexed. Removed deprecated attribute `expireAfterSeconds` from @CompoundIndex.

Original pull request: #219.
2014-08-26 14:33:47 +02:00
Christoph Strobl
ec1a6b5edd DATAMONGO-1025 - Fix creation of nested named index.
We new prefix explicitly named indexes on nested types (eg. for embedded properties) with the path pointing to the property. This avoids errors having equally named index definitions on different paths pointing to the same type within one collection.

Along the way we harmonized index naming for geospatial index definitions where only the properties field name was taken into account where it should have been the full property path.

Original pull request: #219.
2014-08-26 14:33:47 +02:00
Oliver Gierke
adc5485c09 DATAMONGO-1032 - Polished Asciidoctor documentation. 2014-08-26 14:24:51 +02:00
Oliver Gierke
f622b2916d DATAMONGO-1021 - After release cleanups. 2014-08-13 16:32:42 +02:00
Spring Buildmaster
26be0cf948 DATAMONGO-1021 - Prepare next development iteration. 2014-08-13 07:02:43 -07:00
716 changed files with 87978 additions and 18164 deletions

12
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,12 @@
<!--
Thank you for proposing a pull request. This template will guide you through the essential steps necessary for a pull request.
Make sure that:
-->
- [ ] You have read the [Spring Data contribution guidelines](https://github.com/spring-projects/spring-data-build/blob/master/CONTRIBUTING.adoc).
- [ ] There is a ticket in the bug tracker for the project in our [JIRA](https://jira.spring.io/browse/DATAMONGO).
- [ ] You use the code formatters provided [here](https://github.com/spring-projects/spring-data-build/tree/master/etc/ide) and have them applied to your changes. Dont submit any formatting related changes.
- [ ] You submit test cases (unit or integration tests) that back your changes.
- [ ] You added yourself as author in the headers of the classes you touched. Amend the date range in the Apache license header if needed. For new types, add the license header (copy from another file and set the current year only).

1
.gitignore vendored
View File

@@ -15,3 +15,4 @@ src/ant/.ant-targets-upload-dist.xml
atlassian-ide-plugin.xml
/.gradle/
/.idea/
*.graphml

38
.travis.yml Normal file
View File

@@ -0,0 +1,38 @@
language: java
jdk:
- oraclejdk8
before_script:
- mongod --version
services:
- mongodb
env:
matrix:
- PROFILE=ci
- PROFILE=mongo36-next
# Current MongoDB version is 2.4.2 as of 2016-04, see https://github.com/travis-ci/travis-ci/issues/3694
# apt-get starts a MongoDB instance so it's not started using before_script
addons:
apt:
sources:
- mongodb-3.4-precise
packages:
- mongodb-org-server
- mongodb-org-shell
- oracle-java8-installer
sudo: false
cache:
directories:
- $HOME/.m2
install:
- |-
mongo admin --eval "db.adminCommand({setFeatureCompatibilityVersion: '3.4'});"
script: "mvn clean dependency:list test -P${PROFILE} -Dsort"

27
CODE_OF_CONDUCT.adoc Normal file
View File

@@ -0,0 +1,27 @@
= Contributor Code of Conduct
As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information, such as physical or electronic addresses,
without explicit permission
* Other unethical or unprofessional conduct
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting a project maintainer at spring-code-of-conduct@pivotal.io.
All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances.
Maintainers are obligated to maintain confidentiality with regard to the reporter of an incident.
This Code of Conduct is adapted from the http://contributor-covenant.org[Contributor Covenant], version 1.3.0, available at http://contributor-covenant.org/version/1/3/0/[contributor-covenant.org/version/1/3/0/].

View File

@@ -1 +0,0 @@
You find the contribution guidelines for Spring Data projects [here](https://github.com/spring-projects/spring-data-build/blob/master/CONTRIBUTING.md).

3
CONTRIBUTING.adoc Normal file
View File

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

View File

@@ -1,3 +1,6 @@
[![Spring Data MongoDB](https://spring.io/badges/spring-data-mongodb/ga.svg)](http://projects.spring.io/spring-data-mongodb#quick-start)
[![Spring Data MongoDB](https://spring.io/badges/spring-data-mongodb/snapshot.svg)](http://projects.spring.io/spring-data-mongodb#quick-start)
# Spring Data MongoDB
The primary goal of the [Spring Data](http://projects.spring.io/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.
@@ -26,7 +29,7 @@ Add the Maven dependency:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.5.0.RELEASE</version>
<version>${version}.RELEASE</version>
</dependency>
```
@@ -36,7 +39,7 @@ If you'd rather like the latest snapshots of the upcoming major version, use our
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.6.0.BUILD-SNAPSHOT</version>
<version>${version}.BUILD-SNAPSHOT</version>
</dependency>
<repository>
@@ -140,8 +143,8 @@ public class MyService {
Here are some ways for you to get involved in the community:
* Get involved with the Spring community on Stackoverflow and help out on the [spring-data-mongodb](http://stackoverflow.com/questions/tagged/spring-data-mongodb) tag by responding to questions and joining the debate.
* Create [JIRA](https://jira.springframework.org/browse/DATADOC) tickets for bugs and new features and comment and vote on the ones that you are interested in.
* Create [JIRA](https://jira.spring.io/browse/DATAMONGO) tickets for bugs and new features and comment and vote on the ones that you are interested in.
* Github is for social coding: if you want to write code, we encourage contributions through pull requests from [forks of this repository](http://help.github.com/forking/). If you want to contribute code this way, please reference a JIRA ticket as well covering the specific issue you are addressing.
* Watch for upcoming articles on Spring by [subscribing](http://spring.io/blog) to spring.io.
Before we accept a non-trivial patch or pull request we will need you to sign the [contributor's agreement](https://support.springsource.com/spring_committer_signup). Signing the contributor's agreement does not grant anyone commit rights to the main repository, but it does mean that we can accept your contributions, and you will get an author credit if we do. Active contributors might be asked to join the core team, and given the ability to merge pull requests.
Before we accept a non-trivial patch or pull request we will need you to [sign the Contributor License Agreement](https://cla.pivotal.io/sign/spring). Signing the contributors agreement does not grant anyone commit rights to the main repository, but it does mean that we can accept your contributions, and you will get an author credit if we do. If you forget to do so, you'll be reminded when you submit a pull request. Active contributors might be asked to join the core team, and given the ability to merge pull requests.

View File

@@ -1,291 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="12">
<profile kind="CodeFormatterProfile" name="Spring Data" version="12">
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
<setting id="org.eclipse.jdt.core.compiler.source" value="1.7"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="120"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="tab"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.compiler.compliance" value="1.7"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode" value="enabled"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="120"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.7"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
</profile>
</profiles>

2
lombok.config Normal file
View File

@@ -0,0 +1,2 @@
lombok.nonNull.exceptionType = IllegalArgumentException
lombok.log.fieldName = LOG

87
pom.xml
View File

@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.6.0.RC1</version>
<version>2.0.2.RELEASE</version>
<packaging>pom</packaging>
<name>Spring Data MongoDB</name>
@@ -15,23 +15,22 @@
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>1.5.0.RC1</version>
<relativePath>../spring-data-build/parent/pom.xml</relativePath>
<version>2.0.2.RELEASE</version>
</parent>
<modules>
<module>spring-data-mongodb</module>
<module>spring-data-mongodb-cross-store</module>
<module>spring-data-mongodb-log4j</module>
<module>spring-data-mongodb-distribution</module>
</modules>
<properties>
<project.type>multi</project.type>
<dist.id>spring-data-mongodb</dist.id>
<springdata.commons>1.9.0.RC1</springdata.commons>
<mongo>2.12.3</mongo>
<mongo.osgi>2.12.3</mongo.osgi>
<springdata.commons>2.0.2.RELEASE</springdata.commons>
<mongo>3.5.0</mongo>
<mongo.reactivestreams>1.6.0</mongo.reactivestreams>
<jmh.version>1.19</jmh.version>
</properties>
<developers>
@@ -101,14 +100,42 @@
</roles>
<timezone>+1</timezone>
</developer>
<developer>
<id>mpaluch</id>
<name>Mark Paluch</name>
<email>mpaluch at pivotal.io</email>
<organization>Pivotal</organization>
<organizationUrl>http://www.pivotal.io</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>+1</timezone>
</developer>
</developers>
<profiles>
<!-- not-yet available profile>
<id>mongo35-next</id>
<properties>
<mongo>3.5.1-SNAPSHOT</mongo>
</properties>
<repositories>
<repository>
<id>mongo-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</repository>
</repositories>
</profile -->
<profile>
<id>mongo-next</id>
<id>mongo36-next</id>
<properties>
<mongo>2.12.5-SNAPSHOT</mongo>
<mongo>3.6.0-SNAPSHOT</mongo>
</properties>
<repositories>
@@ -121,20 +148,28 @@
</profile>
<profile>
<id>mongo-3-next</id>
<properties>
<mongo>3.0.0-SNAPSHOT</mongo>
</properties>
<repositories>
<repository>
<id>mongo-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</repository>
</repositories>
<id>release</id>
<build>
<plugins>
<plugin>
<groupId>org.jfrog.buildinfo</groupId>
<artifactId>artifactory-maven-plugin</artifactId>
<inherited>false</inherited>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>benchmarks</id>
<modules>
<module>spring-data-mongodb</module>
<module>spring-data-mongodb-cross-store</module>
<module>spring-data-mongodb-distribution</module>
<module>spring-data-mongodb-benchmarks</module>
</modules>
</profile>
</profiles>
<dependencies>
@@ -148,15 +183,15 @@
<repositories>
<repository>
<id>spring-libs-milestone</id>
<url>http://repo.spring.io/libs-milestone</url>
<id>spring-libs-release</id>
<url>https://repo.spring.io/libs-release</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-plugins-release</id>
<url>http://repo.spring.io/plugins-release</url>
<url>https://repo.spring.io/plugins-release</url>
</pluginRepository>
</pluginRepositories>

View File

@@ -0,0 +1,76 @@
# Benchmarks
Benchmarks are based on [JMH](http://openjdk.java.net/projects/code-tools/jmh/).
# Running Benchmarks
Running benchmarks is disabled by default and can be activated via the `benchmarks` profile.
To run the benchmarks with default settings use.
```bash
mvn -P benchmarks clean test
```
A basic report will be printed to the CLI.
```bash
# Run complete. Total time: 00:00:15
Benchmark Mode Cnt Score Error Units
MappingMongoConverterBenchmark.readObject thrpt 10 1920157,631 ± 64310,809 ops/s
MappingMongoConverterBenchmark.writeObject thrpt 10 782732,857 ± 53804,130 ops/s
```
## Running all Benchmarks of a specific class
To run all Benchmarks of a specific class, just provide its simple class name via the `benchmark` command line argument.
```bash
mvn -P benchmarks clean test -D benchmark=MappingMongoConverterBenchmark
```
## Running a single Benchmark
To run a single Benchmark provide its containing class simple name followed by `#` and the method name via the `benchmark` command line argument.
```bash
mvn -P benchmarks clean test -D benchmark=MappingMongoConverterBenchmark#readObjectWith2Properties
```
# Saving Benchmark Results
A detailed benchmark report is stored in JSON format in the `/target/reports/performance` directory.
To store the report in a different location use the `benchmarkReportDir` command line argument.
## MongoDB
Results can be directly piped to MongoDB by providing a valid [Connection String](https://docs.mongodb.com/manual/reference/connection-string/) via the `publishTo` command line argument.
```bash
mvn -P benchmarks clean test -D publishTo=mongodb://127.0.0.1:27017
```
NOTE: If the uri does not explicitly define a database the default `spring-data-mongodb-benchmarks` is used.
## HTTP Endpoint
The benchmark report can also be posted as `application/json` to an HTTP Endpoint by providing a valid URl via the `publishTo` command line argument.
```bash
mvn -P benchmarks clean test -D publishTo=http://127.0.0.1:8080/capture-benchmarks
```
# Customizing Benchmarks
Following options can be set via command line.
Option | Default Value
--- | ---
warmupIterations | 10
warmupTime | 1 (seconds)
measurementIterations | 10
measurementTime | 1 (seconds)
forks | 1
benchmarkReportDir | /target/reports/performance (always relative to project root dir)
benchmark | .* (single benchmark via `classname#benchmark`)
publishTo | \[not set\] (mongodb-uri or http-endpoint)

View File

@@ -0,0 +1,111 @@
<?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 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>2.0.2.RELEASE</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>spring-data-mongodb-benchmarks</artifactId>
<packaging>jar</packaging>
<name>Spring Data MongoDB - Microbenchmarks</name>
<properties>
<!-- Skip tests by default; run only if -DskipTests=false is specified or benchmarks profile is activated -->
<skipTests>true</skipTests>
</properties>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>${jmh.version}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>benchmarks</id>
<properties>
<skipTests>false</skipTests>
</properties>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>2.2.2</version>
<executions>
<execution>
<goals>
<goal>revision</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>default-jar</id>
<phase>never</phase>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<testSourceDirectory>${project.build.sourceDirectory}</testSourceDirectory>
<testClassesDirectory>${project.build.outputDirectory}</testClassesDirectory>
<excludes>
<exclude>**/AbstractMicrobenchmark.java</exclude>
<exclude>**/*$*.class</exclude>
<exclude>**/generated/*.class</exclude>
</excludes>
<includes>
<include>**/*Benchmark*</include>
</includes>
<systemPropertyVariables>
<benchmarkReportDir>${project.build.directory}/reports/performance</benchmarkReportDir>
<project.version>${project.version}</project.version>
<git.dirty>${git.dirty}</git.dirty>
<git.commit.id>${git.commit.id}</git.commit.id>
<git.branch>${git.branch}</git.branch>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,180 @@
/*
* Copyright 2017 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
*
* http://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.bson.Document;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.TearDown;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.ExecutableFindOperation.FindWithQuery;
import org.springframework.data.mongodb.core.ExecutableFindOperation.TerminatingFind;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.microbenchmark.AbstractMicrobenchmark;
import com.mongodb.MongoClient;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoCollection;
/**
* @author Christoph Strobl
*/
public class ProjectionsBenchmark extends AbstractMicrobenchmark {
private static final String DB_NAME = "projections-benchmark";
private static final String COLLECTION_NAME = "projections";
private MongoTemplate template;
private MongoClient client;
private MongoCollection<Document> mongoCollection;
private Person source;
private FindWithQuery<Person> asPerson;
private FindWithQuery<DtoProjection> asDtoProjection;
private FindWithQuery<ClosedProjection> asClosedProjection;
private FindWithQuery<OpenProjection> asOpenProjection;
private TerminatingFind<Person> asPersonWithFieldsRestriction;
private Document fields = new Document("firstname", 1);
@Setup
public void setUp() {
client = new MongoClient(new ServerAddress());
template = new MongoTemplate(client, DB_NAME);
source = new Person();
source.firstname = "luke";
source.lastname = "skywalker";
source.address = new Address();
source.address.street = "melenium falcon 1";
source.address.city = "deathstar";
template.save(source, COLLECTION_NAME);
asPerson = template.query(Person.class).inCollection(COLLECTION_NAME);
asDtoProjection = template.query(Person.class).inCollection(COLLECTION_NAME).as(DtoProjection.class);
asClosedProjection = template.query(Person.class).inCollection(COLLECTION_NAME).as(ClosedProjection.class);
asOpenProjection = template.query(Person.class).inCollection(COLLECTION_NAME).as(OpenProjection.class);
asPersonWithFieldsRestriction = template.query(Person.class).inCollection(COLLECTION_NAME)
.matching(new BasicQuery(new Document(), fields));
mongoCollection = client.getDatabase(DB_NAME).getCollection(COLLECTION_NAME);
}
@TearDown
public void tearDown() {
client.dropDatabase(DB_NAME);
client.close();
}
/**
* Set the baseline for comparison by using the plain MongoDB java driver api without any additional fluff.
*
* @return
*/
@Benchmark // DATAMONGO-1733
public Object baseline() {
return mongoCollection.find().first();
}
/**
* Read into the domain type including all fields.
*
* @return
*/
@Benchmark // DATAMONGO-1733
public Object readIntoDomainType() {
return asPerson.all();
}
/**
* Read into the domain type but restrict query to only return one field.
*
* @return
*/
@Benchmark // DATAMONGO-1733
public Object readIntoDomainTypeRestrictingToOneField() {
return asPersonWithFieldsRestriction.all();
}
/**
* Read into dto projection that only needs to map one field back.
*
* @return
*/
@Benchmark // DATAMONGO-1733
public Object readIntoDtoProjectionWithOneField() {
return asDtoProjection.all();
}
/**
* Read into closed interface projection.
*
* @return
*/
@Benchmark // DATAMONGO-1733
public Object readIntoClosedProjectionWithOneField() {
return asClosedProjection.all();
}
/**
* Read into an open projection backed by the mapped domain object.
*
* @return
*/
@Benchmark // DATAMONGO-1733
public Object readIntoOpenProjection() {
return asOpenProjection.all();
}
static class Person {
@Id String id;
String firstname;
String lastname;
Address address;
}
static class Address {
String city;
String street;
}
static class DtoProjection {
@Field("firstname") String name;
}
static interface ClosedProjection {
String getFirstname();
}
static interface OpenProjection {
@Value("#{target.firstname}")
String name();
}
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright 2017 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
*
* http://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.convert;
import static org.springframework.data.mongodb.core.query.Criteria.*;
import static org.springframework.data.mongodb.core.query.Query.*;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
import org.bson.types.ObjectId;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.microbenchmark.AbstractMicrobenchmark;
import com.mongodb.MongoClient;
import com.mongodb.ServerAddress;
/**
* @author Christoph Strobl
*/
@State(Scope.Benchmark)
public class DbRefMappingBenchmark extends AbstractMicrobenchmark {
private static final String DB_NAME = "dbref-loading-benchmark";
private MongoClient client;
private MongoTemplate template;
private Query queryObjectWithDBRef;
private Query queryObjectWithDBRefList;
@Setup
public void setUp() throws Exception {
client = new MongoClient(new ServerAddress());
template = new MongoTemplate(client, DB_NAME);
List<RefObject> refObjects = new ArrayList<>();
for (int i = 0; i < 1; i++) {
RefObject o = new RefObject();
template.save(o);
refObjects.add(o);
}
ObjectWithDBRef singleDBRef = new ObjectWithDBRef();
singleDBRef.ref = refObjects.iterator().next();
template.save(singleDBRef);
ObjectWithDBRef multipleDBRefs = new ObjectWithDBRef();
multipleDBRefs.refList = refObjects;
template.save(multipleDBRefs);
queryObjectWithDBRef = query(where("id").is(singleDBRef.id));
queryObjectWithDBRefList = query(where("id").is(multipleDBRefs.id));
}
@TearDown
public void tearDown() {
client.dropDatabase(DB_NAME);
client.close();
}
@Benchmark // DATAMONGO-1720
public ObjectWithDBRef readSingleDbRef() {
return template.findOne(queryObjectWithDBRef, ObjectWithDBRef.class);
}
@Benchmark // DATAMONGO-1720
public ObjectWithDBRef readMultipleDbRefs() {
return template.findOne(queryObjectWithDBRefList, ObjectWithDBRef.class);
}
@Data
static class ObjectWithDBRef {
private @Id ObjectId id;
private @DBRef RefObject ref;
private @DBRef List<RefObject> refList;
}
@Data
static class RefObject {
private @Id String id;
private String someValue;
}
}

View File

@@ -0,0 +1,181 @@
/*
* Copyright 2017 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
*
* http://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.convert;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.springframework.data.annotation.Id;
import org.springframework.data.geo.Point;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.microbenchmark.AbstractMicrobenchmark;
import com.mongodb.MongoClient;
import com.mongodb.ServerAddress;
/**
* @author Christoph Strobl
*/
@State(Scope.Benchmark)
public class MappingMongoConverterBenchmark extends AbstractMicrobenchmark {
private static final String DB_NAME = "mapping-mongo-converter-benchmark";
private MongoClient client;
private MongoMappingContext mappingContext;
private MappingMongoConverter converter;
private Document documentWith2Properties, documentWith2PropertiesAnd1Nested;
private Customer objectWith2PropertiesAnd1Nested;
private Document documentWithFlatAndComplexPropertiesPlusListAndMap;
private SlightlyMoreComplexObject objectWithFlatAndComplexPropertiesPlusListAndMap;
@Setup
public void setUp() throws Exception {
client = new MongoClient(new ServerAddress());
this.mappingContext = new MongoMappingContext();
this.mappingContext.setInitialEntitySet(Collections.singleton(Customer.class));
this.mappingContext.afterPropertiesSet();
DbRefResolver dbRefResolver = new DefaultDbRefResolver(new SimpleMongoDbFactory(client, DB_NAME));
this.converter = new MappingMongoConverter(dbRefResolver, mappingContext);
this.converter.setCustomConversions(new MongoCustomConversions(Collections.emptyList()));
this.converter.afterPropertiesSet();
// just a flat document
this.documentWith2Properties = new Document("firstname", "Dave").append("lastname", "Matthews");
// document with a nested one
Document address = new Document("zipCode", "ABCDE").append("city", "Some Place");
this.documentWith2PropertiesAnd1Nested = new Document("firstname", "Dave").//
append("lastname", "Matthews").//
append("address", address);
// object equivalent of documentWith2PropertiesAnd1Nested
this.objectWith2PropertiesAnd1Nested = new Customer("Dave", "Matthews", new Address("zipCode", "City"));
// a bit more challenging object with list & map conversion.
objectWithFlatAndComplexPropertiesPlusListAndMap = new SlightlyMoreComplexObject();
objectWithFlatAndComplexPropertiesPlusListAndMap.id = UUID.randomUUID().toString();
objectWithFlatAndComplexPropertiesPlusListAndMap.addressList = Arrays.asList(new Address("zip-1", "city-1"),
new Address("zip-2", "city-2"));
objectWithFlatAndComplexPropertiesPlusListAndMap.customer = objectWith2PropertiesAnd1Nested;
objectWithFlatAndComplexPropertiesPlusListAndMap.customerMap = new LinkedHashMap<>();
objectWithFlatAndComplexPropertiesPlusListAndMap.customerMap.put("dave", objectWith2PropertiesAnd1Nested);
objectWithFlatAndComplexPropertiesPlusListAndMap.customerMap.put("deborah",
new Customer("Deborah Anne", "Dyer", new Address("?", "london")));
objectWithFlatAndComplexPropertiesPlusListAndMap.customerMap.put("eddie",
new Customer("Eddie", "Vedder", new Address("??", "Seattle")));
objectWithFlatAndComplexPropertiesPlusListAndMap.intOne = Integer.MIN_VALUE;
objectWithFlatAndComplexPropertiesPlusListAndMap.intTwo = Integer.MAX_VALUE;
objectWithFlatAndComplexPropertiesPlusListAndMap.location = new Point(-33.865143, 151.209900);
objectWithFlatAndComplexPropertiesPlusListAndMap.renamedField = "supercalifragilisticexpialidocious";
objectWithFlatAndComplexPropertiesPlusListAndMap.stringOne = "¯\\_(ツ)_/¯";
objectWithFlatAndComplexPropertiesPlusListAndMap.stringTwo = " (╯°□°)╯︵ ┻━┻";
// JSON equivalent of objectWithFlatAndComplexPropertiesPlusListAndMap
documentWithFlatAndComplexPropertiesPlusListAndMap = Document.parse(
"{ \"_id\" : \"517f6aee-e9e0-44f0-88ed-f3694a019f27\", \"intOne\" : -2147483648, \"intTwo\" : 2147483647, \"stringOne\" : \"¯\\\\_(ツ)_/¯\", \"stringTwo\" : \" (╯°□°)╯︵ ┻━┻\", \"explicit-field-name\" : \"supercalifragilisticexpialidocious\", \"location\" : { \"x\" : -33.865143, \"y\" : 151.2099 }, \"objectWith2PropertiesAnd1Nested\" : { \"firstname\" : \"Dave\", \"lastname\" : \"Matthews\", \"address\" : { \"zipCode\" : \"zipCode\", \"city\" : \"City\" } }, \"addressList\" : [{ \"zipCode\" : \"zip-1\", \"city\" : \"city-1\" }, { \"zipCode\" : \"zip-2\", \"city\" : \"city-2\" }], \"customerMap\" : { \"dave\" : { \"firstname\" : \"Dave\", \"lastname\" : \"Matthews\", \"address\" : { \"zipCode\" : \"zipCode\", \"city\" : \"City\" } }, \"deborah\" : { \"firstname\" : \"Deborah Anne\", \"lastname\" : \"Dyer\", \"address\" : { \"zipCode\" : \"?\", \"city\" : \"london\" } }, \"eddie\" : { \"firstname\" : \"Eddie\", \"lastname\" : \"Vedder\", \"address\" : { \"zipCode\" : \"??\", \"city\" : \"Seattle\" } } }, \"_class\" : \"org.springframework.data.mongodb.core.convert.MappingMongoConverterBenchmark$SlightlyMoreComplexObject\" }");
}
@TearDown
public void tearDown() {
client.dropDatabase(DB_NAME);
client.close();
}
@Benchmark // DATAMONGO-1720
public Customer readObjectWith2Properties() {
return converter.read(Customer.class, documentWith2Properties);
}
@Benchmark // DATAMONGO-1720
public Customer readObjectWith2PropertiesAnd1NestedObject() {
return converter.read(Customer.class, documentWith2PropertiesAnd1Nested);
}
@Benchmark // DATAMONGO-1720
public Document writeObjectWith2PropertiesAnd1NestedObject() {
Document sink = new Document();
converter.write(objectWith2PropertiesAnd1Nested, sink);
return sink;
}
@Benchmark // DATAMONGO-1720
public Object readObjectWithListAndMapsOfComplexType() {
return converter.read(SlightlyMoreComplexObject.class, documentWithFlatAndComplexPropertiesPlusListAndMap);
}
@Benchmark // DATAMONGO-1720
public Object writeObjectWithListAndMapsOfComplexType() {
Document sink = new Document();
converter.write(objectWithFlatAndComplexPropertiesPlusListAndMap, sink);
return sink;
}
@Getter
@RequiredArgsConstructor
static class Customer {
private @Id ObjectId id;
private final String firstname, lastname;
private final Address address;
}
@Getter
@AllArgsConstructor
static class Address {
private String zipCode, city;
}
@Data
static class SlightlyMoreComplexObject {
@Id String id;
int intOne, intTwo;
String stringOne, stringTwo;
@Field("explicit-field-name") String renamedField;
Point location;
Customer customer;
List<Address> addressList;
Map<String, Customer> customerMap;
}
}

View File

@@ -0,0 +1,328 @@
/*
* Copyright 2017 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
*
* http://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.microbenchmark;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import org.junit.Test;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.results.RunResult;
import org.openjdk.jmh.results.format.ResultFormatType;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.ChainedOptionsBuilder;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.TimeValue;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;
/**
* @author Christoph Strobl
*/
@Warmup(iterations = AbstractMicrobenchmark.WARMUP_ITERATIONS)
@Measurement(iterations = AbstractMicrobenchmark.MEASUREMENT_ITERATIONS)
@Fork(AbstractMicrobenchmark.FORKS)
@State(Scope.Thread)
public class AbstractMicrobenchmark {
static final int WARMUP_ITERATIONS = 5;
static final int MEASUREMENT_ITERATIONS = 10;
static final int FORKS = 1;
static final String[] JVM_ARGS = { "-server", "-XX:+HeapDumpOnOutOfMemoryError", "-Xms1024m", "-Xmx1024m",
"-XX:MaxDirectMemorySize=1024m" };
private final StandardEnvironment environment = new StandardEnvironment();
/**
* Run matching {@link org.openjdk.jmh.annotations.Benchmark} methods with options collected from
* {@link org.springframework.core.env.Environment}.
*
* @throws Exception
* @see #options(String)
*/
@Test
public void run() throws Exception {
String includes = includes();
if (!includes.contains(org.springframework.util.ClassUtils.getShortName(getClass()))) {
return;
}
publishResults(new Runner(options(includes).build()).run());
}
/**
* Get the regex for all benchmarks to be included in the run. By default every benchmark within classes matching the
* current ones short name. <br />
* The {@literal benchmark} command line argument allows overriding the defaults using {@code #} as class / method
* name separator.
*
* @return never {@literal null}.
* @see org.springframework.util.ClassUtils#getShortName(Class)
*/
protected String includes() {
String tests = environment.getProperty("benchmark", String.class);
if (!StringUtils.hasText(tests)) {
return ".*" + org.springframework.util.ClassUtils.getShortName(getClass()) + ".*";
}
if (!tests.contains("#")) {
return ".*" + tests + ".*";
}
String[] args = tests.split("#");
return ".*" + args[0] + "." + args[1];
}
/**
* Collect all options for the {@link Runner}.
*
* @param includes regex for matching benchmarks to be included in the run.
* @return never {@literal null}.
* @throws Exception
*/
protected ChainedOptionsBuilder options(String includes) throws Exception {
ChainedOptionsBuilder optionsBuilder = new OptionsBuilder().include(includes).jvmArgs(jvmArgs());
optionsBuilder = warmup(optionsBuilder);
optionsBuilder = measure(optionsBuilder);
optionsBuilder = forks(optionsBuilder);
optionsBuilder = report(optionsBuilder);
return optionsBuilder;
}
/**
* JVM args to apply to {@link Runner} via its {@link org.openjdk.jmh.runner.options.Options}.
*
* @return {@link #JVM_ARGS} by default.
*/
protected String[] jvmArgs() {
String[] args = new String[JVM_ARGS.length];
System.arraycopy(JVM_ARGS, 0, args, 0, JVM_ARGS.length);
return args;
}
/**
* Read {@code warmupIterations} property from {@link org.springframework.core.env.Environment}.
*
* @return -1 if not set.
*/
protected int getWarmupIterations() {
return environment.getProperty("warmupIterations", Integer.class, -1);
}
/**
* Read {@code measurementIterations} property from {@link org.springframework.core.env.Environment}.
*
* @return -1 if not set.
*/
protected int getMeasurementIterations() {
return environment.getProperty("measurementIterations", Integer.class, -1);
}
/**
* Read {@code forks} property from {@link org.springframework.core.env.Environment}.
*
* @return -1 if not set.
*/
protected int getForksCount() {
return environment.getProperty("forks", Integer.class, -1);
}
/**
* Read {@code benchmarkReportDir} property from {@link org.springframework.core.env.Environment}.
*
* @return {@literal null} if not set.
*/
protected String getReportDirectory() {
return environment.getProperty("benchmarkReportDir");
}
/**
* Read {@code measurementTime} property from {@link org.springframework.core.env.Environment}.
*
* @return -1 if not set.
*/
protected long getMeasurementTime() {
return environment.getProperty("measurementTime", Long.class, -1L);
}
/**
* Read {@code warmupTime} property from {@link org.springframework.core.env.Environment}.
*
* @return -1 if not set.
*/
protected long getWarmupTime() {
return environment.getProperty("warmupTime", Long.class, -1L);
}
/**
* {@code project.version_yyyy-MM-dd_ClassName.json} eg.
* {@literal 1.11.0.BUILD-SNAPSHOT_2017-03-07_MappingMongoConverterBenchmark.json}
*
* @return
*/
protected String reportFilename() {
StringBuilder sb = new StringBuilder();
if (environment.containsProperty("project.version")) {
sb.append(environment.getProperty("project.version"));
sb.append("_");
}
sb.append(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
sb.append("_");
sb.append(org.springframework.util.ClassUtils.getShortName(getClass()));
sb.append(".json");
return sb.toString();
}
/**
* Apply measurement options to {@link ChainedOptionsBuilder}.
*
* @param optionsBuilder must not be {@literal null}.
* @return {@link ChainedOptionsBuilder} with options applied.
* @see #getMeasurementIterations()
* @see #getMeasurementTime()
*/
private ChainedOptionsBuilder measure(ChainedOptionsBuilder optionsBuilder) {
int measurementIterations = getMeasurementIterations();
long measurementTime = getMeasurementTime();
if (measurementIterations > 0) {
optionsBuilder = optionsBuilder.measurementIterations(measurementIterations);
}
if (measurementTime > 0) {
optionsBuilder = optionsBuilder.measurementTime(TimeValue.seconds(measurementTime));
}
return optionsBuilder;
}
/**
* Apply warmup options to {@link ChainedOptionsBuilder}.
*
* @param optionsBuilder must not be {@literal null}.
* @return {@link ChainedOptionsBuilder} with options applied.
* @see #getWarmupIterations()
* @see #getWarmupTime()
*/
private ChainedOptionsBuilder warmup(ChainedOptionsBuilder optionsBuilder) {
int warmupIterations = getWarmupIterations();
long warmupTime = getWarmupTime();
if (warmupIterations > 0) {
optionsBuilder = optionsBuilder.warmupIterations(warmupIterations);
}
if (warmupTime > 0) {
optionsBuilder = optionsBuilder.warmupTime(TimeValue.seconds(warmupTime));
}
return optionsBuilder;
}
/**
* Apply forks option to {@link ChainedOptionsBuilder}.
*
* @param optionsBuilder must not be {@literal null}.
* @return {@link ChainedOptionsBuilder} with options applied.
* @see #getForksCount()
*/
private ChainedOptionsBuilder forks(ChainedOptionsBuilder optionsBuilder) {
int forks = getForksCount();
if (forks <= 0) {
return optionsBuilder;
}
return optionsBuilder.forks(forks);
}
/**
* Apply report option to {@link ChainedOptionsBuilder}.
*
* @param optionsBuilder must not be {@literal null}.
* @return {@link ChainedOptionsBuilder} with options applied.
* @throws IOException if report file cannot be created.
* @see #getReportDirectory()
*/
private ChainedOptionsBuilder report(ChainedOptionsBuilder optionsBuilder) throws IOException {
String reportDir = getReportDirectory();
if (!StringUtils.hasText(reportDir)) {
return optionsBuilder;
}
String reportFilePath = reportDir + (reportDir.endsWith(File.separator) ? "" : File.separator) + reportFilename();
File file = ResourceUtils.getFile(reportFilePath);
if (file.exists()) {
file.delete();
} else {
file.getParentFile().mkdirs();
file.createNewFile();
}
optionsBuilder.resultFormat(ResultFormatType.JSON);
optionsBuilder.result(reportFilePath);
return optionsBuilder;
}
/**
* Publish results to an external system.
*
* @param results must not be {@literal null}.
*/
private void publishResults(Collection<RunResult> results) {
if (CollectionUtils.isEmpty(results) || !environment.containsProperty("publishTo")) {
return;
}
String uri = environment.getProperty("publishTo");
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));
}
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright 2017 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
*
* http://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.microbenchmark;
import lombok.SneakyThrows;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Collection;
import org.openjdk.jmh.results.RunResult;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.util.CollectionUtils;
/**
* {@link ResultsWriter} implementation of {@link URLConnection}.
*
* @since 2.0
*/
class HttpResultsWriter implements ResultsWriter {
private final String url;
HttpResultsWriter(String url) {
this.url = url;
}
@Override
@SneakyThrows
public void write(Collection<RunResult> results) {
if (CollectionUtils.isEmpty(results)) {
return;
}
StandardEnvironment env = new StandardEnvironment();
String projectVersion = env.getProperty("project.version", "unknown");
String gitBranch = env.getProperty("git.branch", "unknown");
String gitDirty = env.getProperty("git.dirty", "no");
String gitCommitId = env.getProperty("git.commit.id", "unknown");
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setConnectTimeout((int) Duration.ofSeconds(1).toMillis());
connection.setReadTimeout((int) Duration.ofSeconds(1).toMillis());
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.addRequestProperty("X-Project-Version", projectVersion);
connection.addRequestProperty("X-Git-Branch", gitBranch);
connection.addRequestProperty("X-Git-Dirty", gitDirty);
connection.addRequestProperty("X-Git-Commit-Id", gitCommitId);
try (OutputStream output = connection.getOutputStream()) {
output.write(ResultsWriter.jsonifyResults(results).getBytes(StandardCharsets.UTF_8));
}
if (connection.getResponseCode() >= 400) {
throw new IllegalStateException(
String.format("Status %d %s", connection.getResponseCode(), connection.getResponseMessage()));
}
}
}

View File

@@ -0,0 +1,131 @@
/*
* Copyright 2017 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
*
* http://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.microbenchmark;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import org.bson.Document;
import org.openjdk.jmh.results.RunResult;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import com.mongodb.BasicDBObject;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
import com.mongodb.client.MongoDatabase;
import com.mongodb.util.JSON;
/**
* MongoDB specific {@link ResultsWriter} implementation.
*
* @author Christoph Strobl
* @since 2.0
*/
class MongoResultsWriter implements ResultsWriter {
private final String uri;
MongoResultsWriter(String uri) {
this.uri = uri;
}
@Override
public void write(Collection<RunResult> results) {
Date now = new Date();
StandardEnvironment env = new StandardEnvironment();
String projectVersion = env.getProperty("project.version", "unknown");
String gitBranch = env.getProperty("git.branch", "unknown");
String gitDirty = env.getProperty("git.dirty", "no");
String gitCommitId = env.getProperty("git.commit.id", "unknown");
MongoClientURI uri = new MongoClientURI(this.uri);
MongoClient client = new MongoClient(uri);
String dbName = StringUtils.hasText(uri.getDatabase()) ? uri.getDatabase() : "spring-data-mongodb-benchmarks";
MongoDatabase db = client.getDatabase(dbName);
for (BasicDBObject dbo : (List<BasicDBObject>) JSON.parse(ResultsWriter.jsonifyResults(results))) {
String collectionName = extractClass(dbo.get("benchmark").toString());
Document sink = new Document();
sink.append("_version", projectVersion);
sink.append("_branch", gitBranch);
sink.append("_commit", gitCommitId);
sink.append("_dirty", gitDirty);
sink.append("_method", extractBenchmarkName(dbo.get("benchmark").toString()));
sink.append("_date", now);
sink.append("_snapshot", projectVersion.toLowerCase().contains("snapshot"));
sink.putAll(dbo);
db.getCollection(collectionName).insertOne(fixDocumentKeys(sink));
}
client.close();
}
/**
* Replace {@code .} by {@code ,}.
*
* @param doc
* @return
*/
private Document fixDocumentKeys(Document doc) {
Document sanitized = new Document();
for (Object key : doc.keySet()) {
Object value = doc.get(key);
if (value instanceof Document) {
value = fixDocumentKeys((Document) value);
} else if (value instanceof BasicDBObject) {
value = fixDocumentKeys(new Document((BasicDBObject) value));
}
if (key instanceof String) {
String newKey = (String) key;
if (newKey.contains(".")) {
newKey = newKey.replace('.', ',');
}
sanitized.put(newKey, value);
} else {
sanitized.put(ObjectUtils.nullSafeToString(key).replace('.', ','), value);
}
}
return sanitized;
}
private static String extractClass(String source) {
String tmp = source.substring(0, source.lastIndexOf('.'));
return tmp.substring(tmp.lastIndexOf(".") + 1);
}
private static String extractBenchmarkName(String source) {
return source.substring(source.lastIndexOf(".") + 1);
}
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright 2017 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
*
* http://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.microbenchmark;
import lombok.SneakyThrows;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import org.openjdk.jmh.results.RunResult;
import org.openjdk.jmh.results.format.ResultFormatFactory;
import org.openjdk.jmh.results.format.ResultFormatType;
/**
* @author Christoph Strobl
* @since 2.0
*/
interface ResultsWriter {
/**
* Write the {@link RunResult}s.
*
* @param results can be {@literal null}.
*/
void write(Collection<RunResult> results);
/**
* Get the uri specific {@link ResultsWriter}.
*
* @param uri must not be {@literal null}.
* @return
*/
static ResultsWriter forUri(String uri) {
return uri.startsWith("mongodb:") ? new MongoResultsWriter(uri) : new HttpResultsWriter(uri);
}
/**
* Convert {@link RunResult}s to JMH Json representation.
*
* @param results
* @return json string representation of results.
* @see org.openjdk.jmh.results.format.JSONResultFormat
*/
@SneakyThrows
static String jsonifyResults(Collection<RunResult> results) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ResultFormatFactory.getInstance(ResultFormatType.JSON, new PrintStream(baos, true, "UTF-8")).writeOut(results);
return new String(baos.toByteArray(), StandardCharsets.UTF_8);
}
}

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d %5p %40.40c:%4L - %m%n</pattern>
</encoder>
</appender>
<root level="error">
<appender-ref ref="console" />
</root>
</configuration>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<aspectj>
<aspects>
<aspect name="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect" />
<aspect name="org.springframework.data.mongodb.crossstore.MongoDocumentBacking" />
</aspects>
</aspectj>

View File

@@ -2,22 +2,23 @@
<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 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.6.0.RC1</version>
<version>2.0.2.RELEASE</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>spring-data-mongodb-cross-store</artifactId>
<name>Spring Data MongoDB - Cross-Store Support</name>
<properties>
<jpa>1.0.0.Final</jpa>
<hibernate>3.6.10.Final</hibernate>
<jpa>2.1.1</jpa>
<hibernate>5.2.1.Final</hibernate>
<java-module-name>spring.data.mongodb.cross.store</java-module-name>
</properties>
<dependencies>
<!-- Spring -->
@@ -48,7 +49,14 @@
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.6.0.RC1</version>
<version>2.0.2.RELEASE</version>
</dependency>
<!-- reactive -->
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<optional>true</optional>
</dependency>
<dependency>
@@ -59,8 +67,8 @@
<!-- JPA -->
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<groupId>org.eclipse.persistence</groupId>
<artifactId>javax.persistence</artifactId>
<version>${jpa}</version>
<optional>true</optional>
</dependency>
@@ -81,13 +89,13 @@
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.0.0.GA</version>
<version>${validation}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.0.2.GA</version>
<version>5.2.4.Final</version>
<scope>test</scope>
</dependency>
@@ -126,10 +134,11 @@
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
</aspectLibraries>
<complianceLevel>${source.level}</complianceLevel>
<source>${source.level}</source>
<target>${source.level}</target>
<xmlConfigured>aop.xml</xmlConfigured>
</configuration>
</plugin>
</plugins>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* Copyright 2011-2017 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.
@@ -17,6 +17,12 @@ package org.springframework.data.mongodb.crossstore;
import org.springframework.data.crossstore.ChangeSetBacked;
/**
* @author Thomas Risberg
* @author Oliver Gierke
* @deprecated will be removed without replacement.
*/
@Deprecated
public interface DocumentBacked extends ChangeSetBacked {
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2014 the original author or authors.
* Copyright 2011-2017 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.
@@ -17,6 +17,7 @@ package org.springframework.data.mongodb.crossstore;
import javax.persistence.EntityManagerFactory;
import org.bson.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
@@ -29,15 +30,19 @@ import org.springframework.data.mongodb.core.CollectionCallback;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.util.ClassUtils;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.MongoException;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.Filters;
import com.mongodb.client.result.DeleteResult;
/**
* @author Thomas Risberg
* @author Oliver Gierke
* @author Alex Vengrovsk
* @author Mark Paluch
* @deprecated will be removed without replacement.
*/
@Deprecated
public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
private static final String ENTITY_CLASS = "_entity_class";
@@ -45,7 +50,7 @@ public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
private static final String ENTITY_FIELD_NAME = "_entity_field_name";
private static final String ENTITY_FIELD_CLASS = "_entity_field_class";
protected final Logger log = LoggerFactory.getLogger(getClass());
private final Logger log = LoggerFactory.getLogger(getClass());
private MongoTemplate mongoTemplate;
private EntityManagerFactory entityManagerFactory;
@@ -72,29 +77,29 @@ public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
String collName = getCollectionNameForEntity(entityClass);
final DBObject dbk = new BasicDBObject();
final Document dbk = new Document();
dbk.put(ENTITY_ID, id);
dbk.put(ENTITY_CLASS, entityClass.getName());
if (log.isDebugEnabled()) {
log.debug("Loading MongoDB data for " + dbk);
log.debug("Loading MongoDB data for {}", dbk);
}
mongoTemplate.execute(collName, new CollectionCallback<Object>() {
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
for (DBObject dbo : collection.find(dbk)) {
public Object doInCollection(MongoCollection<Document> collection) throws MongoException, DataAccessException {
for (Document dbo : collection.find(dbk)) {
String key = (String) dbo.get(ENTITY_FIELD_NAME);
if (log.isDebugEnabled()) {
log.debug("Processing key: " + key);
log.debug("Processing key: {}", key);
}
if (!changeSet.getValues().containsKey(key)) {
String className = (String) dbo.get(ENTITY_FIELD_CLASS);
if (className == null) {
throw new DataIntegrityViolationException("Unble to convert property " + key + ": Invalid metadata, "
+ ENTITY_FIELD_CLASS + " not available");
throw new DataIntegrityViolationException(
"Unble to convert property " + key + ": Invalid metadata, " + ENTITY_FIELD_CLASS + " not available");
}
Class<?> clazz = ClassUtils.resolveClassName(className, ClassUtils.getDefaultClassLoader());
Object value = mongoTemplate.getConverter().read(clazz, dbo);
if (log.isDebugEnabled()) {
log.debug("Adding to ChangeSet: " + key);
log.debug("Adding to ChangeSet: {}", key);
}
changeSet.set(key, value);
}
@@ -109,9 +114,9 @@ public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
* @see org.springframework.data.crossstore.ChangeSetPersister#getPersistentId(org.springframework.data.crossstore.ChangeSetBacked, org.springframework.data.crossstore.ChangeSet)
*/
public Object getPersistentId(ChangeSetBacked entity, ChangeSet cs) throws DataAccessException {
log.debug("getPersistentId called on " + entity);
if (log.isDebugEnabled()) {
log.debug("getPersistentId called on {}", entity);
}
if (entityManagerFactory == null) {
throw new DataAccessResourceFailureException("EntityManagerFactory cannot be null");
}
@@ -130,7 +135,7 @@ public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
}
if (log.isDebugEnabled()) {
log.debug("Flush: changeset: " + cs.getValues());
log.debug("Flush: changeset: {}", cs.getValues());
}
String collName = getCollectionNameForEntity(entity.getClass());
@@ -141,30 +146,34 @@ public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
for (String key : cs.getValues().keySet()) {
if (key != null && !key.startsWith("_") && !key.equals(ChangeSetPersister.ID_KEY)) {
Object value = cs.getValues().get(key);
final DBObject dbQuery = new BasicDBObject();
final Document dbQuery = new Document();
dbQuery.put(ENTITY_ID, getPersistentId(entity, cs));
dbQuery.put(ENTITY_CLASS, entity.getClass().getName());
dbQuery.put(ENTITY_FIELD_NAME, key);
DBObject dbId = mongoTemplate.execute(collName, new CollectionCallback<DBObject>() {
public DBObject doInCollection(DBCollection collection) throws MongoException, DataAccessException {
return collection.findOne(dbQuery);
final Document dbId = mongoTemplate.execute(collName, new CollectionCallback<Document>() {
public Document doInCollection(MongoCollection<Document> collection)
throws MongoException, DataAccessException {
Document id = collection.find(dbQuery).first();
return id;
}
});
if (value == null) {
if (log.isDebugEnabled()) {
log.debug("Flush: removing: " + dbQuery);
log.debug("Flush: removing: {}", dbQuery);
}
mongoTemplate.execute(collName, new CollectionCallback<Object>() {
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
collection.remove(dbQuery);
public Object doInCollection(MongoCollection<Document> collection)
throws MongoException, DataAccessException {
DeleteResult dr = collection.deleteMany(dbQuery);
return null;
}
});
} else {
final DBObject dbDoc = new BasicDBObject();
final Document dbDoc = new Document();
dbDoc.putAll(dbQuery);
if (log.isDebugEnabled()) {
log.debug("Flush: saving: " + dbQuery);
log.debug("Flush: saving: {}", dbQuery);
}
mongoTemplate.getConverter().write(value, dbDoc);
dbDoc.put(ENTITY_FIELD_CLASS, value.getClass().getName());
@@ -172,8 +181,18 @@ public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
dbDoc.put("_id", dbId.get("_id"));
}
mongoTemplate.execute(collName, new CollectionCallback<Object>() {
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
collection.save(dbDoc);
public Object doInCollection(MongoCollection<Document> collection)
throws MongoException, DataAccessException {
if (dbId != null) {
collection.replaceOne(Filters.eq("_id", dbId.get("_id")), dbDoc);
} else {
if (dbDoc.containsKey("_id") && dbDoc.get("_id") == null) {
dbDoc.remove("_id");
}
collection.insertOne(dbDoc);
}
return null;
}
});

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* Copyright 2011-2017 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.
@@ -40,7 +40,9 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
* Aspect to turn an object annotated with @Document into a persistent document using Mongo.
*
* @author Thomas Risberg
* @deprecated will be removed without replacement.
*/
@Deprecated
public aspect MongoDocumentBacking {
private static final Logger LOGGER = LoggerFactory.getLogger(MongoDocumentBacking.class);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* Copyright 2011-2017 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.
@@ -22,7 +22,9 @@ import java.lang.annotation.Target;
/**
* @author Thomas Risberg
* @deprecated will be removed without replacement.
*/
@Deprecated
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD })
public @interface RelatedDocument {

View File

@@ -18,6 +18,7 @@ package org.springframework.data.mongodb.crossstore;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.bson.Document;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@@ -36,8 +37,6 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import com.mongodb.DBObject;
/**
* Integration tests for MongoDB cross-store persistence (mainly {@link MongoChangeSetPersister}).
*
@@ -48,14 +47,11 @@ import com.mongodb.DBObject;
@ContextConfiguration("classpath:/META-INF/spring/applicationContext.xml")
public class CrossStoreMongoTests {
@Autowired
MongoTemplate mongoTemplate;
@Autowired MongoTemplate mongoTemplate;
@PersistenceContext
EntityManager entityManager;
@PersistenceContext EntityManager entityManager;
@Autowired
PlatformTransactionManager transactionManager;
@Autowired PlatformTransactionManager transactionManager;
TransactionTemplate txTemplate;
@Before
@@ -187,7 +183,7 @@ public class CrossStoreMongoTests {
boolean weFound3 = false;
for (DBObject dbo : this.mongoTemplate.getCollection(mongoTemplate.getCollectionName(Person.class)).find()) {
for (Document dbo : this.mongoTemplate.getCollection(mongoTemplate.getCollectionName(Person.class)).find()) {
Assert.assertTrue(!dbo.get("_entity_id").equals(2L));
if (dbo.get("_entity_id").equals(3L)) {
weFound3 = true;

View File

@@ -20,13 +20,13 @@
<mongo:mapping-converter/>
<!-- Mongo config -->
<bean id="mongo" class="org.springframework.data.mongodb.core.MongoFactoryBean">
<bean id="mongoClient" class="org.springframework.data.mongodb.core.MongoClientFactoryBean">
<property name="host" value="localhost"/>
<property name="port" value="27017"/>
</bean>
<bean id="mongoDbFactory" class="org.springframework.data.mongodb.core.SimpleMongoDbFactory">
<constructor-arg name="mongo" ref="mongo"/>
<constructor-arg name="mongoClient" ref="mongoClient"/>
<constructor-arg name="databaseName" value="database"/>
</bean>

View File

@@ -1,18 +0,0 @@
Bundle-SymbolicName: org.springframework.data.mongodb.crossstore
Bundle-Name: Spring Data MongoDB Cross Store Support
Bundle-Vendor: Pivotal Software, Inc.
Bundle-ManifestVersion: 2
Import-Package:
sun.reflect;version="0";resolution:=optional
Export-Template:
org.springframework.data.mongodb.crossstore.*;version="${project.version}"
Import-Template:
com.mongodb.*;version="${mongo.osgi:[=.=.=,+1.0.0)}",
javax.persistence.*;version="${jpa:[=.=.=,+1.0.0)}",
org.aspectj.*;version="${aspectj:[1.0.0, 2.0.0)}",
org.bson.*;version="0",
org.slf4j.*;version="${slf4j:[=.=.=,+1.0.0)}",
org.springframework.*;version="${spring:[=.=.=.=,+1.0.0)}",
org.springframework.data.*;version="${springdata.commons:[=.=.=.=,+1.0.0)}",
org.springframework.data.mongodb.*;version="${project.version:[=.=.=.=,+1.0.0)}",
org.w3c.dom.*;version="0"

View File

@@ -13,7 +13,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.6.0.RC1</version>
<version>2.0.2.RELEASE</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -1,52 +0,0 @@
# MongoDB Log4J Appender
This module sets up a Log4J appender that puts logging events in MongoDB. It is fully configurable
and connects directly to the MongoDB server using the driver. It has no dependency on any Spring package.
To use it, configure a host, port, (optionally) applicationId, and database property in your Log4J configuration:
log4j.appender.stdout=org.springframework.data.mongodb.log4j.MongoLog4jAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n
log4j.appender.stdout.host = localhost
log4j.appender.stdout.port = 27017
log4j.appender.stdout.database = logs
log4j.appender.stdout.collectionPattern = %c
log4j.appender.stdout.applicationId = my.application
log4j.appender.stdout.warnOrHigherWriteConcern = FSYNC_SAFE
It will even support properties in your MDC (so long as they're Strings or support .toString()).
The collection name is configurable as well. If you don't specify anything, it will use the Category name.
If you want to specify a collection name, you can give it a Log4J pattern layout format string which will have
the following additional MDC variables in the context when the collection name is rendered:
"year" = Calendar.YEAR
"month" = Calendar.MONTH + 1
"day" = Calendar.DAY_OF_MONTH
"hour" = Calendar.HOUR_OF_DAY
"applicationId" = configured applicationId
An example log entry might look like:
{
"_id" : ObjectId("4d89341a8ef397e06940d5cd"),
"applicationId" : "my.application",
"name" : "org.springframework.data.mongodb.log4j.MongoLog4jAppenderIntegrationTests",
"level" : "DEBUG",
"timestamp" : ISODate("2011-03-23T16:53:46.778Z"),
"properties" : {
"property" : "one"
},
"message" : "DEBUG message"
}
To set WriteConcern levels for WARN or higher messages, set warnOrHigherWriteConcern to one of the following:
* FSYNC_SAFE
* NONE
* NORMAL
* REPLICAS_SAFE
* SAFE
[http://api.mongodb.org/java/2.5-pre-/com/mongodb/WriteConcern.html#field_detail](http://api.mongodb.org/java/2.5-pre-/com/mongodb/WriteConcern.html#field_detail)

View File

@@ -1,30 +0,0 @@
<?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 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.6.0.RC1</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>spring-data-mongodb-log4j</artifactId>
<name>Spring Data MongoDB - Log4J Appender</name>
<properties>
<log4j>1.2.16</log4j>
</properties>
<dependencies>
<!-- Logging -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j}</version>
</dependency>
</dependencies>
</project>

View File

@@ -1,226 +0,0 @@
/*
* Copyright 2011-2013 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
*
* http://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.log4j;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Map;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Level;
import org.apache.log4j.MDC;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.spi.LoggingEvent;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.Mongo;
import com.mongodb.WriteConcern;
/**
* Log4j appender writing log entries into a MongoDB instance.
*
* @author Jon Brisbin
* @author Oliver Gierke
*/
public class MongoLog4jAppender extends AppenderSkeleton {
public static final String LEVEL = "level";
public static final String NAME = "name";
public static final String APP_ID = "applicationId";
public static final String TIMESTAMP = "timestamp";
public static final String PROPERTIES = "properties";
public static final String TRACEBACK = "traceback";
public static final String MESSAGE = "message";
public static final String YEAR = "year";
public static final String MONTH = "month";
public static final String DAY = "day";
public static final String HOUR = "hour";
protected String host = "localhost";
protected int port = 27017;
protected String database = "logs";
protected String collectionPattern = "%c";
protected PatternLayout collectionLayout = new PatternLayout(collectionPattern);
protected String applicationId = System.getProperty("APPLICATION_ID", null);
protected WriteConcern warnOrHigherWriteConcern = WriteConcern.SAFE;
protected WriteConcern infoOrLowerWriteConcern = WriteConcern.NORMAL;
protected Mongo mongo;
protected DB db;
public MongoLog4jAppender() {
}
public MongoLog4jAppender(boolean isActive) {
super(isActive);
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getDatabase() {
return database;
}
public void setDatabase(String database) {
this.database = database;
}
public String getCollectionPattern() {
return collectionPattern;
}
public void setCollectionPattern(String collectionPattern) {
this.collectionPattern = collectionPattern;
this.collectionLayout = new PatternLayout(collectionPattern);
}
public String getApplicationId() {
return applicationId;
}
public void setApplicationId(String applicationId) {
this.applicationId = applicationId;
}
public void setWarnOrHigherWriteConcern(String wc) {
this.warnOrHigherWriteConcern = WriteConcern.valueOf(wc);
}
public String getWarnOrHigherWriteConcern() {
return warnOrHigherWriteConcern.toString();
}
public String getInfoOrLowerWriteConcern() {
return infoOrLowerWriteConcern.toString();
}
public void setInfoOrLowerWriteConcern(String wc) {
this.infoOrLowerWriteConcern = WriteConcern.valueOf(wc);
}
protected void connectToMongo() throws UnknownHostException {
this.mongo = new Mongo(host, port);
this.db = mongo.getDB(database);
}
/*
* (non-Javadoc)
* @see org.apache.log4j.AppenderSkeleton#append(org.apache.log4j.spi.LoggingEvent)
*/
@Override
@SuppressWarnings({ "unchecked" })
protected void append(final LoggingEvent event) {
if (null == db) {
try {
connectToMongo();
} catch (UnknownHostException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
BasicDBObject dbo = new BasicDBObject();
if (null != applicationId) {
dbo.put(APP_ID, applicationId);
MDC.put(APP_ID, applicationId);
}
dbo.put(NAME, event.getLogger().getName());
dbo.put(LEVEL, event.getLevel().toString());
Calendar tstamp = Calendar.getInstance();
tstamp.setTimeInMillis(event.getTimeStamp());
dbo.put(TIMESTAMP, tstamp.getTime());
// Copy properties into document
Map<Object, Object> props = event.getProperties();
if (null != props && props.size() > 0) {
BasicDBObject propsDbo = new BasicDBObject();
for (Map.Entry<Object, Object> entry : props.entrySet()) {
propsDbo.put(entry.getKey().toString(), entry.getValue().toString());
}
dbo.put(PROPERTIES, propsDbo);
}
// Copy traceback info (if there is any) into the document
String[] traceback = event.getThrowableStrRep();
if (null != traceback && traceback.length > 0) {
BasicDBList tbDbo = new BasicDBList();
tbDbo.addAll(Arrays.asList(traceback));
dbo.put(TRACEBACK, tbDbo);
}
// Put the rendered message into the document
dbo.put(MESSAGE, event.getRenderedMessage());
// Insert the document
Calendar now = Calendar.getInstance();
MDC.put(YEAR, now.get(Calendar.YEAR));
MDC.put(MONTH, String.format("%1$02d", now.get(Calendar.MONTH) + 1));
MDC.put(DAY, String.format("%1$02d", now.get(Calendar.DAY_OF_MONTH)));
MDC.put(HOUR, String.format("%1$02d", now.get(Calendar.HOUR_OF_DAY)));
String coll = collectionLayout.format(event);
MDC.remove(YEAR);
MDC.remove(MONTH);
MDC.remove(DAY);
MDC.remove(HOUR);
if (null != applicationId) {
MDC.remove(APP_ID);
}
WriteConcern wc;
if (event.getLevel().isGreaterOrEqual(Level.WARN)) {
wc = warnOrHigherWriteConcern;
} else {
wc = infoOrLowerWriteConcern;
}
db.getCollection(coll).insert(dbo, wc);
}
/*
* (non-Javadoc)
* @see org.apache.log4j.AppenderSkeleton#close()
*/
public void close() {
if (mongo != null) {
mongo.close();
}
}
/*
* (non-Javadoc)
* @see org.apache.log4j.AppenderSkeleton#requiresLayout()
*/
public boolean requiresLayout() {
return true;
}
}

View File

@@ -1,5 +0,0 @@
/**
* Infrastructure for to use MongoDB as a logging sink.
*/
package org.springframework.data.mongodb.log4j;

View File

@@ -1,77 +0,0 @@
/*
* Copyright 2011-2013 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
*
* http://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.log4j;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.util.Calendar;
import org.apache.log4j.Logger;
import org.apache.log4j.MDC;
import org.junit.Before;
import org.junit.Test;
import com.mongodb.DB;
import com.mongodb.DBCursor;
import com.mongodb.Mongo;
/**
* Integration tests for {@link MongoLog4jAppender}.
*
* @author Jon Brisbin
* @author Oliver Gierke
*/
public class MongoLog4jAppenderIntegrationTests {
static final String NAME = MongoLog4jAppenderIntegrationTests.class.getName();
Logger log = Logger.getLogger(NAME);
Mongo mongo;
DB db;
String collection;
@Before
public void setUp() throws Exception {
mongo = new Mongo("localhost", 27017);
db = mongo.getDB("logs");
Calendar now = Calendar.getInstance();
collection = String.valueOf(now.get(Calendar.YEAR)) + String.format("%1$02d", now.get(Calendar.MONTH) + 1);
db.getCollection(collection).drop();
}
@Test
public void testLogging() {
log.debug("DEBUG message");
log.info("INFO message");
log.warn("WARN message");
log.error("ERROR message");
DBCursor msgs = db.getCollection(collection).find();
assertThat(msgs.count(), is(4));
}
@Test
public void testProperties() {
MDC.put("property", "one");
log.debug("DEBUG message");
}
}

View File

@@ -1,13 +0,0 @@
log4j.rootCategory=INFO, stdout
log4j.appender.stdout=org.springframework.data.mongodb.log4j.MongoLog4jAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n
log4j.appender.stdout.host = localhost
log4j.appender.stdout.port = 27017
log4j.appender.stdout.database = logs
log4j.appender.stdout.collectionPattern = %X{year}%X{month}
log4j.appender.stdout.applicationId = my.application
log4j.appender.stdout.warnOrHigherWriteConcern = FSYNC_SAFE
log4j.category.org.springframework.data.mongodb=DEBUG

View File

@@ -1,9 +0,0 @@
Bundle-SymbolicName: org.springframework.data.mongodb.log4j
Bundle-Name: Spring Data Mongo DB Log4J Appender
Bundle-Vendor: Pivotal Software, Inc.
Bundle-ManifestVersion: 2
Import-Package:
sun.reflect;version="0";resolution:=optional
Import-Template:
com.mongodb.*;version="${mongo.osgi:[=.=.=,+1.0.0)}",
org.apache.log4j.*;version="${log4j:[=.=.=,+1.0.0)}"

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<context version="7.1.10.209">
<context version="7.2.2.230">
<scope type="Project" name="spring-data-mongodb">
<element type="TypeFilterReferenceOverridden" name="Filter">
<element type="IncludeTypePattern" name="org.springframework.data.mongodb.**"/>
@@ -35,6 +35,12 @@
<dependency toName="Project|spring-data-mongodb::Layer|Repositories::Subsystem|API" type="AllowedDependency"/>
<dependency toName="Project|spring-data-mongodb::Layer|Repositories::Subsystem|Implementation" type="AllowedDependency"/>
</element>
<element type="Subsystem" name="CDI">
<element type="TypeFilter" name="Assignment">
<element type="IncludeTypePattern" name="**.cdi.**"/>
</element>
<stereotype name="Unrestricted"/>
</element>
<dependency toName="Project|spring-data-mongodb::Layer|Config" type="AllowedDependency"/>
<dependency toName="Project|spring-data-mongodb::Layer|Core" type="AllowedDependency"/>
</element>
@@ -76,6 +82,11 @@
</element>
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Geospatial" type="AllowedDependency"/>
</element>
<element type="Subsystem" name="Script">
<element type="TypeFilter" name="Assignment">
<element type="IncludeTypePattern" name="**.script.**"/>
</element>
</element>
<element type="Subsystem" name="Conversion">
<element type="TypeFilter" name="Assignment">
<element type="IncludeTypePattern" name="**.core.convert.**"/>
@@ -83,6 +94,7 @@
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Geospatial" type="AllowedDependency"/>
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Mapping" type="AllowedDependency"/>
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Query" type="AllowedDependency"/>
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Script" type="AllowedDependency"/>
</element>
<element type="Subsystem" name="SpEL">
<element type="TypeFilter" name="Assignment">
@@ -105,6 +117,11 @@
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Mapping" type="AllowedDependency"/>
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Query" type="AllowedDependency"/>
</element>
<element type="Subsystem" name="MapReduce">
<element type="TypeFilter" name="Assignment">
<element type="IncludeTypePattern" name="**.mapreduce.**"/>
</element>
</element>
<element type="Subsystem" name="Core">
<element type="TypeFilter" name="Assignment">
<element type="WeakTypePattern" name="**.core.**"/>
@@ -113,8 +130,10 @@
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Conversion" type="AllowedDependency"/>
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Geospatial" type="AllowedDependency"/>
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Index" type="AllowedDependency"/>
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|MapReduce" type="AllowedDependency"/>
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Mapping" type="AllowedDependency"/>
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Query" type="AllowedDependency"/>
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Script" type="AllowedDependency"/>
</element>
<element type="Subsystem" name="Util">
<element type="TypeFilter" name="Assignment">
@@ -169,7 +188,32 @@
</element>
<element type="Subsystem" name="Querydsl">
<element type="TypeFilter" name="Assignment">
<element type="IncludeTypePattern" name="com.mysema.query.**"/>
<element type="IncludeTypePattern" name="com.querydsl.**"/>
</element>
</element>
<element type="Subsystem" name="Slf4j">
<element type="TypeFilter" name="Assignment">
<element type="IncludeTypePattern" name="org.slf4j.**"/>
</element>
</element>
<element type="Subsystem" name="Jackson">
<element type="TypeFilter" name="Assignment">
<element type="IncludeTypePattern" name="com.fasterxml.jackson.**"/>
</element>
</element>
<element type="Subsystem" name="DOM">
<element type="TypeFilter" name="Assignment">
<element type="IncludeTypePattern" name="org.w3c.dom.**"/>
</element>
</element>
<element type="Subsystem" name="AOP Alliance">
<element type="TypeFilter" name="Assignment">
<element type="IncludeTypePattern" name="org.aopalliance.**"/>
</element>
</element>
<element type="Subsystem" name="Guava">
<element type="TypeFilter" name="Assignment">
<element type="IncludeTypePattern" name="com.google.common.**"/>
</element>
</element>
</architecture>

View File

@@ -2,7 +2,7 @@
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-data-mongodb</artifactId>
<name>Spring Data MongoDB - Core</name>
@@ -11,18 +11,19 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.6.0.RC1</version>
<version>2.0.2.RELEASE</version>
<relativePath>../pom.xml</relativePath>
</parent>
<properties>
<validation>1.0.0.GA</validation>
<objenesis>1.3</objenesis>
<equalsverifier>1.7.8</equalsverifier>
<java-module-name>spring.data.mongodb</java-module-name>
</properties>
<dependencies>
<!-- Spring -->
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
@@ -50,7 +51,7 @@
<artifactId>spring-expression</artifactId>
</dependency>
<!-- Spring Data -->
<!-- Spring Data -->
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>spring-data-commons</artifactId>
@@ -58,14 +59,14 @@
</dependency>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-mongodb</artifactId>
<version>${querydsl}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl}</version>
<scope>provided</scope>
@@ -77,8 +78,81 @@
<version>1.0</version>
<optional>true</optional>
</dependency>
<!-- reactive -->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-reactivestreams</artifactId>
<version>${mongo.reactivestreams}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-async</artifactId>
<version>${mongo}</version>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.mongodb</groupId>
<artifactId>bson</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.reactivex</groupId>
<artifactId>rxjava</artifactId>
<version>${rxjava}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.reactivex</groupId>
<artifactId>rxjava-reactive-streams</artifactId>
<version>${rxjava-reactive-streams}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.reactivex.rxjava2</groupId>
<artifactId>rxjava</artifactId>
<version>${rxjava2}</version>
<optional>true</optional>
</dependency>
<!-- CDI -->
<!-- Dependency order required to build against CDI 1.0 and test with CDI 2.0 -->
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jcdi_2.0_spec</artifactId>
<version>1.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.interceptor</groupId>
<artifactId>javax.interceptor-api</artifactId>
<version>1.2.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
@@ -86,27 +160,20 @@
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>el-api</artifactId>
<version>${cdi}</version>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>${javax-annotation-api}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.openwebbeans.test</groupId>
<artifactId>cditest-owb</artifactId>
<groupId>org.apache.openwebbeans</groupId>
<artifactId>openwebbeans-se</artifactId>
<version>${webbeans}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>test</scope>
</dependency>
<!-- JSR 303 Validation -->
<dependency>
@@ -115,7 +182,7 @@
<version>${validation}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.objenesis</groupId>
<artifactId>objenesis</artifactId>
@@ -126,27 +193,102 @@
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.2.0.Final</version>
<version>5.2.4.Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>${jodatime}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.threeten</groupId>
<artifactId>threetenbp</artifactId>
<version>${threetenbp}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>${slf4j}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>nl.jqno.equalsverifier</groupId>
<artifactId>equalsverifier</artifactId>
<version>${equalsverifier}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>de.schauderhaft.degraph</groupId>
<artifactId>degraph-check</artifactId>
<version>0.1.4</version>
<scope>test</scope>
</dependency>
<!-- Kotlin extension -->
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
<version>${kotlin}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test</artifactId>
<version>${kotlin}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.nhaarman</groupId>
<artifactId>mockito-kotlin</artifactId>
<version>1.5.0</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
</exclusion>
<exclusion>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
</exclusion>
<exclusion>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
@@ -155,7 +297,7 @@
<version>${apt}</version>
<dependencies>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl}</version>
</dependency>
@@ -177,7 +319,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12</version>
<configuration>
<useFile>false</useFile>
<includes>
@@ -185,13 +326,22 @@
</includes>
<excludes>
<exclude>**/PerformanceTests.java</exclude>
<exclude>**/ReactivePerformanceTests.java</exclude>
</excludes>
<systemPropertyVariables>
<java.util.logging.config.file>src/test/resources/logging.properties</java.util.logging.config.file>
<reactor.trace.cancel>true</reactor.trace.cancel>
</systemPropertyVariables>
<properties>
<property>
<name>listener</name>
<value>org.springframework.data.mongodb.test.util.CleanMongoDBJunitRunListener</value>
</property>
</properties>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2015 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
*
* http://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.List;
import org.springframework.dao.DataAccessException;
import com.mongodb.BulkWriteError;
import com.mongodb.BulkWriteException;
import com.mongodb.BulkWriteResult;
/**
* Is thrown when errors occur during bulk operations.
*
* @author Tobias Trelle
* @author Oliver Gierke
* @since 1.9
*/
public class BulkOperationException extends DataAccessException {
private static final long serialVersionUID = 73929601661154421L;
private final List<BulkWriteError> errors;
private final BulkWriteResult result;
/**
* Creates a new {@link BulkOperationException} with the given message and source {@link BulkWriteException}.
*
* @param message must not be {@literal null}.
* @param source must not be {@literal null}.
*/
public BulkOperationException(String message, BulkWriteException source) {
super(message, source);
this.errors = source.getWriteErrors();
this.result = source.getWriteResult();
}
public List<BulkWriteError> getErrors() {
return errors;
}
public BulkWriteResult getResult() {
return result;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2012 the original author or authors.
* Copyright 2010-2017 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.
@@ -17,16 +17,18 @@ package org.springframework.data.mongodb;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.data.authentication.UserCredentials;
import org.springframework.lang.Nullable;
/**
* Exception being thrown in case we cannot connect to a MongoDB instance.
*
*
* @author Oliver Gierke
* @author Mark Paluch
*/
public class CannotGetMongoDbConnectionException extends DataAccessResourceFailureException {
private final UserCredentials credentials;
private final String database;
private final @Nullable String database;
private static final long serialVersionUID = 1172099106475265589L;
@@ -40,7 +42,7 @@ public class CannotGetMongoDbConnectionException extends DataAccessResourceFailu
this(msg, null, UserCredentials.NO_CREDENTIALS);
}
public CannotGetMongoDbConnectionException(String msg, String database, UserCredentials credentials) {
public CannotGetMongoDbConnectionException(String msg, @Nullable String database, UserCredentials credentials) {
super(msg);
this.database = database;
this.credentials = credentials;
@@ -48,7 +50,7 @@ public class CannotGetMongoDbConnectionException extends DataAccessResourceFailu
/**
* Returns the {@link UserCredentials} that were used when trying to connect to the MongoDB instance.
*
*
* @return
*/
public UserCredentials getCredentials() {
@@ -57,9 +59,10 @@ public class CannotGetMongoDbConnectionException extends DataAccessResourceFailu
/**
* Returns the name of the database trying to be accessed.
*
*
* @return
*/
@Nullable
public String getDatabase() {
return database;
}

View File

@@ -20,6 +20,7 @@ import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.mongodb.core.MongoExceptionTranslator;
import com.mongodb.DB;
import com.mongodb.client.MongoDatabase;
/**
* Interface for factories creating {@link DB} instances.
@@ -35,7 +36,7 @@ public interface MongoDbFactory {
* @return
* @throws DataAccessException
*/
DB getDb() throws DataAccessException;
MongoDatabase getDb() throws DataAccessException;
/**
* Creates a {@link DB} instance to access the database with the given name.
@@ -44,7 +45,7 @@ public interface MongoDbFactory {
* @return
* @throws DataAccessException
*/
DB getDb(String dbName) throws DataAccessException;
MongoDatabase getDb(String dbName) throws DataAccessException;
/**
* Exposes a shared {@link MongoExceptionTranslator}.
@@ -52,4 +53,6 @@ public interface MongoDbFactory {
* @return will never be {@literal null}.
*/
PersistenceExceptionTranslator getExceptionTranslator();
DB getLegacyDb();
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2016 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
*
* http://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 org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.mongodb.core.MongoExceptionTranslator;
import com.mongodb.reactivestreams.client.MongoDatabase;
/**
* Interface for factories creating reactive {@link MongoDatabase} instances.
*
* @author Mark Paluch
* @since 2.0
*/
public interface ReactiveMongoDatabaseFactory {
/**
* Creates a default {@link MongoDatabase} instance.
*
* @return
* @throws DataAccessException
*/
MongoDatabase getMongoDatabase() throws DataAccessException;
/**
* Creates a {@link MongoDatabase} instance to access the database with the given name.
*
* @param dbName must not be {@literal null} or empty.
* @return
* @throws DataAccessException
*/
MongoDatabase getMongoDatabase(String dbName) throws DataAccessException;
/**
* Exposes a shared {@link MongoExceptionTranslator}.
*
* @return will never be {@literal null}.
*/
PersistenceExceptionTranslator getExceptionTranslator();
}

View File

@@ -1,246 +1,114 @@
/*
* Copyright 2011-2014 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
*
* http://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.config;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.data.annotation.Persistent;
import org.springframework.data.authentication.UserCredentials;
import org.springframework.data.mapping.context.MappingContextIsNewStrategyFactory;
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.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.core.convert.CustomConversions;
import org.springframework.data.mongodb.core.convert.DbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.support.CachingIsNewStrategyFactory;
import org.springframework.data.support.IsNewStrategyFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import com.mongodb.Mongo;
/**
* Base class for Spring Data MongoDB configuration using JavaConfig.
*
* @author Mark Pollack
* @author Oliver Gierke
* @author Thomas Darimont
* @author Ryan Tenney
*/
@Configuration
public abstract class AbstractMongoConfiguration {
/**
* Return the name of the database to connect to.
*
* @return must not be {@literal null}.
*/
protected abstract String getDatabaseName();
/**
* Return the name of the authentication database to use. Defaults to {@literal null} and will turn into the value
* returned by {@link #getDatabaseName()} later on effectively.
*
* @return
*/
protected String getAuthenticationDatabaseName() {
return null;
}
/**
* Return the {@link Mongo} instance to connect to. Annotate with {@link Bean} in case you want to expose a
* {@link Mongo} instance to the {@link org.springframework.context.ApplicationContext}.
*
* @return
* @throws Exception
*/
public abstract Mongo mongo() throws Exception;
/**
* Creates a {@link MongoTemplate}.
*
* @return
* @throws Exception
*/
@Bean
public MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongoDbFactory(), mappingMongoConverter());
}
/**
* Creates a {@link SimpleMongoDbFactory} to be used by the {@link MongoTemplate}. Will use the {@link Mongo} instance
* configured in {@link #mongo()}.
*
* @see #mongo()
* @see #mongoTemplate()
* @return
* @throws Exception
*/
@Bean
public MongoDbFactory mongoDbFactory() throws Exception {
return new SimpleMongoDbFactory(mongo(), getDatabaseName(), getUserCredentials(), getAuthenticationDatabaseName());
}
/**
* Return the base package to scan for mapped {@link Document}s. Will return the package name of the configuration
* class' (the concrete class, not this one here) by default. So if you have a {@code com.acme.AppConfig} extending
* {@link AbstractMongoConfiguration} the base package will be considered {@code com.acme} unless the method is
* overriden to implement alternate behaviour.
*
* @return the base package to scan for mapped {@link Document} classes or {@literal null} to not enable scanning for
* entities.
*/
protected String getMappingBasePackage() {
Package mappingBasePackage = getClass().getPackage();
return mappingBasePackage == null ? null : mappingBasePackage.getName();
}
/**
* Return {@link UserCredentials} to be used when connecting to the MongoDB instance or {@literal null} if none shall
* be used.
*
* @return
*/
protected UserCredentials getUserCredentials() {
return null;
}
/**
* Creates a {@link MongoMappingContext} equipped with entity classes scanned from the mapping base package.
*
* @see #getMappingBasePackage()
* @return
* @throws ClassNotFoundException
*/
@Bean
public MongoMappingContext mongoMappingContext() throws ClassNotFoundException {
MongoMappingContext mappingContext = new MongoMappingContext();
mappingContext.setInitialEntitySet(getInitialEntitySet());
mappingContext.setSimpleTypeHolder(customConversions().getSimpleTypeHolder());
mappingContext.setFieldNamingStrategy(fieldNamingStrategy());
return mappingContext;
}
/**
* Returns a {@link MappingContextIsNewStrategyFactory} wrapped into a {@link CachingIsNewStrategyFactory}.
*
* @return
* @throws ClassNotFoundException
*/
@Bean
public IsNewStrategyFactory isNewStrategyFactory() throws ClassNotFoundException {
return new CachingIsNewStrategyFactory(new MappingContextIsNewStrategyFactory(mongoMappingContext()));
}
/**
* Register custom {@link Converter}s in a {@link CustomConversions} object if required. These
* {@link CustomConversions} will be registered with the {@link #mappingMongoConverter()} and
* {@link #mongoMappingContext()}. Returns an empty {@link CustomConversions} instance by default.
*
* @return must not be {@literal null}.
*/
@Bean
public CustomConversions customConversions() {
return new CustomConversions(Collections.emptyList());
}
/**
* Creates a {@link MappingMongoConverter} using the configured {@link #mongoDbFactory()} and
* {@link #mongoMappingContext()}. Will get {@link #customConversions()} applied.
*
* @see #customConversions()
* @see #mongoMappingContext()
* @see #mongoDbFactory()
* @return
* @throws Exception
*/
@Bean
public MappingMongoConverter mappingMongoConverter() throws Exception {
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext());
converter.setCustomConversions(customConversions());
return converter;
}
/**
* Scans the mapping base package for classes annotated with {@link Document}.
*
* @see #getMappingBasePackage()
* @return
* @throws ClassNotFoundException
*/
protected Set<Class<?>> getInitialEntitySet() throws ClassNotFoundException {
String basePackage = getMappingBasePackage();
Set<Class<?>> initialEntitySet = new HashSet<Class<?>>();
if (StringUtils.hasText(basePackage)) {
ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(
false);
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Document.class));
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Persistent.class));
for (BeanDefinition candidate : componentProvider.findCandidateComponents(basePackage)) {
initialEntitySet.add(ClassUtils.forName(candidate.getBeanClassName(),
AbstractMongoConfiguration.class.getClassLoader()));
}
}
return initialEntitySet;
}
/**
* Configures whether to abbreviate field names for domain objects by configuring a
* {@link CamelCaseAbbreviatingFieldNamingStrategy} on the {@link MongoMappingContext} instance created. For advanced
* customization needs, consider overriding {@link #mappingMongoConverter()}.
*
* @return
*/
protected boolean abbreviateFieldNames() {
return false;
}
/**
* Configures a {@link FieldNamingStrategy} on the {@link MongoMappingContext} instance created.
*
* @return
* @since 1.5
*/
protected FieldNamingStrategy fieldNamingStrategy() {
return abbreviateFieldNames() ? new CamelCaseAbbreviatingFieldNamingStrategy()
: PropertyNameFieldNamingStrategy.INSTANCE;
}
}
/*
* Copyright 2011-2017 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
*
* http://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.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.core.convert.DbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.lang.Nullable;
import com.mongodb.MongoClient;
/**
* Base class for Spring Data MongoDB configuration using JavaConfig.
*
* @author Mark Pollack
* @author Oliver Gierke
* @author Thomas Darimont
* @author Ryan Tenney
* @author Christoph Strobl
* @author Mark Paluch
* @see MongoConfigurationSupport
*/
@Configuration
public abstract class
AbstractMongoConfiguration extends MongoConfigurationSupport {
/**
* Return the {@link MongoClient} instance to connect to. Annotate with {@link Bean} in case you want to expose a
* {@link MongoClient} instance to the {@link org.springframework.context.ApplicationContext}.
*
* @return
*/
public abstract MongoClient mongoClient();
/**
* Creates a {@link MongoTemplate}.
*
* @return
*/
@Bean
public MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongoDbFactory(), mappingMongoConverter());
}
/**
* Creates a {@link SimpleMongoDbFactory} to be used by the {@link MongoTemplate}. Will use the {@link MongoClient}
* instance configured in {@link #mongo()}.
*
* @see #mongoClient()
* @see #mongoTemplate()
* @return
*/
@Bean
public MongoDbFactory mongoDbFactory() {
return new SimpleMongoDbFactory(mongoClient(), getDatabaseName());
}
/**
* Return the base package to scan for mapped {@link Document}s. Will return the package name of the configuration
* class' (the concrete class, not this one here) by default. So if you have a {@code com.acme.AppConfig} extending
* {@link AbstractMongoConfiguration} the base package will be considered {@code com.acme} unless the method is
* overridden to implement alternate behavior.
*
* @return the base package to scan for mapped {@link Document} classes or {@literal null} to not enable scanning for
* entities.
* @deprecated use {@link #getMappingBasePackages()} instead.
*/
@Deprecated
@Nullable
protected String getMappingBasePackage() {
Package mappingBasePackage = getClass().getPackage();
return mappingBasePackage == null ? null : mappingBasePackage.getName();
}
/**
* Creates a {@link MappingMongoConverter} using the configured {@link #mongoDbFactory()} and
* {@link #mongoMappingContext()}. Will get {@link #customConversions()} applied.
*
* @see #customConversions()
* @see #mongoMappingContext()
* @see #mongoDbFactory()
* @return
* @throws Exception
*/
@Bean
public MappingMongoConverter mappingMongoConverter() throws Exception {
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext());
converter.setCustomConversions(customConversions());
return converter;
}
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright 2016-2017 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
*
* http://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.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.ReactiveMongoDatabaseFactory;
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import org.springframework.data.mongodb.core.SimpleReactiveMongoDatabaseFactory;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import com.mongodb.reactivestreams.client.MongoClient;
/**
* Base class for reactive Spring Data MongoDB configuration using JavaConfig.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.0
* @see MongoConfigurationSupport
*/
@Configuration
public abstract class AbstractReactiveMongoConfiguration extends MongoConfigurationSupport {
/**
* Return the Reactive Streams {@link MongoClient} instance to connect to. Annotate with {@link Bean} in case you want
* to expose a {@link MongoClient} instance to the {@link org.springframework.context.ApplicationContext}.
*
* @return never {@literal null}.
*/
public abstract MongoClient reactiveMongoClient();
/**
* Creates {@link ReactiveMongoOperations}.
*
* @return never {@literal null}.
*/
@Bean
public ReactiveMongoOperations reactiveMongoTemplate() throws Exception {
return new ReactiveMongoTemplate(reactiveMongoDbFactory(), mappingMongoConverter());
}
/**
* Creates a {@link ReactiveMongoDatabaseFactory} to be used by the {@link ReactiveMongoOperations}. Will use the
* {@link MongoClient} instance configured in {@link #reactiveMongoClient()}.
*
* @see #reactiveMongoClient()
* @see #reactiveMongoTemplate()
* @return never {@literal null}.
*/
@Bean
public ReactiveMongoDatabaseFactory reactiveMongoDbFactory() {
return new SimpleReactiveMongoDatabaseFactory(reactiveMongoClient(), getDatabaseName());
}
/**
* Creates a {@link MappingMongoConverter} using the configured {@link #reactiveMongoDbFactory()} and
* {@link #mongoMappingContext()}. Will get {@link #customConversions()} applied.
*
* @see #customConversions()
* @see #mongoMappingContext()
* @see #reactiveMongoDbFactory()
* @return never {@literal null}.
* @throws Exception
*/
@Bean
public MappingMongoConverter mappingMongoConverter() throws Exception {
MappingMongoConverter converter = new MappingMongoConverter(ReactiveMongoTemplate.NO_OP_REF_RESOLVER,
mongoMappingContext());
converter.setCustomConversions(customConversions());
return converter;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2014 the original author or authors.
* Copyright 2011-2017 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.
@@ -21,13 +21,14 @@ package org.springframework.data.mongodb.config;
* @author Jon Brisbin
* @author Oliver Gierke
* @author Martin Baumgartner
* @author Christoph Strobl
*/
public abstract class BeanNames {
public static final String MAPPING_CONTEXT_BEAN_NAME = "mongoMappingContext";
static final String INDEX_HELPER_BEAN_NAME = "indexCreationHelper";
static final String MONGO_BEAN_NAME = "mongo";
static final String MONGO_BEAN_NAME = "mongoClient";
static final String DB_FACTORY_BEAN_NAME = "mongoDbFactory";
static final String VALIDATING_EVENT_LISTENER_BEAN_NAME = "validatingMongoEventListener";
static final String IS_NEW_STRATEGY_FACTORY_BEAN_NAME = "isNewStrategyFactory";

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2013 the original author or authors.
* Copyright 2015-2017 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.
@@ -13,33 +13,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.query;
package org.springframework.data.mongodb.config;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.context.annotation.Bean;
import org.springframework.data.mongodb.core.geo.GeoJsonModule;
import org.springframework.data.web.config.SpringDataJacksonModules;
/**
* An enum that specifies the ordering for sort or index specifications
* Configuration class to expose {@link GeoJsonModule} as a Spring bean.
*
* @deprecated prefer {@link Direction}
* @author Thomas Risberg
* @author Oliver Gierke
* @author Jens Schauder
*/
@Deprecated
public enum Order {
public class GeoJsonConfiguration implements SpringDataJacksonModules {
ASCENDING {
@Override
public Direction toDirection() {
return Direction.ASC;
}
},
DESCENDING {
@Override
public Direction toDirection() {
return Direction.DESC;
}
};
public abstract Direction toDirection();
@Bean
public GeoJsonModule geoJsonModule() {
return new GeoJsonModule();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2014 the original author or authors.
* Copyright 2011-2017 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.
@@ -53,8 +53,9 @@ import org.springframework.data.annotation.Persistent;
import org.springframework.data.config.BeanComponentDefinitionBuilder;
import org.springframework.data.mapping.context.MappingContextIsNewStrategyFactory;
import org.springframework.data.mapping.model.CamelCaseAbbreviatingFieldNamingStrategy;
import org.springframework.data.mongodb.core.convert.CustomConversions;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
import org.springframework.data.mongodb.core.convert.QueryMapper;
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
@@ -67,12 +68,13 @@ import org.w3c.dom.Element;
/**
* Bean definition parser for the {@code mapping-converter} element.
*
*
* @author Jon Brisbin
* @author Oliver Gierke
* @author Maciej Walkowiak
* @author Thomas Darimont
* @author Christoph Strobl
* @author Mark Paluch
*/
public class MappingMongoConverterParser implements BeanDefinitionParser {
@@ -120,27 +122,36 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
converterBuilder.addPropertyValue("customConversions", conversionsDefinition);
}
if (!registry.containsBeanDefinition("indexOperationsProvider")) {
BeanDefinitionBuilder indexOperationsProviderBuilder = BeanDefinitionBuilder
.genericBeanDefinition("org.springframework.data.mongodb.core.DefaultIndexOperationsProvider");
indexOperationsProviderBuilder.addConstructorArgReference(dbFactoryRef);
indexOperationsProviderBuilder.addConstructorArgValue(BeanDefinitionBuilder
.genericBeanDefinition(QueryMapper.class).addConstructorArgReference(id).getBeanDefinition());
parserContext.registerBeanComponent(
new BeanComponentDefinition(indexOperationsProviderBuilder.getBeanDefinition(), "indexOperationsProvider"));
}
try {
registry.getBeanDefinition(INDEX_HELPER_BEAN_NAME);
} catch (NoSuchBeanDefinitionException ignored) {
if (!StringUtils.hasText(dbFactoryRef)) {
dbFactoryRef = DB_FACTORY_BEAN_NAME;
}
BeanDefinitionBuilder indexHelperBuilder = BeanDefinitionBuilder
.genericBeanDefinition(MongoPersistentEntityIndexCreator.class);
indexHelperBuilder.addConstructorArgReference(ctxRef);
indexHelperBuilder.addConstructorArgReference(dbFactoryRef);
indexHelperBuilder.addConstructorArgReference("indexOperationsProvider");
indexHelperBuilder.addDependsOn(ctxRef);
parserContext.registerBeanComponent(new BeanComponentDefinition(indexHelperBuilder.getBeanDefinition(),
INDEX_HELPER_BEAN_NAME));
parserContext.registerBeanComponent(
new BeanComponentDefinition(indexHelperBuilder.getBeanDefinition(), INDEX_HELPER_BEAN_NAME));
}
BeanDefinition validatingMongoEventListener = potentiallyCreateValidatingMongoEventListener(element, parserContext);
if (validatingMongoEventListener != null) {
parserContext.registerBeanComponent(new BeanComponentDefinition(validatingMongoEventListener,
VALIDATING_EVENT_LISTENER_BEAN_NAME));
parserContext.registerBeanComponent(
new BeanComponentDefinition(validatingMongoEventListener, VALIDATING_EVENT_LISTENER_BEAN_NAME));
}
parserContext.registerBeanComponent(new BeanComponentDefinition(converterBuilder.getBeanDefinition(), id));
@@ -279,7 +290,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
}
}
BeanDefinitionBuilder conversionsBuilder = BeanDefinitionBuilder.rootBeanDefinition(CustomConversions.class);
BeanDefinitionBuilder conversionsBuilder = BeanDefinitionBuilder.rootBeanDefinition(MongoCustomConversions.class);
conversionsBuilder.addConstructorArgValue(converterBeans);
AbstractBeanDefinition conversionsBean = conversionsBuilder.getBeanDefinition();
@@ -327,8 +338,8 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
return beanDef;
}
parserContext.getReaderContext().error(
"Element <converter> must specify 'ref' or contain a bean definition for the converter", element);
parserContext.getReaderContext()
.error("Element <converter> must specify 'ref' or contain a bean definition for the converter", element);
return null;
}
@@ -340,15 +351,15 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
mappingContextStrategyFactoryBuilder.addConstructorArgReference(mappingContextRef);
BeanComponentDefinitionBuilder builder = new BeanComponentDefinitionBuilder(element, context);
context.registerBeanComponent(builder.getComponent(mappingContextStrategyFactoryBuilder,
IS_NEW_STRATEGY_FACTORY_BEAN_NAME));
context.registerBeanComponent(
builder.getComponent(mappingContextStrategyFactoryBuilder, IS_NEW_STRATEGY_FACTORY_BEAN_NAME));
return IS_NEW_STRATEGY_FACTORY_BEAN_NAME;
}
/**
* {@link TypeFilter} that returns {@literal false} in case any of the given delegates matches.
*
*
* @author Oliver Gierke
*/
private static class NegatingFilter implements TypeFilter {
@@ -357,11 +368,13 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
/**
* Creates a new {@link NegatingFilter} with the given delegates.
*
*
* @param filters
*/
public NegatingFilter(TypeFilter... filters) {
Assert.notNull(filters);
Assert.notNull(filters, "TypeFilters must not be null");
this.delegates = new HashSet<TypeFilter>(Arrays.asList(filters));
}
@@ -369,7 +382,8 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
* (non-Javadoc)
* @see org.springframework.core.type.filter.TypeFilter#match(org.springframework.core.type.classreading.MetadataReader, org.springframework.core.type.classreading.MetadataReaderFactory)
*/
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
for (TypeFilter delegate : delegates) {
if (delegate.match(metadataReader, metadataReaderFactory)) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2014 the original author or authors.
* Copyright 2013-2016 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.
@@ -15,24 +15,24 @@
*/
package org.springframework.data.mongodb.config;
import static org.springframework.beans.factory.config.BeanDefinition.*;
import static org.springframework.data.mongodb.config.BeanNames.*;
import java.lang.annotation.Annotation;
import org.springframework.beans.factory.FactoryBean;
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.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
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.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.core.mapping.event.AuditingEventListener;
import org.springframework.data.support.IsNewStrategyFactory;
import org.springframework.util.Assert;
/**
@@ -71,7 +71,6 @@ class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
Assert.notNull(annotationMetadata, "AnnotationMetadata must not be null!");
Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");
defaultDependenciesIfNecessary(registry, annotationMetadata);
super.registerBeanDefinitions(annotationMetadata, registry);
}
@@ -85,7 +84,11 @@ class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
Assert.notNull(configuration, "AuditingConfiguration must not be null!");
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(IsNewAwareAuditingHandler.class);
builder.addConstructorArgReference(MAPPING_CONTEXT_BEAN_NAME);
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(MongoMappingContextLookup.class);
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
builder.addConstructorArgValue(definition.getBeanDefinition());
return configureDefaultAuditHandlerAttributes(configuration, builder);
}
@@ -102,29 +105,58 @@ class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
BeanDefinitionBuilder listenerBeanDefinitionBuilder = BeanDefinitionBuilder
.rootBeanDefinition(AuditingEventListener.class);
listenerBeanDefinitionBuilder.addConstructorArgValue(ParsingUtils.getObjectFactoryBeanDefinition(
getAuditingHandlerBeanName(), registry));
listenerBeanDefinitionBuilder
.addConstructorArgValue(ParsingUtils.getObjectFactoryBeanDefinition(getAuditingHandlerBeanName(), registry));
registerInfrastructureBeanWithId(listenerBeanDefinitionBuilder.getBeanDefinition(),
AuditingEventListener.class.getName(), registry);
}
/**
* Register default bean definitions for a {@link MongoMappingContext} and an {@link IsNewStrategyFactory} in case we
* don't find beans with the assumed names in the registry.
*
* @param registry the {@link BeanDefinitionRegistry} to use to register the components into.
* @param source the source which the registered components shall be registered with
* Simple helper to be able to wire the {@link MappingContext} from a {@link MappingMongoConverter} bean available in
* the application context.
*
* @author Oliver Gierke
*/
private void defaultDependenciesIfNecessary(BeanDefinitionRegistry registry, Object source) {
static class MongoMappingContextLookup
implements FactoryBean<MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty>> {
if (!registry.containsBeanDefinition(MAPPING_CONTEXT_BEAN_NAME)) {
private final MappingMongoConverter converter;
RootBeanDefinition definition = new RootBeanDefinition(MongoMappingContext.class);
definition.setRole(ROLE_INFRASTRUCTURE);
definition.setSource(source);
/**
* Creates a new {@link MongoMappingContextLookup} for the given {@link MappingMongoConverter}.
*
* @param converter must not be {@literal null}.
*/
public MongoMappingContextLookup(MappingMongoConverter converter) {
this.converter = converter;
}
registry.registerBeanDefinition(MAPPING_CONTEXT_BEAN_NAME, definition);
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#getObject()
*/
@Override
public MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> getObject() throws Exception {
return converter.getMappingContext();
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
*/
@Override
public Class<?> getObjectType() {
return MappingContext.class;
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
*/
@Override
public boolean isSingleton() {
return true;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2014 the original author or authors.
* Copyright 2015 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.
@@ -15,29 +15,25 @@
*/
package org.springframework.data.mongodb.config;
import java.util.Map;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.CustomEditorConfigurer;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.config.BeanComponentDefinitionBuilder;
import org.springframework.data.config.ParsingUtils;
import org.springframework.data.mongodb.core.MongoFactoryBean;
import org.springframework.data.mongodb.core.MongoClientFactoryBean;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* Parser for &lt;mongo;gt; definitions.
* Parser for {@code mongo-client} definitions.
*
* @author Mark Pollack
* @author Oliver Gierke
* @author Christoph Strobl
* @since 1.7
*/
public class MongoParser implements BeanDefinitionParser {
public class MongoClientParser implements BeanDefinitionParser {
/*
* (non-Javadoc)
@@ -50,12 +46,13 @@ public class MongoParser implements BeanDefinitionParser {
BeanComponentDefinitionBuilder helper = new BeanComponentDefinitionBuilder(element, parserContext);
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MongoFactoryBean.class);
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MongoClientFactoryBean.class);
ParsingUtils.setPropertyValue(builder, element, "port", "port");
ParsingUtils.setPropertyValue(builder, element, "host", "host");
ParsingUtils.setPropertyValue(builder, element, "write-concern", "writeConcern");
ParsingUtils.setPropertyValue(builder, element, "credentials", "credentials");
MongoParsingUtils.parseMongoOptions(element, builder);
MongoParsingUtils.parseMongoClientOptions(element, builder);
MongoParsingUtils.parseReplicaSet(element, builder);
String defaultedId = StringUtils.hasText(id) ? id : BeanNames.MONGO_BEAN_NAME;
@@ -64,30 +61,25 @@ public class MongoParser implements BeanDefinitionParser {
BeanComponentDefinition mongoComponent = helper.getComponent(builder, defaultedId);
parserContext.registerBeanComponent(mongoComponent);
BeanComponentDefinition serverAddressPropertyEditor = helper.getComponent(registerServerAddressPropertyEditor());
BeanComponentDefinition serverAddressPropertyEditor = helper.getComponent(MongoParsingUtils
.getServerAddressPropertyEditorBuilder());
parserContext.registerBeanComponent(serverAddressPropertyEditor);
BeanComponentDefinition writeConcernPropertyEditor = helper.getComponent(MongoParsingUtils
BeanComponentDefinition writeConcernEditor = helper.getComponent(MongoParsingUtils
.getWriteConcernPropertyEditorBuilder());
parserContext.registerBeanComponent(writeConcernPropertyEditor);
parserContext.registerBeanComponent(writeConcernEditor);
BeanComponentDefinition readPreferenceEditor = helper.getComponent(MongoParsingUtils
.getReadPreferencePropertyEditorBuilder());
parserContext.registerBeanComponent(readPreferenceEditor);
BeanComponentDefinition credentialsEditor = helper.getComponent(MongoParsingUtils
.getMongoCredentialPropertyEditor());
parserContext.registerBeanComponent(credentialsEditor);
parserContext.popAndRegisterContainingComponent();
return mongoComponent.getBeanDefinition();
}
/**
* One should only register one bean definition but want to have the convenience of using
* AbstractSingleBeanDefinitionParser but have the side effect of registering a 'default' property editor with the
* container.
*/
private BeanDefinitionBuilder registerServerAddressPropertyEditor() {
Map<String, String> customEditors = new ManagedMap<String, String>();
customEditors.put("com.mongodb.ServerAddress[]",
"org.springframework.data.mongodb.config.ServerAddressPropertyEditor");
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
builder.addPropertyValue("customEditors", customEditors);
return builder;
}
}

View File

@@ -0,0 +1,193 @@
/*
* Copyright 2016-2017 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
*
* http://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.config;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.data.annotation.Persistent;
import org.springframework.data.convert.CustomConversions;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.context.MappingContextIsNewStrategyFactory;
import org.springframework.data.mapping.context.PersistentEntities;
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.core.convert.MongoCustomConversions;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.support.CachingIsNewStrategyFactory;
import org.springframework.data.support.IsNewStrategyFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* Base class for Spring Data MongoDB to be extended for JavaConfiguration usage.
*
* @author Mark Paluch
* @since 2.0
*/
public abstract class MongoConfigurationSupport {
/**
* Return the name of the database to connect to.
*
* @return must not be {@literal null}.
*/
protected abstract String getDatabaseName();
/**
* Returns the base packages to scan for MongoDB mapped entities at startup. Will return the package name of the
* configuration class' (the concrete class, not this one here) by default. So if you have a
* {@code com.acme.AppConfig} extending {@link MongoConfigurationSupport} the base package will be considered
* {@code com.acme} unless the method is overridden to implement alternate behavior.
*
* @return the base packages to scan for mapped {@link Document} classes or an empty collection to not enable scanning
* for entities.
* @since 1.10
*/
protected Collection<String> getMappingBasePackages() {
Package mappingBasePackage = getClass().getPackage();
return Collections.singleton(mappingBasePackage == null ? null : mappingBasePackage.getName());
}
/**
* Creates a {@link MongoMappingContext} equipped with entity classes scanned from the mapping base package.
*
* @see #getMappingBasePackages()
* @return
* @throws ClassNotFoundException
*/
@Bean
public MongoMappingContext mongoMappingContext() throws ClassNotFoundException {
MongoMappingContext mappingContext = new MongoMappingContext();
mappingContext.setInitialEntitySet(getInitialEntitySet());
mappingContext.setSimpleTypeHolder(customConversions().getSimpleTypeHolder());
mappingContext.setFieldNamingStrategy(fieldNamingStrategy());
return mappingContext;
}
/**
* Returns a {@link MappingContextIsNewStrategyFactory} wrapped into a {@link CachingIsNewStrategyFactory}.
*
* @return
* @throws ClassNotFoundException
*/
@Bean
public IsNewStrategyFactory isNewStrategyFactory() throws ClassNotFoundException {
return new CachingIsNewStrategyFactory(new MappingContextIsNewStrategyFactory(
new PersistentEntities(Arrays.<MappingContext<?, ?>> asList(new MappingContext[] { mongoMappingContext() }))));
}
/**
* Register custom {@link Converter}s in a {@link CustomConversions} object if required. These
* {@link CustomConversions} will be registered with the {@link #mappingMongoConverter()} and
* {@link #mongoMappingContext()}. Returns an empty {@link MongoCustomConversions} instance by default.
*
* @return must not be {@literal null}.
*/
@Bean
public CustomConversions customConversions() {
return new MongoCustomConversions(Collections.emptyList());
}
/**
* Scans the mapping base package for classes annotated with {@link Document}. By default, it scans for entities in
* all packages returned by {@link #getMappingBasePackages()}.
*
* @see #getMappingBasePackages()
* @return
* @throws ClassNotFoundException
*/
protected Set<Class<?>> getInitialEntitySet() throws ClassNotFoundException {
Set<Class<?>> initialEntitySet = new HashSet<Class<?>>();
for (String basePackage : getMappingBasePackages()) {
initialEntitySet.addAll(scanForEntities(basePackage));
}
return initialEntitySet;
}
/**
* Scans the given base package for entities, i.e. MongoDB specific types annotated with {@link Document} and
* {@link Persistent}.
*
* @param basePackage must not be {@literal null}.
* @return
* @throws ClassNotFoundException
* @since 1.10
*/
protected Set<Class<?>> scanForEntities(String basePackage) throws ClassNotFoundException {
if (!StringUtils.hasText(basePackage)) {
return Collections.emptySet();
}
Set<Class<?>> initialEntitySet = new HashSet<Class<?>>();
if (StringUtils.hasText(basePackage)) {
ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(
false);
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Document.class));
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Persistent.class));
for (BeanDefinition candidate : componentProvider.findCandidateComponents(basePackage)) {
initialEntitySet
.add(ClassUtils.forName(candidate.getBeanClassName(), MongoConfigurationSupport.class.getClassLoader()));
}
}
return initialEntitySet;
}
/**
* Configures whether to abbreviate field names for domain objects by configuring a
* {@link CamelCaseAbbreviatingFieldNamingStrategy} on the {@link MongoMappingContext} instance created. For advanced
* customization needs, consider overriding {@link #mappingMongoConverter()}.
*
* @return
*/
protected boolean abbreviateFieldNames() {
return false;
}
/**
* Configures a {@link FieldNamingStrategy} on the {@link MongoMappingContext} instance created.
*
* @return
* @since 1.5
*/
protected FieldNamingStrategy fieldNamingStrategy() {
return abbreviateFieldNames() ? new CamelCaseAbbreviatingFieldNamingStrategy()
: PropertyNameFieldNamingStrategy.INSTANCE;
}
}

View File

@@ -0,0 +1,214 @@
/*
* Copyright 2015-2017 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
*
* http://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.config;
import java.beans.PropertyEditorSupport;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
import com.mongodb.MongoCredential;
/**
* Parse a {@link String} to a Collection of {@link MongoCredential}.
*
* @author Christoph Strobl
* @author Oliver Gierke
* @since 1.7
*/
public class MongoCredentialPropertyEditor extends PropertyEditorSupport {
private static final Pattern GROUP_PATTERN = Pattern.compile("(\\\\?')(.*?)\\1");
private static final String AUTH_MECHANISM_KEY = "uri.authMechanism";
private static final String USERNAME_PASSWORD_DELIMITER = ":";
private static final String DATABASE_DELIMITER = "@";
private static final String OPTIONS_DELIMITER = "?";
private static final String OPTION_VALUE_DELIMITER = "&";
/*
* (non-Javadoc)
* @see java.beans.PropertyEditorSupport#setAsText(java.lang.String)
*/
@Override
public void setAsText(@Nullable String text) throws IllegalArgumentException {
if (!StringUtils.hasText(text)) {
return;
}
List<MongoCredential> credentials = new ArrayList<>();
for (String credentialString : extractCredentialsString(text)) {
String[] userNameAndPassword = extractUserNameAndPassword(credentialString);
String database = extractDB(credentialString);
Properties options = extractOptions(credentialString);
if (!options.isEmpty()) {
if (options.containsKey(AUTH_MECHANISM_KEY)) {
String authMechanism = options.getProperty(AUTH_MECHANISM_KEY);
if (MongoCredential.GSSAPI_MECHANISM.equals(authMechanism)) {
verifyUserNamePresent(userNameAndPassword);
credentials.add(MongoCredential.createGSSAPICredential(userNameAndPassword[0]));
} else if (MongoCredential.MONGODB_CR_MECHANISM.equals(authMechanism)) {
verifyUsernameAndPasswordPresent(userNameAndPassword);
verifyDatabasePresent(database);
credentials.add(MongoCredential.createMongoCRCredential(userNameAndPassword[0], database,
userNameAndPassword[1].toCharArray()));
} else if (MongoCredential.MONGODB_X509_MECHANISM.equals(authMechanism)) {
verifyUserNamePresent(userNameAndPassword);
credentials.add(MongoCredential.createMongoX509Credential(userNameAndPassword[0]));
} else if (MongoCredential.PLAIN_MECHANISM.equals(authMechanism)) {
verifyUsernameAndPasswordPresent(userNameAndPassword);
verifyDatabasePresent(database);
credentials.add(MongoCredential.createPlainCredential(userNameAndPassword[0], database,
userNameAndPassword[1].toCharArray()));
} else if (MongoCredential.SCRAM_SHA_1_MECHANISM.equals(authMechanism)) {
verifyUsernameAndPasswordPresent(userNameAndPassword);
verifyDatabasePresent(database);
credentials.add(MongoCredential.createScramSha1Credential(userNameAndPassword[0], database,
userNameAndPassword[1].toCharArray()));
} else {
throw new IllegalArgumentException(
String.format("Cannot create MongoCredentials for unknown auth mechanism '%s'!", authMechanism));
}
}
} else {
verifyUsernameAndPasswordPresent(userNameAndPassword);
verifyDatabasePresent(database);
credentials.add(
MongoCredential.createCredential(userNameAndPassword[0], database, userNameAndPassword[1].toCharArray()));
}
}
setValue(credentials);
}
private List<String> extractCredentialsString(String source) {
Matcher matcher = GROUP_PATTERN.matcher(source);
List<String> list = new ArrayList<>();
while (matcher.find()) {
String value = StringUtils.trimLeadingCharacter(matcher.group(), '\'');
list.add(StringUtils.trimTrailingCharacter(value, '\''));
}
if (!list.isEmpty()) {
return list;
}
return Arrays.asList(source.split(","));
}
private static String[] extractUserNameAndPassword(String text) {
int index = text.lastIndexOf(DATABASE_DELIMITER);
index = index != -1 ? index : text.lastIndexOf(OPTIONS_DELIMITER);
if (index == -1) {
return new String[] {};
}
return Arrays.stream(text.substring(0, index).split(USERNAME_PASSWORD_DELIMITER))
.map(MongoCredentialPropertyEditor::decodeParameter).toArray(String[]::new);
}
private static String extractDB(String text) {
int dbSeparationIndex = text.lastIndexOf(DATABASE_DELIMITER);
if (dbSeparationIndex == -1) {
return "";
}
String tmp = text.substring(dbSeparationIndex + 1);
int optionsSeparationIndex = tmp.lastIndexOf(OPTIONS_DELIMITER);
return optionsSeparationIndex > -1 ? tmp.substring(0, optionsSeparationIndex) : tmp;
}
private static Properties extractOptions(String text) {
int optionsSeparationIndex = text.lastIndexOf(OPTIONS_DELIMITER);
int dbSeparationIndex = text.lastIndexOf(OPTIONS_DELIMITER);
if (optionsSeparationIndex == -1 || dbSeparationIndex > optionsSeparationIndex) {
return new Properties();
}
Properties properties = new Properties();
for (String option : text.substring(optionsSeparationIndex + 1).split(OPTION_VALUE_DELIMITER)) {
String[] optionArgs = option.split("=");
properties.put(optionArgs[0], optionArgs[1]);
}
return properties;
}
private static void verifyUsernameAndPasswordPresent(String[] source) {
verifyUserNamePresent(source);
if (source.length != 2) {
throw new IllegalArgumentException(
"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'!");
}
}
private static void verifyUserNamePresent(String[] source) {
if (source.length == 0 || !StringUtils.hasText(source[0])) {
throw new IllegalArgumentException("Credentials need to specify username!");
}
}
private static String decodeParameter(String it) {
try {
return URLDecoder.decode(it, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException("o_O UTF-8 not supported!", e);
}
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2011-2014 by the original author(s).
* Copyright 2011-2017 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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,
@@ -18,6 +18,10 @@ package org.springframework.data.mongodb.config;
import static org.springframework.data.config.ParsingUtils.*;
import static org.springframework.data.mongodb.config.MongoParsingUtils.*;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
@@ -26,26 +30,41 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.authentication.UserCredentials;
import org.springframework.data.config.BeanComponentDefinitionBuilder;
import org.springframework.data.mongodb.core.MongoFactoryBean;
import org.springframework.data.mongodb.core.MongoClientFactoryBean;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
import com.mongodb.Mongo;
import com.mongodb.MongoClientURI;
import com.mongodb.MongoURI;
/**
* {@link BeanDefinitionParser} to parse {@code db-factory} elements into {@link BeanDefinition}s.
*
*
* @author Jon Brisbin
* @author Oliver Gierke
* @author Thomas Darimont
* @author Christoph Strobl
* @author Viktor Khoroshko
* @author Mark Paluch
*/
public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
/*
private static final Set<String> MONGO_URI_ALLOWED_ADDITIONAL_ATTRIBUTES;
static {
Set<String> mongoUriAllowedAdditionalAttributes = new HashSet<String>();
mongoUriAllowedAdditionalAttributes.add("id");
mongoUriAllowedAdditionalAttributes.add("write-concern");
MONGO_URI_ALLOWED_ADDITIONAL_ATTRIBUTES = Collections.unmodifiableSet(mongoUriAllowedAdditionalAttributes);
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#resolveId(org.w3c.dom.Element, org.springframework.beans.factory.support.AbstractBeanDefinition, org.springframework.beans.factory.xml.ParserContext)
*/
@@ -57,36 +76,30 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
return StringUtils.hasText(id) ? id : BeanNames.DB_FACTORY_BEAN_NAME;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#parseInternal(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)
*/
@Override
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
BeanComponentDefinitionBuilder helper = new BeanComponentDefinitionBuilder(element, parserContext);
String uri = element.getAttribute("uri");
String mongoRef = element.getAttribute("mongo-ref");
String dbname = element.getAttribute("dbname");
BeanDefinition userCredentials = getUserCredentialsBeanDefinition(element, parserContext);
// Common setup
BeanDefinitionBuilder dbFactoryBuilder = BeanDefinitionBuilder.genericBeanDefinition(SimpleMongoDbFactory.class);
setPropertyValue(dbFactoryBuilder, element, "write-concern", "writeConcern");
if (StringUtils.hasText(uri)) {
if (StringUtils.hasText(mongoRef) || StringUtils.hasText(dbname) || userCredentials != null) {
parserContext.getReaderContext().error("Configure either Mongo URI or details individually!", source);
}
BeanDefinition mongoUri = getMongoUri(element, parserContext);
dbFactoryBuilder.addConstructorArgValue(getMongoUri(uri));
if (mongoUri != null) {
dbFactoryBuilder.addConstructorArgValue(mongoUri);
return getSourceBeanDefinition(dbFactoryBuilder, parserContext, element);
}
BeanComponentDefinitionBuilder helper = new BeanComponentDefinitionBuilder(element, parserContext);
String mongoRef = element.getAttribute("mongo-ref");
String dbname = element.getAttribute("dbname");
// Defaulting
if (StringUtils.hasText(mongoRef)) {
dbFactoryBuilder.addConstructorArgReference(mongoRef);
@@ -95,8 +108,6 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
}
dbFactoryBuilder.addConstructorArgValue(StringUtils.hasText(dbname) ? dbname : "db");
dbFactoryBuilder.addConstructorArgValue(userCredentials);
dbFactoryBuilder.addConstructorArgValue(element.getAttribute("authentication-dbname"));
BeanDefinitionBuilder writeConcernPropertyEditorBuilder = getWriteConcernPropertyEditorBuilder();
@@ -110,14 +121,14 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
/**
* Registers a default {@link BeanDefinition} of a {@link Mongo} instance and returns the name under which the
* {@link Mongo} instance was registered under.
*
*
* @param element must not be {@literal null}.
* @param parserContext must not be {@literal null}.
* @return
*/
private BeanDefinition registerMongoBeanDefinition(Element element, ParserContext parserContext) {
BeanDefinitionBuilder mongoBuilder = BeanDefinitionBuilder.genericBeanDefinition(MongoFactoryBean.class);
BeanDefinitionBuilder mongoBuilder = BeanDefinitionBuilder.genericBeanDefinition(MongoClientFactoryBean.class);
setPropertyValue(mongoBuilder, element, "host");
setPropertyValue(mongoBuilder, element, "port");
@@ -125,36 +136,43 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
}
/**
* Returns a {@link BeanDefinition} for a {@link UserCredentials} object.
*
* @param element
* @return the {@link BeanDefinition} or {@literal null} if neither username nor password given.
* Creates a {@link BeanDefinition} for a {@link MongoURI} or {@link MongoClientURI} depending on configured
* attributes. <br />
* Errors when configured element contains {@literal uri} or {@literal client-uri} along with other attributes except
* {@literal write-concern} and/or {@literal id}.
*
* @param element must not be {@literal null}.
* @param parserContext
* @return {@literal null} in case no client-/uri defined.
*/
private BeanDefinition getUserCredentialsBeanDefinition(Element element, ParserContext context) {
@Nullable
private BeanDefinition getMongoUri(Element element, ParserContext parserContext) {
String username = element.getAttribute("username");
String password = element.getAttribute("password");
boolean hasClientUri = element.hasAttribute("client-uri");
if (!StringUtils.hasText(username) && !StringUtils.hasText(password)) {
if (!hasClientUri && !element.hasAttribute("uri")) {
return null;
}
BeanDefinitionBuilder userCredentialsBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserCredentials.class);
userCredentialsBuilder.addConstructorArgValue(StringUtils.hasText(username) ? username : null);
userCredentialsBuilder.addConstructorArgValue(StringUtils.hasText(password) ? password : null);
int allowedAttributesCount = 1;
for (String attribute : MONGO_URI_ALLOWED_ADDITIONAL_ATTRIBUTES) {
return getSourceBeanDefinition(userCredentialsBuilder, context, element);
}
if (element.hasAttribute(attribute)) {
allowedAttributesCount++;
}
}
/**
* Creates a {@link BeanDefinition} for a {@link MongoURI}.
*
* @param uri
* @return
*/
private BeanDefinition getMongoUri(String uri) {
if (element.getAttributes().getLength() > allowedAttributesCount) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MongoURI.class);
parserContext.getReaderContext().error(
"Configure either " + (hasClientUri ? "Mongo Client URI" : "Mongo URI") + " or details individually!",
parserContext.extractSource(element));
}
Class<?> type = MongoClientURI.class;
String uri = hasClientUri ? element.getAttribute("client-uri") : element.getAttribute("uri");
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(type);
builder.addConstructorArgValue(uri);
return builder.getBeanDefinition();

View File

@@ -1,69 +1,76 @@
/*
* Copyright 2011 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
*
* http://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.config;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.mongodb.core.MongoAdmin;
import org.springframework.data.mongodb.monitor.*;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
public class MongoJmxParser implements BeanDefinitionParser {
public BeanDefinition parse(Element element, ParserContext parserContext) {
String name = element.getAttribute("mongo-ref");
if (!StringUtils.hasText(name)) {
name = "mongo";
}
registerJmxComponents(name, element, parserContext);
return null;
}
protected void registerJmxComponents(String mongoRefName, Element element, ParserContext parserContext) {
Object eleSource = parserContext.extractSource(element);
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
createBeanDefEntry(AssertMetrics.class, compositeDef, mongoRefName, eleSource, parserContext);
createBeanDefEntry(BackgroundFlushingMetrics.class, compositeDef, mongoRefName, eleSource, parserContext);
createBeanDefEntry(BtreeIndexCounters.class, compositeDef, mongoRefName, eleSource, parserContext);
createBeanDefEntry(ConnectionMetrics.class, compositeDef, mongoRefName, eleSource, parserContext);
createBeanDefEntry(GlobalLockMetrics.class, compositeDef, mongoRefName, eleSource, parserContext);
createBeanDefEntry(MemoryMetrics.class, compositeDef, mongoRefName, eleSource, parserContext);
createBeanDefEntry(OperationCounters.class, compositeDef, mongoRefName, eleSource, parserContext);
createBeanDefEntry(ServerInfo.class, compositeDef, mongoRefName, eleSource, parserContext);
createBeanDefEntry(MongoAdmin.class, compositeDef, mongoRefName, eleSource, parserContext);
parserContext.registerComponent(compositeDef);
}
protected void createBeanDefEntry(Class<?> clazz, CompositeComponentDefinition compositeDef, String mongoRefName,
Object eleSource, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
builder.getRawBeanDefinition().setSource(eleSource);
builder.addConstructorArgReference(mongoRefName);
BeanDefinition assertDef = builder.getBeanDefinition();
String assertName = parserContext.getReaderContext().registerWithGeneratedName(assertDef);
compositeDef.addNestedComponent(new BeanComponentDefinition(assertDef, assertName));
}
}
/*
* Copyright 2011-2017 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
*
* http://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.config;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.mongodb.core.MongoAdmin;
import org.springframework.data.mongodb.monitor.*;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* @author Mark Pollack
* @author Thomas Risberg
* @author John Brisbin
* @author Oliver Gierke
* @author Christoph Strobl
*/
public class MongoJmxParser implements BeanDefinitionParser {
public BeanDefinition parse(Element element, ParserContext parserContext) {
String name = element.getAttribute("mongo-ref");
if (!StringUtils.hasText(name)) {
name = BeanNames.MONGO_BEAN_NAME;
}
registerJmxComponents(name, element, parserContext);
return null;
}
protected void registerJmxComponents(String mongoRefName, Element element, ParserContext parserContext) {
Object eleSource = parserContext.extractSource(element);
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
createBeanDefEntry(AssertMetrics.class, compositeDef, mongoRefName, eleSource, parserContext);
createBeanDefEntry(BackgroundFlushingMetrics.class, compositeDef, mongoRefName, eleSource, parserContext);
createBeanDefEntry(BtreeIndexCounters.class, compositeDef, mongoRefName, eleSource, parserContext);
createBeanDefEntry(ConnectionMetrics.class, compositeDef, mongoRefName, eleSource, parserContext);
createBeanDefEntry(GlobalLockMetrics.class, compositeDef, mongoRefName, eleSource, parserContext);
createBeanDefEntry(MemoryMetrics.class, compositeDef, mongoRefName, eleSource, parserContext);
createBeanDefEntry(OperationCounters.class, compositeDef, mongoRefName, eleSource, parserContext);
createBeanDefEntry(ServerInfo.class, compositeDef, mongoRefName, eleSource, parserContext);
createBeanDefEntry(MongoAdmin.class, compositeDef, mongoRefName, eleSource, parserContext);
parserContext.registerComponent(compositeDef);
}
protected void createBeanDefEntry(Class<?> clazz, CompositeComponentDefinition compositeDef, String mongoRefName,
Object eleSource, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
builder.getRawBeanDefinition().setSource(eleSource);
builder.addConstructorArgReference(mongoRefName);
BeanDefinition assertDef = builder.getBeanDefinition();
String assertName = parserContext.getReaderContext().registerWithGeneratedName(assertDef);
compositeDef.addNestedComponent(new BeanComponentDefinition(assertDef, assertName));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2014 the original author or authors.
* Copyright 2011-2017 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.
@@ -22,6 +22,7 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
*
* @author Oliver Gierke
* @author Martin Baumgartner
* @author Christoph Strobl
*/
public class MongoNamespaceHandler extends NamespaceHandlerSupport {
@@ -32,7 +33,7 @@ public class MongoNamespaceHandler extends NamespaceHandlerSupport {
public void init() {
registerBeanDefinitionParser("mapping-converter", new MappingMongoConverterParser());
registerBeanDefinitionParser("mongo", new MongoParser());
registerBeanDefinitionParser("mongo-client", new MongoClientParser());
registerBeanDefinitionParser("db-factory", new MongoDbFactoryParser());
registerBeanDefinitionParser("jmx", new MongoJmxParser());
registerBeanDefinitionParser("auditing", new MongoAuditingBeanDefinitionParser());

View File

@@ -1,106 +1,170 @@
/*
* Copyright 2011-2013 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
*
* http://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.config;
import static org.springframework.data.config.ParsingUtils.*;
import java.util.Map;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.CustomEditorConfigurer;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.data.mongodb.core.MongoOptionsFactoryBean;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
/**
* Utility methods for {@link BeanDefinitionParser} implementations for MongoDB.
*
* @author Mark Pollack
* @author Oliver Gierke
/*
* Copyright 2011-2017 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
*
* http://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.config;
import static org.springframework.data.config.ParsingUtils.*;
import java.util.Map;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.CustomEditorConfigurer;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.data.mongodb.core.MongoClientOptionsFactoryBean;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
/**
* Utility methods for {@link BeanDefinitionParser} implementations for MongoDB.
*
* @author Mark Pollack
* @author Oliver Gierke
* @author Thomas Darimont
*/
abstract class MongoParsingUtils {
private MongoParsingUtils() {
}
/**
* Parses the mongo replica-set element.
*
* @param parserContext the parser context
* @param element the mongo element
* @param mongoBuilder the bean definition builder to populate
* @return
*/
static void parseReplicaSet(Element element, BeanDefinitionBuilder mongoBuilder) {
setPropertyValue(mongoBuilder, element, "replica-set", "replicaSetSeeds");
}
/**
* Parses the mongo:options sub-element. Populates the given attribute factory with the proper attributes.
*
* @return true if parsing actually occured, false otherwise
*/
static boolean parseMongoOptions(Element element, BeanDefinitionBuilder mongoBuilder) {
Element optionsElement = DomUtils.getChildElementByTagName(element, "options");
if (optionsElement == null) {
return false;
}
BeanDefinitionBuilder optionsDefBuilder = BeanDefinitionBuilder
.genericBeanDefinition(MongoOptionsFactoryBean.class);
setPropertyValue(optionsDefBuilder, optionsElement, "connections-per-host", "connectionsPerHost");
setPropertyValue(optionsDefBuilder, optionsElement, "threads-allowed-to-block-for-connection-multiplier",
"threadsAllowedToBlockForConnectionMultiplier");
setPropertyValue(optionsDefBuilder, optionsElement, "max-wait-time", "maxWaitTime");
setPropertyValue(optionsDefBuilder, optionsElement, "connect-timeout", "connectTimeout");
setPropertyValue(optionsDefBuilder, optionsElement, "socket-timeout", "socketTimeout");
setPropertyValue(optionsDefBuilder, optionsElement, "socket-keep-alive", "socketKeepAlive");
setPropertyValue(optionsDefBuilder, optionsElement, "auto-connect-retry", "autoConnectRetry");
setPropertyValue(optionsDefBuilder, optionsElement, "max-auto-connect-retry-time", "maxAutoConnectRetryTime");
setPropertyValue(optionsDefBuilder, optionsElement, "write-number", "writeNumber");
setPropertyValue(optionsDefBuilder, optionsElement, "write-timeout", "writeTimeout");
setPropertyValue(optionsDefBuilder, optionsElement, "write-fsync", "writeFsync");
setPropertyValue(optionsDefBuilder, optionsElement, "slave-ok", "slaveOk");
setPropertyValue(optionsDefBuilder, optionsElement, "ssl", "ssl");
setPropertyReference(optionsDefBuilder, optionsElement, "ssl-socket-factory-ref", "sslSocketFactory");
mongoBuilder.addPropertyValue("mongoOptions", optionsDefBuilder.getBeanDefinition());
return true;
}
/**
* Returns the {@link BeanDefinitionBuilder} to build a {@link BeanDefinition} for a
* {@link WriteConcernPropertyEditor}.
*
* @return
*/
static BeanDefinitionBuilder getWriteConcernPropertyEditorBuilder() {
Map<String, Class<?>> customEditors = new ManagedMap<String, Class<?>>();
customEditors.put("com.mongodb.WriteConcern", WriteConcernPropertyEditor.class);
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
builder.addPropertyValue("customEditors", customEditors);
return builder;
}
}
* @author Christoph Strobl
*/
@SuppressWarnings("deprecation")
abstract class MongoParsingUtils {
private MongoParsingUtils() {}
/**
* Parses the mongo replica-set element.
*
* @param parserContext the parser context
* @param element the mongo element
* @param mongoBuilder the bean definition builder to populate
* @return
*/
static void parseReplicaSet(Element element, BeanDefinitionBuilder mongoBuilder) {
setPropertyValue(mongoBuilder, element, "replica-set", "replicaSetSeeds");
}
/**
* Parses the {@code mongo:client-options} sub-element. Populates the given attribute factory with the proper
* attributes.
*
* @param element must not be {@literal null}.
* @param mongoClientBuilder must not be {@literal null}.
* @return
* @since 1.7
*/
public static boolean parseMongoClientOptions(Element element, BeanDefinitionBuilder mongoClientBuilder) {
Element optionsElement = DomUtils.getChildElementByTagName(element, "client-options");
if (optionsElement == null) {
return false;
}
BeanDefinitionBuilder clientOptionsDefBuilder = BeanDefinitionBuilder
.genericBeanDefinition(MongoClientOptionsFactoryBean.class);
setPropertyValue(clientOptionsDefBuilder, optionsElement, "description", "description");
setPropertyValue(clientOptionsDefBuilder, optionsElement, "min-connections-per-host", "minConnectionsPerHost");
setPropertyValue(clientOptionsDefBuilder, optionsElement, "connections-per-host", "connectionsPerHost");
setPropertyValue(clientOptionsDefBuilder, optionsElement, "threads-allowed-to-block-for-connection-multiplier",
"threadsAllowedToBlockForConnectionMultiplier");
setPropertyValue(clientOptionsDefBuilder, optionsElement, "max-wait-time", "maxWaitTime");
setPropertyValue(clientOptionsDefBuilder, optionsElement, "max-connection-idle-time", "maxConnectionIdleTime");
setPropertyValue(clientOptionsDefBuilder, optionsElement, "max-connection-life-time", "maxConnectionLifeTime");
setPropertyValue(clientOptionsDefBuilder, optionsElement, "connect-timeout", "connectTimeout");
setPropertyValue(clientOptionsDefBuilder, optionsElement, "socket-timeout", "socketTimeout");
setPropertyValue(clientOptionsDefBuilder, optionsElement, "socket-keep-alive", "socketKeepAlive");
setPropertyValue(clientOptionsDefBuilder, optionsElement, "read-preference", "readPreference");
setPropertyValue(clientOptionsDefBuilder, optionsElement, "write-concern", "writeConcern");
setPropertyValue(clientOptionsDefBuilder, optionsElement, "heartbeat-frequency", "heartbeatFrequency");
setPropertyValue(clientOptionsDefBuilder, optionsElement, "min-heartbeat-frequency", "minHeartbeatFrequency");
setPropertyValue(clientOptionsDefBuilder, optionsElement, "heartbeat-connect-timeout", "heartbeatConnectTimeout");
setPropertyValue(clientOptionsDefBuilder, optionsElement, "heartbeat-socket-timeout", "heartbeatSocketTimeout");
setPropertyValue(clientOptionsDefBuilder, optionsElement, "ssl", "ssl");
setPropertyReference(clientOptionsDefBuilder, optionsElement, "ssl-socket-factory-ref", "sslSocketFactory");
setPropertyValue(clientOptionsDefBuilder, optionsElement, "server-selection-timeout", "serverSelectionTimeout");
mongoClientBuilder.addPropertyValue("mongoClientOptions", clientOptionsDefBuilder.getBeanDefinition());
return true;
}
/**
* Returns the {@link BeanDefinitionBuilder} to build a {@link BeanDefinition} for a
* {@link WriteConcernPropertyEditor}.
*
* @return
*/
static BeanDefinitionBuilder getWriteConcernPropertyEditorBuilder() {
Map<String, Class<?>> customEditors = new ManagedMap<String, Class<?>>();
customEditors.put("com.mongodb.WriteConcern", WriteConcernPropertyEditor.class);
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
builder.addPropertyValue("customEditors", customEditors);
return builder;
}
/**
* One should only register one bean definition but want to have the convenience of using
* AbstractSingleBeanDefinitionParser but have the side effect of registering a 'default' property editor with the
* container.
*/
static BeanDefinitionBuilder getServerAddressPropertyEditorBuilder() {
Map<String, String> customEditors = new ManagedMap<String, String>();
customEditors.put("com.mongodb.ServerAddress[]",
"org.springframework.data.mongodb.config.ServerAddressPropertyEditor");
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
builder.addPropertyValue("customEditors", customEditors);
return builder;
}
/**
* Returns the {@link BeanDefinitionBuilder} to build a {@link BeanDefinition} for a
* {@link ReadPreferencePropertyEditor}.
*
* @return
* @since 1.7
*/
static BeanDefinitionBuilder getReadPreferencePropertyEditorBuilder() {
Map<String, Class<?>> customEditors = new ManagedMap<String, Class<?>>();
customEditors.put("com.mongodb.ReadPreference", ReadPreferencePropertyEditor.class);
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
builder.addPropertyValue("customEditors", customEditors);
return builder;
}
/**
* Returns the {@link BeanDefinitionBuilder} to build a {@link BeanDefinition} for a
* {@link MongoCredentialPropertyEditor}.
*
* @return
* @since 1.7
*/
static BeanDefinitionBuilder getMongoCredentialPropertyEditor() {
Map<String, Class<?>> customEditors = new ManagedMap<String, Class<?>>();
customEditors.put("com.mongodb.MongoCredential[]", MongoCredentialPropertyEditor.class);
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
builder.addPropertyValue("customEditors", customEditors);
return builder;
}
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2015-2017 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
*
* http://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.config;
import java.beans.PropertyEditorSupport;
import org.springframework.lang.Nullable;
import com.mongodb.ReadPreference;
/**
* Parse a {@link String} to a {@link ReadPreference}.
*
* @author Christoph Strobl
* @since 1.7
*/
public class ReadPreferencePropertyEditor extends PropertyEditorSupport {
/*
* (non-Javadoc)
* @see java.beans.PropertyEditorSupport#setAsText(java.lang.String)
*/
@Override
public void setAsText(@Nullable String readPreferenceString) throws IllegalArgumentException {
if (readPreferenceString == null) {
return;
}
ReadPreference preference = null;
try {
preference = ReadPreference.valueOf(readPreferenceString);
} catch (IllegalArgumentException ex) {
// ignore this one and try to map it differently
}
if (preference != null) {
setValue(preference);
} else if ("PRIMARY".equalsIgnoreCase(readPreferenceString)) {
setValue(ReadPreference.primary());
} else if ("PRIMARY_PREFERRED".equalsIgnoreCase(readPreferenceString)) {
setValue(ReadPreference.primaryPreferred());
} else if ("SECONDARY".equalsIgnoreCase(readPreferenceString)) {
setValue(ReadPreference.secondary());
} else if ("SECONDARY_PREFERRED".equalsIgnoreCase(readPreferenceString)) {
setValue(ReadPreference.secondaryPreferred());
} else if ("NEAREST".equalsIgnoreCase(readPreferenceString)) {
setValue(ReadPreference.nearest());
} else {
throw new IllegalArgumentException(
String.format("Cannot find matching ReadPreference for %s", readPreferenceString));
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2013 the original author or authors.
* Copyright 2011-2017 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.
@@ -23,6 +23,7 @@ import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -30,10 +31,11 @@ import com.mongodb.ServerAddress;
/**
* Parse a {@link String} to a {@link ServerAddress} array. The format is host1:port1,host2:port2,host3:port3.
*
*
* @author Mark Pollack
* @author Oliver Gierke
* @author Thomas Darimont
* @author Christoph Strobl
*/
public class ServerAddressPropertyEditor extends PropertyEditorSupport {
@@ -49,7 +51,7 @@ public class ServerAddressPropertyEditor extends PropertyEditorSupport {
* @see java.beans.PropertyEditorSupport#setAsText(java.lang.String)
*/
@Override
public void setAsText(String replicaSetString) {
public void setAsText(@Nullable String replicaSetString) {
if (!StringUtils.hasText(replicaSetString)) {
setValue(null);
@@ -78,10 +80,11 @@ public class ServerAddressPropertyEditor extends PropertyEditorSupport {
/**
* Parses the given source into a {@link ServerAddress}.
*
*
* @param source
* @return the
*/
@Nullable
private ServerAddress parseServerAddress(String source) {
if (!StringUtils.hasText(source)) {
@@ -112,7 +115,7 @@ public class ServerAddressPropertyEditor extends PropertyEditorSupport {
/**
* Extract the host and port from the given {@link String}.
*
*
* @param addressAndPortSource must not be {@literal null}.
* @return
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* Copyright 2011-2017 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.
@@ -17,6 +17,9 @@ package org.springframework.data.mongodb.config;
import java.beans.PropertyEditorSupport;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
import com.mongodb.WriteConcern;
/**
@@ -26,6 +29,7 @@ import com.mongodb.WriteConcern;
* string value.
*
* @author Mark Pollack
* @author Christoph Strobl
*/
public class WriteConcernPropertyEditor extends PropertyEditorSupport {
@@ -33,7 +37,11 @@ public class WriteConcernPropertyEditor extends PropertyEditorSupport {
* Parse a string to a List<ServerAddress>
*/
@Override
public void setAsText(String writeConcernString) {
public void setAsText(@Nullable String writeConcernString) {
if (!StringUtils.hasText(writeConcernString)) {
return;
}
WriteConcern writeConcern = WriteConcern.valueOf(writeConcernString);
if (writeConcern != null) {

View File

@@ -1,5 +1,6 @@
/**
* Spring XML namespace configuration for MongoDB specific repositories.
*/
@org.springframework.lang.NonNullApi
package org.springframework.data.mongodb.config;

View File

@@ -0,0 +1,145 @@
/*
* Copyright 2015-2017 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
*
* http://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.List;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
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
* {@link #execute()}.
*
* @author Tobias Trelle
* @author Oliver Gierke
* @since 1.9
*/
public interface BulkOperations {
/**
* Mode for bulk operation.
**/
enum BulkMode {
/** Perform bulk operations in sequence. The first error will cancel processing. */
ORDERED,
/** Perform bulk operations in parallel. Processing will continue on errors. */
UNORDERED
};
/**
* Add a single insert to the bulk operation.
*
* @param documents the document to insert, must not be {@literal null}.
* @return the current {@link BulkOperations} instance with the insert added, will never be {@literal null}.
*/
BulkOperations insert(Object documents);
/**
* Add a list of inserts to the bulk operation.
*
* @param documents List of documents to insert, must not be {@literal null}.
* @return the current {@link BulkOperations} instance with the insert added, will never be {@literal null}.
*/
BulkOperations insert(List<? extends Object> documents);
/**
* Add a single update to the bulk operation. For the update request, only the first matching document is updated.
*
* @param query update criteria, must not be {@literal null}.
* @param update {@link Update} operation to perform, must not be {@literal null}.
* @return the current {@link BulkOperations} instance with the update added, will never be {@literal null}.
*/
BulkOperations updateOne(Query query, Update update);
/**
* Add a list of updates to the bulk operation. For each update request, only the first matching document is updated.
*
* @param updates Update operations to perform.
* @return the current {@link BulkOperations} instance with the update added, will never be {@literal null}.
*/
BulkOperations updateOne(List<Pair<Query, Update>> updates);
/**
* Add a single update to the bulk operation. For the update request, all matching documents are updated.
*
* @param query Update criteria.
* @param update Update operation to perform.
* @return the current {@link BulkOperations} instance with the update added, will never be {@literal null}.
*/
BulkOperations updateMulti(Query query, Update update);
/**
* Add a list of updates to the bulk operation. For each update request, all matching documents are updated.
*
* @param updates Update operations to perform.
* @return The bulk operation.
* @return the current {@link BulkOperations} instance with the update added, will never be {@literal null}.
*/
BulkOperations updateMulti(List<Pair<Query, Update>> updates);
/**
* Add a single upsert to the bulk operation. An upsert is an update if the set of matching documents is not empty,
* else an insert.
*
* @param query Update criteria.
* @param update Update operation to perform.
* @return The bulk operation.
* @return the current {@link BulkOperations} instance with the update added, will never be {@literal null}.
*/
BulkOperations upsert(Query query, Update update);
/**
* Add a list of upserts to the bulk operation. An upsert is an update if the set of matching documents is not empty,
* else an insert.
*
* @param updates Updates/insert operations to perform.
* @return The bulk operation.
* @return the current {@link BulkOperations} instance with the update added, will never be {@literal null}.
*/
BulkOperations upsert(List<Pair<Query, Update>> updates);
/**
* Add a single remove operation to the bulk operation.
*
* @param remove the {@link Query} to select the documents to be removed, must not be {@literal null}.
* @return the current {@link BulkOperations} instance with the removal added, will never be {@literal null}.
*/
BulkOperations remove(Query remove);
/**
* Add a list of remove operations to the bulk operation.
*
* @param removes the remove operations to perform, must not be {@literal null}.
* @return the current {@link BulkOperations} instance with the removal added, will never be {@literal null}.
*/
BulkOperations remove(List<Query> removes);
/**
* Execute all bulk operations using the default write concern.
*
* @return Result of the bulk operation providing counters for inserts/updates etc.
* @throws org.springframework.data.mongodb.BulkOperationException if an error occurred during bulk processing.
*/
BulkWriteResult execute();
}

View File

@@ -1,26 +1,46 @@
/*
* Copyright 2010-2011 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core;
import com.mongodb.DBCollection;
import com.mongodb.MongoException;
import org.springframework.dao.DataAccessException;
public interface CollectionCallback<T> {
T doInCollection(DBCollection collection) throws MongoException, DataAccessException;
}
/*
* Copyright 2010-2017 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
*
* http://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.bson.Document;
import org.springframework.dao.DataAccessException;
import org.springframework.lang.Nullable;
import com.mongodb.MongoException;
import com.mongodb.client.MongoCollection;
/**
* Callback interface for executing actions against a {@link MongoCollection}.
*
* @author Mark Pollak
* @author Grame Rocher
* @author Oliver Gierke
* @author John Brisbin
* @auhtor Christoph Strobl
* @since 1.0
*/
public interface CollectionCallback<T> {
/**
* @param collection never {@literal null}.
* @return can be {@literal null}.
* @throws MongoException
* @throws DataAccessException
*/
@Nullable
T doInCollection(MongoCollection<Document> collection) throws MongoException, DataAccessException;
}

View File

@@ -1,70 +1,166 @@
/*
* Copyright 2010-2011 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
*
* http://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;
/**
* Provides a simple wrapper to encapsulate the variety of settings you can use when creating a collection.
*
* @author Thomas Risberg
*/
public class CollectionOptions {
private Integer maxDocuments;
private Integer size;
private Boolean capped;
/**
* Constructs a new <code>CollectionOptions</code> instance.
*
* @param size the collection size in bytes, this data space is preallocated
* @param maxDocuments the maximum number of documents in the collection.
* @param capped true to created a "capped" collection (fixed size with auto-FIFO behavior based on insertion order),
* false otherwise.
*/
public CollectionOptions(Integer size, Integer maxDocuments, Boolean capped) {
super();
this.maxDocuments = maxDocuments;
this.size = size;
this.capped = capped;
}
public Integer getMaxDocuments() {
return maxDocuments;
}
public void setMaxDocuments(Integer maxDocuments) {
this.maxDocuments = maxDocuments;
}
public Integer getSize() {
return size;
}
public void setSize(Integer size) {
this.size = size;
}
public Boolean getCapped() {
return capped;
}
public void setCapped(Boolean capped) {
this.capped = capped;
}
}
/*
* Copyright 2010-2017 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
*
* http://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;
import org.springframework.util.Assert;
/**
* Provides a simple wrapper to encapsulate the variety of settings you can use when creating a collection.
*
* @author Thomas Risberg
* @author Christoph Strobl
* @author Mark Paluch
*/
public class CollectionOptions {
private @Nullable Long maxDocuments;
private @Nullable Long size;
private @Nullable Boolean capped;
private @Nullable Collation collation;
/**
* Constructs a new <code>CollectionOptions</code> instance.
*
* @param size the collection size in bytes, this data space is preallocated. Can be {@literal null}.
* @param maxDocuments the maximum number of documents in the collection. Can be {@literal null}.
* @param capped true to created a "capped" collection (fixed size with auto-FIFO behavior based on insertion order),
* false otherwise. Can be {@literal null}.
* @deprecated since 2.0 please use {@link CollectionOptions#empty()} as entry point.
*/
@Deprecated
public CollectionOptions(@Nullable Long size, @Nullable Long maxDocuments, @Nullable Boolean capped) {
this(size, maxDocuments, capped, null);
}
private CollectionOptions(@Nullable Long size, @Nullable Long maxDocuments, @Nullable Boolean capped,
@Nullable Collation collation) {
this.maxDocuments = maxDocuments;
this.size = size;
this.capped = capped;
this.collation = collation;
}
/**
* Create new {@link CollectionOptions} by just providing the {@link Collation} to use.
*
* @param collation must not be {@literal null}.
* @return new {@link CollectionOptions}.
* @since 2.0
*/
public static CollectionOptions just(Collation collation) {
Assert.notNull(collation, "Collation must not be null!");
return new CollectionOptions(null, null, null, collation);
}
/**
* Create new empty {@link CollectionOptions}.
*
* @return new {@link CollectionOptions}.
* @since 2.0
*/
public static CollectionOptions empty() {
return new CollectionOptions(null, null, null, null);
}
/**
* 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(int)}.
*
* @return new {@link CollectionOptions}.
* @since 2.0
*/
public CollectionOptions capped() {
return new CollectionOptions(size, maxDocuments, true, collation);
}
/**
* Create new {@link CollectionOptions} with already given settings and {@code maxDocuments} set to given value.
*
* @param maxDocuments can be {@literal null}.
* @return new {@link CollectionOptions}.
* @since 2.0
*/
public CollectionOptions maxDocuments(long maxDocuments) {
return new CollectionOptions(size, maxDocuments, capped, collation);
}
/**
* Create new {@link CollectionOptions} with already given settings and {@code size} set to given value.
*
* @param size can be {@literal null}.
* @return new {@link CollectionOptions}.
* @since 2.0
*/
public CollectionOptions size(long size) {
return new CollectionOptions(size, maxDocuments, capped, collation);
}
/**
* Create new {@link CollectionOptions} with already given settings and {@code collation} set to given value.
*
* @param collation can be {@literal null}.
* @return new {@link CollectionOptions}.
* @since 2.0
*/
public CollectionOptions collation(@Nullable Collation collation) {
return new CollectionOptions(size, maxDocuments, capped, collation);
}
/**
* Get the max number of documents the collection should be limited to.
*
* @return {@link Optional#empty()} if not set.
*/
public Optional<Long> getMaxDocuments() {
return Optional.ofNullable(maxDocuments);
}
/**
* Get the {@literal size} in bytes the collection should be limited to.
*
* @return {@link Optional#empty()} if not set.
*/
public Optional<Long> getSize() {
return Optional.ofNullable(size);
}
/**
* Get if the collection should be capped.
*
* @return {@link Optional#empty()} if not set.
* @since 2.0
*/
public Optional<Boolean> getCapped() {
return Optional.ofNullable(capped);
}
/**
* Get the {@link Collation} settings.
*
* @return {@link Optional#empty()} if not set.
* @since 2.0
*/
public Optional<Collation> getCollation() {
return Optional.ofNullable(collation);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2016 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.
@@ -15,19 +15,22 @@
*/
package org.springframework.data.mongodb.core;
import com.mongodb.DBCursor;
import org.bson.Document;
import com.mongodb.client.FindIterable;
/**
* Simple callback interface to allow customization of a {@link DBCursor}.
* Simple callback interface to allow customization of a {@link FindIterable}.
*
* @author Oliver Gierke
* @author Christoph Strobl
*/
interface CursorPreparer {
/**
* Prepare the given cursor (apply limits, skips and so on). Returns th eprepared cursor.
* Prepare the given cursor (apply limits, skips and so on). Returns the prepared cursor.
*
* @param cursor
*/
DBCursor prepare(DBCursor cursor);
FindIterable<Document> prepare(FindIterable<Document> cursor);
}

View File

@@ -1,25 +1,44 @@
/*
* Copyright 2010-2011 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core;
import com.mongodb.DB;
import com.mongodb.MongoException;
import org.springframework.dao.DataAccessException;
public interface DbCallback<T> {
T doInDB(DB db) throws MongoException, DataAccessException;
}
/*
* Copyright 2010-2017 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
*
* http://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.dao.DataAccessException;
import org.springframework.lang.Nullable;
import com.mongodb.MongoException;
import com.mongodb.client.MongoDatabase;
/**
* Callback interface for executing actions against a {@link MongoDatabase}.
*
* @author Mark Pollak
* @author Graeme Rocher
* @author Thomas Risberg
* @author Oliver Gierke
* @author John Brisbin
* @author Christoph Strobl
*/
public interface DbCallback<T> {
/**
* @param db must not be {@literal null}.
* @return can be {@literal null}.
* @throws MongoException
* @throws DataAccessException
*/
@Nullable
T doInDB(MongoDatabase db) throws MongoException, DataAccessException;
}

View File

@@ -1,66 +0,0 @@
package org.springframework.data.mongodb.core;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.mongodb.DB;
import org.springframework.transaction.support.ResourceHolderSupport;
import org.springframework.util.Assert;
class DbHolder extends ResourceHolderSupport {
private static final Object DEFAULT_KEY = new Object();
private final Map<Object, DB> dbMap = new ConcurrentHashMap<Object, DB>();
public DbHolder(DB db) {
addDB(db);
}
public DbHolder(Object key, DB db) {
addDB(key, db);
}
public DB getDB() {
return getDB(DEFAULT_KEY);
}
public DB getDB(Object key) {
return this.dbMap.get(key);
}
public DB getAnyDB() {
if (!this.dbMap.isEmpty()) {
return this.dbMap.values().iterator().next();
}
return null;
}
public void addDB(DB session) {
addDB(DEFAULT_KEY, session);
}
public void addDB(Object key, DB session) {
Assert.notNull(key, "Key must not be null");
Assert.notNull(session, "DB must not be null");
this.dbMap.put(key, session);
}
public DB removeDB(Object key) {
return this.dbMap.remove(key);
}
public boolean containsDB(DB session) {
return this.dbMap.containsValue(session);
}
public boolean isEmpty() {
return this.dbMap.isEmpty();
}
public boolean doesNotHoldNonDefaultDB() {
synchronized (this.dbMap) {
return this.dbMap.isEmpty() || (this.dbMap.size() == 1 && this.dbMap.containsKey(DEFAULT_KEY));
}
}
}

View File

@@ -0,0 +1,395 @@
/*
* Copyright 2015-2017 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
*
* http://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 lombok.NonNull;
import lombok.Value;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.mongodb.core.convert.QueryMapper;
import org.springframework.data.mongodb.core.convert.UpdateMapper;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.query.Collation;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.util.Pair;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.mongodb.BulkWriteException;
import com.mongodb.WriteConcern;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.BulkWriteOptions;
import com.mongodb.client.model.DeleteManyModel;
import com.mongodb.client.model.DeleteOneModel;
import com.mongodb.client.model.DeleteOptions;
import com.mongodb.client.model.InsertOneModel;
import com.mongodb.client.model.UpdateManyModel;
import com.mongodb.client.model.UpdateOneModel;
import com.mongodb.client.model.UpdateOptions;
import com.mongodb.client.model.WriteModel;
/**
* Default implementation for {@link BulkOperations}.
*
* @author Tobias Trelle
* @author Oliver Gierke
* @author Christoph Strobl
* @author Mark Paluch
* @since 1.9
*/
class DefaultBulkOperations implements BulkOperations {
private final MongoOperations mongoOperations;
private final String collectionName;
private final BulkOperationContext bulkOperationContext;
private final List<WriteModel<Document>> models = new ArrayList<>();
private PersistenceExceptionTranslator exceptionTranslator;
private @Nullable WriteConcern defaultWriteConcern;
private BulkWriteOptions bulkOptions;
/**
* Creates a new {@link DefaultBulkOperations} for the given {@link MongoOperations}, collection name and
* {@link BulkOperationContext}.
*
* @param mongoOperations must not be {@literal null}.
* @param collectionName must not be {@literal null}.
* @param bulkOperationContext must not be {@literal null}.
* @since 2.0
*/
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!");
this.mongoOperations = mongoOperations;
this.collectionName = collectionName;
this.bulkOperationContext = bulkOperationContext;
this.exceptionTranslator = new MongoExceptionTranslator();
this.bulkOptions = getBulkWriteOptions(bulkOperationContext.getBulkMode());
}
/**
* Configures the {@link PersistenceExceptionTranslator} to be used. Defaults to {@link MongoExceptionTranslator}.
*
* @param exceptionTranslator can be {@literal null}.
*/
public void setExceptionTranslator(@Nullable PersistenceExceptionTranslator exceptionTranslator) {
this.exceptionTranslator = exceptionTranslator == null ? new MongoExceptionTranslator() : exceptionTranslator;
}
/**
* Configures the default {@link WriteConcern} to be used. Defaults to {@literal null}.
*
* @param defaultWriteConcern can be {@literal null}.
*/
void setDefaultWriteConcern(@Nullable WriteConcern defaultWriteConcern) {
this.defaultWriteConcern = defaultWriteConcern;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.BulkOperations#insert(java.lang.Object)
*/
@Override
public BulkOperations insert(Object document) {
Assert.notNull(document, "Document must not be null!");
if (document instanceof Document) {
models.add(new InsertOneModel<>((Document) document));
return this;
}
Document sink = new Document();
mongoOperations.getConverter().write(document, sink);
models.add(new InsertOneModel<>(sink));
return this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.BulkOperations#insert(java.util.List)
*/
@Override
public BulkOperations insert(List<? extends Object> documents) {
Assert.notNull(documents, "Documents must not be null!");
documents.forEach(this::insert);
return this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.BulkOperations#updateOne(org.springframework.data.mongodb.core.query.Query, org.springframework.data.mongodb.core.query.Update)
*/
@Override
@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!");
return updateOne(Collections.singletonList(Pair.of(query, update)));
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.BulkOperations#updateOne(java.util.List)
*/
@Override
public BulkOperations updateOne(List<Pair<Query, Update>> updates) {
Assert.notNull(updates, "Updates must not be null!");
for (Pair<Query, Update> update : updates) {
update(update.getFirst(), update.getSecond(), false, false);
}
return this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.BulkOperations#updateMulti(org.springframework.data.mongodb.core.query.Query, org.springframework.data.mongodb.core.query.Update)
*/
@Override
@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!");
return updateMulti(Collections.singletonList(Pair.of(query, update)));
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.BulkOperations#updateMulti(java.util.List)
*/
@Override
public BulkOperations updateMulti(List<Pair<Query, Update>> updates) {
Assert.notNull(updates, "Updates must not be null!");
for (Pair<Query, Update> update : updates) {
update(update.getFirst(), update.getSecond(), false, true);
}
return this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.BulkOperations#upsert(org.springframework.data.mongodb.core.query.Query, org.springframework.data.mongodb.core.query.Update)
*/
@Override
public BulkOperations upsert(Query query, Update update) {
return update(query, update, true, true);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.BulkOperations#upsert(java.util.List)
*/
@Override
public BulkOperations upsert(List<Pair<Query, Update>> updates) {
for (Pair<Query, Update> update : updates) {
upsert(update.getFirst(), update.getSecond());
}
return this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.BulkOperations#remove(org.springframework.data.mongodb.core.query.Query)
*/
@Override
public BulkOperations remove(Query query) {
Assert.notNull(query, "Query must not be null!");
DeleteOptions deleteOptions = new DeleteOptions();
query.getCollation().map(Collation::toMongoCollation).ifPresent(deleteOptions::collation);
models.add(new DeleteManyModel<>(query.getQueryObject(), deleteOptions));
return this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.BulkOperations#remove(java.util.List)
*/
@Override
public BulkOperations remove(List<Query> removes) {
Assert.notNull(removes, "Removals must not be null!");
for (Query query : removes) {
remove(query);
}
return this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.BulkOperations#executeBulk()
*/
@Override
public com.mongodb.bulk.BulkWriteResult execute() {
try {
MongoCollection<Document> collection = mongoOperations.getCollection(collectionName);
if (defaultWriteConcern != null) {
collection = collection.withWriteConcern(defaultWriteConcern);
}
return collection.bulkWrite(models.stream().map(this::mapWriteModel).collect(Collectors.toList()), bulkOptions);
} catch (BulkWriteException o_O) {
DataAccessException toThrow = exceptionTranslator.translateExceptionIfPossible(o_O);
throw toThrow == null ? o_O : toThrow;
} finally {
this.bulkOptions = getBulkWriteOptions(bulkOperationContext.getBulkMode());
}
}
/**
* Performs update and upsert bulk operations.
*
* @param query the {@link Query} to determine documents to update.
* @param update the {@link Update} to perform, must not be {@literal null}.
* @param upsert whether to upsert.
* @param multi whether to issue a multi-update.
* @return the {@link BulkOperations} with the update registered.
*/
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!");
UpdateOptions options = new UpdateOptions();
options.upsert(upsert);
query.getCollation().map(Collation::toMongoCollation).ifPresent(options::collation);
if (multi) {
models.add(new UpdateManyModel<>(query.getQueryObject(), update.getUpdateObject(), options));
} else {
models.add(new UpdateOneModel<>(query.getQueryObject(), update.getUpdateObject(), options));
}
return this;
}
private WriteModel<Document> mapWriteModel(WriteModel<Document> writeModel) {
if (writeModel instanceof UpdateOneModel) {
UpdateOneModel<Document> model = (UpdateOneModel<Document>) writeModel;
return new UpdateOneModel<>(getMappedQuery(model.getFilter()), getMappedUpdate(model.getUpdate()),
model.getOptions());
}
if (writeModel instanceof UpdateManyModel) {
UpdateManyModel<Document> model = (UpdateManyModel<Document>) writeModel;
return new UpdateManyModel<>(getMappedQuery(model.getFilter()), getMappedUpdate(model.getUpdate()),
model.getOptions());
}
if (writeModel instanceof DeleteOneModel) {
DeleteOneModel<Document> model = (DeleteOneModel<Document>) writeModel;
return new DeleteOneModel<>(getMappedQuery(model.getFilter()), model.getOptions());
}
if (writeModel instanceof DeleteManyModel) {
DeleteManyModel<Document> model = (DeleteManyModel<Document>) writeModel;
return new DeleteManyModel<>(getMappedQuery(model.getFilter()), model.getOptions());
}
return writeModel;
}
private Bson getMappedUpdate(Bson update) {
return bulkOperationContext.getUpdateMapper().getMappedObject(update, bulkOperationContext.getEntity());
}
private Bson getMappedQuery(Bson query) {
return bulkOperationContext.getQueryMapper().getMappedObject(query, bulkOperationContext.getEntity());
}
private static BulkWriteOptions getBulkWriteOptions(BulkMode bulkMode) {
BulkWriteOptions options = new BulkWriteOptions();
switch (bulkMode) {
case ORDERED:
return options.ordered(true);
case UNORDERED:
return options.ordered(false);
}
throw new IllegalStateException("BulkMode was null!");
}
/**
* {@link BulkOperationContext} holds information about
* {@link org.springframework.data.mongodb.core.BulkOperations.BulkMode} the entity in use as well as references to
* {@link QueryMapper} and {@link UpdateMapper}.
*
* @author Christoph Strobl
* @since 2.0
*/
@Value
static class BulkOperationContext {
@NonNull BulkMode bulkMode;
@NonNull Optional<? extends MongoPersistentEntity<?>> entity;
@NonNull QueryMapper queryMapper;
@NonNull UpdateMapper updateMapper;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2014 the original author or authors.
* Copyright 2011-2017 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.
@@ -15,90 +15,137 @@
*/
package org.springframework.data.mongodb.core;
import static org.springframework.data.domain.Sort.Direction.*;
import static org.springframework.data.mongodb.core.MongoTemplate.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.bson.Document;
import org.springframework.dao.DataAccessException;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.convert.QueryMapper;
import org.springframework.data.mongodb.core.index.IndexDefinition;
import org.springframework.data.mongodb.core.index.IndexField;
import org.springframework.data.mongodb.core.index.IndexInfo;
import org.springframework.data.mongodb.core.index.IndexOperations;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.MongoException;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.model.IndexOptions;
/**
* Default implementation of {@link IndexOperations}.
*
*
* @author Mark Pollack
* @author Oliver Gierke
* @author Komi Innocent
* @author Christoph Strobl
* @author Mark Paluch
*/
public class DefaultIndexOperations implements IndexOperations {
private static final Double ONE = Double.valueOf(1);
private static final Double MINUS_ONE = Double.valueOf(-1);
private static final Collection<String> TWO_D_IDENTIFIERS = Arrays.asList("2d", "2dsphere");
private static final String PARTIAL_FILTER_EXPRESSION_KEY = "partialFilterExpression";
private final MongoOperations mongoOperations;
private final MongoDbFactory mongoDbFactory;
private final String collectionName;
private final QueryMapper mapper;
private final @Nullable Class<?> type;
/**
* Creates a new {@link DefaultIndexOperations}.
*
* @param mongoOperations must not be {@literal null}.
*
* @param mongoDbFactory must not be {@literal null}.
* @param collectionName must not be {@literal null}.
* @param queryMapper must not be {@literal null}.
*/
public DefaultIndexOperations(MongoOperations mongoOperations, String collectionName) {
public DefaultIndexOperations(MongoDbFactory mongoDbFactory, String collectionName, QueryMapper queryMapper) {
this(mongoDbFactory, collectionName, queryMapper, null);
}
Assert.notNull(mongoOperations, "MongoOperations must not be null!");
/**
* Creates a new {@link DefaultIndexOperations}.
*
* @param mongoDbFactory must not be {@literal null}.
* @param collectionName must not be {@literal null}.
* @param queryMapper must not be {@literal null}.
* @param type Type used for mapping potential partial index filter expression. Can be {@literal null}.
* @since 1.10
*/
public DefaultIndexOperations(MongoDbFactory 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!");
this.mongoOperations = mongoOperations;
this.mongoDbFactory = mongoDbFactory;
this.collectionName = collectionName;
this.mapper = queryMapper;
this.type = type;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.IndexOperations#ensureIndex(org.springframework.data.mongodb.core.index.IndexDefinition)
* @see org.springframework.data.mongodb.core.index.IndexOperations#ensureIndex(org.springframework.data.mongodb.core.index.IndexDefinition)
*/
public void ensureIndex(final IndexDefinition indexDefinition) {
mongoOperations.execute(collectionName, new CollectionCallback<Object>() {
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
DBObject indexOptions = indexDefinition.getIndexOptions();
if (indexOptions != null) {
collection.ensureIndex(indexDefinition.getIndexKeys(), indexOptions);
} else {
collection.ensureIndex(indexDefinition.getIndexKeys());
}
return null;
public String ensureIndex(final IndexDefinition indexDefinition) {
return execute(collection -> {
Document indexOptions = indexDefinition.getIndexOptions();
IndexOptions ops = IndexConverters.indexDefinitionToIndexOptionsConverter().convert(indexDefinition);
if (indexOptions.containsKey(PARTIAL_FILTER_EXPRESSION_KEY)) {
Assert.isInstanceOf(Document.class, indexOptions.get(PARTIAL_FILTER_EXPRESSION_KEY));
ops.partialFilterExpression(mapper.getMappedObject((Document) indexOptions.get(PARTIAL_FILTER_EXPRESSION_KEY),
lookupPersistentEntity(type, collectionName)));
}
return collection.createIndex(indexDefinition.getIndexKeys(), ops);
});
}
@Nullable
private MongoPersistentEntity<?> lookupPersistentEntity(@Nullable Class<?> entityType, String collection) {
if (entityType != null) {
return mapper.getMappingContext().getRequiredPersistentEntity(entityType);
}
Collection<? extends MongoPersistentEntity<?>> entities = mapper.getMappingContext().getPersistentEntities();
for (MongoPersistentEntity<?> entity : entities) {
if (entity.getCollection().equals(collection)) {
return entity;
}
}
return null;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.IndexOperations#dropIndex(java.lang.String)
* @see org.springframework.data.mongodb.core.index.IndexOperations#dropIndex(java.lang.String)
*/
public void dropIndex(final String name) {
mongoOperations.execute(collectionName, new CollectionCallback<Void>() {
public Void doInCollection(DBCollection collection) throws MongoException, DataAccessException {
collection.dropIndex(name);
return null;
}
execute(collection -> {
collection.dropIndex(name);
return null;
});
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.IndexOperations#dropAllIndexes()
* @see org.springframework.data.mongodb.core.index.IndexOperations#dropAllIndexes()
*/
public void dropAllIndexes() {
dropIndex("*");
@@ -106,76 +153,45 @@ public class DefaultIndexOperations implements IndexOperations {
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.IndexOperations#resetIndexCache()
*/
public void resetIndexCache() {
mongoOperations.execute(collectionName, new CollectionCallback<Void>() {
public Void doInCollection(DBCollection collection) throws MongoException, DataAccessException {
collection.resetIndexCache();
return null;
}
});
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.IndexOperations#getIndexInfo()
* @see org.springframework.data.mongodb.core.index.IndexOperations#getIndexInfo()
*/
public List<IndexInfo> getIndexInfo() {
return mongoOperations.execute(collectionName, new CollectionCallback<List<IndexInfo>>() {
public List<IndexInfo> doInCollection(DBCollection collection) throws MongoException, DataAccessException {
List<DBObject> dbObjectList = collection.getIndexInfo();
return getIndexData(dbObjectList);
return execute(new CollectionCallback<List<IndexInfo>>() {
public List<IndexInfo> doInCollection(MongoCollection<Document> collection)
throws MongoException, DataAccessException {
MongoCursor<Document> cursor = collection.listIndexes(Document.class).iterator();
return getIndexData(cursor);
}
private List<IndexInfo> getIndexData(List<DBObject> dbObjectList) {
private List<IndexInfo> getIndexData(MongoCursor<Document> cursor) {
List<IndexInfo> indexInfoList = new ArrayList<IndexInfo>();
for (DBObject ix : dbObjectList) {
while (cursor.hasNext()) {
DBObject keyDbObject = (DBObject) ix.get("key");
int numberOfElements = keyDbObject.keySet().size();
List<IndexField> indexFields = new ArrayList<IndexField>(numberOfElements);
for (String key : keyDbObject.keySet()) {
Object value = keyDbObject.get(key);
if (TWO_D_IDENTIFIERS.contains(value)) {
indexFields.add(IndexField.geo(key));
} else if ("text".equals(value)) {
DBObject weights = (DBObject) ix.get("weights");
for (String fieldName : weights.keySet()) {
indexFields.add(IndexField.text(fieldName, Float.valueOf(weights.get(fieldName).toString())));
}
} else {
Double keyValue = new Double(value.toString());
if (ONE.equals(keyValue)) {
indexFields.add(IndexField.create(key, ASC));
} else if (MINUS_ONE.equals(keyValue)) {
indexFields.add(IndexField.create(key, DESC));
}
}
}
String name = ix.get("name").toString();
boolean unique = ix.containsField("unique") ? (Boolean) ix.get("unique") : false;
boolean dropDuplicates = ix.containsField("dropDups") ? (Boolean) ix.get("dropDups") : false;
boolean sparse = ix.containsField("sparse") ? (Boolean) ix.get("sparse") : false;
String language = ix.containsField("default_language") ? (String) ix.get("default_language") : "";
indexInfoList.add(new IndexInfo(indexFields, name, unique, dropDuplicates, sparse, language));
Document ix = cursor.next();
IndexInfo indexInfo = IndexConverters.documentToIndexInfoConverter().convert(ix);
indexInfoList.add(indexInfo);
}
return indexInfoList;
}
});
}
@Nullable
public <T> T execute(CollectionCallback<T> callback) {
Assert.notNull(callback, "CollectionCallback must not be null!");
try {
MongoCollection<Document> collection = mongoDbFactory.getDb().getCollection(collectionName);
return callback.doInCollection(collection);
} catch (RuntimeException e) {
throw potentiallyConvertRuntimeException(e, mongoDbFactory.getExceptionTranslator());
}
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2016-2017 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
*
* http://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.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.convert.QueryMapper;
import org.springframework.data.mongodb.core.index.IndexOperations;
import org.springframework.data.mongodb.core.index.IndexOperationsProvider;
/**
* {@link IndexOperationsProvider} to obtain {@link IndexOperations} from a given {@link MongoDbFactory}.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.0
*/
class DefaultIndexOperationsProvider implements IndexOperationsProvider {
private final MongoDbFactory mongoDbFactory;
private final QueryMapper mapper;
/**
* @param mongoDbFactory must not be {@literal null}.
* @param mapper must not be {@literal null}.
*/
DefaultIndexOperationsProvider(MongoDbFactory mongoDbFactory, QueryMapper mapper) {
this.mongoDbFactory = mongoDbFactory;
this.mapper = mapper;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.index.IndexOperationsProvider#reactiveIndexOps(java.lang.String)
*/
@Override
public IndexOperations indexOps(String collectionName) {
return new DefaultIndexOperations(mongoDbFactory, collectionName, mapper);
}
}

View File

@@ -0,0 +1,151 @@
/*
* Copyright 2016-2017 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
*
* http://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 reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.Collection;
import java.util.Optional;
import org.bson.Document;
import org.springframework.data.mongodb.core.convert.QueryMapper;
import org.springframework.data.mongodb.core.index.IndexDefinition;
import org.springframework.data.mongodb.core.index.IndexInfo;
import org.springframework.data.mongodb.core.index.ReactiveIndexOperations;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.mongodb.client.model.IndexOptions;
/**
* Default implementation of {@link ReactiveIndexOperations}.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.0
*/
public class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
private static final String PARTIAL_FILTER_EXPRESSION_KEY = "partialFilterExpression";
private final ReactiveMongoOperations mongoOperations;
private final String collectionName;
private final QueryMapper queryMapper;
private final Optional<Class<?>> type;
/**
* Creates a new {@link DefaultReactiveIndexOperations}.
*
* @param mongoOperations must not be {@literal null}.
* @param collectionName must not be {@literal null}.
* @param queryMapper must not be {@literal null}.
*/
public DefaultReactiveIndexOperations(ReactiveMongoOperations mongoOperations, String collectionName,
QueryMapper queryMapper) {
this(mongoOperations, collectionName, queryMapper, Optional.empty());
}
/**
* Creates a new {@link DefaultReactiveIndexOperations}.
*
* @param mongoOperations must not be {@literal null}.
* @param collectionName must not be {@literal null}.
* @param queryMapper must not be {@literal null}.
* @param type used for mapping potential partial index filter expression, must not be {@literal null}.
*/
public DefaultReactiveIndexOperations(ReactiveMongoOperations mongoOperations, String collectionName,
QueryMapper queryMapper, Class<?> type) {
this(mongoOperations, collectionName, queryMapper, Optional.of(type));
}
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!");
this.mongoOperations = mongoOperations;
this.collectionName = collectionName;
this.queryMapper = queryMapper;
this.type = type;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.index.ReactiveIndexOperations#ensureIndex(org.springframework.data.mongodb.core.index.IndexDefinition)
*/
public Mono<String> ensureIndex(final IndexDefinition indexDefinition) {
return mongoOperations.execute(collectionName, collection -> {
Document indexOptions = indexDefinition.getIndexOptions();
IndexOptions ops = IndexConverters.indexDefinitionToIndexOptionsConverter().convert(indexDefinition);
if (indexOptions.containsKey(PARTIAL_FILTER_EXPRESSION_KEY)) {
Assert.isInstanceOf(Document.class, indexOptions.get(PARTIAL_FILTER_EXPRESSION_KEY));
MongoPersistentEntity<?> entity = type
.map(val -> (MongoPersistentEntity) queryMapper.getMappingContext().getRequiredPersistentEntity(val))
.orElseGet(() -> lookupPersistentEntity(collectionName));
ops = ops.partialFilterExpression(
queryMapper.getMappedObject(indexOptions.get(PARTIAL_FILTER_EXPRESSION_KEY, Document.class), entity));
}
return collection.createIndex(indexDefinition.getIndexKeys(), ops);
}).next();
}
@Nullable
private MongoPersistentEntity<?> lookupPersistentEntity(String collection) {
Collection<? extends MongoPersistentEntity<?>> entities = queryMapper.getMappingContext().getPersistentEntities();
return entities.stream() //
.filter(entity -> entity.getCollection().equals(collection)) //
.findFirst() //
.orElse(null);
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.index.ReactiveIndexOperations#dropIndex(java.lang.String)
*/
public Mono<Void> dropIndex(final String name) {
return mongoOperations.execute(collectionName, collection -> collection.dropIndex(name)).then();
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.index.ReactiveIndexOperations#dropAllIndexes()
*/
public Mono<Void> dropAllIndexes() {
return dropIndex("*");
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.index.ReactiveIndexOperations#getIndexInfo()
*/
public Flux<IndexInfo> getIndexInfo() {
return mongoOperations.execute(collectionName, collection -> collection.listIndexes(Document.class)) //
.map(IndexConverters.documentToIndexInfoConverter()::convert);
}
}

View File

@@ -0,0 +1,200 @@
/*
* Copyright 2014-2017 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
*
* http://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 static java.util.UUID.*;
import static org.springframework.data.mongodb.core.query.Criteria.*;
import static org.springframework.data.mongodb.core.query.Query.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.bson.Document;
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;
import org.springframework.util.StringUtils;
import com.mongodb.BasicDBList;
import com.mongodb.MongoException;
import com.mongodb.client.MongoDatabase;
/**
* Default implementation of {@link ScriptOperations} capable of saving and executing {@link ServerSideJavaScript}.
*
* @author Christoph Strobl
* @author Oliver Gierke
* @author Mark Paluch
* @since 1.7
*/
class DefaultScriptOperations implements ScriptOperations {
private static final String SCRIPT_COLLECTION_NAME = "system.js";
private static final String SCRIPT_NAME_PREFIX = "func_";
private final MongoOperations mongoOperations;
/**
* Creates new {@link DefaultScriptOperations} using given {@link MongoOperations}.
*
* @param mongoOperations must not be {@literal null}.
*/
public DefaultScriptOperations(MongoOperations mongoOperations) {
Assert.notNull(mongoOperations, "MongoOperations must not be null!");
this.mongoOperations = mongoOperations;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ScriptOperations#register(org.springframework.data.mongodb.core.script.ExecutableMongoScript)
*/
@Override
public NamedMongoScript register(ExecutableMongoScript script) {
return register(new NamedMongoScript(generateScriptName(), script));
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ScriptOperations#register(org.springframework.data.mongodb.core.script.NamedMongoScript)
*/
@Override
public NamedMongoScript register(NamedMongoScript script) {
Assert.notNull(script, "Script must not be null!");
mongoOperations.save(script, SCRIPT_COLLECTION_NAME);
return script;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ScriptOperations#execute(org.springframework.data.mongodb.core.script.ExecutableMongoScript, java.lang.Object[])
*/
@Override
public Object execute(final ExecutableMongoScript script, final Object... args) {
Assert.notNull(script, "Script must not be null!");
return mongoOperations.execute(new DbCallback<Object>() {
@Override
public Object doInDB(MongoDatabase db) throws MongoException, DataAccessException {
Document command = new Document("$eval", script.getCode());
BasicDBList commandArgs = new BasicDBList();
commandArgs.addAll(Arrays.asList(convertScriptArgs(false, args)));
command.append("args", commandArgs);
return db.runCommand(command).get("retval");
}
});
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ScriptOperations#call(java.lang.String, java.lang.Object[])
*/
@Override
public Object call(final String scriptName, final Object... args) {
Assert.hasText(scriptName, "ScriptName must not be null or empty!");
return mongoOperations.execute(new DbCallback<Object>() {
@Override
public Object doInDB(MongoDatabase db) throws MongoException, DataAccessException {
return db.runCommand(new Document("eval", String.format("%s(%s)", scriptName, convertAndJoinScriptArgs(args))))
.get("retval");
}
});
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ScriptOperations#exists(java.lang.String)
*/
@Override
public boolean exists(String scriptName) {
Assert.hasText(scriptName, "ScriptName must not be null or empty!");
return mongoOperations.exists(query(where("_id").is(scriptName)), NamedMongoScript.class, SCRIPT_COLLECTION_NAME);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ScriptOperations#getScriptNames()
*/
@Override
public Set<String> getScriptNames() {
List<NamedMongoScript> scripts = mongoOperations.findAll(NamedMongoScript.class, SCRIPT_COLLECTION_NAME);
if (CollectionUtils.isEmpty(scripts)) {
return Collections.emptySet();
}
Set<String> scriptNames = new HashSet<String>();
for (NamedMongoScript script : scripts) {
scriptNames.add(script.getName());
}
return scriptNames;
}
private Object[] convertScriptArgs(boolean quote, Object... args) {
if (ObjectUtils.isEmpty(args)) {
return args;
}
List<Object> convertedValues = new ArrayList<Object>(args.length);
for (Object arg : args) {
convertedValues.add(arg instanceof String && quote ? String.format("'%s'", arg)
: this.mongoOperations.getConverter().convertToMongoType(arg));
}
return convertedValues.toArray();
}
private String convertAndJoinScriptArgs(Object... args) {
return ObjectUtils.isEmpty(args) ? "" : StringUtils.arrayToCommaDelimitedString(convertScriptArgs(true, args));
}
/**
* Generate a valid name for the {@literal JavaScript}. MongoDB requires an id of type String for scripts. Calling
* scripts having {@link ObjectId} as id fails. Therefore we create a random UUID without {@code -} (as this won't
* work) an prefix the result with {@link #SCRIPT_NAME_PREFIX}.
*
* @return
*/
private static String generateScriptName() {
return SCRIPT_NAME_PREFIX + randomUUID().toString().replaceAll("-", "");
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2014 the original author or authors.
* Copyright 2015 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.
@@ -15,15 +15,18 @@
*/
package org.springframework.data.mongodb.core;
import org.springframework.transaction.support.ResourceHolder;
import org.springframework.transaction.support.ResourceHolderSynchronization;
import com.mongodb.WriteConcern;
/**
* Default {@link WriteConcernResolver} resolving the {@link WriteConcern} from the given {@link MongoAction}.
*
* @author Oliver Gierke
*/
class MongoSynchronization extends ResourceHolderSynchronization<ResourceHolder, Object> {
enum DefaultWriteConcernResolver implements WriteConcernResolver {
public MongoSynchronization(ResourceHolder resourceHolder, Object resourceKey) {
super(resourceHolder, resourceKey);
INSTANCE;
public WriteConcern resolve(MongoAction action) {
return action.getDefaultWriteConcern();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2011 the original author or authors.
* Copyright 2010-2016 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.
@@ -15,24 +15,26 @@
*/
package org.springframework.data.mongodb.core;
import org.bson.Document;
import org.springframework.dao.DataAccessException;
import com.mongodb.DBObject;
import com.mongodb.MongoException;
/**
* An interface used by {@link MongoTemplate} for processing documents returned from a MongoDB query on a per-document
* basis. Implementations of this interface perform the actual work of prcoessing each document but don't need to worry
* about exception handling. {@MongoException}s will be caught and translated by the calling
* MongoTemplate
*
* An DocumentCallbackHandler is typically stateful: It keeps the result state within the object, to be available later
* for later inspection.
* about exception handling. {@MongoException}s will be caught and translated by the calling MongoTemplate An
* DocumentCallbackHandler is typically stateful: It keeps the result state within the object, to be available later for
* later inspection.
*
* @author Mark Pollack
*
* @author Grame Rocher
* @author Oliver Gierke
* @author John Brisbin
* @author Christoph Strobl
* @since 1.0
*/
public interface DocumentCallbackHandler {
void processDocument(DBObject dbObject) throws MongoException, DataAccessException;
void processDocument(Document document) throws MongoException, DataAccessException;
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright 2017 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
*
* http://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.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.util.CloseableIterator;
/**
* {@link ExecutableAggregationOperation} allows creation and execution of MongoDB aggregation operations in a fluent
* API style. <br />
* The starting {@literal domainType} is used for mapping the {@link Aggregation} provided via {@code by} into the
* MongoDB specific representation, as well as mapping back the resulting {@link org.bson.Document}. An alternative
* input type for mapping the {@link Aggregation} can be provided by using
* {@link org.springframework.data.mongodb.core.aggregation.TypedAggregation}.
*
* <pre>
* <code>
* aggregateAndReturn(Jedi.class)
* .by(newAggregation(Human.class, project("These are not the droids you are looking for")))
* .all();
* </code>
* </pre>
*
* @author Christoph Strobl
* @author Mark Paluch
* @since 2.0
*/
public interface ExecutableAggregationOperation {
/**
* Start creating an aggregation operation that returns results mapped to the given domain type. <br />
* Use {@link org.springframework.data.mongodb.core.aggregation.TypedAggregation} to specify a potentially different
* input type for he aggregation.
*
* @param domainType must not be {@literal null}.
* @return new instance of {@link ExecutableAggregation}.
* @throws IllegalArgumentException if domainType is {@literal null}.
*/
<T> ExecutableAggregation<T> aggregateAndReturn(Class<T> domainType);
/**
* Collection override (Optional).
*
* @author Christoph Strobl
* @since 2.0
*/
interface AggregationWithCollection<T> {
/**
* Explicitly set the name of the collection to perform the query on. <br />
* Skip this step to use the default collection derived from the domain type.
*
* @param collection must not be {@literal null} nor {@literal empty}.
* @return new instance of {@link AggregationWithAggregation}.
* @throws IllegalArgumentException if collection is {@literal null}.
*/
AggregationWithAggregation<T> inCollection(String collection);
}
/**
* Trigger execution by calling one of the terminating methods.
*
* @author Christoph Strobl
* @since 2.0
*/
interface TerminatingAggregation<T> {
/**
* Apply pipeline operations as specified and get all matching elements.
*
* @return never {@literal null}.
*/
AggregationResults<T> all();
/**
* Apply pipeline operations as specified and stream all matching elements. <br />
* Returns a {@link CloseableIterator} that wraps the a Mongo DB {@link com.mongodb.Cursor}
*
* @return a {@link CloseableIterator} that wraps the a Mongo DB {@link com.mongodb.Cursor} that needs to be closed.
* Never {@literal null}.
*/
CloseableIterator<T> stream();
}
/**
* Define the aggregation with pipeline stages.
*
* @author Christoph Strobl
* @since 2.0
*/
interface AggregationWithAggregation<T> {
/**
* Set the aggregation to be used.
*
* @param aggregation must not be {@literal null}.
* @return new instance of {@link TerminatingAggregation}.
* @throws IllegalArgumentException if aggregation is {@literal null}.
*/
TerminatingAggregation<T> by(Aggregation aggregation);
}
/**
* @author Christoph Strobl
* @since 2.0
*/
interface ExecutableAggregation<T> extends AggregationWithCollection<T>, AggregationWithAggregation<T> {}
}

View File

@@ -0,0 +1,141 @@
/*
* Copyright 2017 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
*
* http://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 lombok.AccessLevel;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
import org.springframework.data.util.CloseableIterator;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Implementation of {@link ExecutableAggregationOperation} operating directly on {@link MongoTemplate}.
*
* @author Christoph Strobl
* @author Mark Paluch
* @since 2.0
*/
class ExecutableAggregationOperationSupport implements ExecutableAggregationOperation {
private final MongoTemplate template;
/**
* Create new instance of {@link ExecutableAggregationOperationSupport}.
*
* @param template must not be {@literal null}.
* @throws IllegalArgumentException if template is {@literal null}.
*/
ExecutableAggregationOperationSupport(MongoTemplate template) {
Assert.notNull(template, "Template must not be null!");
this.template = template;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableAggregationOperation#aggregateAndReturn(java.lang.Class)
*/
@Override
public <T> ExecutableAggregation<T> aggregateAndReturn(Class<T> domainType) {
Assert.notNull(domainType, "DomainType must not be null!");
return new ExecutableAggregationSupport<>(template, domainType, null, null);
}
/**
* @author Christoph Strobl
* @since 2.0
*/
@RequiredArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
static class ExecutableAggregationSupport<T>
implements AggregationWithAggregation<T>, ExecutableAggregation<T>, TerminatingAggregation<T> {
@NonNull MongoTemplate template;
@NonNull Class<T> domainType;
@Nullable Aggregation aggregation;
@Nullable String collection;
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableAggregationOperation.AggregationWithCollection#inCollection(java.lang.String)
*/
@Override
public AggregationWithAggregation<T> inCollection(String collection) {
Assert.hasText(collection, "Collection must not be null nor empty!");
return new ExecutableAggregationSupport<>(template, domainType, aggregation, collection);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableAggregationOperation.AggregationWithAggregation#by(org.springframework.data.mongodb.core.aggregation.Aggregation)
*/
@Override
public TerminatingAggregation<T> by(Aggregation aggregation) {
Assert.notNull(aggregation, "Aggregation must not be null!");
return new ExecutableAggregationSupport<>(template, domainType, aggregation, collection);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableAggregationOperation.TerminatingAggregation#all()
*/
@Override
public AggregationResults<T> all() {
return template.aggregate(aggregation, getCollectionName(aggregation), domainType);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableAggregationOperation.TerminatingAggregation#stream()
*/
@Override
public CloseableIterator<T> stream() {
return template.aggregateStream(aggregation, getCollectionName(aggregation), domainType);
}
private String getCollectionName(Aggregation aggregation) {
if (StringUtils.hasText(collection)) {
return collection;
}
if (aggregation instanceof TypedAggregation) {
TypedAggregation<?> typedAggregation = (TypedAggregation<?>) aggregation;
if (typedAggregation.getInputType() != null) {
return template.determineCollectionName(typedAggregation.getInputType());
}
}
return template.determineCollectionName(domainType);
}
}
}

View File

@@ -0,0 +1,226 @@
/*
* Copyright 2017 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
*
* http://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.List;
import java.util.Optional;
import java.util.stream.Stream;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.lang.Nullable;
/**
* {@link ExecutableFindOperation} allows creation and execution of MongoDB find operations in a fluent API style.
* <br />
* The starting {@literal domainType} is used for mapping the {@link Query} provided via {@code matching} into the
* MongoDB specific representation. By default, the originating {@literal domainType} is also used for mapping back the
* result from the {@link org.bson.Document}. However, it is possible to define an different {@literal returnType} via
* {@code as} to mapping the result.<br />
* The collection to operate on is by default derived from the initial {@literal domainType} and can be defined there
* via {@link org.springframework.data.mongodb.core.mapping.Document}. Using {@code inCollection} allows to override the
* collection name for the execution.
*
* <pre>
* <code>
* query(Human.class)
* .inCollection("star-wars")
* .as(Jedi.class)
* .matching(query(where("firstname").is("luke")))
* .all();
* </code>
* </pre>
*
* @author Christoph Strobl
* @author Mark Paluch
* @since 2.0
*/
public interface ExecutableFindOperation {
/**
* Start creating a find operation for the given {@literal domainType}.
*
* @param domainType must not be {@literal null}.
* @return new instance of {@link ExecutableFind}.
* @throws IllegalArgumentException if domainType is {@literal null}.
*/
<T> ExecutableFind<T> query(Class<T> domainType);
/**
* Trigger find execution by calling one of the terminating methods.
*
* @author Christoph Strobl
* @since 2.0
*/
interface TerminatingFind<T> {
/**
* Get exactly zero or one result.
*
* @return {@link Optional#empty()} if no match found.
* @throws org.springframework.dao.IncorrectResultSizeDataAccessException if more than one match found.
*/
default Optional<T> one() {
return Optional.ofNullable(oneValue());
}
/**
* Get exactly zero or one result.
*
* @return {@literal null} if no match found.
* @throws org.springframework.dao.IncorrectResultSizeDataAccessException if more than one match found.
*/
@Nullable
T oneValue();
/**
* Get the first or no result.
*
* @return {@link Optional#empty()} if no match found.
*/
default Optional<T> first() {
return Optional.ofNullable(firstValue());
}
/**
* Get the first or no result.
*
* @return {@literal null} if no match found.
*/
@Nullable
T firstValue();
/**
* Get all matching elements.
*
* @return never {@literal null}.
*/
List<T> all();
/**
* Stream all matching elements.
*
* @return a {@link Stream} that wraps the a Mongo DB {@link com.mongodb.Cursor} that needs to be closed. Never
* {@literal null}.
*/
Stream<T> stream();
/**
* Get the number of matching elements.
*
* @return total number of matching elements.
*/
long count();
/**
* Check for the presence of matching elements.
*
* @return {@literal true} if at least one matching element exists.
*/
boolean exists();
}
/**
* Trigger geonear execution by calling one of the terminating methods.
*
* @author Christoph Strobl
* @since 2.0
*/
interface TerminatingFindNear<T> {
/**
* Find all matching elements and return them as {@link org.springframework.data.geo.GeoResult}.
*
* @return never {@literal null}.
*/
GeoResults<T> all();
}
/**
* Terminating operations invoking the actual query execution.
*
* @author Christoph Strobl
* @since 2.0
*/
interface FindWithQuery<T> extends TerminatingFind<T> {
/**
* Set the filter query to be used.
*
* @param query must not be {@literal null}.
* @return new instance of {@link TerminatingFind}.
* @throws IllegalArgumentException if query is {@literal null}.
*/
TerminatingFind<T> matching(Query query);
/**
* Set the filter query for the geoNear execution.
*
* @param nearQuery must not be {@literal null}.
* @return new instance of {@link TerminatingFindNear}.
* @throws IllegalArgumentException if nearQuery is {@literal null}.
*/
TerminatingFindNear<T> near(NearQuery nearQuery);
}
/**
* Collection override (Optional).
*
* @author Christoph Strobl
* @since 2.0
*/
interface FindWithCollection<T> extends FindWithQuery<T> {
/**
* Explicitly set the name of the collection to perform the query on. <br />
* Skip this step to use the default collection derived from the domain type.
*
* @param collection must not be {@literal null} nor {@literal empty}.
* @return new instance of {@link FindWithProjection}.
* @throws IllegalArgumentException if collection is {@literal null}.
*/
FindWithProjection<T> inCollection(String collection);
}
/**
* Result type override (Optional).
*
* @author Christoph Strobl
* @since 2.0
*/
interface FindWithProjection<T> extends FindWithQuery<T> {
/**
* Define the target type fields should be mapped to. <br />
* Skip this step if you are anyway only interested in the original domain type.
*
* @param resultType must not be {@literal null}.
* @param <R> result type.
* @return new instance of {@link FindWithProjection}.
* @throws IllegalArgumentException if resultType is {@literal null}.
*/
<R> FindWithQuery<R> as(Class<R> resultType);
}
/**
* {@link ExecutableFind} provides methods for constructing lookup operations in a fluent way.
*
* @author Christoph Strobl
* @since 2.0
*/
interface ExecutableFind<T> extends FindWithCollection<T>, FindWithProjection<T> {}
}

View File

@@ -0,0 +1,264 @@
/*
* Copyright 2017 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
*
* http://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 lombok.AccessLevel;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import org.bson.Document;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.SerializationUtils;
import org.springframework.data.util.CloseableIterator;
import org.springframework.data.util.StreamUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import com.mongodb.client.FindIterable;
/**
* Implementation of {@link ExecutableFindOperation}.
*
* @author Christoph Strobl
* @author Mark Paluch
* @since 2.0
*/
class ExecutableFindOperationSupport implements ExecutableFindOperation {
private static final Query ALL_QUERY = new Query();
private final MongoTemplate template;
/**
* Create new {@link ExecutableFindOperationSupport}.
*
* @param template must not be {@literal null}.
* @throws IllegalArgumentException if template is {@literal null}.
*/
ExecutableFindOperationSupport(MongoTemplate template) {
Assert.notNull(template, "Template must not be null!");
this.template = template;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableFindOperation#query(java.lang.Class)
*/
@Override
public <T> ExecutableFind<T> query(Class<T> domainType) {
Assert.notNull(domainType, "DomainType must not be null!");
return new ExecutableFindSupport<>(template, domainType, domainType, null, ALL_QUERY);
}
/**
* @param <T>
* @author Christoph Strobl
* @since 2.0
*/
@RequiredArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
static class ExecutableFindSupport<T>
implements ExecutableFind<T>, FindWithCollection<T>, FindWithProjection<T>, FindWithQuery<T> {
@NonNull MongoTemplate template;
@NonNull Class<?> domainType;
Class<T> returnType;
@Nullable String collection;
Query query;
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableFindOperation.FindWithCollection#inCollection(java.lang.String)
*/
@Override
public FindWithProjection<T> inCollection(String collection) {
Assert.hasText(collection, "Collection name must not be null nor empty!");
return new ExecutableFindSupport<>(template, domainType, returnType, collection, query);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableFindOperation.FindWithProjection#as(Class)
*/
@Override
public <T1> FindWithQuery<T1> as(Class<T1> returnType) {
Assert.notNull(returnType, "ReturnType must not be null!");
return new ExecutableFindSupport<>(template, domainType, returnType, collection, query);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableFindOperation.FindWithQuery#matching(org.springframework.data.mongodb.core.query.Query)
*/
@Override
public TerminatingFind<T> matching(Query query) {
Assert.notNull(query, "Query must not be null!");
return new ExecutableFindSupport<>(template, domainType, returnType, collection, query);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableFindOperation.TerminatingFind#oneValue()
*/
@Override
public T oneValue() {
List<T> result = doFind(new DelegatingQueryCursorPreparer(getCursorPreparer(query, null)).limit(2));
if (ObjectUtils.isEmpty(result)) {
return null;
}
if (result.size() > 1) {
throw new IncorrectResultSizeDataAccessException("Query " + asString() + " returned non unique result.", 1);
}
return result.iterator().next();
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableFindOperation.TerminatingFind#firstValue()
*/
@Override
public T firstValue() {
List<T> result = doFind(new DelegatingQueryCursorPreparer(getCursorPreparer(query, null)).limit(1));
return ObjectUtils.isEmpty(result) ? null : result.iterator().next();
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableFindOperation.TerminatingFind#all()
*/
@Override
public List<T> all() {
return doFind(null);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableFindOperation.TerminatingFind#stream()
*/
@Override
public Stream<T> stream() {
return StreamUtils.createStreamFromIterator(doStream());
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableFindOperation.FindWithQuery#near(org.springframework.data.mongodb.core.query.NearQuery)
*/
@Override
public TerminatingFindNear<T> near(NearQuery nearQuery) {
return () -> template.geoNear(nearQuery, domainType, getCollectionName(), returnType);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableFindOperation.TerminatingFind#count()
*/
@Override
public long count() {
return template.count(query, domainType, getCollectionName());
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableFindOperation.TerminatingFind#exists()
*/
@Override
public boolean exists() {
return template.exists(query, domainType, getCollectionName());
}
private List<T> doFind(@Nullable CursorPreparer preparer) {
Document queryObject = query.getQueryObject();
Document fieldsObject = query.getFieldsObject();
return template.doFind(getCollectionName(), queryObject, fieldsObject, domainType, returnType,
getCursorPreparer(query, preparer));
}
private CloseableIterator<T> doStream() {
return template.doStream(query, domainType, getCollectionName(), returnType);
}
private CursorPreparer getCursorPreparer(Query query, @Nullable CursorPreparer preparer) {
return preparer != null ? preparer : template.new QueryCursorPreparer(query, domainType);
}
private String getCollectionName() {
return StringUtils.hasText(collection) ? collection : template.determineCollectionName(domainType);
}
private String asString() {
return SerializationUtils.serializeToJsonSafely(query);
}
}
/**
* @author Christoph Strobl
* @since 2.0
*/
static class DelegatingQueryCursorPreparer implements CursorPreparer {
private final @Nullable CursorPreparer delegate;
private Optional<Integer> limit = Optional.empty();
DelegatingQueryCursorPreparer(@Nullable CursorPreparer delegate) {
this.delegate = delegate;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.CursorPreparer#prepare(com.mongodb.clientFindIterable)
*/
@Override
public FindIterable<Document> prepare(FindIterable<Document> cursor) {
FindIterable<Document> target = delegate != null ? delegate.prepare(cursor) : cursor;
return limit.map(target::limit).orElse(target);
}
CursorPreparer limit(int limit) {
this.limit = Optional.of(limit);
return this;
}
}
}

View File

@@ -0,0 +1,137 @@
/*
* Copyright 2017 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
*
* http://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.Collection;
import org.springframework.data.mongodb.core.BulkOperations.BulkMode;
import com.mongodb.bulk.BulkWriteResult;
/**
* {@link ExecutableInsertOperation} allows creation and execution of MongoDB insert and bulk insert operations in a
* fluent API style. <br />
* The collection to operate on is by default derived from the initial {@literal domainType} and can be defined there
* via {@link org.springframework.data.mongodb.core.mapping.Document}. Using {@code inCollection} allows to override the
* collection name for the execution.
*
* <pre>
* <code>
* insert(Jedi.class)
* .inCollection("star-wars")
* .one(luke);
* </code>
* </pre>
*
* @author Christoph Strobl
* @author Mark Paluch
* @since 2.0
*/
public interface ExecutableInsertOperation {
/**
* Start creating an insert operation for given {@literal domainType}.
*
* @param domainType must not be {@literal null}.
* @return new instance of {@link ExecutableInsert}.
* @throws IllegalArgumentException if domainType is {@literal null}.
*/
<T> ExecutableInsert<T> insert(Class<T> domainType);
/**
* Trigger insert execution by calling one of the terminating methods.
*
* @author Christoph Strobl
* @since 2.0
*/
interface TerminatingInsert<T> extends TerminatingBulkInsert<T> {
/**
* Insert exactly one object.
*
* @param object must not be {@literal null}.
* @throws IllegalArgumentException if object is {@literal null}.
*/
void one(T object);
/**
* Insert a collection of objects.
*
* @param objects must not be {@literal null}.
* @throws IllegalArgumentException if objects is {@literal null}.
*/
void all(Collection<? extends T> objects);
}
/**
* Trigger bulk insert execution by calling one of the terminating methods.
*
* @author Christoph Strobl
* @since 2.0
*/
interface TerminatingBulkInsert<T> {
/**
* Bulk write collection of objects.
*
* @param objects must not be {@literal null}.
* @return resulting {@link BulkWriteResult}.
* @throws IllegalArgumentException if objects is {@literal null}.
*/
BulkWriteResult bulk(Collection<? extends T> objects);
}
/**
* Collection override (optional).
*
* @author Christoph Strobl
* @since 2.0
*/
interface InsertWithCollection<T> {
/**
* Explicitly set the name of the collection. <br />
* Skip this step to use the default collection derived from the domain type.
*
* @param collection must not be {@literal null} nor {@literal empty}.
* @return new instance of {@link InsertWithBulkMode}.
* @throws IllegalArgumentException if collection is {@literal null}.
*/
InsertWithBulkMode<T> inCollection(String collection);
}
/**
* @author Christoph Strobl
* @since 2.0
*/
interface InsertWithBulkMode<T> extends TerminatingInsert<T> {
/**
* Define the {@link BulkMode} to use for bulk insert operation.
*
* @param bulkMode must not be {@literal null}.
* @return new instance of {@link TerminatingBulkInsert}.
* @throws IllegalArgumentException if bulkMode is {@literal null}.
*/
TerminatingBulkInsert<T> withBulkMode(BulkMode bulkMode);
}
/**
* @author Christoph Strobl
* @since 2.0
*/
interface ExecutableInsert<T> extends TerminatingInsert<T>, InsertWithCollection<T>, InsertWithBulkMode<T> {}
}

View File

@@ -0,0 +1,147 @@
/*
* Copyright 2017 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
*
* http://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 lombok.AccessLevel;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;
import java.util.ArrayList;
import java.util.Collection;
import org.springframework.data.mongodb.core.BulkOperations.BulkMode;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import com.mongodb.bulk.BulkWriteResult;
/**
* Implementation of {@link ExecutableInsertOperation}.
*
* @author Christoph Strobl
* @author Mark Paluch
* @since 2.0
*/
class ExecutableInsertOperationSupport implements ExecutableInsertOperation {
private final MongoTemplate template;
/**
* Create new {@link ExecutableInsertOperationSupport}.
*
* @param template must not be {@literal null}.
* @throws IllegalArgumentException if template is {@literal null}.
*/
ExecutableInsertOperationSupport(MongoTemplate template) {
Assert.notNull(template, "Template must not be null!");
this.template = template;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.coreExecutableInsertOperation#insert(java.lan.Class)
*/
@Override
public <T> ExecutableInsert<T> insert(Class<T> domainType) {
Assert.notNull(domainType, "DomainType must not be null!");
return new ExecutableInsertSupport<>(template, domainType, null, null);
}
/**
* @author Christoph Strobl
* @since 2.0
*/
@RequiredArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
static class ExecutableInsertSupport<T> implements ExecutableInsert<T> {
@NonNull MongoTemplate template;
@NonNull Class<T> domainType;
@Nullable String collection;
@Nullable BulkMode bulkMode;
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableInsertOperation.TerminatingInsert#insert(java.lang.Class)
*/
@Override
public void one(T object) {
Assert.notNull(object, "Object must not be null!");
template.insert(object, getCollectionName());
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableInsertOperation.TerminatingInsert#all(java.util.Collection)
*/
@Override
public void all(Collection<? extends T> objects) {
Assert.notNull(objects, "Objects must not be null!");
template.insert(objects, getCollectionName());
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableInsertOperation.TerminatingBulkInsert#bulk(java.util.Collection)
*/
@Override
public BulkWriteResult bulk(Collection<? extends T> objects) {
Assert.notNull(objects, "Objects must not be null!");
return template.bulkOps(bulkMode != null ? bulkMode : BulkMode.ORDERED, domainType, getCollectionName())
.insert(new ArrayList<>(objects)).execute();
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableInsertOperation.InsertWithCollection#inCollection(java.lang.String)
*/
@Override
public InsertWithBulkMode<T> inCollection(String collection) {
Assert.hasText(collection, "Collection must not be null nor empty.");
return new ExecutableInsertSupport<>(template, domainType, collection, bulkMode);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableInsertOperation.InsertWithBulkMode#withBulkMode(org.springframework.data.mongodb.core.BulkMode)
*/
@Override
public TerminatingBulkInsert<T> withBulkMode(BulkMode bulkMode) {
Assert.notNull(bulkMode, "BulkMode must not be null!");
return new ExecutableInsertSupport<>(template, domainType, collection, bulkMode);
}
private String getCollectionName() {
return StringUtils.hasText(collection) ? collection : template.determineCollectionName(domainType);
}
}
}

View File

@@ -0,0 +1,121 @@
/*
* Copyright 2017 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
*
* http://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.List;
import org.springframework.data.mongodb.core.query.Query;
import com.mongodb.client.result.DeleteResult;
/**
* {@link ExecutableRemoveOperation} allows creation and execution of MongoDB remove / findAndRemove operations in a
* fluent API style. <br />
* The starting {@literal domainType} is used for mapping the {@link Query} provided via {@code matching} into the
* MongoDB specific representation. The collection to operate on is by default derived from the initial
* {@literal domainType} and can be defined there via {@link org.springframework.data.mongodb.core.mapping.Document}.
* Using {@code inCollection} allows to override the collection name for the execution.
*
* <pre>
* <code>
* remove(Jedi.class)
* .inCollection("star-wars")
* .matching(query(where("firstname").is("luke")))
* .all();
* </code>
* </pre>
*
* @author Christoph Strobl
* @author Mark Paluch
* @since 2.0
*/
public interface ExecutableRemoveOperation {
/**
* Start creating a remove operation for the given {@literal domainType}.
*
* @param domainType must not be {@literal null}.
* @return new instance of {@link ExecutableRemove}.
* @throws IllegalArgumentException if domainType is {@literal null}.
*/
<T> ExecutableRemove<T> remove(Class<T> domainType);
/**
* Collection override (optional).
*
* @param <T>
* @author Christoph Strobl
* @since 2.0
*/
interface RemoveWithCollection<T> extends RemoveWithQuery<T> {
/**
* Explicitly set the name of the collection to perform the query on. <br />
* Skip this step to use the default collection derived from the domain type.
*
* @param collection must not be {@literal null} nor {@literal empty}.
* @return new instance of {@link RemoveWithCollection}.
* @throws IllegalArgumentException if collection is {@literal null}.
*/
RemoveWithQuery<T> inCollection(String collection);
}
/**
* @author Christoph Strobl
* @since 2.0
*/
interface TerminatingRemove<T> {
/**
* Remove all documents matching.
*
* @return the {@link DeleteResult}. Never {@literal null}.
*/
DeleteResult all();
/**
* Remove and return all matching documents. <br/>
* <strong>NOTE</strong> The entire list of documents will be fetched before sending the actual delete commands.
* Also, {@link org.springframework.context.ApplicationEvent}s will be published for each and every delete
* operation.
*
* @return empty {@link List} if no match found. Never {@literal null}.
*/
List<T> findAndRemove();
}
/**
* @author Christoph Strobl
* @since 2.0
*/
interface RemoveWithQuery<T> extends TerminatingRemove<T> {
/**
* Define the query filtering elements.
*
* @param query must not be {@literal null}.
* @return new instance of {@link TerminatingRemove}.
* @throws IllegalArgumentException if query is {@literal null}.
*/
TerminatingRemove<T> matching(Query query);
}
/**
* @author Christoph Strobl
* @since 2.0
*/
interface ExecutableRemove<T> extends RemoveWithCollection<T> {}
}

View File

@@ -0,0 +1,135 @@
/*
* Copyright 2017 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
*
* http://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 lombok.AccessLevel;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;
import java.util.List;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import com.mongodb.client.result.DeleteResult;
/**
* Implementation of {@link ExecutableRemoveOperation}.
*
* @author Christoph Strobl
* @author Mark Paluch
* @since 2.0
*/
class ExecutableRemoveOperationSupport implements ExecutableRemoveOperation {
private static final Query ALL_QUERY = new Query();
private final MongoTemplate tempate;
/**
* Create new {@link ExecutableRemoveOperationSupport}.
*
* @param template must not be {@literal null}.
* @throws IllegalArgumentException if template is {@literal null}.
*/
ExecutableRemoveOperationSupport(MongoTemplate template) {
Assert.notNull(template, "Template must not be null!");
this.tempate = template;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableRemoveOperation#remove(java.lang.Class)
*/
@Override
public <T> ExecutableRemove<T> remove(Class<T> domainType) {
Assert.notNull(domainType, "DomainType must not be null!");
return new ExecutableRemoveSupport<>(tempate, domainType, ALL_QUERY, null);
}
/**
* @author Christoph Strobl
* @since 2.0
*/
@RequiredArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
static class ExecutableRemoveSupport<T> implements ExecutableRemove<T>, RemoveWithCollection<T> {
@NonNull MongoTemplate template;
@NonNull Class<T> domainType;
Query query;
@Nullable String collection;
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableRemoveOperation.RemoveWithCollection#inCollection(java.lang.String)
*/
@Override
public RemoveWithQuery<T> inCollection(String collection) {
Assert.hasText(collection, "Collection must not be null nor empty!");
return new ExecutableRemoveSupport<>(template, domainType, query, collection);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableRemoveOperation.RemoveWithQuery#matching(org.springframework.data.mongodb.core.query.Query)
*/
@Override
public TerminatingRemove<T> matching(Query query) {
Assert.notNull(query, "Query must not be null!");
return new ExecutableRemoveSupport<>(template, domainType, query, collection);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableRemoveOperation.TerminatingRemove#all()
*/
@Override
public DeleteResult all() {
String collectionName = getCollectionName();
return template.doRemove(collectionName, query, domainType);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableRemoveOperation.TerminatingRemove#findAndRemove()
*/
@Override
public List<T> findAndRemove() {
String collectionName = getCollectionName();
return template.doFindAndDelete(collectionName, query, domainType);
}
private String getCollectionName() {
return StringUtils.hasText(collection) ? collection : template.determineCollectionName(domainType);
}
}
}

View File

@@ -0,0 +1,191 @@
/*
* Copyright 2017 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
*
* http://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.Query;
import org.springframework.data.mongodb.core.query.Update;
import com.mongodb.client.result.UpdateResult;
import org.springframework.lang.Nullable;
/**
* {@link ExecutableUpdateOperation} allows creation and execution of MongoDB update / findAndModify operations in a
* fluent API style. <br />
* The starting {@literal domainType} is used for mapping the {@link Query} provided via {@code matching}, as well as
* the {@link Update} via {@code apply} into the MongoDB specific representations. The collection to operate on is by
* default derived from the initial {@literal domainType} and can be defined there via
* {@link org.springframework.data.mongodb.core.mapping.Document}. Using {@code inCollection} allows to override the
* collection name for the execution.
*
* <pre>
* <code>
* update(Jedi.class)
* .inCollection("star-wars")
* .matching(query(where("firstname").is("luke")))
* .apply(new Update().set("lastname", "skywalker"))
* .upsert();
* </code>
* </pre>
*
* @author Christoph Strobl
* @author Mark Paluch
* @since 2.0
*/
public interface ExecutableUpdateOperation {
/**
* Start creating an update operation for the given {@literal domainType}.
*
* @param domainType must not be {@literal null}.
* @return new instance of {@link ExecutableUpdate}.
* @throws IllegalArgumentException if domainType is {@literal null}.
*/
<T> ExecutableUpdate<T> update(Class<T> domainType);
/**
* Declare the {@link Update} to apply.
*
* @author Christoph Strobl
* @since 2.0
*/
interface UpdateWithUpdate<T> {
/**
* Set the {@link Update} to be applied.
*
* @param update must not be {@literal null}.
* @return new instance of {@link TerminatingUpdate}.
* @throws IllegalArgumentException if update is {@literal null}.
*/
TerminatingUpdate<T> apply(Update update);
}
/**
* Explicitly define the name of the collection to perform operation in.
*
* @author Christoph Strobl
* @since 2.0
*/
interface UpdateWithCollection<T> {
/**
* Explicitly set the name of the collection to perform the query on. <br />
* Skip this step to use the default collection derived from the domain type.
*
* @param collection must not be {@literal null} nor {@literal empty}.
* @return new instance of {@link UpdateWithCollection}.
* @throws IllegalArgumentException if collection is {@literal null}.
*/
UpdateWithQuery<T> inCollection(String collection);
}
/**
* Define a filter query for the {@link Update}.
*
* @author Christoph Strobl
* @since 2.0
*/
interface UpdateWithQuery<T> extends UpdateWithUpdate<T> {
/**
* Filter documents by given {@literal query}.
*
* @param query must not be {@literal null}.
* @return new instance of {@link UpdateWithQuery}.
* @throws IllegalArgumentException if query is {@literal null}.
*/
UpdateWithUpdate<T> matching(Query query);
}
/**
* Define {@link FindAndModifyOptions}.
*
* @author Christoph Strobl
* @since 2.0
*/
interface FindAndModifyWithOptions<T> {
/**
* Explicitly define {@link FindAndModifyOptions} for the {@link Update}.
*
* @param options must not be {@literal null}.
* @return new instance of {@link FindAndModifyWithOptions}.
* @throws IllegalArgumentException if options is {@literal null}.
*/
TerminatingFindAndModify<T> withOptions(FindAndModifyOptions options);
}
/**
* Trigger findAndModify execution by calling one of the terminating methods.
*/
interface TerminatingFindAndModify<T> {
/**
* Find, modify and return the first matching document.
*
* @return {@link Optional#empty()} if nothing found.
*/
default Optional<T> findAndModify() {
return Optional.ofNullable(findAndModifyValue());
}
/**
* Find, modify and return the first matching document.
*
* @return {@literal null} if nothing found.
*/
@Nullable
T findAndModifyValue();
}
/**
* Trigger update execution by calling one of the terminating methods.
*
* @author Christoph Strobl
* @since 2.0
*/
interface TerminatingUpdate<T> extends TerminatingFindAndModify<T>, FindAndModifyWithOptions<T> {
/**
* Update all matching documents in the collection.
*
* @return never {@literal null}.
*/
UpdateResult all();
/**
* Update the first document in the collection.
*
* @return never {@literal null}.
*/
UpdateResult first();
/**
* Creates a new document if no documents match the filter query or updates the matching ones.
*
* @return never {@literal null}.
*/
UpdateResult upsert();
}
/**
* @author Christoph Strobl
* @since 2.0
*/
interface ExecutableUpdate<T> extends UpdateWithCollection<T>, UpdateWithQuery<T>, UpdateWithUpdate<T> {}
}

View File

@@ -0,0 +1,176 @@
/*
* Copyright 2017 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
*
* http://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 lombok.AccessLevel;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import com.mongodb.client.result.UpdateResult;
/**
* Implementation of {@link ExecutableUpdateOperation}.
*
* @author Christoph Strobl
* @author Mark Paluch
* @since 2.0
*/
class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
private static final Query ALL_QUERY = new Query();
private final MongoTemplate template;
/**
* Creates new {@link ExecutableUpdateOperationSupport}.
*
* @param template must not be {@literal null}.
*/
ExecutableUpdateOperationSupport(MongoTemplate template) {
Assert.notNull(template, "Template must not be null!");
this.template = template;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableUpdateOperation#update(java.lang.Class)
*/
@Override
public <T> ExecutableUpdate<T> update(Class<T> domainType) {
Assert.notNull(domainType, "DomainType must not be null!");
return new ExecutableUpdateSupport<>(template, domainType, ALL_QUERY, null, null, null);
}
/**
* @author Christoph Strobl
* @since 2.0
*/
@RequiredArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
static class ExecutableUpdateSupport<T>
implements ExecutableUpdate<T>, UpdateWithCollection<T>, UpdateWithQuery<T>, TerminatingUpdate<T> {
@NonNull MongoTemplate template;
@NonNull Class<T> domainType;
Query query;
@Nullable Update update;
@Nullable String collection;
@Nullable FindAndModifyOptions options;
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableUpdateOperation.UpdateWithUpdate#apply(Update)
*/
@Override
public TerminatingUpdate<T> apply(Update update) {
Assert.notNull(update, "Update must not be null!");
return new ExecutableUpdateSupport<>(template, domainType, query, update, collection, options);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableUpdateOperation.UpdateWithCollection#inCollection(java.lang.String)
*/
@Override
public UpdateWithQuery<T> inCollection(String collection) {
Assert.hasText(collection, "Collection must not be null nor empty!");
return new ExecutableUpdateSupport<>(template, domainType, query, update, collection, options);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableUpdateOperation.FindAndModifyWithOptions#withOptions(org.springframework.data.mongodb.core.FindAndModifyOptions)
*/
@Override
public TerminatingFindAndModify<T> withOptions(FindAndModifyOptions options) {
Assert.notNull(options, "Options must not be null!");
return new ExecutableUpdateSupport<>(template, domainType, query, update, collection, options);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ReactiveUpdateOperation.UpdateWithQuery#matching(org.springframework.data.mongodb.core.query.Query)
*/
@Override
public UpdateWithUpdate<T> matching(Query query) {
Assert.notNull(query, "Query must not be null!");
return new ExecutableUpdateSupport<>(template, domainType, query, update, collection, options);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableUpdateOperation.TerminatingUpdate#all()
*/
@Override
public UpdateResult all() {
return doUpdate(true, false);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableUpdateOperation.TerminatingUpdate#first()
*/
@Override
public UpdateResult first() {
return doUpdate(false, false);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableUpdateOperation.TerminatingUpdate#upsert()
*/
@Override
public UpdateResult upsert() {
return doUpdate(true, true);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ExecutableUpdateOperation.TerminatingFindAndModify#findAndModifyValue()
*/
@Override
public @Nullable T findAndModifyValue() {
return template.findAndModify(query, update, options != null ? options : new FindAndModifyOptions(), domainType, getCollectionName());
}
private UpdateResult doUpdate(boolean multi, boolean upsert) {
return template.doUpdate(getCollectionName(), query, update, domainType, upsert, multi);
}
private String getCollectionName() {
return StringUtils.hasText(collection) ? collection : template.determineCollectionName(domainType);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2011 the original author or authors.
* Copyright 2010-2017 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.
@@ -15,23 +15,53 @@
*/
package org.springframework.data.mongodb.core;
import java.util.Optional;
import org.springframework.data.mongodb.core.query.Collation;
import org.springframework.lang.Nullable;
/**
* @author Mark Pollak
* @author Oliver Gierke
* @author Christoph Strobl
*/
public class FindAndModifyOptions {
boolean returnNew;
private boolean returnNew;
private boolean upsert;
private boolean remove;
boolean upsert;
boolean remove;
private @Nullable Collation collation;
/**
* Static factory method to create a FindAndModifyOptions instance
*
*
* @return a new instance
*/
public static FindAndModifyOptions options() {
return new FindAndModifyOptions();
}
/**
* @param options
* @return
* @since 2.0
*/
public static FindAndModifyOptions of(@Nullable FindAndModifyOptions source) {
FindAndModifyOptions options = new FindAndModifyOptions();
if (source == null) {
return options;
}
options.returnNew = source.returnNew;
options.upsert = source.upsert;
options.remove = source.remove;
options.collation = source.collation;
return options;
}
public FindAndModifyOptions returnNew(boolean returnNew) {
this.returnNew = returnNew;
return this;
@@ -47,6 +77,19 @@ public class FindAndModifyOptions {
return this;
}
/**
* Define the {@link Collation} specifying language-specific rules for string comparison.
*
* @param collation
* @return
* @since 2.0
*/
public FindAndModifyOptions collation(@Nullable Collation collation) {
this.collation = collation;
return this;
}
public boolean isReturnNew() {
return returnNew;
}
@@ -59,4 +102,14 @@ public class FindAndModifyOptions {
return remove;
}
/**
* Get the {@link Collation} specifying language-specific rules for string comparison.
*
* @return
* @since 2.0
*/
public Optional<Collation> getCollation() {
return Optional.ofNullable(collation);
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2016-2017 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core;
import com.mongodb.reactivestreams.client.FindPublisher;
/**
* Simple callback interface to allow customization of a {@link FindPublisher}.
*
* @author Mark Paluch
*/
interface FindPublisherPreparer {
/**
* Prepare the given cursor (apply limits, skips and so on). Returns the prepared cursor.
*
* @param findPublisher must not be {@literal null}.
*/
<T> FindPublisher<T> prepare(FindPublisher<T> findPublisher);
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright 2017 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
*
* http://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;
/**
* Stripped down interface providing access to a fluent API that specifies a basic set of MongoDB operations.
*
* @author Christoph Strobl
* @since 2.0
*/
public interface FluentMongoOperations extends ExecutableFindOperation, ExecutableInsertOperation,
ExecutableUpdateOperation, ExecutableRemoveOperation, ExecutableAggregationOperation {}

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2016-2017 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
*
* http://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.bson.Document;
import org.springframework.util.Assert;
/**
* Value object to mitigate different representations of geo command execution results in MongoDB.
*
* @author Oliver Gierke
* @author Christoph Strobl
* @soundtrack Fruitcake - Jeff Coffin (The Inside of the Outside)
* @since 1.9
*/
class GeoCommandStatistics {
private static final GeoCommandStatistics NONE = new GeoCommandStatistics(new Document());
private final Document source;
/**
* Creates a new {@link GeoCommandStatistics} instance with the given source document.
*
* @param source must not be {@literal null}.
*/
private GeoCommandStatistics(Document source) {
Assert.notNull(source, "Source document must not be null!");
this.source = source;
}
/**
* Creates a new {@link GeoCommandStatistics} from the given command result extracting the statistics.
*
* @param commandResult must not be {@literal null}.
* @return
*/
public static GeoCommandStatistics from(Document commandResult) {
Assert.notNull(commandResult, "Command result must not be null!");
Object stats = commandResult.get("stats");
return stats == null ? NONE : new GeoCommandStatistics((Document) stats);
}
/**
* Returns the average distance reported by the command result. Mitigating a removal of the field in case the command
* didn't return any result introduced in MongoDB 3.2 RC1.
*
* @return
* @see <a href="https://jira.mongodb.org/browse/SERVER-21024">MongoDB Jira SERVER-21024</a>
*/
public double getAverageDistance() {
Object averageDistance = source.get("avgDistance");
return averageDistance == null ? Double.NaN : (Double) averageDistance;
}
}

View File

@@ -0,0 +1,136 @@
/*
* Copyright 2016-2017 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
*
* http://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.concurrent.TimeUnit;
import org.bson.Document;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.mongodb.core.index.IndexDefinition;
import org.springframework.data.mongodb.core.index.IndexInfo;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import com.mongodb.client.model.Collation;
import com.mongodb.client.model.IndexOptions;
/**
* {@link Converter Converters} for index-related MongoDB documents/types.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.0
*/
abstract class IndexConverters {
private static final Converter<IndexDefinition, IndexOptions> DEFINITION_TO_MONGO_INDEX_OPTIONS;
private static final Converter<Document, IndexInfo> DOCUMENT_INDEX_INFO;
static {
DEFINITION_TO_MONGO_INDEX_OPTIONS = getIndexDefinitionIndexOptionsConverter();
DOCUMENT_INDEX_INFO = getDocumentIndexInfoConverter();
}
private IndexConverters() {
}
static Converter<IndexDefinition, IndexOptions> indexDefinitionToIndexOptionsConverter() {
return DEFINITION_TO_MONGO_INDEX_OPTIONS;
}
static Converter<Document, IndexInfo> documentToIndexInfoConverter() {
return DOCUMENT_INDEX_INFO;
}
private static Converter<IndexDefinition, IndexOptions> getIndexDefinitionIndexOptionsConverter() {
return indexDefinition -> {
Document indexOptions = indexDefinition.getIndexOptions();
IndexOptions ops = new IndexOptions();
if (indexOptions.containsKey("name")) {
ops = ops.name(indexOptions.get("name").toString());
}
if (indexOptions.containsKey("unique")) {
ops = ops.unique((Boolean) indexOptions.get("unique"));
}
if (indexOptions.containsKey("sparse")) {
ops = ops.sparse((Boolean) indexOptions.get("sparse"));
}
if (indexOptions.containsKey("background")) {
ops = ops.background((Boolean) indexOptions.get("background"));
}
if (indexOptions.containsKey("expireAfterSeconds")) {
ops = ops.expireAfter((Long) indexOptions.get("expireAfterSeconds"), TimeUnit.SECONDS);
}
if (indexOptions.containsKey("min")) {
ops = ops.min(((Number) indexOptions.get("min")).doubleValue());
}
if (indexOptions.containsKey("max")) {
ops = ops.max(((Number) indexOptions.get("max")).doubleValue());
}
if (indexOptions.containsKey("bits")) {
ops = ops.bits((Integer) indexOptions.get("bits"));
}
if (indexOptions.containsKey("bucketSize")) {
ops = ops.bucketSize(((Number) indexOptions.get("bucketSize")).doubleValue());
}
if (indexOptions.containsKey("default_language")) {
ops = ops.defaultLanguage(indexOptions.get("default_language").toString());
}
if (indexOptions.containsKey("language_override")) {
ops = ops.languageOverride(indexOptions.get("language_override").toString());
}
if (indexOptions.containsKey("weights")) {
ops = ops.weights((org.bson.Document) indexOptions.get("weights"));
}
for (String key : indexOptions.keySet()) {
if (ObjectUtils.nullSafeEquals("2dsphere", indexOptions.get(key))) {
ops = ops.sphereVersion(2);
}
}
if (indexOptions.containsKey("partialFilterExpression")) {
ops = ops.partialFilterExpression((org.bson.Document) indexOptions.get("partialFilterExpression"));
}
if (indexOptions.containsKey("collation")) {
ops = ops.collation(fromDocument(indexOptions.get("collation", Document.class)));
}
return ops;
};
}
@Nullable
public static Collation fromDocument(@Nullable Document source) {
if (source == null) {
return null;
}
return org.springframework.data.mongodb.core.query.Collation.from(source).toMongoCollation();
}
private static Converter<Document, IndexInfo> getDocumentIndexInfoConverter() {
return IndexInfo::indexInfoOf;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2012 the original author or authors.
* Copyright 2011-2017 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.
@@ -15,9 +15,10 @@
*/
package org.springframework.data.mongodb.core;
import org.bson.Document;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.mongodb.DBObject;
import com.mongodb.WriteConcern;
/**
@@ -31,30 +32,33 @@ import com.mongodb.WriteConcern;
*
* @author Mark Pollack
* @author Oliver Gierke
* @author Christoph Strobl
*/
public class MongoAction {
private final String collectionName;
private final WriteConcern defaultWriteConcern;
private final Class<?> entityType;
private final MongoActionOperation mongoActionOperation;
private final DBObject query;
private final DBObject document;
private final @Nullable WriteConcern defaultWriteConcern;
private final @Nullable Class<?> entityType;
private final @Nullable Document query;
private final @Nullable Document document;
/**
* Create an instance of a {@link MongoAction}.
*
* @param defaultWriteConcern the default write concern.
* @param mongoActionOperation action being taken against the collection
* @param defaultWriteConcern the default write concern. Can be {@literal null}.
* @param mongoActionOperation action being taken against the collection. Must not be {@literal null}.
* @param collectionName the collection name, must not be {@literal null} or empty.
* @param entityType the POJO that is being operated against
* @param document the converted DBObject from the POJO or Spring Update object
* @param query the converted DBOjbect from the Spring Query object
* @param entityType the POJO that is being operated against. Can be {@literal null}.
* @param document the converted Document from the POJO or Spring Update object. Can be {@literal null}.
* @param query the converted Document from the Spring Query object. Can be {@literal null}.
*/
public MongoAction(WriteConcern defaultWriteConcern, MongoActionOperation mongoActionOperation,
String collectionName, Class<?> entityType, DBObject document, DBObject query) {
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!");
this.defaultWriteConcern = defaultWriteConcern;
this.mongoActionOperation = mongoActionOperation;
@@ -68,31 +72,28 @@ public class MongoAction {
return collectionName;
}
@Nullable
public WriteConcern getDefaultWriteConcern() {
return defaultWriteConcern;
}
/**
* @deprecated use {@link #getEntityType()} instead.
*/
@Deprecated
public Class<?> getEntityClass() {
return entityType;
}
@Nullable
public Class<?> getEntityType() {
return entityType;
}
@Nullable
public MongoActionOperation getMongoActionOperation() {
return mongoActionOperation;
}
public DBObject getQuery() {
@Nullable
public Document getQuery() {
return query;
}
public DBObject getDocument() {
@Nullable
public Document getDocument() {
return document;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2012 the original author or authors.
* Copyright 2011-2015 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.
@@ -25,5 +25,5 @@ package org.springframework.data.mongodb.core;
*/
public enum MongoActionOperation {
REMOVE, UPDATE, INSERT, INSERT_LIST, SAVE
REMOVE, UPDATE, INSERT, INSERT_LIST, SAVE, BULK;
}

View File

@@ -1,99 +1,78 @@
/*
* Copyright 2011-2013 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
*
* http://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.data.authentication.UserCredentials;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.util.Assert;
import com.mongodb.DB;
import com.mongodb.Mongo;
/**
* Mongo server administration exposed via JMX annotations
*
* @author Mark Pollack
/*
* Copyright 2011-2017 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
*
* http://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.bson.Document;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.util.Assert;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoDatabase;
/**
* Mongo server administration exposed via JMX annotations
*
* @author Mark Pollack
* @author Thomas Darimont
*/
@ManagedResource(description = "Mongo Admin Operations")
public class MongoAdmin implements MongoAdminOperations {
private final Mongo mongo;
private String username;
private String password;
private String authenticationDatabaseName;
public MongoAdmin(Mongo mongo) {
Assert.notNull(mongo);
this.mongo = mongo;
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.core.MongoAdminOperations#dropDatabase(java.lang.String)
*/
@ManagedOperation
public void dropDatabase(String databaseName) {
getDB(databaseName).dropDatabase();
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.core.MongoAdminOperations#createDatabase(java.lang.String)
*/
@ManagedOperation
public void createDatabase(String databaseName) {
getDB(databaseName);
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.core.MongoAdminOperations#getDatabaseStats(java.lang.String)
*/
@ManagedOperation
public String getDatabaseStats(String databaseName) {
return getDB(databaseName).getStats().toString();
}
/**
* Sets the username to use to connect to the Mongo database
*
* @param username The username to use
*/
public void setUsername(String username) {
this.username = username;
}
/**
* Sets the password to use to authenticate with the Mongo database.
*
* @param password The password to use
*/
public void setPassword(String password) {
this.password = password;
}
/**
* Sets the authenticationDatabaseName to use to authenticate with the Mongo database.
*
* @param authenticationDatabaseName The authenticationDatabaseName to use.
*/
public void setAuthenticationDatabaseName(String authenticationDatabaseName) {
this.authenticationDatabaseName = authenticationDatabaseName;
* @author Mark Paluch
* @author Christoph Strobl
*/
@ManagedResource(description = "Mongo Admin Operations")
public class MongoAdmin implements MongoAdminOperations {
private final MongoClient mongoClient;
public MongoAdmin(MongoClient mongoClient) {
Assert.notNull(mongoClient, "MongoClient must not be null!");
this.mongoClient = mongoClient;
}
DB getDB(String databaseName) {
return MongoDbUtils.getDB(mongo, databaseName, new UserCredentials(username, password), authenticationDatabaseName);
}
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.core.MongoAdminOperations#dropDatabase(java.lang.String)
*/
@ManagedOperation
public void dropDatabase(String databaseName) {
getDB(databaseName).drop();
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.core.MongoAdminOperations#createDatabase(java.lang.String)
*/
@ManagedOperation
public void createDatabase(String databaseName) {
getDB(databaseName);
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.core.MongoAdminOperations#getDatabaseStats(java.lang.String)
*/
@ManagedOperation
public String getDatabaseStats(String databaseName) {
return getDB(databaseName).runCommand(new Document("dbStats", 1).append("scale", 1024)).toJson();
}
@ManagedOperation
public String getServerStatus() {
return getDB("admin").runCommand(new Document("serverStatus", 1).append("rangeDeleter", 1).append("repl", 1))
.toJson();
}
MongoDatabase getDB(String databaseName) {
return mongoClient.getDatabase(databaseName);
}
}

View File

@@ -1,34 +1,34 @@
/*
* Copyright 2011-2014 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
*
* http://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.jmx.export.annotation.ManagedOperation;
/**
* @author Mark Pollack
* @author Oliver Gierke
*/
public interface MongoAdminOperations {
@ManagedOperation
void dropDatabase(String databaseName);
@ManagedOperation
void createDatabase(String databaseName);
@ManagedOperation
String getDatabaseStats(String databaseName);
}
/*
* Copyright 2011-2014 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
*
* http://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.jmx.export.annotation.ManagedOperation;
/**
* @author Mark Pollack
* @author Oliver Gierke
*/
public interface MongoAdminOperations {
@ManagedOperation
void dropDatabase(String databaseName);
@ManagedOperation
void createDatabase(String databaseName);
@ManagedOperation
String getDatabaseStats(String databaseName);
}

View File

@@ -0,0 +1,190 @@
/*
* Copyright 2015-2017 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
*
* http://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.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
/**
* Convenient factory for configuring MongoDB.
*
* @author Christoph Strobl
* @author Mark Paluch
* @since 1.7
*/
public class MongoClientFactoryBean extends AbstractFactoryBean<MongoClient> implements PersistenceExceptionTranslator {
private static final PersistenceExceptionTranslator DEFAULT_EXCEPTION_TRANSLATOR = new MongoExceptionTranslator();
private @Nullable MongoClientOptions mongoClientOptions;
private @Nullable String host;
private @Nullable Integer port;
private List<ServerAddress> replicaSetSeeds = Collections.emptyList();
private List<MongoCredential> credentials = Collections.emptyList();
private PersistenceExceptionTranslator exceptionTranslator = DEFAULT_EXCEPTION_TRANSLATOR;
/**
* Set the {@link MongoClientOptions} to be used when creating {@link MongoClient}.
*
* @param mongoClientOptions
*/
public void setMongoClientOptions(@Nullable MongoClientOptions mongoClientOptions) {
this.mongoClientOptions = mongoClientOptions;
}
/**
* Set the list of credentials to be used when creating {@link MongoClient}.
*
* @param credentials can be {@literal null}.
*/
public void setCredentials(@Nullable MongoCredential[] credentials) {
this.credentials = filterNonNullElementsAsList(credentials);
}
/**
* Set the list of {@link ServerAddress} to build up a replica set for.
*
* @param replicaSetSeeds can be {@literal null}.
*/
public void setReplicaSetSeeds(@Nullable ServerAddress[] replicaSetSeeds) {
this.replicaSetSeeds = filterNonNullElementsAsList(replicaSetSeeds);
}
/**
* Configures the host to connect to.
*
* @param host
*/
public void setHost(@Nullable String host) {
this.host = host;
}
/**
* Configures the port to connect to.
*
* @param port
*/
public void setPort(int port) {
this.port = port;
}
/**
* Configures the {@link PersistenceExceptionTranslator} to use.
*
* @param exceptionTranslator
*/
public void setExceptionTranslator(@Nullable PersistenceExceptionTranslator exceptionTranslator) {
this.exceptionTranslator = exceptionTranslator == null ? DEFAULT_EXCEPTION_TRANSLATOR : exceptionTranslator;
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
*/
public Class<? extends MongoClient> getObjectType() {
return MongoClient.class;
}
/*
* (non-Javadoc)
* @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
*/
@Nullable
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
return exceptionTranslator.translateExceptionIfPossible(ex);
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.config.AbstractFactoryBean#createInstance()
*/
@Override
protected MongoClient createInstance() throws Exception {
if (mongoClientOptions == null) {
mongoClientOptions = MongoClientOptions.builder().build();
}
return createMongoClient();
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.config.AbstractFactoryBean#destroyInstance(java.lang.Object)
*/
@Override
protected void destroyInstance(@Nullable MongoClient instance) throws Exception {
if (instance != null) {
instance.close();
}
}
private MongoClient createMongoClient() throws UnknownHostException {
if (!CollectionUtils.isEmpty(replicaSetSeeds)) {
return new MongoClient(replicaSetSeeds, credentials, mongoClientOptions);
}
return new MongoClient(createConfiguredOrDefaultServerAddress(), credentials, mongoClientOptions);
}
private ServerAddress createConfiguredOrDefaultServerAddress() throws UnknownHostException {
ServerAddress defaultAddress = new ServerAddress();
return new ServerAddress(StringUtils.hasText(host) ? host : defaultAddress.getHost(),
port != null ? port.intValue() : defaultAddress.getPort());
}
/**
* Returns the given array as {@link List} with all {@literal null} elements removed.
*
* @param elements the elements to filter <T>, can be {@literal null}.
* @return a new unmodifiable {@link List#} from the given elements without {@literal null}s.
*/
private static <T> List<T> filterNonNullElementsAsList(@Nullable T[] elements) {
if (elements == null) {
return Collections.emptyList();
}
List<T> candidateElements = new ArrayList<T>();
for (T element : elements) {
if (element != null) {
candidateElements.add(element);
}
}
return Collections.unmodifiableList(candidateElements);
}
}

View File

@@ -0,0 +1,314 @@
/*
* Copyright 2015-2017 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
*
* http://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 javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.lang.Nullable;
import com.mongodb.DBDecoderFactory;
import com.mongodb.DBEncoderFactory;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.ReadPreference;
import com.mongodb.WriteConcern;
/**
* A factory bean for construction of a {@link MongoClientOptions} instance.
*
* @author Christoph Strobl
* @author Oliver Gierke
* @author Mark Paluch
* @since 1.7
*/
public class MongoClientOptionsFactoryBean extends AbstractFactoryBean<MongoClientOptions> {
private static final MongoClientOptions DEFAULT_MONGO_OPTIONS = MongoClientOptions.builder().build();
private @Nullable String description = DEFAULT_MONGO_OPTIONS.getDescription();
private int minConnectionsPerHost = DEFAULT_MONGO_OPTIONS.getMinConnectionsPerHost();
private int connectionsPerHost = DEFAULT_MONGO_OPTIONS.getConnectionsPerHost();
private int threadsAllowedToBlockForConnectionMultiplier = DEFAULT_MONGO_OPTIONS
.getThreadsAllowedToBlockForConnectionMultiplier();
private int maxWaitTime = DEFAULT_MONGO_OPTIONS.getMaxWaitTime();
private int maxConnectionIdleTime = DEFAULT_MONGO_OPTIONS.getMaxConnectionIdleTime();
private int maxConnectionLifeTime = DEFAULT_MONGO_OPTIONS.getMaxConnectionLifeTime();
private int connectTimeout = DEFAULT_MONGO_OPTIONS.getConnectTimeout();
private int socketTimeout = DEFAULT_MONGO_OPTIONS.getSocketTimeout();
private boolean socketKeepAlive = DEFAULT_MONGO_OPTIONS.isSocketKeepAlive();
private @Nullable ReadPreference readPreference = DEFAULT_MONGO_OPTIONS.getReadPreference();
private DBDecoderFactory dbDecoderFactory = DEFAULT_MONGO_OPTIONS.getDbDecoderFactory();
private DBEncoderFactory dbEncoderFactory = DEFAULT_MONGO_OPTIONS.getDbEncoderFactory();
private @Nullable WriteConcern writeConcern = DEFAULT_MONGO_OPTIONS.getWriteConcern();
private @Nullable SocketFactory socketFactory = DEFAULT_MONGO_OPTIONS.getSocketFactory();
private boolean cursorFinalizerEnabled = DEFAULT_MONGO_OPTIONS.isCursorFinalizerEnabled();
private boolean alwaysUseMBeans = DEFAULT_MONGO_OPTIONS.isAlwaysUseMBeans();
private int heartbeatFrequency = DEFAULT_MONGO_OPTIONS.getHeartbeatFrequency();
private int minHeartbeatFrequency = DEFAULT_MONGO_OPTIONS.getMinHeartbeatFrequency();
private int heartbeatConnectTimeout = DEFAULT_MONGO_OPTIONS.getHeartbeatConnectTimeout();
private int heartbeatSocketTimeout = DEFAULT_MONGO_OPTIONS.getHeartbeatSocketTimeout();
private String requiredReplicaSetName = DEFAULT_MONGO_OPTIONS.getRequiredReplicaSetName();
private int serverSelectionTimeout = DEFAULT_MONGO_OPTIONS.getServerSelectionTimeout();
private boolean ssl;
private @Nullable SSLSocketFactory sslSocketFactory;
/**
* Set the {@link MongoClient} description.
*
* @param description
*/
public void setDescription(@Nullable String description) {
this.description = description;
}
/**
* Set the minimum number of connections per host.
*
* @param minConnectionsPerHost
*/
public void setMinConnectionsPerHost(int minConnectionsPerHost) {
this.minConnectionsPerHost = minConnectionsPerHost;
}
/**
* Set the number of connections allowed per host. Will block if run out. Default is 10. System property
* {@code MONGO.POOLSIZE} can override
*
* @param connectionsPerHost
*/
public void setConnectionsPerHost(int connectionsPerHost) {
this.connectionsPerHost = connectionsPerHost;
}
/**
* Set the multiplier for connectionsPerHost for # of threads that can block. Default is 5. If connectionsPerHost is
* 10, and threadsAllowedToBlockForConnectionMultiplier is 5, then 50 threads can block more than that and an
* exception will be thrown.
*
* @param threadsAllowedToBlockForConnectionMultiplier
*/
public void setThreadsAllowedToBlockForConnectionMultiplier(int threadsAllowedToBlockForConnectionMultiplier) {
this.threadsAllowedToBlockForConnectionMultiplier = threadsAllowedToBlockForConnectionMultiplier;
}
/**
* Set the max wait time of a blocking thread for a connection. Default is 12000 ms (2 minutes)
*
* @param maxWaitTime
*/
public void setMaxWaitTime(int maxWaitTime) {
this.maxWaitTime = maxWaitTime;
}
/**
* The maximum idle time for a pooled connection.
*
* @param maxConnectionIdleTime
*/
public void setMaxConnectionIdleTime(int maxConnectionIdleTime) {
this.maxConnectionIdleTime = maxConnectionIdleTime;
}
/**
* Set the maximum life time for a pooled connection.
*
* @param maxConnectionLifeTime
*/
public void setMaxConnectionLifeTime(int maxConnectionLifeTime) {
this.maxConnectionLifeTime = maxConnectionLifeTime;
}
/**
* Set the connect timeout in milliseconds. 0 is default and infinite.
*
* @param connectTimeout
*/
public void setConnectTimeout(int connectTimeout) {
this.connectTimeout = connectTimeout;
}
/**
* Set the socket timeout. 0 is default and infinite.
*
* @param socketTimeout
*/
public void setSocketTimeout(int socketTimeout) {
this.socketTimeout = socketTimeout;
}
/**
* Set the keep alive flag, controls whether or not to have socket keep alive timeout. Defaults to false.
*
* @param socketKeepAlive
*/
public void setSocketKeepAlive(boolean socketKeepAlive) {
this.socketKeepAlive = socketKeepAlive;
}
/**
* Set the {@link ReadPreference}.
*
* @param readPreference
*/
public void setReadPreference(@Nullable ReadPreference readPreference) {
this.readPreference = readPreference;
}
/**
* Set the {@link WriteConcern} that will be the default value used when asking the {@link MongoDbFactory} for a DB
* object.
*
* @param writeConcern
*/
public void setWriteConcern(@Nullable WriteConcern writeConcern) {
this.writeConcern = writeConcern;
}
/**
* @param socketFactory
*/
public void setSocketFactory(@Nullable SocketFactory socketFactory) {
this.socketFactory = socketFactory;
}
/**
* Set the frequency that the driver will attempt to determine the current state of each server in the cluster.
*
* @param heartbeatFrequency
*/
public void setHeartbeatFrequency(int heartbeatFrequency) {
this.heartbeatFrequency = heartbeatFrequency;
}
/**
* In the event that the driver has to frequently re-check a server's availability, it will wait at least this long
* since the previous check to avoid wasted effort.
*
* @param minHeartbeatFrequency
*/
public void setMinHeartbeatFrequency(int minHeartbeatFrequency) {
this.minHeartbeatFrequency = minHeartbeatFrequency;
}
/**
* Set the connect timeout for connections used for the cluster heartbeat.
*
* @param heartbeatConnectTimeout
*/
public void setHeartbeatConnectTimeout(int heartbeatConnectTimeout) {
this.heartbeatConnectTimeout = heartbeatConnectTimeout;
}
/**
* Set the socket timeout for connections used for the cluster heartbeat.
*
* @param heartbeatSocketTimeout
*/
public void setHeartbeatSocketTimeout(int heartbeatSocketTimeout) {
this.heartbeatSocketTimeout = heartbeatSocketTimeout;
}
/**
* Configures the name of the replica set.
*
* @param requiredReplicaSetName
*/
public void setRequiredReplicaSetName(String requiredReplicaSetName) {
this.requiredReplicaSetName = requiredReplicaSetName;
}
/**
* This controls if the driver should us an SSL connection. Defaults to |@literal false}.
*
* @param ssl
*/
public void setSsl(boolean ssl) {
this.ssl = ssl;
}
/**
* Set the {@link SSLSocketFactory} to use for the {@literal SSL} connection. If none is configured here,
* {@link SSLSocketFactory#getDefault()} will be used.
*
* @param sslSocketFactory
*/
public void setSslSocketFactory(@Nullable SSLSocketFactory sslSocketFactory) {
this.sslSocketFactory = sslSocketFactory;
this.ssl = sslSocketFactory != null;
}
/**
* Set the {@literal server selection timeout} in msec for a 3.x MongoDB Java driver. If not set the default value of
* 30 sec will be used. A value of 0 means that it will timeout immediately if no server is available. A negative
* value means to wait indefinitely.
*
* @param serverSelectionTimeout in msec.
*/
public void setServerSelectionTimeout(int serverSelectionTimeout) {
this.serverSelectionTimeout = serverSelectionTimeout;
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.config.AbstractFactoryBean#createInstance()
*/
@SuppressWarnings("ConstantConditions")
@Override
protected MongoClientOptions createInstance() throws Exception {
SocketFactory socketFactoryToUse = ssl
? (sslSocketFactory != null ? sslSocketFactory : SSLSocketFactory.getDefault())
: this.socketFactory;
return MongoClientOptions.builder() //
.alwaysUseMBeans(this.alwaysUseMBeans) //
.connectionsPerHost(this.connectionsPerHost) //
.connectTimeout(connectTimeout) //
.cursorFinalizerEnabled(cursorFinalizerEnabled) //
.dbDecoderFactory(dbDecoderFactory) //
.dbEncoderFactory(dbEncoderFactory) //
.description(description) //
.heartbeatConnectTimeout(heartbeatConnectTimeout) //
.heartbeatFrequency(heartbeatFrequency) //
.heartbeatSocketTimeout(heartbeatSocketTimeout) //
.maxConnectionIdleTime(maxConnectionIdleTime) //
.maxConnectionLifeTime(maxConnectionLifeTime) //
.maxWaitTime(maxWaitTime) //
.minConnectionsPerHost(minConnectionsPerHost) //
.minHeartbeatFrequency(minHeartbeatFrequency) //
.readPreference(readPreference) //
.requiredReplicaSetName(requiredReplicaSetName) //
.serverSelectionTimeout(serverSelectionTimeout) //
.socketFactory(socketFactoryToUse) //
.socketKeepAlive(socketKeepAlive) //
.socketTimeout(socketTimeout) //
.threadsAllowedToBlockForConnectionMultiplier(threadsAllowedToBlockForConnectionMultiplier) //
.writeConcern(writeConcern).build();
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
*/
public Class<?> getObjectType() {
return MongoClientOptions.class;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013 the original author or authors.
* Copyright 2013-2017 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.
@@ -16,6 +16,7 @@
package org.springframework.data.mongodb.core;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.mongodb.WriteResult;
@@ -40,7 +41,7 @@ public class MongoDataIntegrityViolationException extends DataIntegrityViolation
* @param actionOperation the {@link MongoActionOperation} that caused the exception, must not be {@literal null}.
*/
public MongoDataIntegrityViolationException(String message, WriteResult writeResult,
MongoActionOperation actionOperation) {
MongoActionOperation actionOperation) {
super(message);

View File

@@ -1,196 +0,0 @@
/*
* Copyright 2010-2013 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
*
* http://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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.authentication.UserCredentials;
import org.springframework.data.mongodb.CannotGetMongoDbConnectionException;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
import com.mongodb.DB;
import com.mongodb.Mongo;
/**
* Helper class featuring helper methods for internal MongoDb classes. Mainly intended for internal use within the
* framework.
*
* @author Thomas Risberg
* @author Graeme Rocher
* @author Oliver Gierke
* @author Randy Watler
* @author Thomas Darimont
* @since 1.0
*/
public abstract class MongoDbUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(MongoDbUtils.class);
/**
* Private constructor to prevent instantiation.
*/
private MongoDbUtils() {
}
/**
* Obtains a {@link DB} connection for the given {@link Mongo} instance and database name
*
* @param mongo the {@link Mongo} instance, must not be {@literal null}.
* @param databaseName the database name, must not be {@literal null} or empty.
* @return the {@link DB} connection
*/
public static DB getDB(Mongo mongo, String databaseName) {
return doGetDB(mongo, databaseName, UserCredentials.NO_CREDENTIALS, true, databaseName);
}
/**
* Obtains a {@link DB} connection for the given {@link Mongo} instance and database name
*
* @param mongo the {@link Mongo} instance, must not be {@literal null}.
* @param databaseName the database name, must not be {@literal null} or empty.
* @param credentials the credentials to use, must not be {@literal null}.
* @return the {@link DB} connection
*/
public static DB getDB(Mongo mongo, String databaseName, UserCredentials credentials) {
return getDB(mongo, databaseName, credentials, databaseName);
}
public static DB getDB(Mongo mongo, String databaseName, UserCredentials credentials,
String authenticationDatabaseName) {
Assert.notNull(mongo, "No Mongo instance specified!");
Assert.hasText(databaseName, "Database name must be given!");
Assert.notNull(credentials, "Credentials must not be null, use UserCredentials.NO_CREDENTIALS!");
Assert.hasText(authenticationDatabaseName, "Authentication database name must not be null or empty!");
return doGetDB(mongo, databaseName, credentials, true, authenticationDatabaseName);
}
private static DB doGetDB(Mongo mongo, String databaseName, UserCredentials credentials, boolean allowCreate,
String authenticationDatabaseName) {
DbHolder dbHolder = (DbHolder) TransactionSynchronizationManager.getResource(mongo);
// Do we have a populated holder and TX sync active?
if (dbHolder != null && !dbHolder.isEmpty() && TransactionSynchronizationManager.isSynchronizationActive()) {
DB db = dbHolder.getDB(databaseName);
// DB found but not yet synchronized
if (db != null && !dbHolder.isSynchronizedWithTransaction()) {
LOGGER.debug("Registering Spring transaction synchronization for existing MongoDB {}.", databaseName);
TransactionSynchronizationManager.registerSynchronization(new MongoSynchronization(dbHolder, mongo));
dbHolder.setSynchronizedWithTransaction(true);
}
if (db != null) {
return db;
}
}
// Lookup fresh database instance
LOGGER.debug("Getting Mongo Database name=[{}]", databaseName);
DB db = mongo.getDB(databaseName);
boolean credentialsGiven = credentials.hasUsername() && credentials.hasPassword();
DB authDb = databaseName.equals(authenticationDatabaseName) ? db : mongo.getDB(authenticationDatabaseName);
synchronized (authDb) {
if (credentialsGiven && !authDb.isAuthenticated()) {
String username = credentials.getUsername();
String password = credentials.hasPassword() ? credentials.getPassword() : null;
if (!authDb.authenticate(username, password == null ? null : password.toCharArray())) {
throw new CannotGetMongoDbConnectionException("Failed to authenticate to database [" + databaseName + "], "
+ credentials.toString(), databaseName, credentials);
}
}
}
// TX sync active, bind new database to thread
if (TransactionSynchronizationManager.isSynchronizationActive()) {
LOGGER.debug("Registering Spring transaction synchronization for MongoDB instance {}.", databaseName);
DbHolder holderToUse = dbHolder;
if (holderToUse == null) {
holderToUse = new DbHolder(databaseName, db);
} else {
holderToUse.addDB(databaseName, db);
}
// synchronize holder only if not yet synchronized
if (!holderToUse.isSynchronizedWithTransaction()) {
TransactionSynchronizationManager.registerSynchronization(new MongoSynchronization(holderToUse, mongo));
holderToUse.setSynchronizedWithTransaction(true);
}
if (holderToUse != dbHolder) {
TransactionSynchronizationManager.bindResource(mongo, holderToUse);
}
}
// Check whether we are allowed to return the DB.
if (!allowCreate && !isDBTransactional(db, mongo)) {
throw new IllegalStateException("No Mongo DB bound to thread, "
+ "and configuration does not allow creation of non-transactional one here");
}
return db;
}
/**
* Return whether the given DB instance is transactional, that is, bound to the current thread by Spring's transaction
* facilities.
*
* @param db the DB to check
* @param mongo the Mongo instance that the DB was created with (may be <code>null</code>)
* @return whether the DB is transactional
*/
public static boolean isDBTransactional(DB db, Mongo mongo) {
if (mongo == null) {
return false;
}
DbHolder dbHolder = (DbHolder) TransactionSynchronizationManager.getResource(mongo);
return dbHolder != null && dbHolder.containsDB(db);
}
/**
* Perform actual closing of the Mongo DB object, catching and logging any cleanup exceptions thrown.
*
* @param db the DB to close (may be <code>null</code>)
*/
public static void closeDB(DB db) {
if (db != null) {
LOGGER.debug("Closing Mongo DB object");
try {
db.requestDone();
} catch (Throwable ex) {
LOGGER.debug("Unexpected exception on closing Mongo DB object", ex);
}
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2013 the original author or authors.
* Copyright 2010-2017 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.
@@ -15,23 +15,30 @@
*/
package org.springframework.data.mongodb.core;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.bson.BsonInvalidOperationException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.dao.PermissionDeniedDataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.mongodb.BulkOperationException;
import org.springframework.data.mongodb.UncategorizedMongoDbException;
import org.springframework.data.mongodb.util.MongoDbErrorCodes;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import com.mongodb.MongoCursorNotFoundException;
import com.mongodb.BulkWriteException;
import com.mongodb.MongoBulkWriteException;
import com.mongodb.MongoException;
import com.mongodb.MongoException.CursorNotFound;
import com.mongodb.MongoException.DuplicateKey;
import com.mongodb.MongoException.Network;
import com.mongodb.MongoInternalException;
import com.mongodb.MongoServerSelectionException;
import com.mongodb.MongoSocketException;
import com.mongodb.MongoTimeoutException;
import com.mongodb.MongoServerException;
import com.mongodb.bulk.BulkWriteError;
/**
* Simple {@link PersistenceExceptionTranslator} for Mongo. Convert the given runtime exception to an appropriate
@@ -40,52 +47,86 @@ import com.mongodb.MongoTimeoutException;
*
* @author Oliver Gierke
* @author Michal Vich
* @author Christoph Strobl
*/
public class MongoExceptionTranslator implements PersistenceExceptionTranslator {
private static final Set<String> DULICATE_KEY_EXCEPTIONS = new HashSet<String>(
Arrays.asList("MongoException.DuplicateKey", "DuplicateKeyException"));
private static final Set<String> RESOURCE_FAILURE_EXCEPTIONS = new HashSet<String>(
Arrays.asList("MongoException.Network", "MongoSocketException", "MongoException.CursorNotFound",
"MongoCursorNotFoundException", "MongoServerSelectionException", "MongoTimeoutException"));
private static final Set<String> RESOURCE_USAGE_EXCEPTIONS = new HashSet<String>(
Arrays.asList("MongoInternalException"));
private static final Set<String> DATA_INTEGRETY_EXCEPTIONS = new HashSet<String>(
Arrays.asList("WriteConcernException", "MongoWriteException", "MongoBulkWriteException"));
/*
* (non-Javadoc)
* @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
*/
@Nullable
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
// Check for well-known MongoException subclasses.
if (ex instanceof DuplicateKey || ex instanceof DuplicateKeyException) {
if (ex instanceof BsonInvalidOperationException) {
throw new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
}
String exception = ClassUtils.getShortName(ClassUtils.getUserClass(ex.getClass()));
if (DULICATE_KEY_EXCEPTIONS.contains(exception)) {
return new DuplicateKeyException(ex.getMessage(), ex);
}
if (ex instanceof Network || ex instanceof MongoSocketException) {
if (RESOURCE_FAILURE_EXCEPTIONS.contains(exception)) {
return new DataAccessResourceFailureException(ex.getMessage(), ex);
}
if (ex instanceof CursorNotFound || ex instanceof MongoCursorNotFoundException) {
return new DataAccessResourceFailureException(ex.getMessage(), ex);
}
if (ex instanceof MongoServerSelectionException) {
return new DataAccessResourceFailureException(ex.getMessage(), ex);
}
if (ex instanceof MongoTimeoutException) {
return new DataAccessResourceFailureException(ex.getMessage(), ex);
}
if (ex instanceof MongoInternalException) {
if (RESOURCE_USAGE_EXCEPTIONS.contains(exception)) {
return new InvalidDataAccessResourceUsageException(ex.getMessage(), ex);
}
if (DATA_INTEGRETY_EXCEPTIONS.contains(exception)) {
if (ex instanceof MongoServerException) {
if (((MongoServerException) ex).getCode() == 11000) {
return new DuplicateKeyException(ex.getMessage(), ex);
}
if (ex instanceof MongoBulkWriteException) {
for (BulkWriteError x : ((MongoBulkWriteException) ex).getWriteErrors()) {
if (x.getCode() == 11000) {
return new DuplicateKeyException(ex.getMessage(), ex);
}
}
}
}
return new DataIntegrityViolationException(ex.getMessage(), ex);
}
if (ex instanceof BulkWriteException) {
return new BulkOperationException(ex.getMessage(), (BulkWriteException) ex);
}
// All other MongoExceptions
if (ex instanceof MongoException) {
int code = ((MongoException) ex).getCode();
if (code == 11000 || code == 11001) {
if (MongoDbErrorCodes.isDuplicateKeyCode(code)) {
throw new DuplicateKeyException(ex.getMessage(), ex);
} else if (code == 12000 || code == 13440) {
} else if (MongoDbErrorCodes.isDataAccessResourceFailureCode(code)) {
throw new DataAccessResourceFailureException(ex.getMessage(), ex);
} else if (code == 10003 || code == 12001 || code == 12010 || code == 12011 || code == 12012) {
} else if (MongoDbErrorCodes.isInvalidDataAccessApiUsageCode(code) || code == 10003 || code == 12001
|| code == 12010 || code == 12011 || code == 12012) {
throw new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
} else if (MongoDbErrorCodes.isPermissionDeniedCode(code)) {
throw new PermissionDeniedDataAccessException(ex.getMessage(), ex);
}
return new UncategorizedMongoDbException(ex.getMessage(), ex);
}

View File

@@ -1,192 +0,0 @@
/*
* Copyright 2010-2013 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
*
* http://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.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.mongodb.CannotGetMongoDbConnectionException;
import org.springframework.util.StringUtils;
import com.mongodb.Mongo;
import com.mongodb.MongoOptions;
import com.mongodb.ServerAddress;
import com.mongodb.WriteConcern;
/**
* Convenient factory for configuring MongoDB.
*
* @author Thomas Risberg
* @author Graeme Rocher
* @author Oliver Gierke
* @author Thomas Darimont
* @since 1.0
*/
public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, DisposableBean,
PersistenceExceptionTranslator {
private Mongo mongo;
private MongoOptions mongoOptions;
private String host;
private Integer port;
private WriteConcern writeConcern;
private List<ServerAddress> replicaSetSeeds;
private List<ServerAddress> replicaPair;
private PersistenceExceptionTranslator exceptionTranslator = new MongoExceptionTranslator();
public void setMongoOptions(MongoOptions mongoOptions) {
this.mongoOptions = mongoOptions;
}
public void setReplicaSetSeeds(ServerAddress[] replicaSetSeeds) {
this.replicaSetSeeds = filterNonNullElementsAsList(replicaSetSeeds);
}
/**
* @deprecated use {@link #setReplicaSetSeeds(ServerAddress[])} instead
*
* @param replicaPair
*/
@Deprecated
public void setReplicaPair(ServerAddress[] replicaPair) {
this.replicaPair = filterNonNullElementsAsList(replicaPair);
}
/**
* @param elements the elements to filter <T>
* @return a new unmodifiable {@link List#} from the given elements without nulls
*/
private <T> List<T> filterNonNullElementsAsList(T[] elements) {
if (elements == null) {
return Collections.emptyList();
}
List<T> candidateElements = new ArrayList<T>();
for (T element : elements) {
if (element != null) {
candidateElements.add(element);
}
}
return Collections.unmodifiableList(candidateElements);
}
public void setHost(String host) {
this.host = host;
}
public void setPort(int port) {
this.port = port;
}
/**
* Sets the {@link WriteConcern} to be configured for the {@link Mongo} instance to be created.
*
* @param writeConcern
*/
public void setWriteConcern(WriteConcern writeConcern) {
this.writeConcern = writeConcern;
}
public void setExceptionTranslator(PersistenceExceptionTranslator exceptionTranslator) {
this.exceptionTranslator = exceptionTranslator;
}
public Mongo getObject() throws Exception {
return mongo;
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
*/
public Class<? extends Mongo> getObjectType() {
return Mongo.class;
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
*/
public boolean isSingleton() {
return true;
}
/*
* (non-Javadoc)
* @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
*/
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
return exceptionTranslator.translateExceptionIfPossible(ex);
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@SuppressWarnings("deprecation")
public void afterPropertiesSet() throws Exception {
Mongo mongo;
ServerAddress defaultOptions = new ServerAddress();
if (mongoOptions == null) {
mongoOptions = new MongoOptions();
}
if (!isNullOrEmpty(replicaPair)) {
if (replicaPair.size() < 2) {
throw new CannotGetMongoDbConnectionException("A replica pair must have two server entries");
}
mongo = new Mongo(replicaPair.get(0), replicaPair.get(1), mongoOptions);
} else if (!isNullOrEmpty(replicaSetSeeds)) {
mongo = new Mongo(replicaSetSeeds, mongoOptions);
} else {
String mongoHost = StringUtils.hasText(host) ? host : defaultOptions.getHost();
mongo = port != null ? new Mongo(new ServerAddress(mongoHost, port), mongoOptions) : new Mongo(mongoHost,
mongoOptions);
}
if (writeConcern != null) {
mongo.setWriteConcern(writeConcern);
}
this.mongo = mongo;
}
private boolean isNullOrEmpty(Collection<?> elements) {
return elements == null || elements.isEmpty();
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
public void destroy() throws Exception {
this.mongo.close();
}
}

View File

@@ -1,248 +0,0 @@
/*
* Copyright 2010-2014 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
*
* http://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 javax.net.ssl.SSLSocketFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import com.mongodb.MongoOptions;
/**
* A factory bean for construction of a {@link MongoOptions} instance.
*
* @author Graeme Rocher
* @author Mark Pollack
* @author Mike Saavedra
* @author Thomas Darimont
*/
@SuppressWarnings("deprecation")
public class MongoOptionsFactoryBean implements FactoryBean<MongoOptions>, InitializingBean {
private static final MongoOptions DEFAULT_MONGO_OPTIONS = new MongoOptions();
private int connectionsPerHost = DEFAULT_MONGO_OPTIONS.connectionsPerHost;
private int threadsAllowedToBlockForConnectionMultiplier = DEFAULT_MONGO_OPTIONS.threadsAllowedToBlockForConnectionMultiplier;
private int maxWaitTime = DEFAULT_MONGO_OPTIONS.maxWaitTime;
private int connectTimeout = DEFAULT_MONGO_OPTIONS.connectTimeout;
private int socketTimeout = DEFAULT_MONGO_OPTIONS.socketTimeout;
private boolean socketKeepAlive = DEFAULT_MONGO_OPTIONS.socketKeepAlive;
private boolean autoConnectRetry = DEFAULT_MONGO_OPTIONS.autoConnectRetry;
private long maxAutoConnectRetryTime = DEFAULT_MONGO_OPTIONS.maxAutoConnectRetryTime;
private int writeNumber = DEFAULT_MONGO_OPTIONS.w;
private int writeTimeout = DEFAULT_MONGO_OPTIONS.wtimeout;
private boolean writeFsync = DEFAULT_MONGO_OPTIONS.fsync;
private boolean slaveOk = DEFAULT_MONGO_OPTIONS.slaveOk;
private boolean ssl;
private SSLSocketFactory sslSocketFactory;
private MongoOptions options;
/**
* Configures the maximum number of connections allowed per host until we will block.
*
* @param connectionsPerHost
*/
public void setConnectionsPerHost(int connectionsPerHost) {
this.connectionsPerHost = connectionsPerHost;
}
/**
* A multiplier for connectionsPerHost for # of threads that can block a connection. If connectionsPerHost is 10, and
* threadsAllowedToBlockForConnectionMultiplier is 5, then 50 threads can block. If more threads try to block an
* exception will be thrown.
*
* @param threadsAllowedToBlockForConnectionMultiplier
*/
public void setThreadsAllowedToBlockForConnectionMultiplier(int threadsAllowedToBlockForConnectionMultiplier) {
this.threadsAllowedToBlockForConnectionMultiplier = threadsAllowedToBlockForConnectionMultiplier;
}
/**
* Max wait time of a blocking thread for a connection.
*
* @param maxWaitTime
*/
public void setMaxWaitTime(int maxWaitTime) {
this.maxWaitTime = maxWaitTime;
}
/**
* Configures the connect timeout in milliseconds. Defaults to 0 (infinite time).
*
* @param connectTimeout
*/
public void setConnectTimeout(int connectTimeout) {
this.connectTimeout = connectTimeout;
}
/**
* Configures the socket timeout. Defaults to 0 (infinite time).
*
* @param socketTimeout
*/
public void setSocketTimeout(int socketTimeout) {
this.socketTimeout = socketTimeout;
}
/**
* Configures whether or not to have socket keep alive turned on (SO_KEEPALIVE). Defaults to {@literal false}.
*
* @param socketKeepAlive
*/
public void setSocketKeepAlive(boolean socketKeepAlive) {
this.socketKeepAlive = socketKeepAlive;
}
/**
* This specifies the number of servers to wait for on the write operation, and exception raising behavior. The 'w'
* option to the getlasterror command. Defaults to 0.
* <ul>
* <li>-1 = don't even report network errors</li>
* <li>0 = default, don't call getLastError by default</li>
* <li>1 = basic, call getLastError, but don't wait for slaves</li>
* <li>2 += wait for slaves</li>
* </ul>
*
* @param writeNumber the number of servers to wait for on the write operation, and exception raising behavior.
*/
public void setWriteNumber(int writeNumber) {
this.writeNumber = writeNumber;
}
/**
* Configures the timeout for write operations in milliseconds. This defaults to {@literal 0} (indefinite).
*
* @param writeTimeout
*/
public void setWriteTimeout(int writeTimeout) {
this.writeTimeout = writeTimeout;
}
/**
* Configures whether or not to fsync. The 'fsync' option to the getlasterror command. Defaults to {@literal false}.
*
* @param writeFsync to fsync on <code>write (true)<code>, otherwise {@literal false}.
*/
public void setWriteFsync(boolean writeFsync) {
this.writeFsync = writeFsync;
}
/**
* Configures whether or not the system retries automatically on a failed connect. This defaults to {@literal false}.
*/
public void setAutoConnectRetry(boolean autoConnectRetry) {
this.autoConnectRetry = autoConnectRetry;
}
/**
* Configures the maximum amount of time in millisecons to spend retrying to open connection to the same server. This
* defaults to {@literal 0}, which means to use the default {@literal 15s} if {@link #autoConnectRetry} is on.
*
* @param maxAutoConnectRetryTime the maxAutoConnectRetryTime to set
*/
public void setMaxAutoConnectRetryTime(long maxAutoConnectRetryTime) {
this.maxAutoConnectRetryTime = maxAutoConnectRetryTime;
}
/**
* Specifies if the driver is allowed to read from secondaries or slaves. Defaults to {@literal false}.
*
* @param slaveOk true if the driver should read from secondaries or slaves.
*/
public void setSlaveOk(boolean slaveOk) {
this.slaveOk = slaveOk;
}
/**
* Specifies if the driver should use an SSL connection to Mongo. This defaults to {@literal false}. By default
* {@link SSLSocketFactory#getDefault()} will be used. See {@link #setSslSocketFactory(SSLSocketFactory)} if you want
* to configure a custom factory.
*
* @param ssl true if the driver should use an SSL connection.
* @see #setSslSocketFactory(SSLSocketFactory)
*/
public void setSsl(boolean ssl) {
this.ssl = ssl;
}
/**
* Specifies the {@link SSLSocketFactory} to use for creating SSL connections to Mongo. Defaults to
* {@link SSLSocketFactory#getDefault()}. Implicitly activates {@link #setSsl(boolean)} if a non-{@literal null} value
* is given.
*
* @param sslSocketFactory the sslSocketFactory to use.
* @see #setSsl(boolean)
*/
public void setSslSocketFactory(SSLSocketFactory sslSocketFactory) {
setSsl(sslSocketFactory != null);
this.sslSocketFactory = sslSocketFactory;
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() {
MongoOptions options = new MongoOptions();
options.connectionsPerHost = connectionsPerHost;
options.threadsAllowedToBlockForConnectionMultiplier = threadsAllowedToBlockForConnectionMultiplier;
options.maxWaitTime = maxWaitTime;
options.connectTimeout = connectTimeout;
options.socketTimeout = socketTimeout;
options.socketKeepAlive = socketKeepAlive;
options.autoConnectRetry = autoConnectRetry;
options.maxAutoConnectRetryTime = maxAutoConnectRetryTime;
options.slaveOk = slaveOk;
options.w = writeNumber;
options.wtimeout = writeTimeout;
options.fsync = writeFsync;
if (ssl) {
options.setSocketFactory(sslSocketFactory != null ? sslSocketFactory : SSLSocketFactory.getDefault());
}
this.options = options;
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#getObject()
*/
public MongoOptions getObject() {
return this.options;
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
*/
public Class<?> getObjectType() {
return MongoOptions.class;
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
*/
public boolean isSingleton() {
return true;
}
}

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