Compare commits

..

216 Commits

Author SHA1 Message Date
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
401 changed files with 34016 additions and 6991 deletions

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

@@ -0,0 +1,9 @@
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).
- [ ] You provide your full name and an email address registered with your GitHub account. If youre a first-time submitter, make sure you have completed the [Contributors License Agreement form](https://support.springsource.com/spring_committer_signup).

View File

@@ -3,13 +3,28 @@ language: java
jdk:
- oraclejdk8
services:
- mongodb
before_script:
- mongod --version
env:
matrix:
- PROFILE=ci
- PROFILE=mongo-next
- PROFILE=mongo3
- PROFILE=mongo3-next
- PROFILE=mongo31
- PROFILE=mongo32
- PROFILE=mongo33
- PROFILE=mongo34-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.2-precise
packages:
- mongodb-org-server
- mongodb-org-shell
sudo: false

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>

107
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.8.0.RC1</version>
<version>2.0.0.M1</version>
<packaging>pom</packaging>
<name>Spring Data MongoDB</name>
@@ -15,7 +15,7 @@
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>1.7.0.RC1</version>
<version>2.0.0.M1</version>
</parent>
<modules>
@@ -28,9 +28,9 @@
<properties>
<project.type>multi</project.type>
<dist.id>spring-data-mongodb</dist.id>
<springdata.commons>1.11.0.RC1</springdata.commons>
<mongo>2.13.0</mongo>
<mongo.osgi>2.13.0</mongo.osgi>
<springdata.commons>2.0.0.M1</springdata.commons>
<mongo>3.2.2</mongo>
<mongo.reactivestreams>1.2.0</mongo.reactivestreams>
</properties>
<developers>
@@ -100,30 +100,25 @@
</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>
<profile>
<id>mongo-next</id>
<properties>
<mongo>2.14.0-SNAPSHOT</mongo>
</properties>
<repositories>
<repository>
<id>mongo-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</repository>
</repositories>
</profile>
<profile>
<id>mongo3</id>
<properties>
<mongo>3.0.2</mongo>
<mongo>3.0.4</mongo>
</properties>
</profile>
@@ -132,7 +127,7 @@
<id>mongo3-next</id>
<properties>
<mongo>3.0.0-SNAPSHOT</mongo>
<mongo>3.0.5-SNAPSHOT</mongo>
</properties>
<repositories>
@@ -143,6 +138,70 @@
</repositories>
</profile>
<profile>
<id>mongo31</id>
<properties>
<mongo>3.1.1</mongo>
</properties>
</profile>
<profile>
<id>mongo32</id>
<properties>
<mongo>3.2.2</mongo>
</properties>
</profile>
<profile>
<id>mongo33</id>
<properties>
<mongo>3.3.0</mongo>
</properties>
<repositories>
<repository>
<id>mongo-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</repository>
</repositories>
</profile>
<profile>
<id>mongo34-next</id>
<properties>
<mongo>3.4.0-SNAPSHOT</mongo>
</properties>
<repositories>
<repository>
<id>mongo-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</repository>
</repositories>
</profile>
<profile>
<id>release</id>
<build>
<plugins>
<plugin>
<groupId>org.jfrog.buildinfo</groupId>
<artifactId>artifactory-maven-plugin</artifactId>
<inherited>false</inherited>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<dependencies>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.8.0.RC1</version>
<version>2.0.0.M1</version>
<relativePath>../pom.xml</relativePath>
</parent>
@@ -14,8 +14,8 @@
<name>Spring Data MongoDB - Cross-Store Support</name>
<properties>
<jpa>2.0.0</jpa>
<hibernate>3.6.10.Final</hibernate>
<jpa>2.1.1</jpa>
<hibernate>5.2.1.Final</hibernate>
</properties>
<dependencies>
@@ -48,7 +48,15 @@
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.8.0.RC1</version>
<version>2.0.0.M1</version>
</dependency>
<!-- reactive -->
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>${reactor}</version>
<optional>true</optional>
</dependency>
<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>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2014 the original author or authors.
* Copyright 2011-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.
@@ -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,14 +30,16 @@ 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
*/
public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
@@ -45,7 +48,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 +75,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 +112,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 +133,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 +144,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 +179,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

@@ -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,7 +20,7 @@
<mongo:mapping-converter/>
<!-- Mongo config -->
<bean id="mongo" class="org.springframework.data.mongodb.core.MongoFactoryBean">
<bean id="mongo" class="org.springframework.data.mongodb.core.MongoClientFactoryBean">
<property name="host" value="localhost"/>
<property name="port" value="27017"/>
</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.8.0.RC1</version>
<version>2.0.0.M1</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.8.0.RC1</version>
<version>2.0.0.M1</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2013 the original author or authors.
* Copyright 2011-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.
@@ -30,6 +30,7 @@ import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.Mongo;
import com.mongodb.MongoClient;
import com.mongodb.WriteConcern;
/**
@@ -37,6 +38,7 @@ import com.mongodb.WriteConcern;
*
* @author Jon Brisbin
* @author Oliver Gierke
* @auhtor Christoph Strobl
*/
public class MongoLog4jAppender extends AppenderSkeleton {
@@ -58,8 +60,8 @@ public class MongoLog4jAppender extends AppenderSkeleton {
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 WriteConcern warnOrHigherWriteConcern = WriteConcern.ACKNOWLEDGED;
protected WriteConcern infoOrLowerWriteConcern = WriteConcern.UNACKNOWLEDGED;
protected Mongo mongo;
protected DB db;
@@ -128,7 +130,7 @@ public class MongoLog4jAppender extends AppenderSkeleton {
}
protected void connectToMongo() throws UnknownHostException {
this.mongo = new Mongo(host, port);
this.mongo = new MongoClient(host, port);
this.db = mongo.getDB(database);
}
@@ -160,7 +162,7 @@ public class MongoLog4jAppender extends AppenderSkeleton {
// Copy properties into document
Map<Object, Object> props = event.getProperties();
if (null != props && props.size() > 0) {
if (null != props && !props.isEmpty()) {
BasicDBObject propsDbo = new BasicDBObject();
for (Map.Entry<Object, Object> entry : props.entrySet()) {
propsDbo.put(entry.getKey().toString(), entry.getValue().toString());

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2013 the original author or authors.
* Copyright 2011-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.
@@ -22,37 +22,44 @@ import java.util.Calendar;
import org.apache.log4j.Logger;
import org.apache.log4j.MDC;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCursor;
import com.mongodb.Mongo;
import com.mongodb.MongoClient;
/**
* Integration tests for {@link MongoLog4jAppender}.
*
* @author Jon Brisbin
* @author Oliver Gierke
* @author Christoph Strobl
*/
public class MongoLog4jAppenderIntegrationTests {
static final String NAME = MongoLog4jAppenderIntegrationTests.class.getName();
Logger log = Logger.getLogger(NAME);
Mongo mongo;
private static final Logger log = Logger.getLogger(NAME);
MongoClient mongo;
DB db;
String collection;
@Before
public void setUp() throws Exception {
mongo = new Mongo("localhost", 27017);
mongo = new MongoClient("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();
}
@After
public void tearDown() {
db.getCollection(collection).remove(new BasicDBObject());
}
@Test
@@ -64,7 +71,6 @@ public class MongoLog4jAppenderIntegrationTests {
log.error("ERROR message");
DBCursor msgs = db.getCollection(collection).find();
assertThat(msgs.count(), is(4));
}

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

@@ -11,14 +11,14 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.8.0.RC1</version>
<version>2.0.0.M1</version>
<relativePath>../pom.xml</relativePath>
</parent>
<properties>
<validation>1.0.0.GA</validation>
<objenesis>1.3</objenesis>
<equalsverifier>1.5</equalsverifier>
<mongo>3.3.0</mongo>
</properties>
<dependencies>
@@ -59,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>
@@ -79,6 +79,52 @@
<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>
<version>${reactor}</version>
<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>
<!-- CDI -->
<dependency>
<groupId>javax.enterprise</groupId>
@@ -127,7 +173,7 @@
<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>
@@ -183,7 +229,7 @@
<version>${apt}</version>
<dependencies>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl}</version>
</dependency>
@@ -213,9 +259,11 @@
</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>

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

@@ -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,5 +1,5 @@
/*
* Copyright 2011-2015 the original author or authors.
* Copyright 2011-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,35 +15,16 @@
*/
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;
import com.mongodb.MongoClient;
@@ -56,16 +37,11 @@ import com.mongodb.MongoClient;
* @author Thomas Darimont
* @author Ryan Tenney
* @author Christoph Strobl
* @author Mark Paluch
* @see MongoConfigurationSupport
*/
@Configuration
public abstract class AbstractMongoConfiguration {
/**
* Return the name of the database to connect to.
*
* @return must not be {@literal null}.
*/
protected abstract String getDatabaseName();
public abstract class AbstractMongoConfiguration extends MongoConfigurationSupport {
/**
* Return the name of the authentication database to use. Defaults to {@literal null} and will turn into the value
@@ -118,11 +94,13 @@ public abstract class AbstractMongoConfiguration {
* 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.
*
* 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
protected String getMappingBasePackage() {
Package mappingBasePackage = getClass().getPackage();
@@ -142,47 +120,6 @@ public abstract class AbstractMongoConfiguration {
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.
@@ -202,53 +139,4 @@ public abstract class AbstractMongoConfiguration {
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;
}
}

View File

@@ -0,0 +1,92 @@
/*
* 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.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.MongoTemplate;
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
import org.springframework.data.mongodb.core.SimpleReactiveMongoDatabaseFactory;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
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
* @since 2.0
* @see MongoConfigurationSupport
*/
@Configuration
public abstract class AbstractReactiveMongoConfiguration 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 ReactiveMongoTemplate}.
*
* @return
*/
@Bean
public ReactiveMongoOperations reactiveMongoTemplate() throws Exception {
return new ReactiveMongoTemplate(mongoDbFactory(), mappingMongoConverter());
}
/**
* Creates a {@link SimpleMongoDbFactory} to be used by the {@link MongoTemplate}. Will use the {@link Mongo} instance
* configured in {@link #mongoClient()}.
*
* @see #mongoClient()
* @see #reactiveMongoTemplate()
* @return
* @throws Exception
*/
@Bean
public ReactiveMongoDatabaseFactory mongoDbFactory() {
return new SimpleReactiveMongoDatabaseFactory(mongoClient(), getDatabaseName());
}
/**
* 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 {
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-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.
@@ -67,12 +67,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,16 +121,21 @@ 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);
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(),
@@ -348,7 +354,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
/**
* {@link TypeFilter} that returns {@literal false} in case any of the given delegates matches.
*
*
* @author Oliver Gierke
*/
private static class NegatingFilter implements TypeFilter {
@@ -357,7 +363,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
/**
* Creates a new {@link NegatingFilter} with the given delegates.
*
*
* @param filters
*/
public NegatingFilter(TypeFilter... filters) {

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

@@ -0,0 +1,203 @@
/*
* 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.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.authentication.UserCredentials;
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.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;
import com.mongodb.MongoClient;
/**
* 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 #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(
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 CustomConversions} instance by default.
*
* @return must not be {@literal null}.
*/
@Bean
public CustomConversions customConversions() {
return new CustomConversions(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

@@ -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;
@@ -28,7 +32,7 @@ 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.util.StringUtils;
import org.w3c.dom.Element;
@@ -44,9 +48,21 @@ import com.mongodb.MongoURI;
* @author Oliver Gierke
* @author Thomas Darimont
* @author Christoph Strobl
* @author Viktor Khoroshko
*/
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)
@@ -70,13 +86,10 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
BeanDefinitionBuilder dbFactoryBuilder = BeanDefinitionBuilder.genericBeanDefinition(SimpleMongoDbFactory.class);
setPropertyValue(dbFactoryBuilder, element, "write-concern", "writeConcern");
BeanDefinition mongoUri = getMongoUri(element);
BeanDefinition mongoUri = getMongoUri(element, parserContext);
if (mongoUri != null) {
if (element.getAttributes().getLength() >= 2 && !element.hasAttribute("write-concern")) {
parserContext.getReaderContext().error("Configure either Mongo URI or details individually!",
parserContext.extractSource(element));
}
dbFactoryBuilder.addConstructorArgValue(mongoUri);
return getSourceBeanDefinition(dbFactoryBuilder, parserContext, element);
}
@@ -118,7 +131,7 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
*/
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");
@@ -149,12 +162,15 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
/**
* Creates a {@link BeanDefinition} for a {@link MongoURI} or {@link MongoClientURI} depending on configured
* attributes.
* 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 getMongoUri(Element element) {
private BeanDefinition getMongoUri(Element element, ParserContext parserContext) {
boolean hasClientUri = element.hasAttribute("client-uri");
@@ -162,6 +178,21 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
return null;
}
int allowedAttributesCount = 1;
for (String attribute : MONGO_URI_ALLOWED_ADDITIONAL_ATTRIBUTES) {
if (element.hasAttribute(attribute)) {
allowedAttributesCount++;
}
}
if (element.getAttributes().getLength() > allowedAttributesCount) {
parserContext.getReaderContext().error(
"Configure either " + (hasClientUri ? "Mongo Client URI" : "Mongo URI") + " or details individually!",
parserContext.extractSource(element));
}
Class<?> type = hasClientUri ? MongoClientURI.class : MongoURI.class;
String uri = hasClientUri ? element.getAttribute("client-uri") : element.getAttribute("uri");

View File

@@ -0,0 +1,145 @@
/*
* Copyright 2015-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.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 {@link BulkOperationException} if an error occurred during bulk processing.
*/
BulkWriteResult execute();
}

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,12 +15,30 @@
*/
package org.springframework.data.mongodb.core;
import com.mongodb.DBCollection;
import com.mongodb.MongoException;
import org.bson.Document;
import org.springframework.dao.DataAccessException;
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> {
T doInCollection(DBCollection collection) throws MongoException, DataAccessException;
/**
* @param collection never {@literal null}.
* @return
* @throws MongoException
* @throws DataAccessException
*/
T doInCollection(MongoCollection<Document> collection) throws MongoException, DataAccessException;
}

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,12 +15,15 @@
*/
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 {
@@ -29,5 +32,5 @@ interface CursorPreparer {
*
* @param cursor
*/
DBCursor prepare(DBCursor cursor);
FindIterable<Document> prepare(FindIterable<Document> cursor);
}

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,11 +15,16 @@
*/
package org.springframework.data.mongodb.core;
import com.mongodb.DB;
import com.mongodb.MongoException;
import org.springframework.dao.DataAccessException;
import com.mongodb.MongoException;
import com.mongodb.client.MongoDatabase;
/**
*
* @param <T>
*/
public interface DbCallback<T> {
T doInDB(DB db) throws MongoException, DataAccessException;
T doInDB(MongoDatabase db) throws MongoException, DataAccessException;
}

View File

@@ -0,0 +1,320 @@
/*
* Copyright 2015-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.core;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.bson.Document;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
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.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.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
* @since 1.9
*/
class DefaultBulkOperations implements BulkOperations {
private final MongoOperations mongoOperations;
private final BulkMode bulkMode;
private final String collectionName;
private PersistenceExceptionTranslator exceptionTranslator;
private WriteConcernResolver writeConcernResolver;
private WriteConcern defaultWriteConcern;
private BulkWriteOptions bulkOptions;
List<WriteModel<Document>> models = new ArrayList<WriteModel<Document>>();
/**
* Creates a new {@link DefaultBulkOperations} for the given {@link MongoOperations}, {@link BulkMode}, collection
* name and {@link WriteConcern}.
*
* @param mongoOperations The underlying {@link MongoOperations}, must not be {@literal null}.
* @param bulkMode must not be {@literal null}.
* @param collectionName Name of the collection to work on, must not be {@literal null} or empty.
* @param entityType the entity type, can be {@literal null}.
*/
DefaultBulkOperations(MongoOperations mongoOperations, BulkMode bulkMode, String collectionName,
Class<?> entityType) {
Assert.notNull(mongoOperations, "MongoOperations must not be null!");
Assert.notNull(bulkMode, "BulkMode must not be null!");
Assert.hasText(collectionName, "Collection name must not be null or empty!");
this.mongoOperations = mongoOperations;
this.bulkMode = bulkMode;
this.collectionName = collectionName;
this.exceptionTranslator = new MongoExceptionTranslator();
this.writeConcernResolver = DefaultWriteConcernResolver.INSTANCE;
this.bulkOptions = initBulkOperation();
}
/**
* Configures the {@link PersistenceExceptionTranslator} to be used. Defaults to {@link MongoExceptionTranslator}.
*
* @param exceptionTranslator can be {@literal null}.
*/
public void setExceptionTranslator(PersistenceExceptionTranslator exceptionTranslator) {
this.exceptionTranslator = exceptionTranslator == null ? new MongoExceptionTranslator() : exceptionTranslator;
}
/**
* Configures the {@link WriteConcernResolver} to be used. Defaults to {@link DefaultWriteConcernResolver}.
*
* @param writeConcernResolver can be {@literal null}.
*/
public void setWriteConcernResolver(WriteConcernResolver writeConcernResolver) {
this.writeConcernResolver = writeConcernResolver == null ? DefaultWriteConcernResolver.INSTANCE
: writeConcernResolver;
}
/**
* Configures the default {@link WriteConcern} to be used. Defaults to {@literal null}.
*
* @param defaultWriteConcern can be {@literal null}.
*/
public void setDefaultWriteConcern(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!");
models.add(new InsertOneModel<Document>((Document) mongoOperations.getConverter().convertToMongoType(document)));
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!");
for (Object document : documents) {
insert(document);
}
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(Arrays.asList(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(Arrays.asList(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!");
models.add(new DeleteManyModel<Document>(query.getQueryObject()));
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, bulkOptions);
} catch (BulkWriteException o_O) {
DataAccessException toThrow = exceptionTranslator.translateExceptionIfPossible(o_O);
throw toThrow == null ? o_O : toThrow;
} finally {
this.bulkOptions = initBulkOperation();
}
}
/**
* 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);
if (multi) {
models.add(new UpdateManyModel<Document>(query.getQueryObject(), update.getUpdateObject(), options));
} else {
models.add(new UpdateOneModel<Document>(query.getQueryObject(), update.getUpdateObject(), options));
}
return this;
}
private final BulkWriteOptions initBulkOperation() {
BulkWriteOptions options = new BulkWriteOptions();
switch (bulkMode) {
case ORDERED:
return options.ordered(true);
case UNORDERED:
return options.ordered(false);
}
throw new IllegalStateException("BulkMode was null!");
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2015 the original author or authors.
* Copyright 2011-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,22 +15,22 @@
*/
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.index.IndexDefinition;
import org.springframework.data.mongodb.core.index.IndexField;
import org.springframework.data.mongodb.core.index.IndexInfo;
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}.
@@ -39,28 +39,25 @@ import com.mongodb.MongoException;
* @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 final MongoOperations mongoOperations;
private final MongoDbFactory mongoDbFactory;
private final String collectionName;
/**
* 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}.
*/
public DefaultIndexOperations(MongoOperations mongoOperations, String collectionName) {
public DefaultIndexOperations(MongoDbFactory mongoDbFactory, String collectionName) {
Assert.notNull(mongoOperations, "MongoOperations must not be null!");
Assert.notNull(mongoDbFactory, "MongoDbFactory must not be null!");
Assert.notNull(collectionName, "Collection name can not be null!");
this.mongoOperations = mongoOperations;
this.mongoDbFactory = mongoDbFactory;
this.collectionName = collectionName;
}
@@ -68,17 +65,18 @@ public class DefaultIndexOperations implements IndexOperations {
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.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.createIndex(indexDefinition.getIndexKeys(), indexOptions);
} else {
collection.createIndex(indexDefinition.getIndexKeys());
}
return null;
public String ensureIndex(final IndexDefinition indexDefinition) {
return execute(collection -> {
Document indexOptions = indexDefinition.getIndexOptions();
if (indexOptions != null) {
IndexOptions ops = IndexConverters.indexDefinitionToIndexOptionsConverter().convert(indexDefinition);
return collection.createIndex(indexDefinition.getIndexKeys(), ops);
}
return collection.createIndex(indexDefinition.getIndexKeys());
});
}
@@ -87,11 +85,10 @@ public class DefaultIndexOperations implements IndexOperations {
* @see org.springframework.data.mongodb.core.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;
});
}
@@ -104,80 +101,46 @@ public class DefaultIndexOperations implements IndexOperations {
dropIndex("*");
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.IndexOperations#resetIndexCache()
*/
@Deprecated
public void resetIndexCache() {
mongoOperations.execute(collectionName, new CollectionCallback<Void>() {
public Void doInCollection(DBCollection collection) throws MongoException, DataAccessException {
ReflectiveDBCollectionInvoker.resetIndexCache(collection);
return null;
}
});
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.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;
}
});
}
public <T> T execute(CollectionCallback<T> callback) {
Assert.notNull(callback);
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,45 @@
/*
* 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.core;
import org.springframework.data.mongodb.MongoDbFactory;
/**
* {@link IndexOperationsProvider} to obtain {@link IndexOperations} from a given {@link MongoDbFactory}. TODO: Review
* me
*
* @author Mark Paluch
* @since 2.0
*/
class DefaultIndexOperationsProvider implements IndexOperationsProvider {
private final MongoDbFactory mongoDbFactory;
/**
* @param mongoDbFactory must not be {@literal null}.
*/
DefaultIndexOperationsProvider(MongoDbFactory mongoDbFactory) {
this.mongoDbFactory = mongoDbFactory;
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.IndexOperationsProvider#reactiveIndexOps(java.lang.String)
*/
@Override
public IndexOperations indexOps(String collectionName) {
return new DefaultIndexOperations(mongoDbFactory, collectionName);
}
}

View File

@@ -0,0 +1,102 @@
/*
* 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.core;
import org.bson.Document;
import org.springframework.data.mongodb.core.index.IndexDefinition;
import org.springframework.data.mongodb.core.index.IndexInfo;
import org.springframework.util.Assert;
import com.mongodb.reactivestreams.client.ListIndexesPublisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* Default implementation of {@link IndexOperations}.
*
* @author Mark Paluch
* @since 1.11
*/
public class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
private final ReactiveMongoOperations mongoOperations;
private final String collectionName;
/**
* Creates a new {@link DefaultReactiveIndexOperations}.
*
* @param mongoOperations must not be {@literal null}.
* @param collectionName must not be {@literal null}.
*/
public DefaultReactiveIndexOperations(ReactiveMongoOperations mongoOperations, String collectionName) {
Assert.notNull(mongoOperations, "ReactiveMongoOperations must not be null!");
Assert.notNull(collectionName, "Collection must not be null!");
this.mongoOperations = mongoOperations;
this.collectionName = collectionName;
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ReactiveIndexOperations#ensureIndex(org.springframework.data.mongodb.core.index.IndexDefinition)
*/
public Mono<String> ensureIndex(final IndexDefinition indexDefinition) {
return mongoOperations.execute(collectionName, (ReactiveCollectionCallback<String>) collection -> {
Document indexOptions = indexDefinition.getIndexOptions();
if (indexOptions != null) {
return collection.createIndex(indexDefinition.getIndexKeys(),
IndexConverters.indexDefinitionToIndexOptionsConverter().convert(indexDefinition));
}
return collection.createIndex(indexDefinition.getIndexKeys());
}).next();
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ReactiveIndexOperations#dropIndex(java.lang.String)
*/
public Mono<Void> dropIndex(final String name) {
return mongoOperations.execute(collectionName, collection -> {
return Mono.from(collection.dropIndex(name));
}).flatMap(success -> Mono.<Void>empty()).next();
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ReactiveIndexOperations#dropAllIndexes()
*/
public Mono<Void> dropAllIndexes() {
return dropIndex("*");
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ReactiveIndexOperations#getIndexInfo()
*/
public Flux<IndexInfo> getIndexInfo() {
return mongoOperations.execute(collectionName, collection -> {
ListIndexesPublisher<Document> indexesPublisher = collection.listIndexes(Document.class);
return Flux.from(indexesPublisher).map(IndexConverters.documentToIndexInfoConverter()::convert);
});
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2015 the original author or authors.
* Copyright 2014-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.
@@ -20,11 +20,13 @@ 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;
@@ -34,8 +36,9 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import com.mongodb.DB;
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}.
@@ -97,8 +100,13 @@ class DefaultScriptOperations implements ScriptOperations {
return mongoOperations.execute(new DbCallback<Object>() {
@Override
public Object doInDB(DB db) throws MongoException, DataAccessException {
return db.eval(script.getCode(), convertScriptArgs(args));
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");
}
});
}
@@ -115,8 +123,10 @@ class DefaultScriptOperations implements ScriptOperations {
return mongoOperations.execute(new DbCallback<Object>() {
@Override
public Object doInDB(DB db) throws MongoException, DataAccessException {
return db.eval(String.format("%s(%s)", scriptName, convertAndJoinScriptArgs(args)));
public Object doInDB(MongoDatabase db) throws MongoException, DataAccessException {
return db.runCommand(new Document("eval", String.format("%s(%s)", scriptName, convertAndJoinScriptArgs(args))))
.get("retval");
}
});
}
@@ -155,7 +165,7 @@ class DefaultScriptOperations implements ScriptOperations {
return scriptNames;
}
private Object[] convertScriptArgs(Object... args) {
private Object[] convertScriptArgs(boolean quote, Object... args) {
if (ObjectUtils.isEmpty(args)) {
return args;
@@ -164,15 +174,15 @@ class DefaultScriptOperations implements ScriptOperations {
List<Object> convertedValues = new ArrayList<Object>(args.length);
for (Object arg : args) {
convertedValues.add(arg instanceof String ? String.format("'%s'", arg) : this.mongoOperations.getConverter()
.convertToMongoType(arg));
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(args));
return ObjectUtils.isEmpty(args) ? "" : StringUtils.arrayToCommaDelimitedString(convertScriptArgs(true, args));
}
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2013 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.
@@ -13,33 +13,20 @@
* 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.core;
import org.springframework.data.domain.Sort.Direction;
import com.mongodb.WriteConcern;
/**
* An enum that specifies the ordering for sort or index specifications
*
* @deprecated prefer {@link Direction}
* @author Thomas Risberg
* Default {@link WriteConcernResolver} resolving the {@link WriteConcern} from the given {@link MongoAction}.
*
* @author Oliver Gierke
*/
@Deprecated
public enum Order {
enum DefaultWriteConcernResolver implements WriteConcernResolver {
ASCENDING {
@Override
public Direction toDirection() {
return Direction.ASC;
}
},
INSTANCE;
DESCENDING {
@Override
public Direction toDirection() {
return Direction.DESC;
}
};
public abstract Direction toDirection();
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,34 @@
/*
* 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.core;
import com.mongodb.DBCursor;
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 cursor
*/
<T> FindPublisher<T> prepare(FindPublisher<T> findPublisher);
}

View File

@@ -0,0 +1,72 @@
/*
* 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.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 https://jira.mongodb.org/browse/SERVER-21024
*/
public double getAverageDistance() {
Object averageDistance = source.get("avgDistance");
return averageDistance == null ? Double.NaN : (Double) averageDistance;
}
}

View File

@@ -0,0 +1,166 @@
/*
* 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.core;
import static org.springframework.data.domain.Sort.Direction.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
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.IndexField;
import org.springframework.data.mongodb.core.index.IndexInfo;
import org.springframework.util.ObjectUtils;
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;
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");
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);
}
}
return ops;
};
}
private static Converter<Document, IndexInfo> getDocumentIndexInfoConverter() {
return ix -> {
Document keyDocument = (Document) ix.get("key");
int numberOfElements = keyDocument.keySet().size();
List<IndexField> indexFields = new ArrayList<IndexField>(numberOfElements);
for (String key : keyDocument.keySet()) {
Object value = keyDocument.get(key);
if (TWO_D_IDENTIFIERS.contains(value)) {
indexFields.add(IndexField.geo(key));
} else if ("text".equals(value)) {
Document weights = (Document) 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.containsKey("unique") ? (Boolean) ix.get("unique") : false;
boolean sparse = ix.containsKey("sparse") ? (Boolean) ix.get("sparse") : false;
String language = ix.containsKey("default_language") ? (String) ix.get("default_language") : "";
return new IndexInfo(indexFields, name, unique, sparse, language);
};
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2015 the original author or authors.
* Copyright 2011-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.
@@ -35,7 +35,7 @@ public interface IndexOperations {
*
* @param indexDefinition must not be {@literal null}.
*/
void ensureIndex(IndexDefinition indexDefinition);
String ensureIndex(IndexDefinition indexDefinition);
/**
* Drops an index from this collection.
@@ -49,15 +49,6 @@ public interface IndexOperations {
*/
void dropAllIndexes();
/**
* Clears all indices that have not yet been applied to this collection.
*
* @deprecated since 1.7. The MongoDB Java driver version 3.0 does no longer support reseting the index cache.
* @throws {@link UnsupportedOperationException} when used with MongoDB Java driver version 3.0.
*/
@Deprecated
void resetIndexCache();
/**
* Returns the index information on the collection.
*

View File

@@ -0,0 +1,66 @@
/*
* 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.core;
import java.util.List;
import org.springframework.data.mongodb.core.index.IndexDefinition;
import org.springframework.data.mongodb.core.index.IndexInfo;
import org.springframework.util.Assert;
/**
* Adapter for creating synchronous {@link IndexOperations}.
*
* @author Christoph Strobl
* @since 2.0
*/
public interface IndexOperationsAdapter extends IndexOperations {
/**
* Obtain a blocking variant of {@link IndexOperations} wrapping {@link ReactiveIndexOperations}.
*
* @param reactiveIndexOperations must not be {@literal null}.
* @return never {@literal null}
*/
static IndexOperationsAdapter blocking(ReactiveIndexOperations reactiveIndexOperations) {
Assert.notNull(reactiveIndexOperations, "ReactiveIndexOperations must not be null!");
return new IndexOperationsAdapter() {
@Override
public String ensureIndex(IndexDefinition indexDefinition) {
return reactiveIndexOperations.ensureIndex(indexDefinition).block();
}
@Override
public void dropIndex(String name) {
reactiveIndexOperations.dropIndex(name).block();
}
@Override
public void dropAllIndexes() {
reactiveIndexOperations.dropAllIndexes().block();
}
@Override
public List<IndexInfo> getIndexInfo() {
return reactiveIndexOperations.getIndexInfo().collectList().block();
}
};
}
}

View File

@@ -0,0 +1,32 @@
/*
* 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.core;
/**
* TODO: Revisit for a better pattern.
* @author Mark Paluch
* @since 2.0
*/
public interface IndexOperationsProvider {
/**
* Returns the operations that can be performed on indexes
*
* @return index operations on the named collection
*/
IndexOperations indexOps(String collectionName);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2012 the original author or authors.
* Copyright 2011-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,9 +15,9 @@
*/
package org.springframework.data.mongodb.core;
import org.bson.Document;
import org.springframework.util.Assert;
import com.mongodb.DBObject;
import com.mongodb.WriteConcern;
/**
@@ -31,6 +31,7 @@ import com.mongodb.WriteConcern;
*
* @author Mark Pollack
* @author Oliver Gierke
* @author Christoph Strobl
*/
public class MongoAction {
@@ -38,8 +39,8 @@ public class MongoAction {
private final WriteConcern defaultWriteConcern;
private final Class<?> entityType;
private final MongoActionOperation mongoActionOperation;
private final DBObject query;
private final DBObject document;
private final Document query;
private final Document document;
/**
* Create an instance of a {@link MongoAction}.
@@ -48,11 +49,11 @@ public class MongoAction {
* @param mongoActionOperation action being taken against the collection
* @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 DBObject from the Spring Query object
* @param document the converted Document from the POJO or Spring Update object
* @param query the converted Document from the Spring Query object
*/
public MongoAction(WriteConcern defaultWriteConcern, MongoActionOperation mongoActionOperation,
String collectionName, Class<?> entityType, DBObject document, DBObject query) {
public MongoAction(WriteConcern defaultWriteConcern, MongoActionOperation mongoActionOperation, String collectionName,
Class<?> entityType, Document document, Document query) {
Assert.hasText(collectionName, "Collection name must not be null or empty!");
@@ -72,14 +73,6 @@ public class MongoAction {
return defaultWriteConcern;
}
/**
* @deprecated use {@link #getEntityType()} instead.
*/
@Deprecated
public Class<?> getEntityClass() {
return entityType;
}
public Class<?> getEntityType() {
return entityType;
}
@@ -88,11 +81,11 @@ public class MongoAction {
return mongoActionOperation;
}
public DBObject getQuery() {
public Document getQuery() {
return query;
}
public DBObject getDocument() {
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,5 +1,5 @@
/*
* Copyright 2010-2015 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.
@@ -16,10 +16,10 @@
package org.springframework.data.mongodb.core;
import java.util.Arrays;
import java.util.HashMap;
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;
@@ -28,10 +28,16 @@ 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.util.ClassUtils;
import com.mongodb.BulkWriteException;
import com.mongodb.MongoBulkWriteException;
import com.mongodb.MongoException;
import com.mongodb.MongoServerException;
import com.mongodb.bulk.BulkWriteError;
/**
* Simple {@link PersistenceExceptionTranslator} for Mongo. Convert the given runtime exception to an appropriate
@@ -44,18 +50,18 @@ import com.mongodb.MongoException;
*/
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> 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_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"));
Arrays.asList("WriteConcernException", "MongoWriteException", "MongoBulkWriteException"));
/*
* (non-Javadoc)
@@ -65,6 +71,10 @@ public class MongoExceptionTranslator implements PersistenceExceptionTranslator
// Check for well-known MongoException subclasses.
if (ex instanceof BsonInvalidOperationException) {
throw new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
}
String exception = ClassUtils.getShortName(ClassUtils.getUserClass(ex.getClass()));
if (DULICATE_KEY_EXCEPTIONS.contains(exception)) {
@@ -80,9 +90,27 @@ public class MongoExceptionTranslator implements PersistenceExceptionTranslator
}
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) {
@@ -106,126 +134,4 @@ public class MongoExceptionTranslator implements PersistenceExceptionTranslator
// that translation should not occur.
return null;
}
/**
* {@link MongoDbErrorCodes} holds MongoDB specific error codes outlined in {@literal mongo/base/error_codes.err}.
*
* @author Christoph Strobl
* @since 1.8
*/
public static final class MongoDbErrorCodes {
static HashMap<Integer, String> dataAccessResourceFailureCodes;
static HashMap<Integer, String> dataIntegrityViolationCodes;
static HashMap<Integer, String> duplicateKeyCodes;
static HashMap<Integer, String> invalidDataAccessApiUsageExeption;
static HashMap<Integer, String> permissionDeniedCodes;
static HashMap<Integer, String> errorCodes;
static {
dataAccessResourceFailureCodes = new HashMap<Integer, String>(10);
dataAccessResourceFailureCodes.put(6, "HostUnreachable");
dataAccessResourceFailureCodes.put(7, "HostNotFound");
dataAccessResourceFailureCodes.put(89, "NetworkTimeout");
dataAccessResourceFailureCodes.put(91, "ShutdownInProgress");
dataAccessResourceFailureCodes.put(12000, "SlaveDelayDifferential");
dataAccessResourceFailureCodes.put(10084, "CannotFindMapFile64Bit");
dataAccessResourceFailureCodes.put(10085, "CannotFindMapFile");
dataAccessResourceFailureCodes.put(10357, "ShutdownInProgress");
dataAccessResourceFailureCodes.put(10359, "Header==0");
dataAccessResourceFailureCodes.put(13440, "BadOffsetInFile");
dataAccessResourceFailureCodes.put(13441, "BadOffsetInFile");
dataAccessResourceFailureCodes.put(13640, "DataFileHeaderCorrupt");
dataIntegrityViolationCodes = new HashMap<Integer, String>(6);
dataIntegrityViolationCodes.put(67, "CannotCreateIndex");
dataIntegrityViolationCodes.put(68, "IndexAlreadyExists");
dataIntegrityViolationCodes.put(85, "IndexOptionsConflict");
dataIntegrityViolationCodes.put(86, "IndexKeySpecsConflict");
dataIntegrityViolationCodes.put(112, "WriteConflict");
dataIntegrityViolationCodes.put(117, "ConflictingOperationInProgress");
duplicateKeyCodes = new HashMap<Integer, String>(3);
duplicateKeyCodes.put(3, "OBSOLETE_DuplicateKey");
duplicateKeyCodes.put(84, "DuplicateKeyValue");
duplicateKeyCodes.put(11000, "DuplicateKey");
duplicateKeyCodes.put(11001, "DuplicateKey");
invalidDataAccessApiUsageExeption = new HashMap<Integer, String>();
invalidDataAccessApiUsageExeption.put(5, "GraphContainsCycle");
invalidDataAccessApiUsageExeption.put(9, "FailedToParse");
invalidDataAccessApiUsageExeption.put(14, "TypeMismatch");
invalidDataAccessApiUsageExeption.put(15, "Overflow");
invalidDataAccessApiUsageExeption.put(16, "InvalidLength");
invalidDataAccessApiUsageExeption.put(20, "IllegalOperation");
invalidDataAccessApiUsageExeption.put(21, "EmptyArrayOperation");
invalidDataAccessApiUsageExeption.put(22, "InvalidBSON");
invalidDataAccessApiUsageExeption.put(23, "AlreadyInitialized");
invalidDataAccessApiUsageExeption.put(29, "NonExistentPath");
invalidDataAccessApiUsageExeption.put(30, "InvalidPath");
invalidDataAccessApiUsageExeption.put(40, "ConflictingUpdateOperators");
invalidDataAccessApiUsageExeption.put(45, "UserDataInconsistent");
invalidDataAccessApiUsageExeption.put(30, "DollarPrefixedFieldName");
invalidDataAccessApiUsageExeption.put(52, "InvalidPath");
invalidDataAccessApiUsageExeption.put(53, "InvalidIdField");
invalidDataAccessApiUsageExeption.put(54, "NotSingleValueField");
invalidDataAccessApiUsageExeption.put(55, "InvalidDBRef");
invalidDataAccessApiUsageExeption.put(56, "EmptyFieldName");
invalidDataAccessApiUsageExeption.put(57, "DottedFieldName");
invalidDataAccessApiUsageExeption.put(59, "CommandNotFound");
invalidDataAccessApiUsageExeption.put(60, "DatabaseNotFound");
invalidDataAccessApiUsageExeption.put(61, "ShardKeyNotFound");
invalidDataAccessApiUsageExeption.put(62, "OplogOperationUnsupported");
invalidDataAccessApiUsageExeption.put(66, "ImmutableField");
invalidDataAccessApiUsageExeption.put(72, "InvalidOptions");
invalidDataAccessApiUsageExeption.put(115, "CommandNotSupported");
invalidDataAccessApiUsageExeption.put(116, "DocTooLargeForCapped");
invalidDataAccessApiUsageExeption.put(130, "SymbolNotFound");
invalidDataAccessApiUsageExeption.put(17280, "KeyTooLong");
invalidDataAccessApiUsageExeption.put(13334, "ShardKeyTooBig");
permissionDeniedCodes = new HashMap<Integer, String>();
permissionDeniedCodes.put(11, "UserNotFound");
permissionDeniedCodes.put(18, "AuthenticationFailed");
permissionDeniedCodes.put(31, "RoleNotFound");
permissionDeniedCodes.put(32, "RolesNotRelated");
permissionDeniedCodes.put(33, "PrvilegeNotFound");
permissionDeniedCodes.put(15847, "CannotAuthenticate");
permissionDeniedCodes.put(16704, "CannotAuthenticateToAdminDB");
permissionDeniedCodes.put(16705, "CannotAuthenticateToAdminDB");
errorCodes = new HashMap<Integer, String>();
errorCodes.putAll(dataAccessResourceFailureCodes);
errorCodes.putAll(dataIntegrityViolationCodes);
errorCodes.putAll(duplicateKeyCodes);
errorCodes.putAll(invalidDataAccessApiUsageExeption);
errorCodes.putAll(permissionDeniedCodes);
}
public static boolean isDataIntegrityViolationCode(Integer errorCode) {
return errorCode == null ? false : dataIntegrityViolationCodes.containsKey(errorCode);
}
public static boolean isDataAccessResourceFailureCode(Integer errorCode) {
return errorCode == null ? false : dataAccessResourceFailureCodes.containsKey(errorCode);
}
public static boolean isDuplicateKeyCode(Integer errorCode) {
return errorCode == null ? false : duplicateKeyCodes.containsKey(errorCode);
}
public static boolean isPermissionDeniedCode(Integer errorCode) {
return errorCode == null ? false : permissionDeniedCodes.containsKey(errorCode);
}
public static boolean isInvalidDataAccessApiUsageCode(Integer errorCode) {
return errorCode == null ? false : invalidDataAccessApiUsageExeption.containsKey(errorCode);
}
public static String getErrorDescription(Integer errorCode) {
return errorCode == null ? null : errorCodes.get(errorCode);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2015 the original author or authors.
* Copyright 2011-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.
@@ -19,7 +19,9 @@ import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.bson.Document;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.mongodb.core.BulkOperations.BulkMode;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
@@ -35,13 +37,12 @@ import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.util.CloseableIterator;
import com.mongodb.CommandResult;
import com.mongodb.Cursor;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.ReadPreference;
import com.mongodb.WriteResult;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
/**
* Interface that specifies a basic set of MongoDB operations. Implemented by {@link MongoTemplate}. Not often used but
@@ -68,12 +69,12 @@ public interface MongoOperations {
/**
* Execute the a MongoDB command expressed as a JSON string. This will call the method JSON.parse that is part of the
* MongoDB driver to convert the JSON string to a DBObject. Any errors that result from executing this command will be
* MongoDB driver to convert the JSON string to a Document. Any errors that result from executing this command will be
* converted into Spring's DAO exception hierarchy.
*
* @param jsonCommand a MongoDB command expressed as a JSON string.
*/
CommandResult executeCommand(String jsonCommand);
Document executeCommand(String jsonCommand);
/**
* Execute a MongoDB command. Any errors that result from executing this command will be converted into Spring's DAO
@@ -81,19 +82,7 @@ public interface MongoOperations {
*
* @param command a MongoDB command
*/
CommandResult executeCommand(DBObject command);
/**
* Execute a MongoDB command. Any errors that result from executing this command will be converted into Spring's DAO
* exception hierarchy.
*
* @param command a MongoDB command
* @param options query options to use
* @deprecated since 1.7. Please use {@link #executeCommand(DBObject, ReadPreference)}, as the MongoDB Java driver
* version 3 no longer supports this operation.
*/
@Deprecated
CommandResult executeCommand(DBObject command, int options);
Document executeCommand(Document command);
/**
* Execute a MongoDB command. Any errors that result from executing this command will be converted into Spring's data
@@ -104,7 +93,7 @@ public interface MongoOperations {
* @return
* @since 1.7
*/
CommandResult executeCommand(DBObject command, ReadPreference readPreference);
Document executeCommand(Document command, ReadPreference readPreference);
/**
* Execute a MongoDB query and iterate over the query results on a per-document basis with a DocumentCallbackHandler.
@@ -151,22 +140,6 @@ public interface MongoOperations {
*/
<T> T execute(String collectionName, CollectionCallback<T> action);
/**
* Executes the given {@link DbCallback} within the same connection to the database so as to ensure consistency in a
* write heavy environment where you may read the data that you wrote. See the comments on {@see <a
* href=http://www.mongodb.org/display/DOCS/Java+Driver+Concurrency>Java Driver Concurrency</a>}
* <p/>
* Allows for returning a result object, that is a domain object or a collection of domain objects.
*
* @param <T> return type
* @param action callback that specified the MongoDB actions to perform on the DB instance
* @return a result object returned by the action or <tt>null</tt>
* @deprecated since 1.7 as the MongoDB Java driver version 3 does not longer support request boundaries via
* {@link DB#requestStart()} and {@link DB#requestDone()}.
*/
@Deprecated
<T> T executeInSession(DbCallback<T> action);
/**
* Executes the given {@link Query} on the entity collection of the specified {@code entityType} backed by a Mongo DB
* {@link Cursor}.
@@ -174,29 +147,44 @@ public interface MongoOperations {
* Returns a {@link CloseableIterator} that wraps the a Mongo DB {@link Cursor} that needs to be closed.
*
* @param <T> element return type
* @param query
* @param entityType
* @return
* @param query must not be {@literal null}.
* @param entityType must not be {@literal null}.
* @return will never be {@literal null}.
* @since 1.7
*/
<T> CloseableIterator<T> stream(Query query, Class<T> entityType);
/**
* Executes the given {@link Query} on the entity collection of the specified {@code entityType} and collection backed
* by a Mongo DB {@link Cursor}.
* <p>
* Returns a {@link CloseableIterator} that wraps the a Mongo DB {@link Cursor} that needs to be closed.
*
* @param <T> element return type
* @param query must not be {@literal null}.
* @param entityType must not be {@literal null}.
* @param collectionName must not be {@literal null} or empty.
* @return will never be {@literal null}.
* @since 1.10
*/
<T> CloseableIterator<T> stream(Query query, Class<T> entityType, String collectionName);
/**
* Create an uncapped collection with a name based on the provided entity class.
*
* @param entityClass class that determines the collection to create
* @return the created collection
*/
<T> DBCollection createCollection(Class<T> entityClass);
<T> MongoCollection<Document> createCollection(Class<T> entityClass);
/**
* Create a collect with a name based on the provided entity class using the options.
* Create a collection with a name based on the provided entity class using the options.
*
* @param entityClass class that determines the collection to create
* @param collectionOptions options to use when creating the collection.
* @return the created collection
*/
<T> DBCollection createCollection(Class<T> entityClass, CollectionOptions collectionOptions);
<T> MongoCollection<Document> createCollection(Class<T> entityClass, CollectionOptions collectionOptions);
/**
* Create an uncapped collection with the provided name.
@@ -204,16 +192,16 @@ public interface MongoOperations {
* @param collectionName name of the collection
* @return the created collection
*/
DBCollection createCollection(String collectionName);
MongoCollection<Document> createCollection(String collectionName);
/**
* Create a collect with the provided name and options.
* Create a collection with the provided name and options.
*
* @param collectionName name of the collection
* @param collectionOptions options to use when creating the collection.
* @return the created collection
*/
DBCollection createCollection(String collectionName, CollectionOptions collectionOptions);
MongoCollection<Document> createCollection(String collectionName, CollectionOptions collectionOptions);
/**
* A set of collection names.
@@ -230,7 +218,7 @@ public interface MongoOperations {
* @param collectionName name of the collection
* @return an existing collection or a newly created one.
*/
DBCollection getCollection(String collectionName);
MongoCollection<Document> getCollection(String collectionName);
/**
* Check to see if a collection with a name indicated by the entity class exists.
@@ -292,6 +280,34 @@ public interface MongoOperations {
*/
ScriptOperations scriptOps();
/**
* Returns a new {@link BulkOperations} for the given collection.
*
* @param mode the {@link BulkMode} to use for bulk operations, must not be {@literal null}.
* @param collectionName the name of the collection to work on, must not be {@literal null} or empty.
* @return {@link BulkOperations} on the named collection
*/
BulkOperations bulkOps(BulkMode mode, String collectionName);
/**
* Returns a new {@link BulkOperations} for the given entity type.
*
* @param mode the {@link BulkMode} to use for bulk operations, must not be {@literal null}.
* @param entityType the name of the entity class, must not be {@literal null}.
* @return {@link BulkOperations} on the named collection associated of the given entity class.
*/
BulkOperations bulkOps(BulkMode mode, Class<?> entityType);
/**
* Returns a new {@link BulkOperations} for the given entity type and collection name.
*
* @param mode the {@link BulkMode} to use for bulk operations, must not be {@literal null}.
* @param entityClass the name of the entity class, must not be {@literal null}.
* @param collectionName the name of the collection to work on, must not be {@literal null} or empty.
* @return {@link BulkOperations} on the named collection associated with the given entity class.
*/
BulkOperations bulkOps(BulkMode mode, Class<?> entityType, String collectionName);
/**
* Query for a list of objects of type T from the collection used by the entity class.
* <p/>
@@ -600,8 +616,8 @@ public interface MongoOperations {
<T> T findById(Object id, Class<T> entityClass, String collectionName);
/**
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify<a/>
* to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query}.
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify
* <a/> to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query}.
*
* @param query the {@link Query} class that specifies the {@link Criteria} used to find a record and also an optional
* fields specification.
@@ -612,8 +628,8 @@ public interface MongoOperations {
<T> T findAndModify(Query query, Update update, Class<T> entityClass);
/**
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify<a/>
* to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query}.
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify
* <a/> to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query}.
*
* @param query the {@link Query} class that specifies the {@link Criteria} used to find a record and also an optional
* fields specification.
@@ -625,8 +641,8 @@ public interface MongoOperations {
<T> T findAndModify(Query query, Update update, Class<T> entityClass, String collectionName);
/**
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify<a/>
* to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query} taking
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify
* <a/> to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query} taking
* {@link FindAndModifyOptions} into account.
*
* @param query the {@link Query} class that specifies the {@link Criteria} used to find a record and also an optional
@@ -639,8 +655,8 @@ public interface MongoOperations {
<T> T findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass);
/**
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify<a/>
* to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query} taking
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify
* <a/> to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query} taking
* {@link FindAndModifyOptions} into account.
*
* @param query the {@link Query} class that specifies the {@link Criteria} used to find a record and also an optional
@@ -728,9 +744,9 @@ public interface MongoOperations {
* <p/>
* If you object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property is a
* String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from ObjectId to your
* property type will be handled by Spring's BeanWrapper class that leverages Type Conversion API. See <a
* href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html#core-convert"
* >Spring's Type Conversion"</a> for more details.
* property type will be handled by Spring's BeanWrapper class that leverages Type Conversion API. See
* <a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html#core-convert" >
* Spring's Type Conversion"</a> for more details.
* <p/>
* <p/>
* Insert is used to initially store the object into the database. To update an existing object use the save method.
@@ -785,9 +801,9 @@ public interface MongoOperations {
* <p/>
* If you object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property is a
* String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from ObjectId to your
* property type will be handled by Spring's BeanWrapper class that leverages Type Conversion API. See <a
* href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html#core-convert"
* >Spring's Type Conversion"</a> for more details.
* property type will be handled by Spring's BeanWrapper class that leverages Type Conversion API. See
* <a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html#core-convert" >
* Spring's Type Conversion"</a> for more details.
*
* @param objectToSave the object to store in the collection
*/
@@ -820,7 +836,7 @@ public interface MongoOperations {
* @param entityClass class that determines the collection to use
* @return the WriteResult which lets you access the results of the previous write.
*/
WriteResult upsert(Query query, Update update, Class<?> entityClass);
UpdateResult upsert(Query query, Update update, Class<?> entityClass);
/**
* Performs an upsert. If no document is found that matches the query, a new document is created and inserted by
@@ -832,7 +848,7 @@ public interface MongoOperations {
* @param collectionName name of the collection to update the object in
* @return the WriteResult which lets you access the results of the previous write.
*/
WriteResult upsert(Query query, Update update, String collectionName);
UpdateResult upsert(Query query, Update update, String collectionName);
/**
* Performs an upsert. If no document is found that matches the query, a new document is created and inserted by
@@ -844,7 +860,7 @@ public interface MongoOperations {
* @param collectionName name of the collection to update the object in
* @return the WriteResult which lets you access the results of the previous write.
*/
WriteResult upsert(Query query, Update update, Class<?> entityClass, String collectionName);
UpdateResult upsert(Query query, Update update, Class<?> entityClass, String collectionName);
/**
* Updates the first object that is found in the collection of the entity class that matches the query document with
@@ -856,7 +872,7 @@ public interface MongoOperations {
* @param entityClass class that determines the collection to use
* @return the WriteResult which lets you access the results of the previous write.
*/
WriteResult updateFirst(Query query, Update update, Class<?> entityClass);
UpdateResult updateFirst(Query query, Update update, Class<?> entityClass);
/**
* Updates the first object that is found in the specified collection that matches the query document criteria with
@@ -868,7 +884,7 @@ public interface MongoOperations {
* @param collectionName name of the collection to update the object in
* @return the WriteResult which lets you access the results of the previous write.
*/
WriteResult updateFirst(Query query, Update update, String collectionName);
UpdateResult updateFirst(Query query, Update update, String collectionName);
/**
* Updates the first object that is found in the specified collection that matches the query document criteria with
@@ -881,7 +897,7 @@ public interface MongoOperations {
* @param collectionName name of the collection to update the object in
* @return the WriteResult which lets you access the results of the previous write.
*/
WriteResult updateFirst(Query query, Update update, Class<?> entityClass, String collectionName);
UpdateResult updateFirst(Query query, Update update, Class<?> entityClass, String collectionName);
/**
* Updates all objects that are found in the collection for the entity class that matches the query document criteria
@@ -893,7 +909,7 @@ public interface MongoOperations {
* @param entityClass class that determines the collection to use
* @return the WriteResult which lets you access the results of the previous write.
*/
WriteResult updateMulti(Query query, Update update, Class<?> entityClass);
UpdateResult updateMulti(Query query, Update update, Class<?> entityClass);
/**
* Updates all objects that are found in the specified collection that matches the query document criteria with the
@@ -905,7 +921,7 @@ public interface MongoOperations {
* @param collectionName name of the collection to update the object in
* @return the WriteResult which lets you access the results of the previous write.
*/
WriteResult updateMulti(Query query, Update update, String collectionName);
UpdateResult updateMulti(Query query, Update update, String collectionName);
/**
* Updates all objects that are found in the collection for the entity class that matches the query document criteria
@@ -918,14 +934,14 @@ public interface MongoOperations {
* @param collectionName name of the collection to update the object in
* @return the WriteResult which lets you access the results of the previous write.
*/
WriteResult updateMulti(final Query query, final Update update, Class<?> entityClass, String collectionName);
UpdateResult updateMulti(final Query query, final Update update, Class<?> entityClass, String collectionName);
/**
* Remove the given object from the collection by id.
*
* @param object
*/
WriteResult remove(Object object);
DeleteResult remove(Object object);
/**
* Removes the given object from the given collection.
@@ -933,7 +949,7 @@ public interface MongoOperations {
* @param object
* @param collection must not be {@literal null} or empty.
*/
WriteResult remove(Object object, String collection);
DeleteResult remove(Object object, String collection);
/**
* Remove all documents that match the provided query document criteria from the the collection used to store the
@@ -942,7 +958,7 @@ public interface MongoOperations {
* @param query
* @param entityClass
*/
WriteResult remove(Query query, Class<?> entityClass);
DeleteResult remove(Query query, Class<?> entityClass);
/**
* Remove all documents that match the provided query document criteria from the the collection used to store the
@@ -952,7 +968,7 @@ public interface MongoOperations {
* @param entityClass
* @param collectionName
*/
WriteResult remove(Query query, Class<?> entityClass, String collectionName);
DeleteResult remove(Query query, Class<?> entityClass, String collectionName);
/**
* Remove all documents from the specified collection that match the provided query document criteria. There is no
@@ -961,7 +977,7 @@ public interface MongoOperations {
* @param query the query document that specifies the criteria used to remove a record
* @param collectionName name of the collection where the objects will removed
*/
WriteResult remove(Query query, String collectionName);
DeleteResult remove(Query query, String collectionName);
/**
* Returns and removes all documents form the specified collection that match the provided query.
@@ -1002,5 +1018,4 @@ public interface MongoOperations {
* @return
*/
MongoConverter getConverter();
}

View File

@@ -0,0 +1,34 @@
/*
* 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.core;
import org.springframework.dao.DataAccessException;
import com.mongodb.MongoException;
import com.mongodb.reactivestreams.client.MongoCollection;
import org.bson.Document;
import org.reactivestreams.Publisher;
/**
* @author Mark Paluch
* @param <T>
* @since 2.0
*/
public interface ReactiveCollectionCallback<T> {
Publisher<T> doInCollection(MongoCollection<Document> collection) throws MongoException, DataAccessException;
}

View File

@@ -0,0 +1,32 @@
/*
* 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.core;
import org.springframework.dao.DataAccessException;
import com.mongodb.MongoException;
import com.mongodb.reactivestreams.client.MongoDatabase;
import org.reactivestreams.Publisher;
/**
* @author Mark Paluch
* @param <T>
* @since 2.0
*/
public interface ReactiveDatabaseCallback<T> {
Publisher<T> doInDB(MongoDatabase db) throws MongoException, DataAccessException;
}

View File

@@ -0,0 +1,62 @@
/*
* 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.core;
import java.util.List;
import org.springframework.data.mongodb.core.index.IndexDefinition;
import org.springframework.data.mongodb.core.index.IndexInfo;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* Index operations on a collection.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.0
*/
public interface ReactiveIndexOperations {
/**
* Ensure that an index for the provided {@link IndexDefinition} exists for the collection indicated by the entity
* class. If not it will be created.
*
* @param indexDefinition must not be {@literal null}.
*/
Mono<String> ensureIndex(IndexDefinition indexDefinition);
/**
* Drops an index from this collection.
*
* @param name name of index to drop
*/
Mono<Void> dropIndex(String name);
/**
* Drops all indices from this collection.
*/
Mono<Void> dropAllIndexes();
/**
* Returns the index information on the collection.
*
* @return index information on the collection
*/
Flux<IndexInfo> getIndexInfo();
}

View File

@@ -0,0 +1,129 @@
/*
* 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.core;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.util.StringUtils;
import com.mongodb.async.client.MongoClientSettings;
import com.mongodb.reactivestreams.client.MongoClient;
import com.mongodb.reactivestreams.client.MongoClients;
/**
* Convenient factory for configuring a reactive streams {@link MongoClient}.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.0
*/
public class ReactiveMongoClientFactoryBean extends AbstractFactoryBean<MongoClient>
implements PersistenceExceptionTranslator {
private static final PersistenceExceptionTranslator DEFAULT_EXCEPTION_TRANSLATOR = new MongoExceptionTranslator();
private String connectionString;
private String host;
private Integer port;
private MongoClientSettings mongoClientSettings;
private PersistenceExceptionTranslator exceptionTranslator = DEFAULT_EXCEPTION_TRANSLATOR;
/**
* Configures the host to connect to.
*
* @param host
*/
public void setHost(String host) {
this.host = host;
}
/**
* Configures the port to connect to.
*
* @param port
*/
public void setPort(int port) {
this.port = port;
}
/**
* Configures the connection string.
*
* @param connectionString
*/
public void setConnectionString(String connectionString) {
this.connectionString = connectionString;
}
/**
* Configures the mongo client settings.
*
* @param mongoClientSettings
*/
public void setMongoClientSettings(MongoClientSettings mongoClientSettings) {
this.mongoClientSettings = mongoClientSettings;
}
/**
* Configures the {@link PersistenceExceptionTranslator} to use.
*
* @param exceptionTranslator
*/
public void setExceptionTranslator(PersistenceExceptionTranslator exceptionTranslator) {
this.exceptionTranslator = exceptionTranslator == null ? DEFAULT_EXCEPTION_TRANSLATOR : exceptionTranslator;
}
@Override
public Class<?> getObjectType() {
return MongoClient.class;
}
@Override
protected MongoClient createInstance() throws Exception {
if (mongoClientSettings != null) {
return MongoClients.create(mongoClientSettings);
}
if (StringUtils.hasText(connectionString)) {
return MongoClients.create(connectionString);
}
if (StringUtils.hasText(host)) {
if (port != null) {
return MongoClients.create(String.format("mongodb://%s:%d", host, port));
}
return MongoClients.create(String.format("mongodb://%s", host));
}
throw new IllegalStateException(
"Cannot create MongoClients. One of the following is required: mongoClientSettings, connectionString or host/port");
}
@Override
protected void destroyInstance(MongoClient instance) throws Exception {
instance.close();
}
@Override
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
return exceptionTranslator.translateExceptionIfPossible(ex);
}
}

View File

@@ -0,0 +1,206 @@
/*
* 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.core;
import java.util.ArrayList;
import java.util.List;
import org.bson.codecs.configuration.CodecRegistry;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.util.Assert;
import com.mongodb.MongoCredential;
import com.mongodb.ReadConcern;
import com.mongodb.ReadPreference;
import com.mongodb.WriteConcern;
import com.mongodb.async.client.MongoClientSettings;
import com.mongodb.connection.ClusterSettings;
import com.mongodb.connection.ConnectionPoolSettings;
import com.mongodb.connection.ServerSettings;
import com.mongodb.connection.SocketSettings;
import com.mongodb.connection.SslSettings;
import com.mongodb.connection.StreamFactoryFactory;
/**
* A factory bean for construction of a {@link MongoClientSettings} instance to be used with the async MongoDB driver.
*
* @author Mark Paluch
* @since 2.0
*/
public class ReactiveMongoClientSettingsFactoryBean extends AbstractFactoryBean<MongoClientSettings> {
private static final MongoClientSettings DEFAULT_MONGO_SETTINGS = MongoClientSettings.builder().build();
private ReadPreference readPreference = DEFAULT_MONGO_SETTINGS.getReadPreference();
private WriteConcern writeConcern = DEFAULT_MONGO_SETTINGS.getWriteConcern();
private ReadConcern readConcern = DEFAULT_MONGO_SETTINGS.getReadConcern();
private List<MongoCredential> credentialList = new ArrayList<>();
private StreamFactoryFactory streamFactoryFactory = DEFAULT_MONGO_SETTINGS.getStreamFactoryFactory();
private CodecRegistry codecRegistry = DEFAULT_MONGO_SETTINGS.getCodecRegistry();
private ClusterSettings clusterSettings = DEFAULT_MONGO_SETTINGS.getClusterSettings();
private SocketSettings socketSettings = DEFAULT_MONGO_SETTINGS.getSocketSettings();
private SocketSettings heartbeatSocketSettings = DEFAULT_MONGO_SETTINGS.getHeartbeatSocketSettings();
private ConnectionPoolSettings connectionPoolSettings = DEFAULT_MONGO_SETTINGS.getConnectionPoolSettings();
private ServerSettings serverSettings = DEFAULT_MONGO_SETTINGS.getServerSettings();
private SslSettings sslSettings = DEFAULT_MONGO_SETTINGS.getSslSettings();
/**
* Set the {@link ReadPreference}.
*
* @param readPreference
*/
public void setReadPreference(ReadPreference readPreference) {
this.readPreference = readPreference;
}
/**
* Set the {@link WriteConcern}.
*
* @param writeConcern
*/
public void setWriteConcern(WriteConcern writeConcern) {
this.writeConcern = writeConcern;
}
/**
* Set the {@link ReadConcern}.
*
* @param readConcern
*/
public void setReadConcern(ReadConcern readConcern) {
this.readConcern = readConcern;
}
/**
* Set the List of {@link MongoCredential}s.
*
* @param credentialList must not be {@literal null}.
*/
public void setCredentialList(List<MongoCredential> credentialList) {
Assert.notNull(credentialList, "CredendialList must not be null!");
this.credentialList.addAll(credentialList);
}
/**
* Adds the {@link MongoCredential} to the list of credentials.
*
* @param mongoCredential must not be {@literal null}.
*/
public void addMongoCredential(MongoCredential mongoCredential) {
Assert.notNull(mongoCredential, "MongoCredential must not be null!");
this.credentialList.add(mongoCredential);
}
/**
* Set the {@link StreamFactoryFactory}.
*
* @param streamFactoryFactory
*/
public void setStreamFactoryFactory(StreamFactoryFactory streamFactoryFactory) {
this.streamFactoryFactory = streamFactoryFactory;
}
/**
* Set the {@link CodecRegistry}.
*
* @param codecRegistry
*/
public void setCodecRegistry(CodecRegistry codecRegistry) {
this.codecRegistry = codecRegistry;
}
/**
* Set the {@link ClusterSettings}.
*
* @param clusterSettings
*/
public void setClusterSettings(ClusterSettings clusterSettings) {
this.clusterSettings = clusterSettings;
}
/**
* Set the {@link SocketSettings}.
*
* @param socketSettings
*/
public void setSocketSettings(SocketSettings socketSettings) {
this.socketSettings = socketSettings;
}
/**
* Set the heartbeat {@link SocketSettings}.
*
* @param heartbeatSocketSettings
*/
public void setHeartbeatSocketSettings(SocketSettings heartbeatSocketSettings) {
this.heartbeatSocketSettings = heartbeatSocketSettings;
}
/**
* Set the {@link ConnectionPoolSettings}.
*
* @param connectionPoolSettings
*/
public void setConnectionPoolSettings(ConnectionPoolSettings connectionPoolSettings) {
this.connectionPoolSettings = connectionPoolSettings;
}
/**
* Set the {@link ServerSettings}.
*
* @param serverSettings
*/
public void setServerSettings(ServerSettings serverSettings) {
this.serverSettings = serverSettings;
}
/**
* Set the {@link SslSettings}.
*
* @param sslSettings
*/
public void setSslSettings(SslSettings sslSettings) {
this.sslSettings = sslSettings;
}
@Override
public Class<?> getObjectType() {
return MongoClientSettings.class;
}
@Override
protected MongoClientSettings createInstance() throws Exception {
return MongoClientSettings.builder() //
.readPreference(readPreference) //
.writeConcern(writeConcern) //
.readConcern(readConcern) //
.credentialList(credentialList) //
.streamFactoryFactory(streamFactoryFactory) //
.codecRegistry(codecRegistry) //
.clusterSettings(clusterSettings) //
.socketSettings(socketSettings) //
.heartbeatSocketSettings(heartbeatSocketSettings) //
.connectionPoolSettings(connectionPoolSettings) //
.serverSettings(serverSettings) //
.sslSettings(sslSettings) //
.build();
}
}

View File

@@ -0,0 +1,51 @@
/*
* 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.core;
import com.mongodb.reactivestreams.client.MongoClient;
import com.mongodb.reactivestreams.client.MongoDatabase;
/**
* Helper class featuring helper methods for internal MongoDb classes. Mainly intended for internal use within the
* framework.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.0
*/
public abstract class ReactiveMongoDbUtils {
/**
* Private constructor to prevent instantiation.
*/
private ReactiveMongoDbUtils() {}
/**
* Obtains a {@link MongoDatabase} connection for the given {@link MongoClient} instance and database name
*
* @param mongo the {@link MongoClient} instance, must not be {@literal null}.
* @param databaseName the database name, must not be {@literal null} or empty.
* @return the {@link MongoDatabase} connection
*/
public static MongoDatabase getMongoDatabase(MongoClient mongo, String databaseName) {
return doGetMongoDatabase(mongo, databaseName, true);
}
private static MongoDatabase doGetMongoDatabase(MongoClient mongo, String databaseName, boolean allowCreate) {
return mongo.getDatabase(databaseName);
}
}

View File

@@ -0,0 +1,945 @@
/*
* 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.core;
import java.util.Collection;
import org.bson.Document;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscription;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import com.mongodb.ReadPreference;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import com.mongodb.reactivestreams.client.MongoCollection;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* Interface that specifies a basic set of MongoDB operations executed in a reactive way.
* <p>
* Implemented by {@link ReactiveMongoTemplate}. Not often used but a useful option for extensibility and testability
* (as it can be easily mocked, stubbed, or be the target of a JDK proxy). Command execution using
* {@link ReactiveMongoOperations} is deferred until subscriber subscribes to the {@link Publisher}.
*
* @author Mark Paluch
* @author Christoph Strobl
* @see Flux
* @see Mono
* @see http://projectreactor.io/docs/
* @since 2.0
*/
public interface ReactiveMongoOperations {
/**
* Returns the reactive operations that can be performed on indexes
*
* @return index operations on the named collection
*/
ReactiveIndexOperations indexOps(String collectionName);
/**
* Returns the reactive operations that can be performed on indexes
*
* @return index operations on the named collection associated with the given entity class
*/
ReactiveIndexOperations indexOps(Class<?> entityClass);
/**
* Execute the a MongoDB command expressed as a JSON string. This will call the method JSON.parse that is part of the
* MongoDB driver to convert the JSON string to a DBObject. Any errors that result from executing this command will be
* converted into Spring's DAO exception hierarchy.
*
* @param jsonCommand a MongoDB command expressed as a JSON string.
* @return a result object returned by the action
*/
Mono<Document> executeCommand(String jsonCommand);
/**
* Execute a MongoDB command. Any errors that result from executing this command will be converted into Spring's DAO
* exception hierarchy.
*
* @param command a MongoDB command
* @return a result object returned by the action
*/
Mono<Document> executeCommand(Document command);
/**
* Execute a MongoDB command. Any errors that result from executing this command will be converted into Spring's data
* access exception hierarchy.
*
* @param command a MongoDB command, must not be {@literal null}.
* @param readPreference read preferences to use, can be {@literal null}.
* @return a result object returned by the action
*/
Mono<Document> executeCommand(Document command, ReadPreference readPreference);
/**
* Executes a {@link ReactiveDatabaseCallback} translating any exceptions as necessary.
* <p/>
* Allows for returning a result object, that is a domain object or a collection of domain objects.
*
* @param <T> return type
* @param action callback object that specifies the MongoDB actions to perform on the passed in DB instance.
* @return a result object returned by the action
*/
<T> Flux<T> execute(ReactiveDatabaseCallback<T> action);
/**
* Executes the given {@link ReactiveCollectionCallback} on the entity collection of the specified class.
* <p/>
* Allows for returning a result object, that is a domain object or a collection of domain objects.
*
* @param entityClass class that determines the collection to use
* @param <T> return type
* @param action callback object that specifies the MongoDB action
* @return a result object returned by the action or <tt>null</tt>
*/
<T> Flux<T> execute(Class<?> entityClass, ReactiveCollectionCallback<T> action);
/**
* Executes the given {@link ReactiveCollectionCallback} on the collection of the given name.
* <p/>
* Allows for returning a result object, that is a domain object or a collection of domain objects.
*
* @param <T> return type
* @param collectionName the name of the collection that specifies which DBCollection instance will be passed into
* @param action callback object that specifies the MongoDB action the callback action.
* @return a result object returned by the action or <tt>null</tt>
*/
<T> Flux<T> execute(String collectionName, ReactiveCollectionCallback<T> action);
/**
* Create an uncapped collection with a name based on the provided entity class.
*
* @param entityClass class that determines the collection to create
* @return the created collection
*/
<T> Mono<MongoCollection<Document>> createCollection(Class<T> entityClass);
/**
* Create a collection with a name based on the provided entity class using the options.
*
* @param entityClass class that determines the collection to create
* @param collectionOptions options to use when creating the collection.
* @return the created collection
*/
<T> Mono<MongoCollection<Document>> createCollection(Class<T> entityClass, CollectionOptions collectionOptions);
/**
* Create an uncapped collection with the provided name.
*
* @param collectionName name of the collection
* @return the created collection
*/
Mono<MongoCollection<Document>> createCollection(String collectionName);
/**
* Create a collection with the provided name and options.
*
* @param collectionName name of the collection
* @param collectionOptions options to use when creating the collection.
* @return the created collection
*/
Mono<MongoCollection<Document>> createCollection(String collectionName, CollectionOptions collectionOptions);
/**
* A set of collection names.
*
* @return Flux of collection names
*/
Flux<String> getCollectionNames();
/**
* Get a collection by name, creating it if it doesn't exist.
* <p/>
* Translate any exceptions as necessary.
*
* @param collectionName name of the collection
* @return an existing collection or a newly created one.
*/
MongoCollection<Document> getCollection(String collectionName);
/**
* Check to see if a collection with a name indicated by the entity class exists.
* <p/>
* Translate any exceptions as necessary.
*
* @param entityClass class that determines the name of the collection
* @return true if a collection with the given name is found, false otherwise.
*/
<T> Mono<Boolean> collectionExists(Class<T> entityClass);
/**
* Check to see if a collection with a given name exists.
* <p/>
* Translate any exceptions as necessary.
*
* @param collectionName name of the collection
* @return true if a collection with the given name is found, false otherwise.
*/
Mono<Boolean> collectionExists(String collectionName);
/**
* Drop the collection with the name indicated by the entity class.
* <p/>
* Translate any exceptions as necessary.
*
* @param entityClass class that determines the collection to drop/delete.
*/
<T> Mono<Void> dropCollection(Class<T> entityClass);
/**
* Drop the collection with the given name.
* <p/>
* Translate any exceptions as necessary.
*
* @param collectionName name of the collection to drop/delete.
*/
Mono<Void> dropCollection(String collectionName);
/**
* Query for a {@link Flux} of objects of type T from the collection used by the entity class.
* <p/>
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless
* configured otherwise, an instance of {@link MappingMongoConverter} will be used.
* <p/>
* If your collection does not contain a homogeneous collection of types, this operation will not be an efficient way
* to map objects since the test for class type is done in the client and not on the server.
* @param entityClass the parametrized type of the returned {@link Flux}.
*
* @return the converted collection
*/
<T> Flux<T> findAll(Class<T> entityClass);
/**
* Query for a {@link Flux} of objects of type T from the specified collection.
* <p/>
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless
* configured otherwise, an instance of {@link MappingMongoConverter} will be used.
* <p/>
* If your collection does not contain a homogeneous collection of types, this operation will not be an efficient way
* to map objects since the test for class type is done in the client and not on the server.
*
* @param entityClass the parametrized type of the returned {@link Flux}.
* @param collectionName name of the collection to retrieve the objects from
* @return the converted collection
*/
<T> Flux<T> findAll(Class<T> entityClass, String collectionName);
/**
* Map the results of an ad-hoc query on the collection for the entity class to a single instance of an object of the
* specified type.
* <p/>
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless
* configured otherwise, an instance of {@link MappingMongoConverter} will be used.
* <p/>
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
* feature rich {@link Query}.
*
* @param query the query class that specifies the criteria used to find a record and also an optional fields
* specification
* @param entityClass the parametrized type of the returned {@link Mono}.
* @return the converted object
*/
<T> Mono<T> findOne(Query query, Class<T> entityClass);
/**
* Map the results of an ad-hoc query on the specified collection to a single instance of an object of the specified
* type.
* <p/>
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless
* configured otherwise, an instance of {@link MappingMongoConverter} will be used.
* <p/>
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
* feature rich {@link Query}.
*
* @param query the query class that specifies the criteria used to find a record and also an optional fields
* specification
* @param entityClass the parametrized type of the returned {@link Mono}.
* @param collectionName name of the collection to retrieve the objects from
* @return the converted object
*/
<T> Mono<T> findOne(Query query, Class<T> entityClass, String collectionName);
/**
* Determine result of given {@link Query} contains at least one element.
*
* @param query the {@link Query} class that specifies the criteria used to find a record.
* @param collectionName name of the collection to check for objects.
* @return
*/
Mono<Boolean> exists(Query query, String collectionName);
/**
* Determine result of given {@link Query} contains at least one element.
*
* @param query the {@link Query} class that specifies the criteria used to find a record.
* @param entityClass the parametrized type.
* @return
*/
Mono<Boolean> exists(Query query, Class<?> entityClass);
/**
* Determine result of given {@link Query} contains at least one element.
*
* @param query the {@link Query} class that specifies the criteria used to find a record.
* @param entityClass the parametrized type.
* @param collectionName name of the collection to check for objects.
* @return
*/
Mono<Boolean> exists(Query query, Class<?> entityClass, String collectionName);
/**
* Map the results of an ad-hoc query on the collection for the entity class to a {@link Flux} of the specified type.
* <p/>
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless
* configured otherwise, an instance of {@link MappingMongoConverter} will be used.
* <p/>
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
* feature rich {@link Query}.
*
* @param query the query class that specifies the criteria used to find a record and also an optional fields
* specification
* @param entityClass the parametrized type of the returned {@link Flux}.
* @return the {@link Flux} of converted objects
*/
<T> Flux<T> find(Query query, Class<T> entityClass);
/**
* Map the results of an ad-hoc query on the specified collection to a {@link Flux} of the specified type.
* <p/>
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless
* configured otherwise, an instance of {@link MappingMongoConverter} will be used.
* <p/>
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
* feature rich {@link Query}.
*
* @param query the query class that specifies the criteria used to find a record and also an optional fields
* specification
* @param entityClass the parametrized type of the returned {@link Flux}.
* @param collectionName name of the collection to retrieve the objects from
* @return the {@link Flux} of converted objects
*/
<T> Flux<T> find(Query query, Class<T> entityClass, String collectionName);
/**
* Returns a document with the given id mapped onto the given class. The collection the query is ran against will be
* derived from the given target class as well.
*
* @param <T>
* @param id the id of the document to return.
* @param entityClass the type the document shall be converted into.
* @return the document with the given id mapped onto the given target class.
*/
<T> Mono<T> findById(Object id, Class<T> entityClass);
/**
* Returns the document with the given id from the given collection mapped onto the given target class.
*
* @param id the id of the document to return
* @param entityClass the type to convert the document to
* @param collectionName the collection to query for the document
* @param <T>
* @return
*/
<T> Mono<T> findById(Object id, Class<T> entityClass, String collectionName);
/**
* Returns {@link Flux} of {@link GeoResult} for all entities matching the given {@link NearQuery}. Will consider entity mapping
* information to determine the collection the query is ran against. Note, that MongoDB limits the number of results
* by default. Make sure to add an explicit limit to the {@link NearQuery} if you expect a particular number of
* results.
*
* @param near must not be {@literal null}.
* @param entityClass must not be {@literal null}.
* @return
*/
<T> Flux<GeoResult<T>> geoNear(NearQuery near, Class<T> entityClass);
/**
* Returns {@link Flux} of {@link GeoResult} for all entities matching the given {@link NearQuery}. Note, that MongoDB limits the
* number of results by default. Make sure to add an explicit limit to the {@link NearQuery} if you expect a
* particular number of results.
*
* @param near must not be {@literal null}.
* @param entityClass must not be {@literal null}.
* @param collectionName the collection to trigger the query against. If no collection name is given the entity class
* will be inspected.
* @return
*/
<T> Flux<GeoResult<T>> geoNear(NearQuery near, Class<T> entityClass, String collectionName);
/**
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify <a/>
* to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query}.
*
* @param query the {@link Query} class that specifies the {@link Criteria} used to find a record and also an optional
* fields specification.
* @param update the {@link Update} to apply on matching documents.
* @param entityClass the parametrized type.
* @return
*/
<T> Mono<T> findAndModify(Query query, Update update, Class<T> entityClass);
/**
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify <a/>
* to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query}.
*
* @param query the {@link Query} class that specifies the {@link Criteria} used to find a record and also an optional
* fields specification.
* @param update the {@link Update} to apply on matching documents.
* @param entityClass the parametrized type.
* @param collectionName the collection to query.
* @return
*/
<T> Mono<T> findAndModify(Query query, Update update, Class<T> entityClass, String collectionName);
/**
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify <a/>
* to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query} taking
* {@link FindAndModifyOptions} into account.
*
* @param query the {@link Query} class that specifies the {@link Criteria} used to find a record and also an optional
* fields specification.
* @param update the {@link Update} to apply on matching documents.
* @param options the {@link FindAndModifyOptions} holding additional information.
* @param entityClass the parametrized type.
* @return
*/
<T> Mono<T> findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass);
/**
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify <a/>
* to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query} taking
* {@link FindAndModifyOptions} into account.
*
* @param query the {@link Query} class that specifies the {@link Criteria} used to find a record and also an optional
* fields specification.
* @param update the {@link Update} to apply on matching documents.
* @param options the {@link FindAndModifyOptions} holding additional information.
* @param entityClass the parametrized type.
* @param collectionName the collection to query.
* @return
*/
<T> Mono<T> findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass,
String collectionName);
/**
* Map the results of an ad-hoc query on the collection for the entity type to a single instance of an object of the
* specified type. The first document that matches the query is returned and also removed from the collection in the
* database.
* <p/>
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}.
* <p/>
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
* feature rich {@link Query}.
*
* @param query the query class that specifies the criteria used to find a record and also an optional fields
* specification
* @param entityClass the parametrized type of the returned {@link Mono}.
* @return the converted object
*/
<T> Mono<T> findAndRemove(Query query, Class<T> entityClass);
/**
* Map the results of an ad-hoc query on the specified collection to a single instance of an object of the specified
* type. The first document that matches the query is returned and also removed from the collection in the database.
* <p/>
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless
* configured otherwise, an instance of {@link MappingMongoConverter} will be used.
* <p/>
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
* feature rich {@link Query}.
*
* @param query the query class that specifies the criteria used to find a record and also an optional fields
* specification
* @param entityClass the parametrized type of the returned {@link Mono}.
* @param collectionName name of the collection to retrieve the objects from.
* @return the converted object
*/
<T> Mono<T> findAndRemove(Query query, Class<T> entityClass, String collectionName);
/**
* Returns the number of documents for the given {@link Query} by querying the collection of the given entity class.
*
* @param query
* @param entityClass must not be {@literal null}.
* @return
*/
Mono<Long> count(Query query, Class<?> entityClass);
/**
* Returns the number of documents for the given {@link Query} querying the given collection. The given {@link Query}
* must solely consist of document field references as we lack type information to map potential property references
* onto document fields. TO make sure the query gets mapped, use {@link #count(Query, Class, String)}.
*
* @param query
* @param collectionName must not be {@literal null} or empty.
* @return
* @see #count(Query, Class, String)
*/
Mono<Long> count(Query query, String collectionName);
/**
* Returns the number of documents for the given {@link Query} by querying the given collection using the given entity
* class to map the given {@link Query}.
*
* @param query
* @param entityClass must not be {@literal null}.
* @param collectionName must not be {@literal null} or empty.
* @return
*/
Mono<Long> count(Query query, Class<?> entityClass, String collectionName);
/**
* Insert the object into the collection for the entity type of the object to save.
* <p/>
* The object is converted to the MongoDB native representation using an instance of {@see MongoConverter}.
* <p/>
* If you object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property is a
* String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from ObjectId to your
* property type will be handled by Spring's BeanWrapper class that leverages Type Conversion API. See
* <a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html#core-convert" >
* Spring's Type Conversion"</a> for more details.
* <p/>
* <p/>
* Insert is used to initially store the object into the database. To update an existing object use the save method.
*
* @param objectToSave the object to store in the collection.
* @return
*/
<T> Mono<T> insert(T objectToSave);
/**
* Insert the object into the specified collection.
* <p/>
* The object is converted to the MongoDB native representation using an instance of {@see MongoConverter}. Unless
* configured otherwise, an instance of {@link MappingMongoConverter} will be used.
* <p/>
* Insert is used to initially store the object into the database. To update an existing object use the save method.
*
* @param objectToSave the object to store in the collection
* @param collectionName name of the collection to store the object in
* @return
*/
<T> Mono<T> insert(T objectToSave, String collectionName);
/**
* Insert a Collection of objects into a collection in a single batch write to the database.
*
* @param batchToSave the batch of objects to save.
* @param entityClass class that determines the collection to use
* @return
*/
<T> Flux<T> insert(Collection<? extends T> batchToSave, Class<?> entityClass);
/**
* Insert a batch of objects into the specified collection in a single batch write to the database.
*
* @param batchToSave the list of objects to save.
* @param collectionName name of the collection to store the object in
* @return
*/
<T> Flux<T> insert(Collection<? extends T> batchToSave, String collectionName);
/**
* Insert a mixed Collection of objects into a database collection determining the collection name to use based on the
* class.
*
* @param objectsToSave the list of objects to save.
* @return
*/
<T> Flux<T> insertAll(Collection<? extends T> objectsToSave);
/**
* Insert the object into the collection for the entity type of the object to save.
* <p/>
* The object is converted to the MongoDB native representation using an instance of {@see MongoConverter}.
* <p/>
* If you object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property is a
* String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from ObjectId to your
* property type will be handled by Spring's BeanWrapper class that leverages Type Conversion API. See
* <a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html#core-convert" >
* Spring's Type Conversion"</a> for more details.
* <p/>
* <p/>
* Insert is used to initially store the object into the database. To update an existing object use the save method.
*
* @param objectToSave the object to store in the collection.
* @return
*/
<T> Mono<T> insert(Mono<? extends T> objectToSave);
/**
* Insert a Collection of objects into a collection in a single batch write to the database.
*
* @param batchToSave the publisher which provides objects to save.
* @param entityClass class that determines the collection to use
* @return
*/
<T> Flux<T> insertAll(Mono<? extends Collection<? extends T>> batchToSave, Class<?> entityClass);
/**
* Insert objects into the specified collection in a single batch write to the database.
*
* @param batchToSave the publisher which provides objects to save.
* @param collectionName name of the collection to store the object in
* @return
*/
<T> Flux<T> insertAll(Mono<? extends Collection<? extends T>> batchToSave, String collectionName);
/**
* Insert a mixed Collection of objects into a database collection determining the collection name to use based on the
* class.
*
* @param objectsToSave the publisher which provides objects to save.
* @return
*/
<T> Flux<T> insertAll(Mono<? extends Collection<? extends T>> objectsToSave);
/**
* Save the object to the collection for the entity type of the object to save. This will perform an insert if the
* object is not already present, that is an 'upsert'.
* <p/>
* The object is converted to the MongoDB native representation using an instance of {@see MongoConverter}. Unless
* configured otherwise, an instance of {@link MappingMongoConverter} will be used.
* <p/>
* If you object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property is a
* String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from ObjectId to your
* property type will be handled by Spring's BeanWrapper class that leverages Type Conversion API. See
* <a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html#core-convert" >
* Spring's Type Conversion"</a> for more details.
*
* @param objectToSave the object to store in the collection
* @return
*/
<T> Mono<T> save(T objectToSave);
/**
* Save the object to the specified collection. This will perform an insert if the object is not already present, that
* is an 'upsert'.
* <p/>
* The object is converted to the MongoDB native representation using an instance of {@see MongoConverter}. Unless
* configured otherwise, an instance of {@link MappingMongoConverter} will be used.
* <p/>
* If you object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property is a
* String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from ObjectId to your
* property type will be handled by Spring's BeanWrapper class that leverages Type Conversion API. See <a
* http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html#core-convert">Spring's
* Type Conversion"</a> for more details.
*
* @param objectToSave the object to store in the collection
* @param collectionName name of the collection to store the object in
* @return
*/
<T> Mono<T> save(T objectToSave, String collectionName);
/**
* Save the object to the collection for the entity type of the object to save. This will perform an insert if the
* object is not already present, that is an 'upsert'.
* <p/>
* The object is converted to the MongoDB native representation using an instance of {@see MongoConverter}. Unless
* configured otherwise, an instance of {@link MappingMongoConverter} will be used.
* <p/>
* If you object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property is a
* String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from ObjectId to your
* property type will be handled by Spring's BeanWrapper class that leverages Type Conversion API. See
* <a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html#core-convert" >
* Spring's Type Conversion"</a> for more details.
*
* @param objectToSave the object to store in the collection
* @return
*/
<T> Mono<T> save(Mono<? extends T> objectToSave);
/**
* Save the object to the specified collection. This will perform an insert if the object is not already present, that
* is an 'upsert'.
* <p/>
* The object is converted to the MongoDB native representation using an instance of {@see MongoConverter}. Unless
* configured otherwise, an instance of {@link MappingMongoConverter} will be used.
* <p/>
* If you object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property is a
* String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from ObjectId to your
* property type will be handled by Spring's BeanWrapper class that leverages Type Conversion API. See <a
* http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html#core-convert">Spring's
* Type Conversion"</a> for more details.
*
* @param objectToSave the object to store in the collection
* @param collectionName name of the collection to store the object in
* @return
*/
<T> Mono<T> save(Mono<? extends T> objectToSave, String collectionName);
/**
* Performs an upsert. If no document is found that matches the query, a new document is created and inserted by
* combining the query document and the update document.
*
* @param query the query document that specifies the criteria used to select a record to be upserted
* @param update the update document that contains the updated object or $ operators to manipulate the existing object
* @param entityClass class that determines the collection to use
* @return the WriteResult which lets you access the results of the previous write.
*/
Mono<UpdateResult> upsert(Query query, Update update, Class<?> entityClass);
/**
* Performs an upsert. If no document is found that matches the query, a new document is created and inserted by
* combining the query document and the update document.
*
* @param query the query document that specifies the criteria used to select a record to be updated
* @param update the update document that contains the updated object or $ operators to manipulate the existing
* object.
* @param collectionName name of the collection to update the object in
* @return the WriteResult which lets you access the results of the previous write.
*/
Mono<UpdateResult> upsert(Query query, Update update, String collectionName);
/**
* Performs an upsert. If no document is found that matches the query, a new document is created and inserted by
* combining the query document and the update document.
*
* @param query the query document that specifies the criteria used to select a record to be upserted
* @param update the update document that contains the updated object or $ operators to manipulate the existing object
* @param entityClass class of the pojo to be operated on
* @param collectionName name of the collection to update the object in
* @return the WriteResult which lets you access the results of the previous write.
*/
Mono<UpdateResult> upsert(Query query, Update update, Class<?> entityClass, String collectionName);
/**
* Updates the first object that is found in the collection of the entity class that matches the query document with
* the provided update document.
*
* @param query the query document that specifies the criteria used to select a record to be updated
* @param update the update document that contains the updated object or $ operators to manipulate the existing
* object.
* @param entityClass class that determines the collection to use
* @return the WriteResult which lets you access the results of the previous write.
*/
Mono<UpdateResult> updateFirst(Query query, Update update, Class<?> entityClass);
/**
* Updates the first object that is found in the specified collection that matches the query document criteria with
* the provided updated document.
*
* @param query the query document that specifies the criteria used to select a record to be updated
* @param update the update document that contains the updated object or $ operators to manipulate the existing
* object.
* @param collectionName name of the collection to update the object in
* @return the WriteResult which lets you access the results of the previous write.
*/
Mono<UpdateResult> updateFirst(Query query, Update update, String collectionName);
/**
* Updates the first object that is found in the specified collection that matches the query document criteria with
* the provided updated document.
*
* @param query the query document that specifies the criteria used to select a record to be updated
* @param update the update document that contains the updated object or $ operators to manipulate the existing
* object.
* @param entityClass class of the pojo to be operated on
* @param collectionName name of the collection to update the object in
* @return the WriteResult which lets you access the results of the previous write.
*/
Mono<UpdateResult> updateFirst(Query query, Update update, Class<?> entityClass, String collectionName);
/**
* Updates all objects that are found in the collection for the entity class that matches the query document criteria
* with the provided updated document.
*
* @param query the query document that specifies the criteria used to select a record to be updated
* @param update the update document that contains the updated object or $ operators to manipulate the existing
* object.
* @param entityClass class that determines the collection to use
* @return the WriteResult which lets you access the results of the previous write.
*/
Mono<UpdateResult> updateMulti(Query query, Update update, Class<?> entityClass);
/**
* Updates all objects that are found in the specified collection that matches the query document criteria with the
* provided updated document.
*
* @param query the query document that specifies the criteria used to select a record to be updated
* @param update the update document that contains the updated object or $ operators to manipulate the existing
* object.
* @param collectionName name of the collection to update the object in
* @return the WriteResult which lets you access the results of the previous write.
*/
Mono<UpdateResult> updateMulti(Query query, Update update, String collectionName);
/**
* Updates all objects that are found in the collection for the entity class that matches the query document criteria
* with the provided updated document.
*
* @param query the query document that specifies the criteria used to select a record to be updated
* @param update the update document that contains the updated object or $ operators to manipulate the existing
* object.
* @param entityClass class of the pojo to be operated on
* @param collectionName name of the collection to update the object in
* @return the WriteResult which lets you access the results of the previous write.
*/
Mono<UpdateResult> updateMulti(final Query query, final Update update, Class<?> entityClass, String collectionName);
/**
* Remove the given object from the collection by id.
*
* @param object
* @return
*/
Mono<DeleteResult> remove(Object object);
/**
* Removes the given object from the given collection.
*
* @param object
* @param collection must not be {@literal null} or empty.
*/
Mono<DeleteResult> remove(Object object, String collection);
/**
* Remove the given object from the collection by id.
*
* @param objectToRemove
* @return
*/
Mono<DeleteResult> remove(Mono<? extends Object> objectToRemove);
/**
* Removes the given object from the given collection.
*
* @param objectToRemove
* @param collection must not be {@literal null} or empty.
* @return
*/
Mono<DeleteResult> remove(Mono<? extends Object> objectToRemove, String collection);
/**
* Remove all documents that match the provided query document criteria from the the collection used to store the
* entityClass. The Class parameter is also used to help convert the Id of the object if it is present in the query.
*
* @param query
* @param entityClass
* @return
*/
Mono<DeleteResult> remove(Query query, Class<?> entityClass);
/**
* Remove all documents that match the provided query document criteria from the the collection used to store the
* entityClass. The Class parameter is also used to help convert the Id of the object if it is present in the query.
*
* @param query
* @param entityClass
* @param collectionName
* @return
*/
Mono<DeleteResult> remove(Query query, Class<?> entityClass, String collectionName);
/**
* Remove all documents from the specified collection that match the provided query document criteria. There is no
* conversion/mapping done for any criteria using the id field.
*
* @param query the query document that specifies the criteria used to remove a record
* @param collectionName name of the collection where the objects will removed
*/
Mono<DeleteResult> remove(Query query, String collectionName);
/**
* Returns and removes all documents form the specified collection that match the provided query.
*
* @param query
* @param collectionName
* @return
*/
<T> Flux<T> findAllAndRemove(Query query, String collectionName);
/**
* Returns and removes all documents matching the given query form the collection used to store the entityClass.
*
* @param query
* @param entityClass
* @return
*/
<T> Flux<T> findAllAndRemove(Query query, Class<T> entityClass);
/**
* Returns and removes all documents that match the provided query document criteria from the the collection used to
* store the entityClass. The Class parameter is also used to help convert the Id of the object if it is present in
* the query.
*
* @param query
* @param entityClass
* @param collectionName
* @return
*/
<T> Flux<T> findAllAndRemove(Query query, Class<T> entityClass, String collectionName);
/**
* Map the results of an ad-hoc query on the collection for the entity class to a stream of objects of the specified
* type. The stream uses a {@link com.mongodb.CursorType#TailableAwait tailable} cursor that may be an infinite
* stream. The stream will not be completed unless the {@link org.reactivestreams.Subscription} is
* {@link Subscription#cancel() canceled}.
* <p/>
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless
* configured otherwise, an instance of {@link MappingMongoConverter} will be used.
* <p/>
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
* feature rich {@link Query}.
*
* @param query the query class that specifies the criteria used to find a record and also an optional fields
* specification
* @param entityClass the parametrized type of the returned {@link Flux}.
* @return the {@link Flux} of converted objects
*/
<T> Flux<T> tail(Query query, Class<T> entityClass);
/**
* Map the results of an ad-hoc query on the collection for the entity class to a stream of objects of the specified
* type. The stream uses a {@link com.mongodb.CursorType#TailableAwait tailable} cursor that may be an infinite
* stream. The stream will not be completed unless the {@link org.reactivestreams.Subscription} is
* {@link Subscription#cancel() canceled}.
* <p/>
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless
* configured otherwise, an instance of {@link MappingMongoConverter} will be used.
* <p/>
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
* feature rich {@link Query}.
*
* @param query the query class that specifies the criteria used to find a record and also an optional fields
* specification
* @param entityClass the parametrized type of the returned {@link Flux}.
* @param collectionName name of the collection to retrieve the objects from
* @return the {@link Flux} of converted objects
*/
<T> Flux<T> tail(Query query, Class<T> entityClass, String collectionName);
/**
* Returns the underlying {@link MongoConverter}.
*
* @return
*/
MongoConverter getConverter();
}

View File

@@ -20,10 +20,10 @@ import static org.springframework.util.ReflectionUtils.*;
import java.lang.reflect.Method;
import org.bson.Document;
import org.springframework.data.mongodb.util.MongoClientVersion;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
/**
* {@link ReflectiveDBCollectionInvoker} provides reflective access to {@link DBCollection} API that is not consistently
@@ -40,7 +40,7 @@ class ReflectiveDBCollectionInvoker {
static {
GEN_INDEX_NAME_METHOD = findMethod(DBCollection.class, "genIndexName", DBObject.class);
GEN_INDEX_NAME_METHOD = findMethod(DBCollection.class, "genIndexName", Document.class);
RESET_INDEX_CHACHE_METHOD = findMethod(DBCollection.class, "resetIndexCache");
}
@@ -53,7 +53,7 @@ class ReflectiveDBCollectionInvoker {
* @param keys the names of the fields used in this index
* @return
*/
public static String generateIndexName(DBObject keys) {
public static String generateIndexName(Document keys) {
if (isMongo3Driver()) {
return genIndexName(keys);
@@ -79,14 +79,14 @@ class ReflectiveDBCollectionInvoker {
}
/**
* Borrowed from MongoDB Java driver version 2. See <a
* href="http://github.com/mongodb/mongo-java-driver/blob/r2.13.0/src/main/com/mongodb/DBCollection.java#L754"
* >http://github.com/mongodb/mongo-java-driver/blob/r2.13.0/src/main/com/mongodb/DBCollection.java#L754</a>
* Borrowed from MongoDB Java driver version 2. See
* <a href="http://github.com/mongodb/mongo-java-driver/blob/r2.13.0/src/main/com/mongodb/DBCollection.java#L754" >
* http://github.com/mongodb/mongo-java-driver/blob/r2.13.0/src/main/com/mongodb/DBCollection.java#L754</a>
*
* @param keys
* @return
*/
private static String genIndexName(DBObject keys) {
private static String genIndexName(Document keys) {
StringBuilder name = new StringBuilder();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-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.

View File

@@ -22,6 +22,7 @@ import java.lang.reflect.Method;
import com.mongodb.MongoException;
import com.mongodb.WriteResult;
import com.mongodb.client.result.UpdateResult;
/**
* {@link ReflectiveWriteResultInvoker} provides reflective access to {@link WriteResult} API that is not consistently
@@ -35,6 +36,7 @@ final class ReflectiveWriteResultInvoker {
private static final Method GET_ERROR_METHOD;
private static final Method WAS_ACKNOWLEDGED_METHOD;
private static final Method WAS_ACKNOWLEDGED_METHOD_UR;
private ReflectiveWriteResultInvoker() {}
@@ -42,6 +44,7 @@ final class ReflectiveWriteResultInvoker {
GET_ERROR_METHOD = findMethod(WriteResult.class, "getError");
WAS_ACKNOWLEDGED_METHOD = findMethod(WriteResult.class, "wasAcknowledged");
WAS_ACKNOWLEDGED_METHOD_UR = findMethod(UpdateResult.class, "wasAcknowledged");
}
/**
@@ -64,4 +67,12 @@ final class ReflectiveWriteResultInvoker {
public static boolean wasAcknowledged(WriteResult writeResult) {
return isMongo3Driver() ? ((Boolean) invokeMethod(WAS_ACKNOWLEDGED_METHOD, writeResult)).booleanValue() : true;
}
/**
* @param writeResult
* @return return in case of MongoDB Java driver version 2.
*/
public static boolean wasAcknowledged(UpdateResult writeResult) {
return isMongo3Driver() ? ((Boolean) invokeMethod(WAS_ACKNOWLEDGED_METHOD_UR, writeResult)).booleanValue() : true;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2015 the original author or authors.
* Copyright 2011-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.
@@ -33,6 +33,7 @@ import com.mongodb.MongoClientURI;
import com.mongodb.MongoException;
import com.mongodb.MongoURI;
import com.mongodb.WriteConcern;
import com.mongodb.client.MongoDatabase;
/**
* Factory to create {@link DB} instances from a {@link Mongo} instance.
@@ -187,7 +188,7 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
* (non-Javadoc)
* @see org.springframework.data.mongodb.MongoDbFactory#getDb()
*/
public DB getDb() throws DataAccessException {
public MongoDatabase getDb() throws DataAccessException {
return getDb(databaseName);
}
@@ -195,18 +196,17 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
* (non-Javadoc)
* @see org.springframework.data.mongodb.MongoDbFactory#getDb(java.lang.String)
*/
@SuppressWarnings("deprecation")
public DB getDb(String dbName) throws DataAccessException {
public MongoDatabase getDb(String dbName) throws DataAccessException {
Assert.hasText(dbName, "Database name must not be empty.");
DB db = MongoDbUtils.getDB(mongo, dbName, credentials, authenticationDatabaseName);
MongoDatabase db = ((MongoClient) mongo).getDatabase(dbName);
if (writeConcern != null) {
db.setWriteConcern(writeConcern);
if (writeConcern == null) {
return db;
}
return db;
return db.withWriteConcern(writeConcern);
}
/**
@@ -232,4 +232,10 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
public PersistenceExceptionTranslator getExceptionTranslator() {
return this.exceptionTranslator;
}
@SuppressWarnings("deprecation")
@Override
public DB getLegacyDb() {
return mongo.getDB(databaseName);
}
}

View File

@@ -0,0 +1,134 @@
/*
* 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.core;
import java.net.UnknownHostException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.mongodb.ReactiveMongoDatabaseFactory;
import org.springframework.util.Assert;
import com.mongodb.ConnectionString;
import com.mongodb.WriteConcern;
import com.mongodb.reactivestreams.client.MongoClient;
import com.mongodb.reactivestreams.client.MongoClients;
import com.mongodb.reactivestreams.client.MongoDatabase;
/**
* Factory to create {@link MongoDatabase} instances from a {@link MongoClient} instance.
*
* @author Mark Paluch
* @since 2.0
*/
public class SimpleReactiveMongoDatabaseFactory implements DisposableBean, ReactiveMongoDatabaseFactory {
private final MongoClient mongo;
private final String databaseName;
private final boolean mongoInstanceCreated;
private final PersistenceExceptionTranslator exceptionTranslator;
private WriteConcern writeConcern;
/**
* Creates a new {@link SimpleReactiveMongoDatabaseFactory} instance from the given {@link ConnectionString}.
*
* @param connectionString must not be {@literal null}.
* @throws UnknownHostException
*/
public SimpleReactiveMongoDatabaseFactory(ConnectionString connectionString) throws UnknownHostException {
this(MongoClients.create(connectionString), connectionString.getDatabase(), true);
}
/**
* Creates a new {@link SimpleReactiveMongoDatabaseFactory} instance from the given {@link MongoClient}.
*
* @param mongoClient must not be {@literal null}.
* @param databaseName must not be {@literal null}.
* @since 1.7
*/
public SimpleReactiveMongoDatabaseFactory(MongoClient mongoClient, String databaseName) {
this(mongoClient, databaseName, false);
}
private SimpleReactiveMongoDatabaseFactory(MongoClient client, String databaseName, boolean mongoInstanceCreated) {
Assert.notNull(client, "MongoClient must not be null!");
Assert.hasText(databaseName, "Database name must not be empty!");
Assert.isTrue(databaseName.matches("[\\w-]+"),
"Database name must only contain letters, numbers, underscores and dashes!");
this.mongo = client;
this.databaseName = databaseName;
this.mongoInstanceCreated = mongoInstanceCreated;
this.exceptionTranslator = new MongoExceptionTranslator();
}
/**
* Configures the {@link WriteConcern} to be used on the {@link MongoDatabase} instance being created.
*
* @param writeConcern the writeConcern to set
*/
public void setWriteConcern(WriteConcern writeConcern) {
this.writeConcern = writeConcern;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.ReactiveMongoDbFactory#getMongoDatabase()
*/
public MongoDatabase getMongoDatabase() throws DataAccessException {
return getMongoDatabase(databaseName);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.ReactiveMongoDbFactory#getMongoDatabase(java.lang.String)
*/
public MongoDatabase getMongoDatabase(String dbName) throws DataAccessException {
Assert.hasText(dbName, "Database name must not be empty.");
MongoDatabase db = ReactiveMongoDbUtils.getMongoDatabase(mongo, dbName);
if (writeConcern != null) {
db = db.withWriteConcern(writeConcern);
}
return db;
}
/**
* Clean up the Mongo instance if it was created by the factory itself.
*
* @see DisposableBean#destroy()
*/
public void destroy() throws Exception {
if (mongoInstanceCreated) {
mongo.close();
}
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.ReactiveMongoDbFactory#getExceptionTranslator()
*/
public PersistenceExceptionTranslator getExceptionTranslator() {
return this.exceptionTranslator;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 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.
@@ -21,26 +21,29 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.bson.Document;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
import org.springframework.data.mongodb.core.aggregation.Fields.AggregationField;
import org.springframework.data.mongodb.core.aggregation.FieldsExposingAggregationOperation.InheritsFieldsAggregationOperation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.SerializationUtils;
import org.springframework.util.Assert;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* An {@code Aggregation} is a representation of a list of aggregation steps to be performed by the MongoDB Aggregation
* Framework.
*
*
* @author Tobias Trelle
* @author Thomas Darimont
* @author Oliver Gierke
* @author Mark Paluch
* @author Alessio Fachechi
* @author Christoph Strobl
* @author Nikolay Bogdanov
* @since 1.3
*/
public class Aggregation {
@@ -65,7 +68,7 @@ public class Aggregation {
/**
* Creates a new {@link Aggregation} from the given {@link AggregationOperation}s.
*
*
* @param operations must not be {@literal null} or empty.
*/
public static Aggregation newAggregation(List<? extends AggregationOperation> operations) {
@@ -74,7 +77,7 @@ public class Aggregation {
/**
* Creates a new {@link Aggregation} from the given {@link AggregationOperation}s.
*
*
* @param operations must not be {@literal null} or empty.
*/
public static Aggregation newAggregation(AggregationOperation... operations) {
@@ -84,7 +87,7 @@ public class Aggregation {
/**
* Returns a copy of this {@link Aggregation} with the given {@link AggregationOptions} set. Note that options are
* supported in MongoDB version 2.6+.
*
*
* @param options must not be {@literal null}.
* @return
* @since 1.6
@@ -97,7 +100,7 @@ public class Aggregation {
/**
* Creates a new {@link TypedAggregation} for the given type and {@link AggregationOperation}s.
*
*
* @param type must not be {@literal null}.
* @param operations must not be {@literal null} or empty.
*/
@@ -107,7 +110,7 @@ public class Aggregation {
/**
* Creates a new {@link TypedAggregation} for the given type and {@link AggregationOperation}s.
*
*
* @param type must not be {@literal null}.
* @param operations must not be {@literal null} or empty.
*/
@@ -117,7 +120,7 @@ public class Aggregation {
/**
* Creates a new {@link Aggregation} from the given {@link AggregationOperation}s.
*
*
* @param aggregationOperations must not be {@literal null} or empty.
*/
protected Aggregation(AggregationOperation... aggregationOperations) {
@@ -137,7 +140,7 @@ public class Aggregation {
/**
* Creates a new {@link Aggregation} from the given {@link AggregationOperation}s.
*
*
* @param aggregationOperations must not be {@literal null} or empty.
*/
protected Aggregation(List<AggregationOperation> aggregationOperations) {
@@ -146,23 +149,34 @@ public class Aggregation {
/**
* Creates a new {@link Aggregation} from the given {@link AggregationOperation}s.
*
*
* @param aggregationOperations must not be {@literal null} or empty.
* @param options must not be {@literal null} or empty.
*/
protected Aggregation(List<AggregationOperation> aggregationOperations, AggregationOptions options) {
Assert.notNull(aggregationOperations, "AggregationOperations must not be null!");
Assert.isTrue(aggregationOperations.size() > 0, "At least one AggregationOperation has to be provided");
Assert.isTrue(!aggregationOperations.isEmpty(), "At least one AggregationOperation has to be provided");
Assert.notNull(options, "AggregationOptions must not be null!");
// check $out is the last operation if it exists
for (AggregationOperation aggregationOperation : aggregationOperations) {
if (aggregationOperation instanceof OutOperation && !isLast(aggregationOperation, aggregationOperations)) {
throw new IllegalArgumentException("The $out operator must be the last stage in the pipeline.");
}
}
this.operations = aggregationOperations;
this.options = options;
}
private boolean isLast(AggregationOperation aggregationOperation, List<AggregationOperation> aggregationOperations) {
return aggregationOperations.indexOf(aggregationOperation) == aggregationOperations.size() - 1;
}
/**
* A pointer to the previous {@link AggregationOperation}.
*
*
* @return
*/
public static String previousOperation() {
@@ -171,7 +185,7 @@ public class Aggregation {
/**
* Creates a new {@link ProjectionOperation} including the given fields.
*
*
* @param fields must not be {@literal null}.
* @return
*/
@@ -181,7 +195,7 @@ public class Aggregation {
/**
* Creates a new {@link ProjectionOperation} includeing the given {@link Fields}.
*
*
* @param fields must not be {@literal null}.
* @return
*/
@@ -191,17 +205,61 @@ public class Aggregation {
/**
* Factory method to create a new {@link UnwindOperation} for the field with the given name.
*
* @param fieldName must not be {@literal null} or empty.
*
* @param field must not be {@literal null} or empty.
* @return
*/
public static UnwindOperation unwind(String field) {
return new UnwindOperation(field(field));
}
/**
* Factory method to create a new {@link UnwindOperation} for the field with the given name and
* {@code preserveNullAndEmptyArrays}. Note that extended unwind is supported in MongoDB version 3.2+.
*
* @param field must not be {@literal null} or empty.
* @param preserveNullAndEmptyArrays {@literal true} to output the document if path is {@literal null}, missing or
* array is empty.
* @return new {@link UnwindOperation}
* @since 1.10
*/
public static UnwindOperation unwind(String field, boolean preserveNullAndEmptyArrays) {
return new UnwindOperation(field(field), preserveNullAndEmptyArrays);
}
/**
* Factory method to create a new {@link UnwindOperation} for the field with the given name including the name of a
* new field to hold the array index of the element as {@code arrayIndex}. Note that extended unwind is supported in
* MongoDB version 3.2+.
*
* @param field must not be {@literal null} or empty.
* @param arrayIndex must not be {@literal null} or empty.
* @return new {@link UnwindOperation}
* @since 1.10
*/
public static UnwindOperation unwind(String field, String arrayIndex) {
return new UnwindOperation(field(field), field(arrayIndex), false);
}
/**
* Factory method to create a new {@link UnwindOperation} for the field with the given nameincluding the name of a new
* field to hold the array index of the element as {@code arrayIndex} using {@code preserveNullAndEmptyArrays}. Note
* that extended unwind is supported in MongoDB version 3.2+.
*
* @param field must not be {@literal null} or empty.
* @param arrayIndex must not be {@literal null} or empty.
* @param preserveNullAndEmptyArrays {@literal true} to output the document if path is {@literal null}, missing or
* array is empty.
* @return new {@link UnwindOperation}
* @since 1.10
*/
public static UnwindOperation unwind(String field, String arrayIndex, boolean preserveNullAndEmptyArrays) {
return new UnwindOperation(field(field), field(arrayIndex), preserveNullAndEmptyArrays);
}
/**
* Creates a new {@link GroupOperation} for the given fields.
*
*
* @param fields must not be {@literal null}.
* @return
*/
@@ -211,7 +269,7 @@ public class Aggregation {
/**
* Creates a new {@link GroupOperation} for the given {@link Fields}.
*
*
* @param fields must not be {@literal null}.
* @return
*/
@@ -221,7 +279,7 @@ public class Aggregation {
/**
* Factory method to create a new {@link SortOperation} for the given {@link Sort}.
*
*
* @param sort must not be {@literal null}.
* @return
*/
@@ -231,7 +289,7 @@ public class Aggregation {
/**
* Factory method to create a new {@link SortOperation} for the given sort {@link Direction} and {@code fields}.
*
*
* @param direction must not be {@literal null}.
* @param fields must not be {@literal null}.
* @return
@@ -242,17 +300,28 @@ public class Aggregation {
/**
* Creates a new {@link SkipOperation} skipping the given number of elements.
*
*
* @param elementsToSkip must not be less than zero.
* @return
* @deprecated prepare to get this one removed in favor of {@link #skip(long)}.
*/
public static SkipOperation skip(int elementsToSkip) {
return new SkipOperation(elementsToSkip);
}
/**
* Creates a new {@link SkipOperation} skipping the given number of elements.
*
* @param elementsToSkip must not be less than zero.
* @return
*/
public static SkipOperation skip(long elementsToSkip) {
return new SkipOperation(elementsToSkip);
}
/**
* Creates a new {@link LimitOperation} limiting the result to the given number of elements.
*
*
* @param maxElements must not be less than zero.
* @return
*/
@@ -262,7 +331,7 @@ public class Aggregation {
/**
* Creates a new {@link MatchOperation} using the given {@link Criteria}.
*
*
* @param criteria must not be {@literal null}.
* @return
*/
@@ -270,12 +339,116 @@ public class Aggregation {
return new MatchOperation(criteria);
}
/**
* Creates a new {@link OutOperation} using the given collection name. This operation must be the last operation in
* the pipeline.
*
* @param outCollectionName collection name to export aggregation results. The {@link OutOperation} creates a new
* collection in the current database if one does not already exist. The collection is not visible until the
* aggregation completes. If the aggregation fails, MongoDB does not create the collection. Must not be
* {@literal null}.
* @return
*/
public static OutOperation out(String outCollectionName) {
return new OutOperation(outCollectionName);
}
/**
* Creates a new {@link LookupOperation}.
*
* @param from must not be {@literal null}.
* @param localField must not be {@literal null}.
* @param foreignField must not be {@literal null}.
* @param as must not be {@literal null}.
* @return never {@literal null}.
* @since 1.9
*/
public static LookupOperation lookup(String from, String localField, String foreignField, String as) {
return lookup(field(from), field(localField), field(foreignField), field(as));
}
/**
* Creates a new {@link LookupOperation} for the given {@link Fields}.
*
* @param from must not be {@literal null}.
* @param localField must not be {@literal null}.
* @param foreignField must not be {@literal null}.
* @param as must not be {@literal null}.
* @return never {@literal null}.
* @since 1.9
*/
public static LookupOperation lookup(Field from, Field localField, Field foreignField, Field as) {
return new LookupOperation(from, localField, foreignField, as);
}
/**
* Creates a new {@link IfNullOperator} for the given {@code field} and {@code replacement} value.
*
* @param field must not be {@literal null}.
* @param replacement must not be {@literal null}.
* @return never {@literal null}.
* @since 1.10
*/
public static IfNullOperator ifNull(String field, Object replacement) {
return IfNullOperator.newBuilder().ifNull(field).thenReplaceWith(replacement);
}
/**
* Creates a new {@link IfNullOperator} for the given {@link Field} and {@link Field} to obtain a value from.
*
* @param field must not be {@literal null}.
* @param replacement must not be {@literal null}.
* @return never {@literal null}.
* @since 1.10
*/
public static IfNullOperator ifNull(Field field, Field replacement) {
return IfNullOperator.newBuilder().ifNull(field).thenReplaceWith(replacement);
}
/**
* Creates a new {@link IfNullOperator} for the given {@link Field} and {@code replacement} value.
*
* @param field must not be {@literal null}.
* @param replacement must not be {@literal null}.
* @return never {@literal null}.
* @since 1.10
*/
public static IfNullOperator ifNull(Field field, Object replacement) {
return IfNullOperator.newBuilder().ifNull(field).thenReplaceWith(replacement);
}
/**
* Creates a new {@link ConditionalOperator} for the given {@link Field} that holds a {@literal boolean} value.
*
* @param booleanField must not be {@literal null}.
* @param then must not be {@literal null}.
* @param otherwise must not be {@literal null}.
* @return never {@literal null}.
* @since 1.10
*/
public static ConditionalOperator conditional(Field booleanField, Object then, Object otherwise) {
return ConditionalOperator.newBuilder().when(booleanField).then(then).otherwise(otherwise);
}
/**
* Creates a new {@link ConditionalOperator} for the given {@link Criteria}.
*
* @param criteria must not be {@literal null}.
* @param then must not be {@literal null}.
* @param otherwise must not be {@literal null}.
* @return never {@literal null}.
* @since 1.10
*/
public static ConditionalOperator conditional(Criteria criteria, Object then, Object otherwise) {
return ConditionalOperator.newBuilder().when(criteria).then(then).otherwise(otherwise);
}
/**
* Creates a new {@link Fields} instance for the given field names.
*
* @see Fields#fields(String...)
*
* @param fields must not be {@literal null}.
* @return
* @see Fields#fields(String...)
*/
public static Fields fields(String... fields) {
return Fields.fields(fields);
@@ -283,7 +456,7 @@ public class Aggregation {
/**
* Creates a new {@link Fields} instance from the given field name and target reference.
*
*
* @param name must not be {@literal null} or empty.
* @param target must not be {@literal null} or empty.
* @return
@@ -295,7 +468,7 @@ public class Aggregation {
/**
* Creates a new {@link GeoNearOperation} instance from the given {@link NearQuery} and the{@code distanceField}. The
* {@code distanceField} defines output field that contains the calculated distance.
*
*
* @param query must not be {@literal null}.
* @param distanceField must not be {@literal null} or empty.
* @return
@@ -307,7 +480,7 @@ public class Aggregation {
/**
* Returns a new {@link AggregationOptions.Builder}.
*
*
* @return
* @since 1.6
*/
@@ -316,27 +489,33 @@ public class Aggregation {
}
/**
* Converts this {@link Aggregation} specification to a {@link DBObject}.
*
* Converts this {@link Aggregation} specification to a {@link Document}.
*
* @param inputCollectionName the name of the input collection
* @return the {@code DBObject} representing this aggregation
* @return the {@code Document} representing this aggregation
*/
public DBObject toDbObject(String inputCollectionName, AggregationOperationContext rootContext) {
public Document toDocument(String inputCollectionName, AggregationOperationContext rootContext) {
AggregationOperationContext context = rootContext;
List<DBObject> operationDocuments = new ArrayList<DBObject>(operations.size());
List<Document> operationDocuments = new ArrayList<Document>(operations.size());
for (AggregationOperation operation : operations) {
operationDocuments.add(operation.toDBObject(context));
operationDocuments.add(operation.toDocument(context));
if (operation instanceof FieldsExposingAggregationOperation) {
FieldsExposingAggregationOperation exposedFieldsOperation = (FieldsExposingAggregationOperation) operation;
context = new ExposedFieldsAggregationOperationContext(exposedFieldsOperation.getFields(), rootContext);
if (operation instanceof InheritsFieldsAggregationOperation) {
context = new InheritingExposedFieldsAggregationOperationContext(exposedFieldsOperation.getFields(), context);
} else {
context = new ExposedFieldsAggregationOperationContext(exposedFieldsOperation.getFields(), context);
}
}
}
DBObject command = new BasicDBObject("aggregate", inputCollectionName);
Document command = new Document("aggregate", inputCollectionName);
command.put("pipeline", operationDocuments);
command = options.applyAndReturnPotentiallyChangedCommand(command);
@@ -351,23 +530,23 @@ public class Aggregation {
@Override
public String toString() {
return SerializationUtils
.serializeToJsonSafely(toDbObject("__collection__", new NoOpAggregationOperationContext()));
.serializeToJsonSafely(toDocument("__collection__", new NoOpAggregationOperationContext()));
}
/**
* Simple {@link AggregationOperationContext} that just returns {@link FieldReference}s as is.
*
*
* @author Oliver Gierke
*/
private static class NoOpAggregationOperationContext implements AggregationOperationContext {
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getMappedObject(com.mongodb.DBObject)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getMappedObject(com.mongodb.Document)
*/
@Override
public DBObject getMappedObject(DBObject dbObject) {
return dbObject;
public Document getMappedObject(Document document) {
return document;
}
/*
@@ -391,7 +570,7 @@ public class Aggregation {
/**
* Describes the system variables available in MongoDB aggregation framework pipeline expressions.
*
*
* @author Thomas Darimont
* @see http://docs.mongodb.org/manual/reference/aggregation-variables
*/
@@ -404,7 +583,7 @@ public class Aggregation {
/**
* Return {@literal true} if the given {@code fieldRef} denotes a well-known system variable, {@literal false}
* otherwise.
*
*
* @param fieldRef may be {@literal null}.
* @return
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-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,23 +15,24 @@
*/
package org.springframework.data.mongodb.core.aggregation;
import com.mongodb.DBObject;
import org.bson.Document;
/**
* An {@link AggregationExpression} can be used with field expressions in aggregation pipeline stages like
* {@code project} and {@code group}.
*
*
* @author Thomas Darimont
* @author Oliver Gierke
* @author Christoph Strobl
*/
interface AggregationExpression {
public interface AggregationExpression {
/**
* Turns the {@link AggregationExpression} into a {@link DBObject} within the given
* Turns the {@link AggregationExpression} into a {@link Document} within the given
* {@link AggregationOperationContext}.
*
*
* @param context
* @return
*/
DBObject toDbObject(AggregationOperationContext context);
Document toDocument(AggregationOperationContext context);
}

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.data.mongodb.core.aggregation;
import org.bson.Document;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressionTransformer.AggregationExpressionTransformationContext;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
import org.springframework.data.mongodb.core.spel.ExpressionNode;
@@ -22,16 +23,16 @@ import org.springframework.data.mongodb.core.spel.ExpressionTransformationContex
import org.springframework.data.mongodb.core.spel.ExpressionTransformer;
import org.springframework.util.Assert;
import com.mongodb.DBObject;
/**
* Interface to type an {@link ExpressionTransformer} to the contained
* {@link AggregationExpressionTransformationContext}.
*
* @author Oliver Gierke
* @author Christoph Strobl
* @since 1.4
*/
interface AggregationExpressionTransformer extends
ExpressionTransformer<AggregationExpressionTransformationContext<ExpressionNode>> {
interface AggregationExpressionTransformer
extends ExpressionTransformer<AggregationExpressionTransformationContext<ExpressionNode>> {
/**
* A special {@link ExpressionTransformationContextSupport} to be aware of the {@link AggregationOperationContext}.
@@ -39,8 +40,8 @@ interface AggregationExpressionTransformer extends
* @author Oliver Gierke
* @author Thomas Darimont
*/
public static class AggregationExpressionTransformationContext<T extends ExpressionNode> extends
ExpressionTransformationContextSupport<T> {
class AggregationExpressionTransformationContext<T extends ExpressionNode>
extends ExpressionTransformationContextSupport<T> {
private final AggregationOperationContext aggregationContext;
@@ -53,7 +54,7 @@ interface AggregationExpressionTransformer extends
* @param aggregationContext must not be {@literal null}.
*/
public AggregationExpressionTransformationContext(T currentNode, ExpressionNode parentNode,
DBObject previousOperationObject, AggregationOperationContext context) {
Document previousOperationObject, AggregationOperationContext context) {
super(currentNode, parentNode, previousOperationObject);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-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.
@@ -16,19 +16,20 @@
package org.springframework.data.mongodb.core.aggregation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.bson.Document;
import org.springframework.util.Assert;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* An enum of supported {@link AggregationExpression}s in aggregation pipeline stages.
*
* @author Thomas Darimont
* @author Oliver Gierke
* @since 1.10
* @author Christoph Strobl
* @author Mark Paluch
* @since 1.7
*/
public enum AggregationFunctionExpressions {
@@ -56,7 +57,7 @@ public enum AggregationFunctionExpressions {
static class FunctionExpression implements AggregationExpression {
private final String name;
private final Object[] values;
private final List<Object> values;
/**
* Creates a new {@link FunctionExpression} for the given name and values.
@@ -70,29 +71,29 @@ public enum AggregationFunctionExpressions {
Assert.notNull(values, "Values must not be null!");
this.name = name;
this.values = values;
this.values = Arrays.asList(values);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.Expression#toDbObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
* @see org.springframework.data.mongodb.core.aggregation.Expression#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public DBObject toDbObject(AggregationOperationContext context) {
public Document toDocument(AggregationOperationContext context) {
List<Object> args = new ArrayList<Object>(values.length);
List<Object> args = new ArrayList<Object>(values.size());
for (int i = 0; i < values.length; i++) {
args.add(unpack(values[i], context));
for (Object value : values) {
args.add(unpack(value, context));
}
return new BasicDBObject("$" + name, args);
return new Document("$" + name, args);
}
private static Object unpack(Object value, AggregationOperationContext context) {
if (value instanceof AggregationExpression) {
return ((AggregationExpression) value).toDbObject(context);
return ((AggregationExpression) value).toDocument(context);
}
if (value instanceof Field) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013 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,7 +15,7 @@
*/
package org.springframework.data.mongodb.core.aggregation;
import com.mongodb.DBObject;
import org.bson.Document;
/**
* Represents one single operation in an aggregation pipeline.
@@ -23,15 +23,16 @@ import com.mongodb.DBObject;
* @author Sebastian Herold
* @author Thomas Darimont
* @author Oliver Gierke
* @author Christoph Strobl
* @since 1.3
*/
public interface AggregationOperation {
/**
* Turns the {@link AggregationOperation} into a {@link DBObject} by using the given
* Turns the {@link AggregationOperation} into a {@link Document} by using the given
* {@link AggregationOperationContext}.
*
* @return the DBObject
* @return the Document
*/
DBObject toDBObject(AggregationOperationContext context);
Document toDocument(AggregationOperationContext context);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013 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,25 +15,25 @@
*/
package org.springframework.data.mongodb.core.aggregation;
import org.bson.Document;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
import com.mongodb.DBObject;
/**
* The context for an {@link AggregationOperation}.
*
* @author Oliver Gierke
* @author Christoph Strobl
* @since 1.3
*/
public interface AggregationOperationContext {
/**
* Returns the mapped {@link DBObject}, potentially converting the source considering mapping metadata etc.
* Returns the mapped {@link Document}, potentially converting the source considering mapping metadata etc.
*
* @param dbObject will never be {@literal null}.
* @param document will never be {@literal null}.
* @return must not be {@literal null}.
*/
DBObject getMappedObject(DBObject dbObject);
Document getMappedObject(Document document);
/**
* Returns a {@link FieldReference} for the given field or {@literal null} if the context does not expose the given

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014 the original author or authors.
* Copyright 2014-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,8 +15,7 @@
*/
package org.springframework.data.mongodb.core.aggregation;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import org.bson.Document;
/**
* Holds a set of configurable aggregation options that can be used within an aggregation pipeline. A list of support
@@ -25,6 +24,7 @@ import com.mongodb.DBObject;
*
* @author Thomas Darimont
* @author Oliver Gierke
* @author Christoph Strobl
* @see Aggregation#withOptions(AggregationOptions)
* @see TypedAggregation#withOptions(AggregationOptions)
* @since 1.6
@@ -37,7 +37,7 @@ public class AggregationOptions {
private final boolean allowDiskUse;
private final boolean explain;
private final DBObject cursor;
private final Document cursor;
/**
* Creates a new {@link AggregationOptions}.
@@ -46,7 +46,7 @@ public class AggregationOptions {
* @param explain whether to get the execution plan for the aggregation instead of the actual results.
* @param cursor can be {@literal null}, used to pass additional options to the aggregation.
*/
public AggregationOptions(boolean allowDiskUse, boolean explain, DBObject cursor) {
public AggregationOptions(boolean allowDiskUse, boolean explain, Document cursor) {
this.allowDiskUse = allowDiskUse;
this.explain = explain;
@@ -77,7 +77,7 @@ public class AggregationOptions {
*
* @return
*/
public DBObject getCursor() {
public Document getCursor() {
return cursor;
}
@@ -88,19 +88,19 @@ public class AggregationOptions {
* @param command the aggregation command.
* @return
*/
DBObject applyAndReturnPotentiallyChangedCommand(DBObject command) {
Document applyAndReturnPotentiallyChangedCommand(Document command) {
DBObject result = new BasicDBObject(command.toMap());
Document result = new Document(command);
if (allowDiskUse && !result.containsField(ALLOW_DISK_USE)) {
if (allowDiskUse && !result.containsKey(ALLOW_DISK_USE)) {
result.put(ALLOW_DISK_USE, allowDiskUse);
}
if (explain && !result.containsField(EXPLAIN)) {
if (explain && !result.containsKey(EXPLAIN)) {
result.put(EXPLAIN, explain);
}
if (cursor != null && !result.containsField(CURSOR)) {
if (cursor != null && !result.containsKey(CURSOR)) {
result.put("cursor", cursor);
}
@@ -108,18 +108,18 @@ public class AggregationOptions {
}
/**
* Returns a {@link DBObject} representation of this {@link AggregationOptions}.
* Returns a {@link Document} representation of this {@link AggregationOptions}.
*
* @return
*/
public DBObject toDbObject() {
public Document toDocument() {
DBObject dbo = new BasicDBObject();
dbo.put(ALLOW_DISK_USE, allowDiskUse);
dbo.put(EXPLAIN, explain);
dbo.put(CURSOR, cursor);
Document document = new Document();
document.put(ALLOW_DISK_USE, allowDiskUse);
document.put(EXPLAIN, explain);
document.put(CURSOR, cursor);
return dbo;
return document;
}
/* (non-Javadoc)
@@ -127,7 +127,7 @@ public class AggregationOptions {
*/
@Override
public String toString() {
return toDbObject().toString();
return toDocument().toJson();
}
/**
@@ -139,7 +139,7 @@ public class AggregationOptions {
private boolean allowDiskUse;
private boolean explain;
private DBObject cursor;
private Document cursor;
/**
* Defines whether to off-load intensive sort-operations to disk.
@@ -171,7 +171,7 @@ public class AggregationOptions {
* @param cursor
* @return
*/
public Builder cursor(DBObject cursor) {
public Builder cursor(Document cursor) {
this.cursor = cursor;
return this;

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.
@@ -19,23 +19,23 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.bson.Document;
import org.springframework.util.Assert;
import com.mongodb.DBObject;
/**
* Collects the results of executing an aggregation operation.
*
* @author Tobias Trelle
* @author Oliver Gierke
* @author Thomas Darimont
* @author Christoph Strobl
* @param <T> The class in which the results are mapped onto.
* @since 1.3
*/
public class AggregationResults<T> implements Iterable<T> {
private final List<T> mappedResults;
private final DBObject rawResults;
private final Document rawResults;
private final String serverUsed;
/**
@@ -44,7 +44,7 @@ public class AggregationResults<T> implements Iterable<T> {
* @param mappedResults must not be {@literal null}.
* @param rawResults must not be {@literal null}.
*/
public AggregationResults(List<T> mappedResults, DBObject rawResults) {
public AggregationResults(List<T> mappedResults, Document rawResults) {
Assert.notNull(mappedResults);
Assert.notNull(rawResults);
@@ -97,7 +97,7 @@ public class AggregationResults<T> implements Iterable<T> {
* @return
* @since 1.6
*/
public DBObject getRawResults() {
public Document getRawResults() {
return rawResults;
}

View File

@@ -0,0 +1,392 @@
/*
* 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.core.aggregation;
import java.util.ArrayList;
import java.util.List;
import org.bson.Document;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* Encapsulates the aggregation framework {@code $cond} operator. A {@link ConditionalOperator} allows nested conditions
* {@code if-then[if-then-else]-else} using {@link Field}, {@link CriteriaDefinition} or a {@link Document custom}
* condition. Replacement values can be either {@link Field field references}, values of simple MongoDB types or values
* that can be converted to a simple MongoDB type.
*
* @see http://docs.mongodb.com/manual/reference/operator/aggregation/cond/
* @author Mark Paluch
* @author Christoph Strobl
* @since 1.10
*/
public class ConditionalOperator implements AggregationExpression {
private final Object condition;
private final Object thenValue;
private final Object otherwiseValue;
/**
* Creates a new {@link ConditionalOperator} for a given {@link Field} and {@code then}/{@code otherwise} values.
*
* @param condition must not be {@literal null}.
* @param thenValue must not be {@literal null}.
* @param otherwiseValue must not be {@literal null}.
*/
public ConditionalOperator(Field condition, Object thenValue, Object otherwiseValue) {
this((Object) condition, thenValue, otherwiseValue);
}
/**
* Creates a new {@link ConditionalOperator} for a given {@link CriteriaDefinition} and {@code then}/{@code otherwise}
* values.
*
* @param condition must not be {@literal null}.
* @param thenValue must not be {@literal null}.
* @param otherwiseValue must not be {@literal null}.
*/
public ConditionalOperator(CriteriaDefinition condition, Object thenValue, Object otherwiseValue) {
this((Object) condition, thenValue, otherwiseValue);
}
/**
* Creates a new {@link ConditionalOperator} for a given {@link Document criteria} and {@code then}/{@code otherwise}
* values.
*
* @param condition must not be {@literal null}.
* @param thenValue must not be {@literal null}.
* @param otherwiseValue must not be {@literal null}.
*/
public ConditionalOperator(Document condition, Object thenValue, Object otherwiseValue) {
this((Object) condition, thenValue, otherwiseValue);
}
private ConditionalOperator(Object condition, Object thenValue, Object otherwiseValue) {
Assert.notNull(condition, "Condition must not be null!");
Assert.notNull(thenValue, "'Then value' must not be null!");
Assert.notNull(otherwiseValue, "'Otherwise value' must not be null!");
assertNotBuilder(condition, "Condition");
assertNotBuilder(thenValue, "'Then value'");
assertNotBuilder(otherwiseValue, "'Otherwise value'");
this.condition = condition;
this.thenValue = thenValue;
this.otherwiseValue = otherwiseValue;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpression#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public Document toDocument(AggregationOperationContext context) {
Document condObject = new Document();
condObject.append("if", resolveCriteria(context, condition));
condObject.append("then", resolveValue(context, thenValue));
condObject.append("else", resolveValue(context, otherwiseValue));
return new Document("$cond", condObject);
}
private Object resolveValue(AggregationOperationContext context, Object value) {
if (value instanceof Document || value instanceof Field) {
return resolve(context, value);
}
if (value instanceof ConditionalOperator) {
return ((ConditionalOperator) value).toDocument(context);
}
return context.getMappedObject(new Document("$set", value)).get("$set");
}
private Object resolveCriteria(AggregationOperationContext context, Object value) {
if (value instanceof Document || value instanceof Field) {
return resolve(context, value);
}
if (value instanceof CriteriaDefinition) {
Document mappedObject = context.getMappedObject(((CriteriaDefinition) value).getCriteriaObject());
List<Object> clauses = new ArrayList<Object>();
clauses.addAll(getClauses(context, mappedObject));
if (clauses.size() == 1) {
return clauses.get(0);
}
return clauses;
}
throw new InvalidDataAccessApiUsageException(
String.format("Invalid value in condition. Supported: Document, Field references, Criteria, got: %s", value));
}
private List<Object> getClauses(AggregationOperationContext context, Document mappedObject) {
List<Object> clauses = new ArrayList<Object>();
for (String key : mappedObject.keySet()) {
Object predicate = mappedObject.get(key);
clauses.addAll(getClauses(context, key, predicate));
}
return clauses;
}
private List<Object> getClauses(AggregationOperationContext context, String key, Object predicate) {
List<Object> clauses = new ArrayList<Object>();
if (predicate instanceof List) {
List<Object> args = new ArrayList<Object>();
for (Object clause : (List<?>) predicate) {
if (clause instanceof Document) {
args.addAll(getClauses(context, (Document) clause));
}
}
clauses.add(new Document(key, args));
} else if (predicate instanceof Document) {
Document nested = (Document) predicate;
for (String s : nested.keySet()) {
if (!isKeyword(s)) {
continue;
}
List<Object> args = new ArrayList<Object>();
args.add("$" + key);
args.add(nested.get(s));
clauses.add(new Document(s, args));
}
} else if (!isKeyword(key)) {
List<Object> args = new ArrayList<Object>();
args.add("$" + key);
args.add(predicate);
clauses.add(new Document("$eq", args));
}
return clauses;
}
/**
* Returns whether the given {@link String} is a MongoDB keyword.
*
* @param candidate
* @return
*/
private boolean isKeyword(String candidate) {
return candidate.startsWith("$");
}
private Object resolve(AggregationOperationContext context, Object value) {
if (value instanceof Document) {
return context.getMappedObject((Document) value);
}
return context.getReference((Field) value).toString();
}
private void assertNotBuilder(Object toCheck, String name) {
Assert.isTrue(!ClassUtils.isAssignableValue(ConditionalExpressionBuilder.class, toCheck),
String.format("%s must not be of type %s", name, ConditionalExpressionBuilder.class.getSimpleName()));
}
/**
* Get a builder that allows fluent creation of {@link ConditionalOperator}.
*
* @return a new {@link ConditionalExpressionBuilder}.
*/
public static ConditionalExpressionBuilder newBuilder() {
return ConditionalExpressionBuilder.newBuilder();
}
/**
* @since 1.10
*/
public static interface WhenBuilder {
/**
* @param booleanExpression expression that yields in a boolean result, must not be {@literal null}.
* @return the {@link ThenBuilder}
*/
ThenBuilder when(Document booleanExpression);
/**
* @param booleanField reference to a field holding a boolean value, must not be {@literal null}.
* @return the {@link ThenBuilder}
*/
ThenBuilder when(Field booleanField);
/**
* @param booleanField name of a field holding a boolean value, must not be {@literal null}.
* @return the {@link ThenBuilder}
*/
ThenBuilder when(String booleanField);
/**
* @param criteria criteria to evaluate, must not be {@literal null}.
* @return the {@link ThenBuilder}
*/
ThenBuilder when(CriteriaDefinition criteria);
}
/**
* @since 1.10
*/
public static interface ThenBuilder {
/**
* @param value the value to be used if the condition evaluates {@literal true}. Can be a {@link Document}, a value
* that is supported by MongoDB or a value that can be converted to a MongoDB representation but must not
* be {@literal null}.
* @return the {@link OtherwiseBuilder}
*/
OtherwiseBuilder then(Object value);
}
/**
* @since 1.10
*/
public static interface OtherwiseBuilder {
/**
* @param value the value to be used if the condition evaluates {@literal false}. Can be a {@link Document}, a value
* that is supported by MongoDB or a value that can be converted to a MongoDB representation but must not
* be {@literal null}.
* @return the {@link ConditionalOperator}
*/
ConditionalOperator otherwise(Object value);
}
/**
* Builder for fluent {@link ConditionalOperator} creation.
*
* @author Mark Paluch
* @since 1.10
*/
public static final class ConditionalExpressionBuilder implements WhenBuilder, ThenBuilder, OtherwiseBuilder {
private Object condition;
private Object thenValue;
private ConditionalExpressionBuilder() {}
/**
* Creates a new builder for {@link ConditionalOperator}.
*
* @return never {@literal null}.
*/
public static ConditionalExpressionBuilder newBuilder() {
return new ConditionalExpressionBuilder();
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperator.WhenBuilder#when(org.bson.Document)
*/
@Override
public ConditionalExpressionBuilder when(Document booleanExpression) {
Assert.notNull(booleanExpression, "'Boolean expression' must not be null!");
this.condition = booleanExpression;
return this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperator.WhenBuilder#when(org.springframework.data.mongodb.core.query.CriteriaDefinition)
*/
@Override
public ThenBuilder when(CriteriaDefinition criteria) {
Assert.notNull(criteria, "Criteria must not be null!");
this.condition = criteria;
return this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperator.WhenBuilder#when(org.springframework.data.mongodb.core.aggregation.Field)
*/
@Override
public ThenBuilder when(Field booleanField) {
Assert.notNull(booleanField, "Boolean field must not be null!");
this.condition = booleanField;
return this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperator.WhenBuilder#when(java.lang.String)
*/
@Override
public ThenBuilder when(String booleanField) {
Assert.hasText(booleanField, "Boolean field name must not be null or empty!");
this.condition = Fields.field(booleanField);
return this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperator.ThenBuilder#then(java.lang.Object)
*/
@Override
public OtherwiseBuilder then(Object thenValue) {
Assert.notNull(thenValue, "'Then-value' must not be null!");
this.thenValue = thenValue;
return this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperator.OtherwiseBuilder#otherwise(java.lang.Object)
*/
@Override
public ConditionalOperator otherwise(Object otherwiseValue) {
Assert.notNull(otherwiseValue, "'Otherwise-value' must not be null!");
return new ConditionalOperator(condition, thenValue, otherwiseValue);
}
}
}

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.
@@ -30,6 +30,7 @@ import org.springframework.util.CompositeIterator;
*
* @author Oliver Gierke
* @author Thomas Darimont
* @author Mark Paluch
* @since 1.3
*/
public final class ExposedFields implements Iterable<ExposedField> {
@@ -203,8 +204,13 @@ public final class ExposedFields implements Iterable<ExposedField> {
public Iterator<ExposedField> iterator() {
CompositeIterator<ExposedField> iterator = new CompositeIterator<ExposedField>();
iterator.add(syntheticFields.iterator());
iterator.add(originalFields.iterator());
if (!syntheticFields.isEmpty()) {
iterator.add(syntheticFields.iterator());
}
if (!originalFields.isEmpty()) {
iterator.add(originalFields.iterator());
}
return iterator;
}

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,18 +15,19 @@
*/
package org.springframework.data.mongodb.core.aggregation;
import org.bson.Document;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
import org.springframework.util.Assert;
import com.mongodb.DBObject;
/**
* {@link AggregationOperationContext} that combines the available field references from a given
* {@code AggregationOperationContext} and an {@link FieldsExposingAggregationOperation}.
*
*
* @author Thomas Darimont
* @author Oliver Gierke
* @author Mark Paluch
* @author Christoph Strobl
* @since 1.4
*/
class ExposedFieldsAggregationOperationContext implements AggregationOperationContext {
@@ -37,11 +38,12 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo
/**
* Creates a new {@link ExposedFieldsAggregationOperationContext} from the given {@link ExposedFields}. Uses the given
* {@link AggregationOperationContext} to perform a mapping to mongo types if necessary.
*
*
* @param exposedFields must not be {@literal null}.
* @param rootContext must not be {@literal null}.
*/
public ExposedFieldsAggregationOperationContext(ExposedFields exposedFields, AggregationOperationContext rootContext) {
public ExposedFieldsAggregationOperationContext(ExposedFields exposedFields,
AggregationOperationContext rootContext) {
Assert.notNull(exposedFields, "ExposedFields must not be null!");
Assert.notNull(rootContext, "RootContext must not be null!");
@@ -52,11 +54,11 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getMappedObject(com.mongodb.DBObject)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getMappedObject(com.mongodb.Document)
*/
@Override
public DBObject getMappedObject(DBObject dbObject) {
return rootContext.getMappedObject(dbObject);
public Document getMappedObject(Document document) {
return rootContext.getMappedObject(document);
}
/*
@@ -79,7 +81,7 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo
/**
* Returns a {@link FieldReference} to the given {@link Field} with the given {@code name}.
*
*
* @param field may be {@literal null}
* @param name must not be {@literal null}
* @return
@@ -88,6 +90,22 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo
Assert.notNull(name, "Name must not be null!");
FieldReference exposedField = resolveExposedField(field, name);
if (exposedField != null) {
return exposedField;
}
throw new IllegalArgumentException(String.format("Invalid reference '%s'!", name));
}
/**
* Resolves a {@link field}/{@link name} for a {@link FieldReference} if possible.
*
* @param field may be {@literal null}
* @param name must not be {@literal null}
* @return the resolved reference or {@literal null}
*/
protected FieldReference resolveExposedField(Field field, String name) {
ExposedField exposedField = exposedFields.getField(name);
if (exposedField != null) {
@@ -111,7 +129,6 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo
return new FieldReference(new ExposedField(name, true));
}
}
throw new IllegalArgumentException(String.format("Invalid reference '%s'!", name));
return null;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013 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.
@@ -16,17 +16,28 @@
package org.springframework.data.mongodb.core.aggregation;
/**
* {@link AggregationOperation} that exposes new {@link ExposedFields} that can be used for later aggregation pipeline
* {@code AggregationOperation}s.
*
* {@link AggregationOperation} that exposes {@link ExposedFields} that can be used for later aggregation pipeline
* {@code AggregationOperation}s. A {@link FieldsExposingAggregationOperation} implementing the
* {@link InheritsFieldsAggregationOperation} will expose fields from its parent operations. Not implementing
* {@link InheritsFieldsAggregationOperation} will replace existing exposed fields.
*
* @author Thomas Darimont
* @author Mark Paluch
*/
public interface FieldsExposingAggregationOperation extends AggregationOperation {
/**
* Returns the fields exposed by the {@link AggregationOperation}.
*
*
* @return will never be {@literal null}.
*/
ExposedFields getFields();
/**
* Marker interface for {@link AggregationOperation} that inherits fields from previous operations.
*/
static interface InheritsFieldsAggregationOperation extends FieldsExposingAggregationOperation {
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 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,12 +15,10 @@
*/
package org.springframework.data.mongodb.core.aggregation;
import org.bson.Document;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.util.Assert;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* Represents a {@code geoNear} aggregation operation.
* <p>
@@ -28,6 +26,7 @@ import com.mongodb.DBObject;
* instances of this class directly.
*
* @author Thomas Darimont
* @author Christoph Strobl
* @since 1.3
*/
public class GeoNearOperation implements AggregationOperation {
@@ -53,14 +52,14 @@ public class GeoNearOperation implements AggregationOperation {
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public DBObject toDBObject(AggregationOperationContext context) {
public Document toDocument(AggregationOperationContext context) {
BasicDBObject command = (BasicDBObject) context.getMappedObject(nearQuery.toDBObject());
Document command = context.getMappedObject(nearQuery.toDocument());
command.put("distanceField", distanceField);
return new BasicDBObject("$geoNear", command);
return new Document("$geoNear", command);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 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.
@@ -21,14 +21,12 @@ import java.util.Collections;
import java.util.List;
import java.util.Locale;
import org.bson.Document;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* Encapsulates the aggregation framework {@code $group}-operation.
* <p>
@@ -39,6 +37,7 @@ import com.mongodb.DBObject;
* @author Sebastian Herold
* @author Thomas Darimont
* @author Oliver Gierke
* @author Christoph Strobl
* @since 1.3
*/
public class GroupOperation implements FieldsExposingAggregationOperation {
@@ -194,7 +193,8 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
}
/**
* Generates an {@link GroupOperationBuilder} for an {@code $last}-expression for the given {@link AggregationExpression}.
* Generates an {@link GroupOperationBuilder} for an {@code $last}-expression for the given
* {@link AggregationExpression}.
*
* @param expr
* @return
@@ -214,7 +214,8 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
}
/**
* Generates an {@link GroupOperationBuilder} for a {@code $first}-expression for the given {@link AggregationExpression}.
* Generates an {@link GroupOperationBuilder} for a {@code $first}-expression for the given
* {@link AggregationExpression}.
*
* @param expr
* @return
@@ -234,7 +235,8 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
}
/**
* Generates an {@link GroupOperationBuilder} for an {@code $avg}-expression for the given {@link AggregationExpression}.
* Generates an {@link GroupOperationBuilder} for an {@code $avg}-expression for the given
* {@link AggregationExpression}.
*
* @param expr
* @return
@@ -278,7 +280,8 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
}
/**
* Generates an {@link GroupOperationBuilder} for an {@code $min}-expression that for the given {@link AggregationExpression}.
* Generates an {@link GroupOperationBuilder} for an {@code $min}-expression that for the given
* {@link AggregationExpression}.
*
* @param expr
* @return
@@ -298,7 +301,8 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
}
/**
* Generates an {@link GroupOperationBuilder} for an {@code $max}-expression that for the given {@link AggregationExpression}.
* Generates an {@link GroupOperationBuilder} for an {@code $max}-expression that for the given
* {@link AggregationExpression}.
*
* @param expr
* @return
@@ -329,12 +333,12 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public com.mongodb.DBObject toDBObject(AggregationOperationContext context) {
public Document toDocument(AggregationOperationContext context) {
BasicDBObject operationObject = new BasicDBObject();
Document operationObject = new Document();
if (idFields.exposesNoNonSyntheticFields()) {
@@ -347,7 +351,7 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
} else {
BasicDBObject inner = new BasicDBObject();
Document inner = new Document();
for (ExposedField field : idFields) {
FieldReference reference = context.getReference(field);
@@ -358,10 +362,10 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
}
for (Operation operation : operations) {
operationObject.putAll(operation.toDBObject(context));
operationObject.putAll(operation.toDocument(context));
}
return new BasicDBObject("$group", operationObject);
return new Document("$group", operationObject);
}
interface Keyword {
@@ -412,8 +416,8 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
return new ExposedField(key, true);
}
public DBObject toDBObject(AggregationOperationContext context) {
return new BasicDBObject(key, new BasicDBObject(op.toString(), getValue(context)));
public Document toDocument(AggregationOperationContext context) {
return new Document(key, new Document(op.toString(), getValue(context)));
}
public Object getValue(AggregationOperationContext context) {
@@ -421,7 +425,7 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
if (reference == null) {
if (value instanceof AggregationExpression) {
return ((AggregationExpression) value).toDbObject(context);
return ((AggregationExpression) value).toDocument(context);
}
return value;

View File

@@ -0,0 +1,195 @@
/*
* 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.core.aggregation;
import java.util.ArrayList;
import java.util.List;
import org.bson.Document;
import org.springframework.util.Assert;
/**
* Encapsulates the aggregation framework {@code $ifNull} operator. Replacement values can be either {@link Field field
* references}, values of simple MongoDB types or values that can be converted to a simple MongoDB type.
*
* @see http://docs.mongodb.com/manual/reference/operator/aggregation/ifNull/
* @author Mark Paluch
* @author Christoph Strobl
* @since 1.10
*/
public class IfNullOperator implements AggregationExpression {
private final Field field;
private final Object value;
/**
* Creates a new {@link IfNullOperator} for the given {@link Field} and replacement {@code value}.
*
* @param field must not be {@literal null}.
* @param value must not be {@literal null}.
*/
public IfNullOperator(Field field, Object value) {
Assert.notNull(field, "Field must not be null!");
Assert.notNull(value, "'Replacement-value' must not be null!");
this.field = field;
this.value = value;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpression#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public Document toDocument(AggregationOperationContext context) {
List<Object> list = new ArrayList<Object>();
list.add(context.getReference(field).toString());
list.add(resolve(value, context));
return new Document("$ifNull", list);
}
private Object resolve(Object value, AggregationOperationContext context) {
if (value instanceof Field) {
return context.getReference((Field) value).toString();
} else if (value instanceof Document) {
return value;
}
return context.getMappedObject(new Document("$set", value)).get("$set");
}
/**
* Get a builder that allows fluent creation of {@link IfNullOperator}.
*
* @return a new {@link IfNullBuilder}.
*/
public static IfNullBuilder newBuilder() {
return IfNullOperatorBuilder.newBuilder();
}
/**
* @since 1.10
*/
public static interface IfNullBuilder {
/**
* @param field the field to check for a {@literal null} value, field reference must not be {@literal null}.
* @return the {@link ThenBuilder}
*/
ThenBuilder ifNull(Field field);
/**
* @param field the field to check for a {@literal null} value, field name must not be {@literal null} or empty.
* @return the {@link ThenBuilder}
*/
ThenBuilder ifNull(String field);
}
/**
* @since 1.10
*/
public static interface ThenBuilder {
/**
* @param field the field holding the replacement value, must not be {@literal null}.
* @return the {@link IfNullOperator}
*/
IfNullOperator thenReplaceWith(Field field);
/**
* @param value the value to be used if the {@code $ifNull }condition evaluates {@literal true}. Can be a
* {@link Document}, a value that is supported by MongoDB or a value that can be converted to a MongoDB
* representation but must not be {@literal null}.
* @return the {@link IfNullOperator}
*/
IfNullOperator thenReplaceWith(Object value);
}
/**
* Builder for fluent {@link IfNullOperator} creation.
*
* @author Mark Paluch
* @since 1.10
*/
public static final class IfNullOperatorBuilder implements IfNullBuilder, ThenBuilder {
private Field field;
private IfNullOperatorBuilder() {}
/**
* Creates a new builder for {@link IfNullOperator}.
*
* @return never {@literal null}.
*/
public static IfNullOperatorBuilder newBuilder() {
return new IfNullOperatorBuilder();
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.IfNullOperator.IfNullBuilder#ifNull(org.springframework.data.mongodb.core.aggregation.Field)
*/
public ThenBuilder ifNull(Field field) {
Assert.notNull(field, "Field must not be null!");
this.field = field;
return this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.IfNullOperator.IfNullBuilder#ifNull(java.lang.String)
*/
public ThenBuilder ifNull(String name) {
Assert.hasText(name, "Field name must not be null or empty!");
this.field = Fields.field(name);
return this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.IfNullOperator.ThenReplaceBuilder#thenReplaceWith(org.springframework.data.mongodb.core.aggregation.Field)
*/
@Override
public IfNullOperator thenReplaceWith(Field replacementField) {
Assert.notNull(replacementField, "Replacement field must not be null!");
return new IfNullOperator(this.field, replacementField);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.IfNullOperator.ThenReplaceBuilder#thenReplaceWith(java.lang.Object)
*/
@Override
public IfNullOperator thenReplaceWith(Object value) {
Assert.notNull(value, "'Replacement-value' must not be null!");
return new IfNullOperator(this.field, value);
}
}
}

View File

@@ -0,0 +1,65 @@
/*
* 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.core.aggregation;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
import org.springframework.util.Assert;
/**
* {@link ExposedFieldsAggregationOperationContext} that inherits fields from its parent
* {@link AggregationOperationContext}.
*
* @author Mark Paluch
*/
class InheritingExposedFieldsAggregationOperationContext extends ExposedFieldsAggregationOperationContext {
private final AggregationOperationContext previousContext;
/**
* Creates a new {@link ExposedFieldsAggregationOperationContext} from the given {@link ExposedFields}. Uses the given
* {@link AggregationOperationContext} to perform a mapping to mongo types if necessary.
*
* @param exposedFields must not be {@literal null}.
* @param previousContext must not be {@literal null}.
*/
public InheritingExposedFieldsAggregationOperationContext(ExposedFields exposedFields,
AggregationOperationContext previousContext) {
super(exposedFields, previousContext);
Assert.notNull(previousContext, "PreviousContext must not be null!");
this.previousContext = previousContext;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.ExposedFieldsAggregationOperationContext#resolveExposedField(org.springframework.data.mongodb.core.aggregation.Field, java.lang.String)
*/
@Override
protected FieldReference resolveExposedField(Field field, String name) {
FieldReference fieldReference = super.resolveExposedField(field, name);
if (fieldReference != null) {
return fieldReference;
}
if (field != null) {
return previousContext.getReference(field);
}
return previousContext.getReference(name);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 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,11 +15,9 @@
*/
package org.springframework.data.mongodb.core.aggregation;
import org.bson.Document;
import org.springframework.util.Assert;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* Encapsulates the {@code $limit}-operation.
* <p>
@@ -29,6 +27,7 @@ import com.mongodb.DBObject;
* @see http://docs.mongodb.org/manual/reference/aggregation/limit/
* @author Thomas Darimont
* @author Oliver Gierke
* @author Christoph Strobl
* @since 1.3
*/
public class LimitOperation implements AggregationOperation {
@@ -46,10 +45,10 @@ public class LimitOperation implements AggregationOperation {
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public DBObject toDBObject(AggregationOperationContext context) {
return new BasicDBObject("$limit", maxElements);
public Document toDocument(AggregationOperationContext context) {
return new Document("$limit", Long.valueOf(maxElements));
}
}

View File

@@ -0,0 +1,194 @@
/*
* 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.core.aggregation;
import org.bson.Document;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
import org.springframework.data.mongodb.core.aggregation.FieldsExposingAggregationOperation.InheritsFieldsAggregationOperation;
import org.springframework.util.Assert;
/**
* Encapsulates the aggregation framework {@code $lookup}-operation. We recommend to use the static factory method
* {@link Aggregation#lookup(String, String, String, String)} instead of creating instances of this class directly.
*
* @author Alessio Fachechi
* @author Christoph Strobl
* @author Mark Paluch
* @see http://docs.mongodb.org/manual/reference/aggregation/lookup/#stage._S_lookup
* @since 1.9
*/
public class LookupOperation implements FieldsExposingAggregationOperation, InheritsFieldsAggregationOperation {
private Field from;
private Field localField;
private Field foreignField;
private ExposedField as;
/**
* Creates a new {@link LookupOperation} for the given {@link Field}s.
*
* @param from must not be {@literal null}.
* @param localField must not be {@literal null}.
* @param foreignField must not be {@literal null}.
* @param as must not be {@literal null}.
*/
public LookupOperation(Field from, Field localField, Field foreignField, Field as) {
Assert.notNull(from, "From must not be null!");
Assert.notNull(localField, "LocalField must not be null!");
Assert.notNull(foreignField, "ForeignField must not be null!");
Assert.notNull(as, "As must not be null!");
this.from = from;
this.localField = localField;
this.foreignField = foreignField;
this.as = new ExposedField(as, true);
}
private LookupOperation() {
// used by builder
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.FieldsExposingAggregationOperation#getFields()
*/
@Override
public ExposedFields getFields() {
return ExposedFields.from(as);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public Document toDocument(AggregationOperationContext context) {
Document lookupObject = new Document();
lookupObject.append("from", from.getTarget());
lookupObject.append("localField", localField.getTarget());
lookupObject.append("foreignField", foreignField.getTarget());
lookupObject.append("as", as.getTarget());
return new Document("$lookup", lookupObject);
}
/**
* Get a builder that allows creation of {@link LookupOperation}.
*
* @return
*/
public static FromBuilder newLookup() {
return new LookupOperationBuilder();
}
public static interface FromBuilder {
/**
* @param name the collection in the same database to perform the join with, must not be {@literal null} or empty.
* @return
*/
LocalFieldBuilder from(String name);
}
public static interface LocalFieldBuilder {
/**
* @param name the field from the documents input to the {@code $lookup} stage, must not be {@literal null} or
* empty.
* @return
*/
ForeignFieldBuilder localField(String name);
}
public static interface ForeignFieldBuilder {
/**
* @param name the field from the documents in the {@code from} collection, must not be {@literal null} or empty.
* @return
*/
AsBuilder foreignField(String name);
}
public static interface AsBuilder {
/**
* @param name the name of the new array field to add to the input documents, must not be {@literal null} or empty.
* @return
*/
LookupOperation as(String name);
}
/**
* Builder for fluent {@link LookupOperation} creation.
*
* @author Christoph Strobl
* @since 1.9
*/
public static final class LookupOperationBuilder
implements FromBuilder, LocalFieldBuilder, ForeignFieldBuilder, AsBuilder {
private final LookupOperation lookupOperation;
private LookupOperationBuilder() {
this.lookupOperation = new LookupOperation();
}
/**
* Creates new builder for {@link LookupOperation}.
*
* @return never {@literal null}.
*/
public static FromBuilder newBuilder() {
return new LookupOperationBuilder();
}
@Override
public LocalFieldBuilder from(String name) {
Assert.hasText(name, "'From' must not be null or empty!");
lookupOperation.from = Fields.field(name);
return this;
}
@Override
public LookupOperation as(String name) {
Assert.hasText(name, "'As' must not be null or empty!");
lookupOperation.as = new ExposedField(Fields.field(name), true);
return new LookupOperation(lookupOperation.from, lookupOperation.localField, lookupOperation.foreignField,
lookupOperation.as);
}
@Override
public AsBuilder foreignField(String name) {
Assert.hasText(name, "'ForeignField' must not be null or empty!");
lookupOperation.foreignField = Fields.field(name);
return this;
}
@Override
public ForeignFieldBuilder localField(String name) {
Assert.hasText(name, "'LocalField' must not be null or empty!");
lookupOperation.localField = Fields.field(name);
return this;
}
}
}

View File

@@ -15,12 +15,10 @@
*/
package org.springframework.data.mongodb.core.aggregation;
import org.bson.Document;
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
import org.springframework.util.Assert;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* Encapsulates the {@code $match}-operation.
* <p>
@@ -51,10 +49,10 @@ public class MatchOperation implements AggregationOperation {
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public DBObject toDBObject(AggregationOperationContext context) {
return new BasicDBObject("$match", context.getMappedObject(criteriaDefinition.getCriteriaObject()));
public Document toDocument(AggregationOperationContext context) {
return new Document("$match", context.getMappedObject(criteriaDefinition.getCriteriaObject()));
}
}

View File

@@ -0,0 +1,51 @@
/*
* 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.core.aggregation;
import org.bson.Document;
import org.springframework.util.Assert;
/**
* Encapsulates the {@code $out}-operation.
* <p>
* We recommend to use the static factory method {@link Aggregation#out(String)} instead of creating instances of this
* class directly.
*
* @see http://docs.mongodb.org/manual/reference/aggregation/out/
* @author Nikolay Bogdanov
* @author Christoph Strobl
*/
public class OutOperation implements AggregationOperation {
private final String collectionName;
/**
* @param outCollectionName Collection name to export the results. Must not be {@literal null}.
*/
public OutOperation(String outCollectionName) {
Assert.notNull(outCollectionName, "Collection name must not be null!");
this.collectionName = outCollectionName;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public Document toDocument(AggregationOperationContext context) {
return new Document("$out", collectionName);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 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.
@@ -20,14 +20,12 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.bson.Document;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
import org.springframework.data.mongodb.core.aggregation.Fields.AggregationField;
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation.ProjectionOperationBuilder.FieldProjection;
import org.springframework.util.Assert;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* Encapsulates the aggregation framework {@code $project}-operation.
* <p>
@@ -42,6 +40,7 @@ import com.mongodb.DBObject;
* @author Thomas Darimont
* @author Oliver Gierke
* @author Christoph Strobl
* @author Mark Paluch
* @since 1.3
*/
public class ProjectionOperation implements FieldsExposingAggregationOperation {
@@ -104,8 +103,8 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
*/
private ProjectionOperation andReplaceLastOneWith(Projection projection) {
List<Projection> projections = this.projections.isEmpty() ? Collections.<Projection> emptyList() : this.projections
.subList(0, this.projections.size() - 1);
List<Projection> projections = this.projections.isEmpty() ? Collections.<Projection> emptyList()
: this.projections.subList(0, this.projections.size() - 1);
return new ProjectionOperation(projections, Arrays.asList(projection));
}
@@ -185,18 +184,18 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public DBObject toDBObject(AggregationOperationContext context) {
public Document toDocument(AggregationOperationContext context) {
BasicDBObject fieldObject = new BasicDBObject();
Document fieldObject = new Document();
for (Projection projection : projections) {
fieldObject.putAll(projection.toDBObject(context));
fieldObject.putAll(projection.toDocument(context));
}
return new BasicDBObject("$project", fieldObject);
return new Document("$project", fieldObject);
}
/**
@@ -226,11 +225,11 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public DBObject toDBObject(AggregationOperationContext context) {
return this.operation.toDBObject(context);
public Document toDocument(AggregationOperationContext context) {
return this.operation.toDocument(context);
}
/**
@@ -240,6 +239,24 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
* @return
*/
public abstract ProjectionOperation as(String alias);
/**
* Apply a conditional projection using {@link ConditionalOperator}.
*
* @param conditionalOperator must not be {@literal null}.
* @return never {@literal null}.
* @since 1.10
*/
public abstract ProjectionOperation applyCondition(ConditionalOperator conditionalOperator);
/**
* Apply a conditional value replacement for {@literal null} values using {@link IfNullOperator}.
*
* @param ifNullOperator must not be {@literal null}.
* @return never {@literal null}.
* @since 1.10
*/
public abstract ProjectionOperation applyCondition(IfNullOperator ifNullOperator);
}
/**
@@ -334,14 +351,15 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.ProjectionOperation.Projection#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
* @see org.springframework.data.mongodb.core.aggregation.ProjectionOperation.Projection#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public DBObject toDBObject(AggregationOperationContext context) {
return new BasicDBObject(getExposedField().getName(), toMongoExpression(context, expression, params));
public Document toDocument(AggregationOperationContext context) {
return new Document(getExposedField().getName(), toMongoExpression(context, expression, params));
}
protected static Object toMongoExpression(AggregationOperationContext context, String expression, Object[] params) {
protected static Object toMongoExpression(AggregationOperationContext context, String expression,
Object[] params) {
return TRANSFORMER.transform(expression, context, params);
}
}
@@ -352,6 +370,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
*
* @author Oliver Gierke
* @author Thomas Darimont
* @author Christoph Strobl
*/
public static class ProjectionOperationBuilder extends AbstractProjectionOperationBuilder {
@@ -369,7 +388,8 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
* @param operation must not be {@literal null}.
* @param previousProjection the previous operation projection, may be {@literal null}.
*/
public ProjectionOperationBuilder(String name, ProjectionOperation operation, OperationProjection previousProjection) {
public ProjectionOperationBuilder(String name, ProjectionOperation operation,
OperationProjection previousProjection) {
super(name, operation);
this.name = name;
@@ -418,7 +438,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
/**
* Allows to specify an alias for the previous projection operation.
*
* @param string
* @param alias
* @return
*/
@Override
@@ -435,6 +455,28 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
return this.operation.and(new FieldProjection(Fields.field(alias, name), null));
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.ProjectionOperation.AbstractProjectionOperationBuilder#transform(org.springframework.data.mongodb.core.aggregation.ConditionalOperator)
*/
@Override
public ProjectionOperation applyCondition(ConditionalOperator conditionalOperator) {
Assert.notNull(conditionalOperator, "ConditionalOperator must not be null!");
return this.operation.and(new ExpressionProjection(Fields.field(name), conditionalOperator));
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.ProjectionOperation.AbstractProjectionOperationBuilder#transform(org.springframework.data.mongodb.core.aggregation.IfNullOperator)
*/
@Override
public ProjectionOperation applyCondition(IfNullOperator ifNullOperator) {
Assert.notNull(ifNullOperator, "IfNullOperator must not be null!");
return this.operation.and(new ExpressionProjection(Fields.field(name), ifNullOperator));
}
/**
* Generates an {@code $add} expression that adds the given number to the previously mentioned field.
*
@@ -562,17 +604,48 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
return project("mod", Fields.field(fieldReference));
}
/**
* Generates a {@code $size} expression that returns the size of the array held by the given field. <br />
*
* @return never {@literal null}.
* @since 1.7
*/
public ProjectionOperationBuilder size() {
return project("size");
}
/**
* Generates a {@code $slice} expression that returns a subset of the array held by the given field. <br />
* If {@literal n} is positive, $slice returns up to the first n elements in the array. <br />
* If {@literal n} is negative, $slice returns up to the last n elements in the array.
*
* @param count max number of elements.
* @return never {@literal null}.
* @since 1.10
*/
public ProjectionOperationBuilder slice(int count) {
return project("slice", count);
}
/**
* Generates a {@code $slice} expression that returns a subset of the array held by the given field. <br />
*
* @param count max number of elements. Must not be negative.
* @param offset the offset within the array to start from.
* @return never {@literal null}.
* @since 1.10
*/
public ProjectionOperationBuilder slice(int count, int offset) {
return project("slice", offset, count);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public DBObject toDBObject(AggregationOperationContext context) {
return this.operation.toDBObject(context);
public Document toDocument(AggregationOperationContext context) {
return this.operation.toDocument(context);
}
/**
@@ -609,11 +682,11 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.ProjectionOperation.Projection#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
* @see org.springframework.data.mongodb.core.aggregation.ProjectionOperation.Projection#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public DBObject toDBObject(AggregationOperationContext context) {
return new BasicDBObject(name, Fields.UNDERSCORE_ID_REF);
public Document toDocument(AggregationOperationContext context) {
return new Document(name, Fields.UNDERSCORE_ID_REF);
}
}
@@ -678,11 +751,11 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.ProjectionOperation.Projection#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
* @see org.springframework.data.mongodb.core.aggregation.ProjectionOperation.Projection#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public DBObject toDBObject(AggregationOperationContext context) {
return new BasicDBObject(field.getName(), renderFieldValue(context));
public Document toDocument(AggregationOperationContext context) {
return new Document(field.getName(), renderFieldValue(context));
}
private Object renderFieldValue(AggregationOperationContext context) {
@@ -732,16 +805,16 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
this.values = Arrays.asList(values);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.ProjectionOperation.Projection#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
* @see org.springframework.data.mongodb.core.aggregation.ProjectionOperation.Projection#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public DBObject toDBObject(AggregationOperationContext context) {
public Document toDocument(AggregationOperationContext context) {
DBObject inner = new BasicDBObject("$" + operation, getOperationArguments(context));
Document inner = new Document("$" + operation, getOperationArguments(context));
return new BasicDBObject(getField().getName(), inner);
return new Document(getField().getName(), inner);
}
protected List<Object> getOperationArguments(AggregationOperationContext context) {
@@ -824,18 +897,18 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.ProjectionOperation.Projection#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
* @see org.springframework.data.mongodb.core.aggregation.ProjectionOperation.Projection#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public DBObject toDBObject(AggregationOperationContext context) {
public Document toDocument(AggregationOperationContext context) {
DBObject nestedObject = new BasicDBObject();
Document nestedObject = new Document();
for (Field field : fields) {
nestedObject.put(field.getName(), context.getReference(field.getTarget()).toString());
}
return new BasicDBObject(name, nestedObject);
return new Document(name, nestedObject);
}
}
@@ -960,13 +1033,13 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
}
/**
* Renders the current {@link Projection} into a {@link DBObject} based on the given
* Renders the current {@link Projection} into a {@link Document} based on the given
* {@link AggregationOperationContext}.
*
* @param context will never be {@literal null}.
* @return
*/
public abstract DBObject toDBObject(AggregationOperationContext context);
public abstract Document toDocument(AggregationOperationContext context);
}
/**
@@ -991,8 +1064,8 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
}
@Override
public DBObject toDBObject(AggregationOperationContext context) {
return new BasicDBObject(field.getName(), expression.toDbObject(context));
public Document toDocument(AggregationOperationContext context) {
return new Document(field.getName(), expression.toDocument(context));
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 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,11 +15,9 @@
*/
package org.springframework.data.mongodb.core.aggregation;
import org.bson.Document;
import org.springframework.util.Assert;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* Encapsulates the aggregation framework {@code $skip}-operation.
* <p>
@@ -29,6 +27,7 @@ import com.mongodb.DBObject;
* @see http://docs.mongodb.org/manual/reference/aggregation/skip/
* @author Thomas Darimont
* @author Oliver Gierke
* @author Christoph Strobl
* @since 1.3
*/
public class SkipOperation implements AggregationOperation {
@@ -38,7 +37,7 @@ public class SkipOperation implements AggregationOperation {
/**
* Creates a new {@link SkipOperation} skipping the given number of elements.
*
* @param skipCount number of documents to skip.
* @param skipCount number of documents to skip, must not be less than zero.
*/
public SkipOperation(long skipCount) {
@@ -48,10 +47,10 @@ public class SkipOperation implements AggregationOperation {
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public DBObject toDBObject(AggregationOperationContext context) {
return new BasicDBObject("$skip", skipCount);
public Document toDocument(AggregationOperationContext context) {
return new Document("$skip", skipCount);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 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,15 +15,13 @@
*/
package org.springframework.data.mongodb.core.aggregation;
import org.bson.Document;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
import org.springframework.util.Assert;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* Encapsulates the aggregation framework {@code $sort}-operation.
* <p>
@@ -33,6 +31,7 @@ import com.mongodb.DBObject;
* @see http://docs.mongodb.org/manual/reference/aggregation/sort/#pipe._S_sort
* @author Thomas Darimont
* @author Oliver Gierke
* @author Christoph Strobl
* @since 1.3
*/
public class SortOperation implements AggregationOperation {
@@ -60,12 +59,12 @@ public class SortOperation implements AggregationOperation {
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public DBObject toDBObject(AggregationOperationContext context) {
public Document toDocument(AggregationOperationContext context) {
BasicDBObject object = new BasicDBObject();
Document object = new Document();
for (Order order : sort) {
@@ -74,6 +73,6 @@ public class SortOperation implements AggregationOperation {
object.put(reference.getRaw(), order.isAscending() ? 1 : -1);
}
return new BasicDBObject("$sort", object);
return new Document("$sort", object);
}
}

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,12 +15,12 @@
*/
package org.springframework.data.mongodb.core.aggregation;
import static org.springframework.data.mongodb.util.DBObjectUtils.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.bson.Document;
import org.springframework.core.GenericTypeResolver;
import org.springframework.data.mongodb.core.spel.ExpressionNode;
import org.springframework.data.mongodb.core.spel.ExpressionTransformationContextSupport;
@@ -40,10 +40,6 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.Assert;
import org.springframework.util.NumberUtils;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* Renders the AST of a SpEL expression as a MongoDB Aggregation Framework projection expression.
*
@@ -131,8 +127,8 @@ class SpelExpressionTransformer implements AggregationExpressionTransformer {
* @author Thomas Darimont
* @author Oliver Gierke
*/
private static abstract class ExpressionNodeConversion<T extends ExpressionNode> implements
AggregationExpressionTransformer {
private static abstract class ExpressionNodeConversion<T extends ExpressionNode>
implements AggregationExpressionTransformer {
private final AggregationExpressionTransformer transformer;
private final Class<? extends ExpressionNode> nodeType;
@@ -188,7 +184,7 @@ class SpelExpressionTransformer implements AggregationExpressionTransformer {
* @param context must not be {@literal null}.
* @return
*/
protected Object transform(ExpressionNode node, ExpressionNode parent, DBObject operation,
protected Object transform(ExpressionNode node, ExpressionNode parent, Document operation,
AggregationExpressionTransformationContext<?> context) {
Assert.notNull(node, "ExpressionNode must not be null!");
@@ -236,7 +232,7 @@ class SpelExpressionTransformer implements AggregationExpressionTransformer {
OperatorNode currentNode = context.getCurrentNode();
DBObject operationObject = createOperationObjectAndAddToPreviousArgumentsIfNecessary(context, currentNode);
Document operationObject = createOperationObjectAndAddToPreviousArgumentsIfNecessary(context, currentNode);
Object leftResult = transform(currentNode.getLeft(), currentNode, operationObject, context);
if (currentNode.isUnaryMinus()) {
@@ -249,32 +245,33 @@ class SpelExpressionTransformer implements AggregationExpressionTransformer {
return operationObject;
}
private DBObject createOperationObjectAndAddToPreviousArgumentsIfNecessary(
private Document createOperationObjectAndAddToPreviousArgumentsIfNecessary(
AggregationExpressionTransformationContext<OperatorNode> context, OperatorNode currentNode) {
DBObject nextDbObject = new BasicDBObject(currentNode.getMongoOperator(), new BasicDBList());
Document nextDocument = new Document(currentNode.getMongoOperator(), new ArrayList<Object>());
if (!context.hasPreviousOperation()) {
return nextDbObject;
return nextDocument;
}
if (context.parentIsSameOperation()) {
// same operator applied in a row e.g. 1 + 2 + 3 carry on with the operation and render as $add: [1, 2 ,3]
nextDbObject = context.getPreviousOperationObject();
nextDocument = context.getPreviousOperationObject();
} else if (!currentNode.isUnaryOperator()) {
// different operator -> add context object for next level to list if arguments of previous expression
context.addToPreviousOperation(nextDbObject);
context.addToPreviousOperation(nextDocument);
}
return nextDbObject;
return nextDocument;
}
private Object convertUnaryMinusOp(ExpressionTransformationContextSupport<OperatorNode> context, Object leftResult) {
private Object convertUnaryMinusOp(ExpressionTransformationContextSupport<OperatorNode> context,
Object leftResult) {
Object result = leftResult instanceof Number ? leftResult
: new BasicDBObject("$multiply", dbList(-1, leftResult));
: new Document("$multiply", Arrays.<Object> asList(Integer.valueOf(-1), leftResult));
if (leftResult != null && context.hasPreviousOperation()) {
context.addToPreviousOperation(result);
@@ -468,7 +465,7 @@ class SpelExpressionTransformer implements AggregationExpressionTransformer {
args.add(transform(childNode, context));
}
return context.addToPreviousOrReturn(new BasicDBObject(node.getMethodName(), dbList(args.toArray())));
return context.addToPreviousOrReturn(new Document(node.getMethodName(), args));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013 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.
@@ -17,6 +17,7 @@ package org.springframework.data.mongodb.core.aggregation;
import static org.springframework.data.mongodb.core.aggregation.Fields.*;
import org.bson.Document;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.context.PersistentPropertyPath;
@@ -27,13 +28,12 @@ import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.util.Assert;
import com.mongodb.DBObject;
/**
* {@link AggregationOperationContext} aware of a particular type and a {@link MappingContext} to potentially translate
* property references into document field names.
*
* @author Oliver Gierke
* @author Christoph Strobl
* @since 1.3
*/
public class TypeBasedAggregationOperationContext implements AggregationOperationContext {
@@ -64,11 +64,11 @@ public class TypeBasedAggregationOperationContext implements AggregationOperatio
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getMappedObject(com.mongodb.DBObject)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getMappedObject(com.mongodb.Document)
*/
@Override
public DBObject getMappedObject(DBObject dbObject) {
return mapper.getMappedObject(dbObject, mappingContext.getPersistentEntity(type));
public Document getMappedObject(Document document) {
return mapper.getMappedObject(document, mappingContext.getPersistentEntity(type));
}
/*
@@ -93,8 +93,8 @@ public class TypeBasedAggregationOperationContext implements AggregationOperatio
private FieldReference getReferenceFor(Field field) {
PersistentPropertyPath<MongoPersistentProperty> propertyPath = mappingContext.getPersistentPropertyPath(
field.getTarget(), type);
PersistentPropertyPath<MongoPersistentProperty> propertyPath = mappingContext
.getPersistentPropertyPath(field.getTarget(), type);
Field mappedField = field(propertyPath.getLeafProperty().getName(),
propertyPath.toDotPath(MongoPersistentProperty.PropertyToFieldNameConverter.INSTANCE));

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 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,12 +15,10 @@
*/
package org.springframework.data.mongodb.core.aggregation;
import org.bson.Document;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
import org.springframework.util.Assert;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* Encapsulates the aggregation framework {@code $unwind}-operation.
* <p>
@@ -30,29 +28,238 @@ import com.mongodb.DBObject;
* @see http://docs.mongodb.org/manual/reference/aggregation/unwind/#pipe._S_unwind
* @author Thomas Darimont
* @author Oliver Gierke
* @author Mark Paluch
* @author Christoph Strobl
* @since 1.3
*/
public class UnwindOperation implements AggregationOperation {
public class UnwindOperation
implements AggregationOperation, FieldsExposingAggregationOperation.InheritsFieldsAggregationOperation {
private final ExposedField field;
private final ExposedField arrayIndex;
private final boolean preserveNullAndEmptyArrays;
/**
* Creates a new {@link UnwindOperation} for the given {@link Field}.
*
*
* @param field must not be {@literal null}.
*/
public UnwindOperation(Field field) {
Assert.notNull(field);
this.field = new ExposedField(field, true);
this(new ExposedField(field, true), false);
}
/*
/**
* Creates a new {@link UnwindOperation} using Mongo 3.2 syntax.
*
* @param field must not be {@literal null}.
* @param preserveNullAndEmptyArrays {@literal true} to output the document if path is {@literal null}, missing or
* array is empty.
* @since 1.10
*/
public UnwindOperation(Field field, boolean preserveNullAndEmptyArrays) {
Assert.notNull(field, "Field must not be null!");
this.field = new ExposedField(field, true);
this.arrayIndex = null;
this.preserveNullAndEmptyArrays = preserveNullAndEmptyArrays;
}
/**
* Creates a new {@link UnwindOperation} using Mongo 3.2 syntax.
*
* @param field must not be {@literal null}.
* @param arrayIndex optional field name to expose the field array index, must not be {@literal null}.
* @param preserveNullAndEmptyArrays {@literal true} to output the document if path is {@literal null}, missing or
* array is empty.
* @since 1.10
*/
public UnwindOperation(Field field, Field arrayIndex, boolean preserveNullAndEmptyArrays) {
Assert.notNull(field, "Field must not be null!");
Assert.notNull(arrayIndex, "ArrayIndex must not be null!");
this.field = new ExposedField(field, true);
this.arrayIndex = new ExposedField(arrayIndex, true);
this.preserveNullAndEmptyArrays = preserveNullAndEmptyArrays;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public DBObject toDBObject(AggregationOperationContext context) {
return new BasicDBObject("$unwind", context.getReference(field).toString());
public Document toDocument(AggregationOperationContext context) {
String path = context.getReference(field).toString();
if (!preserveNullAndEmptyArrays && arrayIndex == null) {
return new Document("$unwind", path);
}
Document unwindArgs = new Document();
unwindArgs.put("path", path);
if (arrayIndex != null) {
unwindArgs.put("includeArrayIndex", arrayIndex.getName());
}
unwindArgs.put("preserveNullAndEmptyArrays", preserveNullAndEmptyArrays);
return new Document("$unwind", unwindArgs);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.FieldsExposingAggregationOperation#getFields()
*/
@Override
public ExposedFields getFields() {
return arrayIndex != null ? ExposedFields.from(arrayIndex) : ExposedFields.from();
}
/**
* Get a builder that allows creation of {@link LookupOperation}.
*
* @return
* @since 1.10
*/
public static PathBuilder newUnwind() {
return UnwindOperationBuilder.newBuilder();
}
/**
* @author Mark Paluch
* @since 1.10
*/
public static interface PathBuilder {
/**
* @param path the path to unwind, must not be {@literal null} or empty.
* @return
*/
IndexBuilder path(String path);
}
/**
* @author Mark Paluch
* @since 1.10
*/
public static interface IndexBuilder {
/**
* Exposes the array index as {@code field}.
*
* @param field field name to expose the field array index, must not be {@literal null} or empty.
* @return
*/
EmptyArraysBuilder arrayIndex(String field);
/**
* Do not expose the array index.
*
* @return
*/
EmptyArraysBuilder noArrayIndex();
}
public static interface EmptyArraysBuilder {
/**
* Output documents if the array is null or empty.
*
* @return
*/
UnwindOperation preserveNullAndEmptyArrays();
/**
* Do not output documents if the array is null or empty.
*
* @return
*/
UnwindOperation skipNullAndEmptyArrays();
}
/**
* Builder for fluent {@link UnwindOperation} creation.
*
* @author Mark Paluch
* @since 1.10
*/
public static final class UnwindOperationBuilder implements PathBuilder, IndexBuilder, EmptyArraysBuilder {
private Field field;
private Field arrayIndex;
private UnwindOperationBuilder() {}
/**
* Creates new builder for {@link UnwindOperation}.
*
* @return never {@literal null}.
*/
public static PathBuilder newBuilder() {
return new UnwindOperationBuilder();
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.UnwindOperation.EmptyArraysBuilder#preserveNullAndEmptyArrays()
*/
@Override
public UnwindOperation preserveNullAndEmptyArrays() {
if (arrayIndex != null) {
return new UnwindOperation(field, arrayIndex, true);
}
return new UnwindOperation(field, true);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.UnwindOperation.EmptyArraysBuilder#skipNullAndEmptyArrays()
*/
@Override
public UnwindOperation skipNullAndEmptyArrays() {
if (arrayIndex != null) {
return new UnwindOperation(field, arrayIndex, false);
}
return new UnwindOperation(field, false);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.UnwindOperation.IndexBuilder#arrayIndex(java.lang.String)
*/
@Override
public EmptyArraysBuilder arrayIndex(String field) {
Assert.hasText(field, "'ArrayIndex' must not be null or empty!");
arrayIndex = Fields.field(field);
return this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.UnwindOperation.IndexBuilder#noArrayIndex()
*/
@Override
public EmptyArraysBuilder noArrayIndex() {
arrayIndex = null;
return this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.UnwindOperation.PathBuilder#path(java.lang.String)
*/
@Override
public UnwindOperationBuilder path(String path) {
Assert.hasText(path, "'Path' must not be null or empty!");
field = Fields.field(path);
return this;
}
}
}

View File

@@ -31,7 +31,7 @@ import org.springframework.data.mongodb.core.convert.MongoConverters.StringToObj
/**
* Base class for {@link MongoConverter} implementations. Sets up a {@link GenericConversionService} and populates basic
* converters. Allows registering {@link CustomConversions}.
*
*
* @author Jon Brisbin
* @author Oliver Gierke
*/
@@ -43,7 +43,7 @@ public abstract class AbstractMongoConverter implements MongoConverter, Initiali
/**
* Creates a new {@link AbstractMongoConverter} using the given {@link GenericConversionService}.
*
*
* @param conversionService
*/
public AbstractMongoConverter(GenericConversionService conversionService) {
@@ -52,7 +52,7 @@ public abstract class AbstractMongoConverter implements MongoConverter, Initiali
/**
* Registers the given custom conversions with the converter.
*
*
* @param conversions
*/
public void setCustomConversions(CustomConversions conversions) {
@@ -61,7 +61,7 @@ public abstract class AbstractMongoConverter implements MongoConverter, Initiali
/**
* Registers {@link EntityInstantiators} to customize entity instantiation.
*
*
* @param instantiators
*/
public void setInstantiators(EntityInstantiators instantiators) {
@@ -75,15 +75,13 @@ public abstract class AbstractMongoConverter implements MongoConverter, Initiali
*/
private void initializeConverters() {
if (!conversionService.canConvert(ObjectId.class, String.class)) {
conversionService.addConverter(ObjectIdToStringConverter.INSTANCE);
}
if (!conversionService.canConvert(String.class, ObjectId.class)) {
conversionService.addConverter(StringToObjectIdConverter.INSTANCE);
}
conversionService.addConverter(ObjectIdToStringConverter.INSTANCE);
conversionService.addConverter(StringToObjectIdConverter.INSTANCE);
if (!conversionService.canConvert(ObjectId.class, BigInteger.class)) {
conversionService.addConverter(ObjectIdToBigIntegerConverter.INSTANCE);
}
if (!conversionService.canConvert(BigInteger.class, ObjectId.class)) {
conversionService.addConverter(BigIntegerToObjectIdConverter.INSTANCE);
}
@@ -91,7 +89,7 @@ public abstract class AbstractMongoConverter implements MongoConverter, Initiali
conversions.registerConvertersIn(conversionService);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.convert.MongoWriter#convertToMongoType(java.lang.Object)
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2015 the original author or authors.
* Copyright 2011-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.
@@ -42,16 +42,6 @@ import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.ThreeTenBackPortConverters;
import org.springframework.data.convert.WritingConverter;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.mongodb.core.convert.MongoConverters.BigDecimalToStringConverter;
import org.springframework.data.mongodb.core.convert.MongoConverters.BigIntegerToStringConverter;
import org.springframework.data.mongodb.core.convert.MongoConverters.NamedMongoScriptToDBObjectConverter;
import org.springframework.data.mongodb.core.convert.MongoConverters.DBObjectToNamedMongoScriptCoverter;
import org.springframework.data.mongodb.core.convert.MongoConverters.DBObjectToStringConverter;
import org.springframework.data.mongodb.core.convert.MongoConverters.StringToBigDecimalConverter;
import org.springframework.data.mongodb.core.convert.MongoConverters.StringToBigIntegerConverter;
import org.springframework.data.mongodb.core.convert.MongoConverters.StringToURLConverter;
import org.springframework.data.mongodb.core.convert.MongoConverters.TermToStringConverter;
import org.springframework.data.mongodb.core.convert.MongoConverters.URLToStringConverter;
import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes;
import org.springframework.data.util.CacheValue;
import org.springframework.util.Assert;
@@ -112,17 +102,7 @@ public class CustomConversions {
// Add user provided converters to make sure they can override the defaults
toRegister.addAll(converters);
toRegister.add(CustomToStringConverter.INSTANCE);
toRegister.add(BigDecimalToStringConverter.INSTANCE);
toRegister.add(StringToBigDecimalConverter.INSTANCE);
toRegister.add(BigIntegerToStringConverter.INSTANCE);
toRegister.add(StringToBigIntegerConverter.INSTANCE);
toRegister.add(URLToStringConverter.INSTANCE);
toRegister.add(StringToURLConverter.INSTANCE);
toRegister.add(DBObjectToStringConverter.INSTANCE);
toRegister.add(TermToStringConverter.INSTANCE);
toRegister.add(NamedMongoScriptToDBObjectConverter.INSTANCE);
toRegister.add(DBObjectToNamedMongoScriptCoverter.INSTANCE);
toRegister.addAll(MongoConverters.getConvertersToRegister());
toRegister.addAll(JodaTimeConverters.getConvertersToRegister());
toRegister.addAll(GeoConverters.getConvertersToRegister());
toRegister.addAll(Jsr310Converters.getConvertersToRegister());
@@ -186,14 +166,15 @@ public class CustomConversions {
}
if (!added) {
throw new IllegalArgumentException("Given set contains element that is neither Converter nor ConverterFactory!");
throw new IllegalArgumentException(
"Given set contains element that is neither Converter nor ConverterFactory!");
}
}
}
/**
* Registers a conversion for the given converter. Inspects either generics or the {@link ConvertiblePair}s returned
* by a {@link GenericConverter}.
* Registers a conversion for the given converter. Inspects either generics of {@link Converter} and
* {@link ConverterFactory} or the {@link ConvertiblePair}s returned by a {@link GenericConverter}.
*
* @param converter
*/
@@ -208,6 +189,10 @@ public class CustomConversions {
for (ConvertiblePair pair : genericConverter.getConvertibleTypes()) {
register(new ConverterRegistration(pair, isReading, isWriting));
}
} else if (converter instanceof ConverterFactory) {
Class<?>[] arguments = GenericTypeResolver.resolveTypeArguments(converter.getClass(), ConverterFactory.class);
register(new ConverterRegistration(arguments[0], arguments[1], isReading, isWriting));
} else if (converter instanceof Converter) {
Class<?>[] arguments = GenericTypeResolver.resolveTypeArguments(converter.getClass(), Converter.class);
register(new ConverterRegistration(arguments[0], arguments[1], isReading, isWriting));
@@ -412,6 +397,10 @@ public class CustomConversions {
INSTANCE;
/*
* (non-Javadoc)
* @see org.springframework.core.convert.converter.GenericConverter#getConvertibleTypes()
*/
public Set<ConvertiblePair> getConvertibleTypes() {
ConvertiblePair localeToString = new ConvertiblePair(Locale.class, String.class);
@@ -420,6 +409,10 @@ public class CustomConversions {
return new HashSet<ConvertiblePair>(Arrays.asList(localeToString, booleanToString));
}
/*
* (non-Javadoc)
* @see org.springframework.core.convert.converter.GenericConverter#convert(java.lang.Object, org.springframework.core.convert.TypeDescriptor, org.springframework.core.convert.TypeDescriptor)
*/
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
return source.toString();
}

View File

@@ -1,132 +0,0 @@
/*
* Copyright 2013-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.core.convert;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.util.Assert;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* Wrapper value object for a {@link BasicDBObject} to be able to access raw values by {@link MongoPersistentProperty}
* references. The accessors will transparently resolve nested document values that a {@link MongoPersistentProperty}
* might refer to through a path expression in field names.
*
* @author Oliver Gierke
*/
class DBObjectAccessor {
private final BasicDBObject dbObject;
/**
* Creates a new {@link DBObjectAccessor} for the given {@link DBObject}.
*
* @param dbObject must be a {@link BasicDBObject} effectively, must not be {@literal null}.
*/
public DBObjectAccessor(DBObject dbObject) {
Assert.notNull(dbObject, "DBObject must not be null!");
Assert.isInstanceOf(BasicDBObject.class, dbObject, "Given DBObject must be a BasicDBObject!");
this.dbObject = (BasicDBObject) dbObject;
}
/**
* Puts the given value into the backing {@link DBObject} based on the coordinates defined through the given
* {@link MongoPersistentProperty}. By default this will be the plain field name. But field names might also consist
* of path traversals so we might need to create intermediate {@link BasicDBObject}s.
*
* @param prop must not be {@literal null}.
* @param value
*/
public void put(MongoPersistentProperty prop, Object value) {
Assert.notNull(prop, "MongoPersistentProperty must not be null!");
String fieldName = prop.getFieldName();
if (!fieldName.contains(".")) {
dbObject.put(fieldName, value);
return;
}
Iterator<String> parts = Arrays.asList(fieldName.split("\\.")).iterator();
DBObject dbObject = this.dbObject;
while (parts.hasNext()) {
String part = parts.next();
if (parts.hasNext()) {
BasicDBObject nestedDbObject = new BasicDBObject();
dbObject.put(part, nestedDbObject);
dbObject = nestedDbObject;
} else {
dbObject.put(part, value);
}
}
}
/**
* Returns the value the given {@link MongoPersistentProperty} refers to. By default this will be a direct field but
* the method will also transparently resolve nested values the {@link MongoPersistentProperty} might refer to through
* a path expression in the field name metadata.
*
* @param property must not be {@literal null}.
* @return
*/
public Object get(MongoPersistentProperty property) {
String fieldName = property.getFieldName();
if (!fieldName.contains(".")) {
return this.dbObject.get(fieldName);
}
Iterator<String> parts = Arrays.asList(fieldName.split("\\.")).iterator();
Map<String, Object> source = this.dbObject;
Object result = null;
while (source != null && parts.hasNext()) {
result = source.get(parts.next());
if (parts.hasNext()) {
source = getAsMap(result);
}
}
return result;
}
@SuppressWarnings("unchecked")
private Map<String, Object> getAsMap(Object source) {
if (source instanceof BasicDBObject) {
return (BasicDBObject) source;
}
if (source instanceof Map) {
return (Map<String, Object>) source;
}
return null;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 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,10 +15,13 @@
*/
package org.springframework.data.mongodb.core.convert;
import org.bson.Document;
import java.util.List;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import com.mongodb.DBObject;
import com.mongodb.DBRef;
/**
@@ -27,6 +30,7 @@ import com.mongodb.DBRef;
* @author Thomas Darimont
* @author Oliver Gierke
* @author Christoph Strobl
* @author Mark Paluch
* @since 1.4
*/
public interface DbRefResolver {
@@ -63,5 +67,17 @@ public interface DbRefResolver {
* @return
* @since 1.7
*/
DBObject fetch(DBRef dbRef);
Document fetch(DBRef dbRef);
/**
* Loads a given {@link List} of {@link DBRef}s from the datasource in one batch. The resulting {@link List} of
* {@link Document} will reflect the ordering of the {@link DBRef} passed in.<br />
* The {@link DBRef} elements in the list must not reference different collections.
*
* @param dbRefs must not be {@literal null}.
* @return never {@literal null}.
* @throws InvalidDataAccessApiUsageException in case not all {@link DBRef} target the same collection.
* @since 1.10
*/
List<Document> bulkFetch(List<DBRef> dbRefs);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014 the original author or authors.
* Copyright 2014-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,6 +15,7 @@
*/
package org.springframework.data.mongodb.core.convert;
import org.bson.Document;
import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
@@ -23,12 +24,11 @@ import org.springframework.data.mapping.model.SpELExpressionEvaluator;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.DBRef;
/**
* @author Oliver Gierke
* @author Christoph Strobl
*/
class DefaultDbRefProxyHandler implements DbRefProxyHandler {
@@ -38,11 +38,12 @@ class DefaultDbRefProxyHandler implements DbRefProxyHandler {
/**
* @param spELContext must not be {@literal null}.
* @param conversionService must not be {@literal null}.
* @param mappingContext must not be {@literal null}.
* @param resolver must not be {@literal null}.
*/
public DefaultDbRefProxyHandler(SpELContext spELContext,
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext, ValueResolver resolver) {
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext,
ValueResolver resolver) {
this.spELContext = spELContext;
this.mappingContext = mappingContext;
@@ -70,7 +71,7 @@ class DefaultDbRefProxyHandler implements DbRefProxyHandler {
SpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(proxy, spELContext);
PersistentPropertyAccessor accessor = entity.getPropertyAccessor(proxy);
DBObject object = new BasicDBObject(idProperty.getFieldName(), source.getId());
Document object = new Document(idProperty.getFieldName(), source.getId());
ObjectPath objectPath = ObjectPath.ROOT.push(proxy, entity, null);
accessor.setProperty(idProperty, resolver.getValueInternal(idProperty, object, evaluator, objectPath));

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 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.
@@ -22,15 +22,21 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.bson.Document;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.Factory;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.mongodb.LazyLoadingException;
import org.springframework.data.mongodb.MongoDbFactory;
@@ -40,8 +46,8 @@ import org.springframework.objenesis.ObjenesisStd;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import com.mongodb.DBObject;
import com.mongodb.DBRef;
import com.mongodb.client.MongoDatabase;
/**
* A {@link DbRefResolver} that resolves {@link org.springframework.data.mongodb.core.mapping.DBRef}s by delegating to a
@@ -50,6 +56,7 @@ import com.mongodb.DBRef;
* @author Thomas Darimont
* @author Oliver Gierke
* @author Christoph Strobl
* @author Mark Paluch
* @since 1.4
*/
public class DefaultDbRefResolver implements DbRefResolver {
@@ -105,10 +112,44 @@ public class DefaultDbRefResolver implements DbRefResolver {
* @see org.springframework.data.mongodb.core.convert.DbRefResolver#fetch(com.mongodb.DBRef)
*/
@Override
public DBObject fetch(DBRef dbRef) {
public Document fetch(DBRef dbRef) {
return ReflectiveDBRefResolver.fetch(mongoDbFactory, dbRef);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.convert.DbRefResolver#bulkFetch(java.util.List)
*/
@Override
public List<Document> bulkFetch(List<DBRef> refs) {
Assert.notNull(mongoDbFactory, "Factory must not be null!");
Assert.notNull(refs, "DBRef to fetch must not be null!");
if (refs.isEmpty()) {
return Collections.emptyList();
}
String collection = refs.iterator().next().getCollectionName();
List<Object> ids = new ArrayList<Object>(refs.size());
for (DBRef ref : refs) {
if (!collection.equals(ref.getCollectionName())) {
throw new InvalidDataAccessApiUsageException(
"DBRefs must all target the same collection for bulk fetch operation.");
}
ids.add(ref.getId());
}
MongoDatabase db = mongoDbFactory.getDb();
List<Document> result = new ArrayList<>();
db.getCollection(collection).find(new Document("_id", new Document("$in", ids))).into(result);
Collections.sort(result, new DbRefByReferencePositionComparator(ids));
return result;
}
/**
* Creates a proxy for the given {@link MongoPersistentProperty} using the given {@link DbRefResolverCallback} to
* eventually resolve the value of the property.
@@ -180,8 +221,8 @@ public class DefaultDbRefResolver implements DbRefResolver {
* @author Oliver Gierke
* @author Christoph Strobl
*/
static class LazyLoadingInterceptor implements MethodInterceptor, org.springframework.cglib.proxy.MethodInterceptor,
Serializable {
static class LazyLoadingInterceptor
implements MethodInterceptor, org.springframework.cglib.proxy.MethodInterceptor, Serializable {
private static final Method INITIALIZE_METHOD, TO_DBREF_METHOD, FINALIZE_METHOD;
@@ -387,11 +428,45 @@ public class DefaultDbRefResolver implements DbRefResolver {
} catch (RuntimeException ex) {
DataAccessException translatedException = this.exceptionTranslator.translateExceptionIfPossible(ex);
throw new LazyLoadingException("Unable to lazily resolve DBRef!", translatedException);
throw new LazyLoadingException("Unable to lazily resolve DBRef!",
translatedException != null ? translatedException : ex);
}
}
return result;
}
}
/**
* {@link Comparator} for sorting {@link Document} that have been loaded in random order by a predefined list of
* reference identifiers.
*
* @author Christoph Strobl
* @author Oliver Gierke
* @since 1.10
*/
private static class DbRefByReferencePositionComparator implements Comparator<Document> {
private final List<Object> reference;
/**
* Creates a new {@link DbRefByReferencePositionComparator} for the given list of reference identifiers.
*
* @param referenceIds must not be {@literal null}.
*/
public DbRefByReferencePositionComparator(List<Object> referenceIds) {
Assert.notNull(referenceIds, "Reference identifiers must not be null!");
this.reference = new ArrayList<Object>(referenceIds);
}
/*
* (non-Javadoc)
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
*/
@Override
public int compare(Document o1, Document o2) {
return Integer.compare(reference.indexOf(o1.get("_id")), reference.indexOf(o2.get("_id")));
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014 the original author or authors.
* Copyright 2014-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,25 +15,26 @@
*/
package org.springframework.data.mongodb.core.convert;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import com.mongodb.DBObject;
/**
* Default implementation of {@link DbRefResolverCallback}.
*
* @author Oliver Gierke
* @author Christoph Strobl
*/
class DefaultDbRefResolverCallback implements DbRefResolverCallback {
private final DBObject surroundingObject;
private final Bson surroundingObject;
private final ObjectPath path;
private final ValueResolver resolver;
private final SpELExpressionEvaluator evaluator;
/**
* Creates a new {@link DefaultDbRefResolverCallback} using the given {@link DBObject}, {@link ObjectPath},
* Creates a new {@link DefaultDbRefResolverCallback} using the given {@link Document}, {@link ObjectPath},
* {@link ValueResolver} and {@link SpELExpressionEvaluator}.
*
* @param surroundingObject must not be {@literal null}.
@@ -41,7 +42,7 @@ class DefaultDbRefResolverCallback implements DbRefResolverCallback {
* @param evaluator must not be {@literal null}.
* @param resolver must not be {@literal null}.
*/
public DefaultDbRefResolverCallback(DBObject surroundingObject, ObjectPath path, SpELExpressionEvaluator evaluator,
public DefaultDbRefResolverCallback(Bson surroundingObject, ObjectPath path, SpELExpressionEvaluator evaluator,
ValueResolver resolver) {
this.surroundingObject = surroundingObject;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2013 the original author or authors.
* Copyright 2011-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.
@@ -20,6 +20,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.data.convert.DefaultTypeMapper;
import org.springframework.data.convert.SimpleTypeInformationMapper;
import org.springframework.data.convert.TypeAliasAccessor;
@@ -30,27 +32,28 @@ import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* Default implementation of {@link MongoTypeMapper} allowing configuration of the key to lookup and store type
* information in {@link DBObject}. The key defaults to {@link #DEFAULT_TYPE_KEY}. Actual type-to-{@link String}
* information in {@link Document}. The key defaults to {@link #DEFAULT_TYPE_KEY}. Actual type-to-{@link String}
* conversion and back is done in {@link #getTypeString(TypeInformation)} or {@link #getTypeInformation(String)}
* respectively.
*
* @author Oliver Gierke
* @author Thomas Darimont
* @author Christoph Strobl
* @author Mark Paluch
*/
public class DefaultMongoTypeMapper extends DefaultTypeMapper<DBObject> implements MongoTypeMapper {
public class DefaultMongoTypeMapper extends DefaultTypeMapper<Bson> implements MongoTypeMapper {
public static final String DEFAULT_TYPE_KEY = "_class";
@SuppressWarnings("rawtypes")//
@SuppressWarnings("rawtypes") //
private static final TypeInformation<List> LIST_TYPE_INFO = ClassTypeInformation.from(List.class);
@SuppressWarnings("rawtypes")//
@SuppressWarnings("rawtypes") //
private static final TypeInformation<Map> MAP_TYPE_INFO = ClassTypeInformation.from(Map.class);
private final TypeAliasAccessor<DBObject> accessor;
private final TypeAliasAccessor<Bson> accessor;
private final String typeKey;
public DefaultMongoTypeMapper() {
@@ -58,20 +61,21 @@ public class DefaultMongoTypeMapper extends DefaultTypeMapper<DBObject> implemen
}
public DefaultMongoTypeMapper(String typeKey) {
this(typeKey, Arrays.asList(SimpleTypeInformationMapper.INSTANCE));
this(typeKey, Arrays.asList(new SimpleTypeInformationMapper()));
}
public DefaultMongoTypeMapper(String typeKey, MappingContext<? extends PersistentEntity<?, ?>, ?> mappingContext) {
this(typeKey, new DBObjectTypeAliasAccessor(typeKey), mappingContext, Arrays
.asList(SimpleTypeInformationMapper.INSTANCE));
this(typeKey, new DocumentTypeAliasAccessor(typeKey), mappingContext,
Arrays.asList(new SimpleTypeInformationMapper()));
}
public DefaultMongoTypeMapper(String typeKey, List<? extends TypeInformationMapper> mappers) {
this(typeKey, new DBObjectTypeAliasAccessor(typeKey), null, mappers);
this(typeKey, new DocumentTypeAliasAccessor(typeKey), null, mappers);
}
private DefaultMongoTypeMapper(String typeKey, TypeAliasAccessor<DBObject> accessor,
MappingContext<? extends PersistentEntity<?, ?>, ?> mappingContext, List<? extends TypeInformationMapper> mappers) {
private DefaultMongoTypeMapper(String typeKey, TypeAliasAccessor<Bson> accessor,
MappingContext<? extends PersistentEntity<?, ?>, ?> mappingContext,
List<? extends TypeInformationMapper> mappers) {
super(accessor, mappingContext, mappers);
@@ -92,7 +96,7 @@ public class DefaultMongoTypeMapper extends DefaultTypeMapper<DBObject> implemen
* @see org.springframework.data.mongodb.core.convert.MongoTypeMapper#writeTypeRestrictions(java.util.Set)
*/
@Override
public void writeTypeRestrictions(DBObject result, Set<Class<?>> restrictedTypes) {
public void writeTypeRestrictions(Document result, Set<Class<?>> restrictedTypes) {
if (restrictedTypes == null || restrictedTypes.isEmpty()) {
return;
@@ -109,27 +113,28 @@ public class DefaultMongoTypeMapper extends DefaultTypeMapper<DBObject> implemen
}
}
accessor.writeTypeTo(result, new BasicDBObject("$in", restrictedMappedTypes));
accessor.writeTypeTo(result, new Document("$in", restrictedMappedTypes));
}
/* (non-Javadoc)
* @see org.springframework.data.convert.DefaultTypeMapper#getFallbackTypeFor(java.lang.Object)
*/
@Override
protected TypeInformation<?> getFallbackTypeFor(DBObject source) {
protected TypeInformation<?> getFallbackTypeFor(Bson source) {
return source instanceof BasicDBList ? LIST_TYPE_INFO : MAP_TYPE_INFO;
}
/**
* {@link TypeAliasAccessor} to store aliases in a {@link DBObject}.
* {@link TypeAliasAccessor} to store aliases in a {@link Document}.
*
* @author Oliver Gierke
*/
public static final class DBObjectTypeAliasAccessor implements TypeAliasAccessor<DBObject> {
public static final class DocumentTypeAliasAccessor implements TypeAliasAccessor<Bson> {
private final String typeKey;
public DBObjectTypeAliasAccessor(String typeKey) {
public DocumentTypeAliasAccessor(String typeKey) {
this.typeKey = typeKey;
}
@@ -137,22 +142,34 @@ public class DefaultMongoTypeMapper extends DefaultTypeMapper<DBObject> implemen
* (non-Javadoc)
* @see org.springframework.data.convert.TypeAliasAccessor#readAliasFrom(java.lang.Object)
*/
public Object readAliasFrom(DBObject source) {
public Object readAliasFrom(Bson source) {
if (source instanceof BasicDBList) {
if (source instanceof List) {
return null;
}
return source.get(typeKey);
if (source instanceof Document) {
return ((Document) source).get(typeKey);
} else if (source instanceof DBObject) {
return ((DBObject) source).get(typeKey);
}
throw new IllegalArgumentException("Cannot read alias from " + source.getClass());
}
/*
* (non-Javadoc)
* @see org.springframework.data.convert.TypeAliasAccessor#writeTypeTo(java.lang.Object, java.lang.Object)
*/
public void writeTypeTo(DBObject sink, Object alias) {
public void writeTypeTo(Bson sink, Object alias) {
if (typeKey != null) {
sink.put(typeKey, alias);
if (sink instanceof Document) {
((Document) sink).put(typeKey, alias);
} else if (sink instanceof DBObject) {
((DBObject) sink).put(typeKey, alias);
}
}
}
}

View File

@@ -0,0 +1,217 @@
/*
* 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.
* 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 java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.util.BsonUtils;
import org.springframework.util.Assert;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* Wrapper value object for a {@link Document} to be able to access raw values by {@link MongoPersistentProperty}
* references. The accessors will transparently resolve nested document values that a {@link MongoPersistentProperty}
* might refer to through a path expression in field names.
*
* @author Oliver Gierke
* @author Christoph Strobl
*/
class DocumentAccessor {
private final Bson document;
/**
* Creates a new {@link DocumentAccessor} for the given {@link Document}.
*
* @param document must be a {@link Document} effectively, must not be {@literal null}.
*/
public DocumentAccessor(Bson document) {
Assert.notNull(document, "Document must not be null!");
if (!(document instanceof Document) && !(document instanceof DBObject)) {
Assert.isInstanceOf(Document.class, document, "Given Bson must be a Document or DBObject!");
}
this.document = document;
}
/**
* Puts the given value into the backing {@link Document} based on the coordinates defined through the given
* {@link MongoPersistentProperty}. By default this will be the plain field name. But field names might also consist
* of path traversals so we might need to create intermediate {@link BasicDocument}s.
*
* @param prop must not be {@literal null}.
* @param value
*/
public void put(MongoPersistentProperty prop, Object value) {
Assert.notNull(prop, "MongoPersistentProperty must not be null!");
String fieldName = prop.getFieldName();
if (!fieldName.contains(".")) {
BsonUtils.addToMap(document, fieldName, value);
return;
}
Iterator<String> parts = Arrays.asList(fieldName.split("\\.")).iterator();
Bson document = this.document;
while (parts.hasNext()) {
String part = parts.next();
if (parts.hasNext()) {
document = getOrCreateNestedDocument(part, document);
} else {
BsonUtils.addToMap(document, part, value);
}
}
}
/**
* Returns the value the given {@link MongoPersistentProperty} refers to. By default this will be a direct field but
* the method will also transparently resolve nested values the {@link MongoPersistentProperty} might refer to through
* a path expression in the field name metadata.
*
* @param property must not be {@literal null}.
* @return
*/
public Object get(MongoPersistentProperty property) {
String fieldName = property.getFieldName();
if (!fieldName.contains(".")) {
return BsonUtils.asMap(this.document).get(fieldName);
}
Iterator<String> parts = Arrays.asList(fieldName.split("\\.")).iterator();
Map<String, Object> source = BsonUtils.asMap(this.document);
Object result = null;
while (source != null && parts.hasNext()) {
result = source.get(parts.next());
if (parts.hasNext()) {
source = getAsMap(result);
}
}
return result;
}
/**
* Returns whether the underlying {@link Document} has a value ({@literal null} or non-{@literal null}) for the given
* {@link MongoPersistentProperty}.
*
* @param property must not be {@literal null}.
* @return
*/
public boolean hasValue(MongoPersistentProperty property) {
Assert.notNull(property, "Property must not be null!");
String fieldName = property.getFieldName();
if (!fieldName.contains(".")) {
if (this.document instanceof Document) {
return ((Document) this.document).containsKey(fieldName);
}
if (this.document instanceof DBObject) {
return ((DBObject) this.document).containsField(fieldName);
}
}
String[] parts = fieldName.split("\\.");
Map<String, Object> source;
if (this.document instanceof Document) {
source = ((Document) this.document);
}else {
source = ((DBObject) this.document).toMap();
}
Object result = null;
for (int i = 1; i < parts.length; i++) {
result = source.get(parts[i - 1]);
source = getAsMap(result);
if (source == null) {
return false;
}
}
return source.containsKey(parts[parts.length - 1]);
}
/**
* Returns the given source object as map, i.e. {@link Document}s and maps as is or {@literal null} otherwise.
*
* @param source can be {@literal null}.
* @return
*/
@SuppressWarnings("unchecked")
private static Map<String, Object> getAsMap(Object source) {
if (source instanceof Document) {
return (Document) source;
}
if (source instanceof BasicDBObject) {
return (BasicDBObject) source;
}
if (source instanceof Map) {
return (Map<String, Object>) source;
}
return null;
}
/**
* Returns the {@link Document} which either already exists in the given source under the given key, or creates a new
* nested one, registers it with the source and returns it.
*
* @param key must not be {@literal null} or empty.
* @param source must not be {@literal null}.
* @return
*/
private static Document getOrCreateNestedDocument(String key, Bson source) {
Object existing = BsonUtils.asMap(source).get(key);
if (existing instanceof Document) {
return (Document) existing;
}
Document nested = new Document();
BsonUtils.addToMap(source, key, nested);
return nested;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2014 the original author or authors.
* Copyright 2012-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.
@@ -17,21 +17,21 @@ package org.springframework.data.mongodb.core.convert;
import java.util.Map;
import org.bson.Document;
import org.springframework.context.expression.MapAccessor;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypedValue;
import com.mongodb.DBObject;
/**
* {@link PropertyAccessor} to allow entity based field access to {@link DBObject}s.
* {@link PropertyAccessor} to allow entity based field access to {@link Document}s.
*
* @author Oliver Gierke
* @author Christoph Strobl
*/
class DBObjectPropertyAccessor extends MapAccessor {
class DocumentPropertyAccessor extends MapAccessor {
static final MapAccessor INSTANCE = new DBObjectPropertyAccessor();
static final MapAccessor INSTANCE = new DocumentPropertyAccessor();
/*
* (non-Javadoc)
@@ -39,7 +39,7 @@ class DBObjectPropertyAccessor extends MapAccessor {
*/
@Override
public Class<?>[] getSpecificTargetClasses() {
return new Class[] { DBObject.class };
return new Class[] { Document.class };
}
/*

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2015 the original author or authors.
* Copyright 2014-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.
@@ -20,6 +20,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.bson.Document;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter;
@@ -44,8 +45,6 @@ import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* Wrapper class to contain useful geo structure converters for the usage with Mongo.
@@ -70,27 +69,27 @@ abstract class GeoConverters {
@SuppressWarnings("unchecked")
public static Collection<? extends Object> getConvertersToRegister() {
return Arrays.asList( //
BoxToDbObjectConverter.INSTANCE //
, PolygonToDbObjectConverter.INSTANCE //
, CircleToDbObjectConverter.INSTANCE //
, SphereToDbObjectConverter.INSTANCE //
, DbObjectToBoxConverter.INSTANCE //
, DbObjectToPolygonConverter.INSTANCE //
, DbObjectToCircleConverter.INSTANCE //
, DbObjectToSphereConverter.INSTANCE //
, DbObjectToPointConverter.INSTANCE //
, PointToDbObjectConverter.INSTANCE //
, GeoCommandToDbObjectConverter.INSTANCE //
, GeoJsonToDbObjectConverter.INSTANCE //
, GeoJsonPointToDbObjectConverter.INSTANCE //
, GeoJsonPolygonToDbObjectConverter.INSTANCE //
, DbObjectToGeoJsonPointConverter.INSTANCE //
, DbObjectToGeoJsonPolygonConverter.INSTANCE //
, DbObjectToGeoJsonLineStringConverter.INSTANCE //
, DbObjectToGeoJsonMultiLineStringConverter.INSTANCE //
, DbObjectToGeoJsonMultiPointConverter.INSTANCE //
, DbObjectToGeoJsonMultiPolygonConverter.INSTANCE //
, DbObjectToGeoJsonGeometryCollectionConverter.INSTANCE);
BoxToDocumentConverter.INSTANCE //
, PolygonToDocumentConverter.INSTANCE //
, CircleToDocumentConverter.INSTANCE //
, SphereToDocumentConverter.INSTANCE //
, DocumentToBoxConverter.INSTANCE //
, DocumentToPolygonConverter.INSTANCE //
, DocumentToCircleConverter.INSTANCE //
, DocumentToSphereConverter.INSTANCE //
, DocumentToPointConverter.INSTANCE //
, PointToDocumentConverter.INSTANCE //
, GeoCommandToDocumentConverter.INSTANCE //
, GeoJsonToDocumentConverter.INSTANCE //
, GeoJsonPointToDocumentConverter.INSTANCE //
, GeoJsonPolygonToDocumentConverter.INSTANCE //
, DocumentToGeoJsonPointConverter.INSTANCE //
, DocumentToGeoJsonPolygonConverter.INSTANCE //
, DocumentToGeoJsonLineStringConverter.INSTANCE //
, DocumentToGeoJsonMultiLineStringConverter.INSTANCE //
, DocumentToGeoJsonMultiPointConverter.INSTANCE //
, DocumentToGeoJsonMultiPolygonConverter.INSTANCE //
, DocumentToGeoJsonGeometryCollectionConverter.INSTANCE);
}
/**
@@ -100,7 +99,7 @@ abstract class GeoConverters {
* @since 1.5
*/
@ReadingConverter
static enum DbObjectToPointConverter implements Converter<DBObject, Point> {
static enum DocumentToPointConverter implements Converter<Document, Point> {
INSTANCE;
@@ -109,11 +108,19 @@ abstract class GeoConverters {
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@Override
public Point convert(DBObject source) {
public Point convert(Document source) {
if (source == null) {
return null;
}
Assert.isTrue(source.keySet().size() == 2, "Source must contain 2 elements");
return source == null ? null : new Point((Double) source.get("x"), (Double) source.get("y"));
if (source.containsKey("type")) {
return DocumentToGeoJsonPointConverter.INSTANCE.convert(source);
}
return new Point((Double) source.get("x"), (Double) source.get("y"));
}
}
@@ -123,7 +130,7 @@ abstract class GeoConverters {
* @author Thomas Darimont
* @since 1.5
*/
static enum PointToDbObjectConverter implements Converter<Point, DBObject> {
static enum PointToDocumentConverter implements Converter<Point, Document> {
INSTANCE;
@@ -132,8 +139,8 @@ abstract class GeoConverters {
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@Override
public DBObject convert(Point source) {
return source == null ? null : new BasicDBObject("x", source.getX()).append("y", source.getY());
public Document convert(Point source) {
return source == null ? null : new Document("x", source.getX()).append("y", source.getY());
}
}
@@ -144,7 +151,7 @@ abstract class GeoConverters {
* @since 1.5
*/
@WritingConverter
static enum BoxToDbObjectConverter implements Converter<Box, DBObject> {
static enum BoxToDocumentConverter implements Converter<Box, Document> {
INSTANCE;
@@ -153,15 +160,15 @@ abstract class GeoConverters {
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@Override
public DBObject convert(Box source) {
public Document convert(Box source) {
if (source == null) {
return null;
}
BasicDBObject result = new BasicDBObject();
result.put("first", PointToDbObjectConverter.INSTANCE.convert(source.getFirst()));
result.put("second", PointToDbObjectConverter.INSTANCE.convert(source.getSecond()));
Document result = new Document();
result.put("first", PointToDocumentConverter.INSTANCE.convert(source.getFirst()));
result.put("second", PointToDocumentConverter.INSTANCE.convert(source.getSecond()));
return result;
}
}
@@ -173,7 +180,7 @@ abstract class GeoConverters {
* @since 1.5
*/
@ReadingConverter
static enum DbObjectToBoxConverter implements Converter<DBObject, Box> {
static enum DocumentToBoxConverter implements Converter<Document, Box> {
INSTANCE;
@@ -182,14 +189,14 @@ abstract class GeoConverters {
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@Override
public Box convert(DBObject source) {
public Box convert(Document source) {
if (source == null) {
return null;
}
Point first = DbObjectToPointConverter.INSTANCE.convert((DBObject) source.get("first"));
Point second = DbObjectToPointConverter.INSTANCE.convert((DBObject) source.get("second"));
Point first = DocumentToPointConverter.INSTANCE.convert((Document) source.get("first"));
Point second = DocumentToPointConverter.INSTANCE.convert((Document) source.get("second"));
return new Box(first, second);
}
@@ -201,7 +208,7 @@ abstract class GeoConverters {
* @author Thomas Darimont
* @since 1.5
*/
static enum CircleToDbObjectConverter implements Converter<Circle, DBObject> {
static enum CircleToDocumentConverter implements Converter<Circle, Document> {
INSTANCE;
@@ -210,14 +217,14 @@ abstract class GeoConverters {
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@Override
public DBObject convert(Circle source) {
public Document convert(Circle source) {
if (source == null) {
return null;
}
DBObject result = new BasicDBObject();
result.put("center", PointToDbObjectConverter.INSTANCE.convert(source.getCenter()));
Document result = new Document();
result.put("center", PointToDocumentConverter.INSTANCE.convert(source.getCenter()));
result.put("radius", source.getRadius().getNormalizedValue());
result.put("metric", source.getRadius().getMetric().toString());
return result;
@@ -225,13 +232,13 @@ abstract class GeoConverters {
}
/**
* Converts a {@link DBObject} into a {@link Circle}.
* Converts a {@link Document} into a {@link Circle}.
*
* @author Thomas Darimont
* @since 1.5
*/
@ReadingConverter
static enum DbObjectToCircleConverter implements Converter<DBObject, Circle> {
static enum DocumentToCircleConverter implements Converter<Document, Circle> {
INSTANCE;
@@ -240,18 +247,18 @@ abstract class GeoConverters {
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@Override
public Circle convert(DBObject source) {
public Circle convert(Document source) {
if (source == null) {
return null;
}
DBObject center = (DBObject) source.get("center");
Document center = (Document) source.get("center");
Double radius = (Double) source.get("radius");
Distance distance = new Distance(radius);
if (source.containsField("metric")) {
if (source.containsKey("metric")) {
String metricString = (String) source.get("metric");
Assert.notNull(metricString, "Metric must not be null!");
@@ -262,7 +269,7 @@ abstract class GeoConverters {
Assert.notNull(center, "Center must not be null!");
Assert.notNull(radius, "Radius must not be null!");
return new Circle(DbObjectToPointConverter.INSTANCE.convert(center), distance);
return new Circle(DocumentToPointConverter.INSTANCE.convert(center), distance);
}
}
@@ -272,7 +279,7 @@ abstract class GeoConverters {
* @author Thomas Darimont
* @since 1.5
*/
static enum SphereToDbObjectConverter implements Converter<Sphere, DBObject> {
static enum SphereToDocumentConverter implements Converter<Sphere, Document> {
INSTANCE;
@@ -281,14 +288,14 @@ abstract class GeoConverters {
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@Override
public DBObject convert(Sphere source) {
public Document convert(Sphere source) {
if (source == null) {
return null;
}
DBObject result = new BasicDBObject();
result.put("center", PointToDbObjectConverter.INSTANCE.convert(source.getCenter()));
Document result = new Document();
result.put("center", PointToDocumentConverter.INSTANCE.convert(source.getCenter()));
result.put("radius", source.getRadius().getNormalizedValue());
result.put("metric", source.getRadius().getMetric().toString());
return result;
@@ -302,7 +309,7 @@ abstract class GeoConverters {
* @since 1.5
*/
@ReadingConverter
static enum DbObjectToSphereConverter implements Converter<DBObject, Sphere> {
static enum DocumentToSphereConverter implements Converter<Document, Sphere> {
INSTANCE;
@@ -311,18 +318,18 @@ abstract class GeoConverters {
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@Override
public Sphere convert(DBObject source) {
public Sphere convert(Document source) {
if (source == null) {
return null;
}
DBObject center = (DBObject) source.get("center");
Document center = (Document) source.get("center");
Double radius = (Double) source.get("radius");
Distance distance = new Distance(radius);
if (source.containsField("metric")) {
if (source.containsKey("metric")) {
String metricString = (String) source.get("metric");
Assert.notNull(metricString, "Metric must not be null!");
@@ -333,7 +340,7 @@ abstract class GeoConverters {
Assert.notNull(center, "Center must not be null!");
Assert.notNull(radius, "Radius must not be null!");
return new Sphere(DbObjectToPointConverter.INSTANCE.convert(center), distance);
return new Sphere(DocumentToPointConverter.INSTANCE.convert(center), distance);
}
}
@@ -343,7 +350,7 @@ abstract class GeoConverters {
* @author Thomas Darimont
* @since 1.5
*/
static enum PolygonToDbObjectConverter implements Converter<Polygon, DBObject> {
static enum PolygonToDocumentConverter implements Converter<Polygon, Document> {
INSTANCE;
@@ -352,20 +359,20 @@ abstract class GeoConverters {
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@Override
public DBObject convert(Polygon source) {
public Document convert(Polygon source) {
if (source == null) {
return null;
}
List<Point> points = source.getPoints();
List<DBObject> pointTuples = new ArrayList<DBObject>(points.size());
List<Document> pointTuples = new ArrayList<Document>(points.size());
for (Point point : points) {
pointTuples.add(PointToDbObjectConverter.INSTANCE.convert(point));
pointTuples.add(PointToDocumentConverter.INSTANCE.convert(point));
}
DBObject result = new BasicDBObject();
Document result = new Document();
result.put("points", pointTuples);
return result;
}
@@ -378,7 +385,7 @@ abstract class GeoConverters {
* @since 1.5
*/
@ReadingConverter
static enum DbObjectToPolygonConverter implements Converter<DBObject, Polygon> {
static enum DocumentToPolygonConverter implements Converter<Document, Polygon> {
INSTANCE;
@@ -388,19 +395,19 @@ abstract class GeoConverters {
*/
@Override
@SuppressWarnings({ "unchecked" })
public Polygon convert(DBObject source) {
public Polygon convert(Document source) {
if (source == null) {
return null;
}
List<DBObject> points = (List<DBObject>) source.get("points");
List<Document> points = (List<Document>) source.get("points");
List<Point> newPoints = new ArrayList<Point>(points.size());
for (DBObject element : points) {
for (Document element : points) {
Assert.notNull(element, "Point elements of polygon must not be null!");
newPoints.add(DbObjectToPointConverter.INSTANCE.convert(element));
newPoints.add(DocumentToPointConverter.INSTANCE.convert(element));
}
return new Polygon(newPoints);
@@ -413,7 +420,7 @@ abstract class GeoConverters {
* @author Thomas Darimont
* @since 1.5
*/
static enum GeoCommandToDbObjectConverter implements Converter<GeoCommand, DBObject> {
static enum GeoCommandToDocumentConverter implements Converter<GeoCommand, Document> {
INSTANCE;
@@ -423,18 +430,18 @@ abstract class GeoConverters {
*/
@Override
@SuppressWarnings("rawtypes")
public DBObject convert(GeoCommand source) {
public Document convert(GeoCommand source) {
if (source == null) {
return null;
}
BasicDBList argument = new BasicDBList();
List argument = new ArrayList();
Shape shape = source.getShape();
if (shape instanceof GeoJson) {
return GeoJsonToDbObjectConverter.INSTANCE.convert((GeoJson) shape);
return GeoJsonToDocumentConverter.INSTANCE.convert((GeoJson) shape);
}
if (shape instanceof Box) {
@@ -464,7 +471,7 @@ abstract class GeoConverters {
argument.add(((Sphere) shape).getRadius().getNormalizedValue());
}
return new BasicDBObject(source.getCommand(), argument);
return new Document(source.getCommand(), argument);
}
}
@@ -473,7 +480,7 @@ abstract class GeoConverters {
* @since 1.7
*/
@SuppressWarnings("rawtypes")
static enum GeoJsonToDbObjectConverter implements Converter<GeoJson, DBObject> {
static enum GeoJsonToDocumentConverter implements Converter<GeoJson, Document> {
INSTANCE;
@@ -482,17 +489,17 @@ abstract class GeoConverters {
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@Override
public DBObject convert(GeoJson source) {
public Document convert(GeoJson source) {
if (source == null) {
return null;
}
DBObject dbo = new BasicDBObject("type", source.getType());
Document dbo = new Document("type", source.getType());
if (source instanceof GeoJsonGeometryCollection) {
BasicDBList dbl = new BasicDBList();
List dbl = new ArrayList();
for (GeoJson geometry : ((GeoJsonGeometryCollection) source).getCoordinates()) {
dbl.add(convert(geometry));
@@ -515,7 +522,7 @@ abstract class GeoConverters {
if (candidate instanceof Iterable) {
BasicDBList dbl = new BasicDBList();
List dbl = new ArrayList();
for (Object element : (Iterable) candidate) {
dbl.add(convertIfNecessarry(element));
@@ -536,7 +543,7 @@ abstract class GeoConverters {
* @author Christoph Strobl
* @since 1.7
*/
static enum GeoJsonPointToDbObjectConverter implements Converter<GeoJsonPoint, DBObject> {
static enum GeoJsonPointToDocumentConverter implements Converter<GeoJsonPoint, Document> {
INSTANCE;
@@ -545,8 +552,8 @@ abstract class GeoConverters {
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@Override
public DBObject convert(GeoJsonPoint source) {
return GeoJsonToDbObjectConverter.INSTANCE.convert(source);
public Document convert(GeoJsonPoint source) {
return GeoJsonToDocumentConverter.INSTANCE.convert(source);
}
}
@@ -554,7 +561,7 @@ abstract class GeoConverters {
* @author Christoph Strobl
* @since 1.7
*/
static enum GeoJsonPolygonToDbObjectConverter implements Converter<GeoJsonPolygon, DBObject> {
static enum GeoJsonPolygonToDocumentConverter implements Converter<GeoJsonPolygon, Document> {
INSTANCE;
@@ -563,8 +570,8 @@ abstract class GeoConverters {
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@Override
public DBObject convert(GeoJsonPolygon source) {
return GeoJsonToDbObjectConverter.INSTANCE.convert(source);
public Document convert(GeoJsonPolygon source) {
return GeoJsonToDocumentConverter.INSTANCE.convert(source);
}
}
@@ -572,7 +579,7 @@ abstract class GeoConverters {
* @author Christoph Strobl
* @since 1.7
*/
static enum DbObjectToGeoJsonPointConverter implements Converter<DBObject, GeoJsonPoint> {
static enum DocumentToGeoJsonPointConverter implements Converter<Document, GeoJsonPoint> {
INSTANCE;
@@ -582,7 +589,7 @@ abstract class GeoConverters {
*/
@Override
@SuppressWarnings("unchecked")
public GeoJsonPoint convert(DBObject source) {
public GeoJsonPoint convert(Document source) {
if (source == null) {
return null;
@@ -591,7 +598,7 @@ abstract class GeoConverters {
Assert.isTrue(ObjectUtils.nullSafeEquals(source.get("type"), "Point"),
String.format("Cannot convert type '%s' to Point.", source.get("type")));
List<Double> dbl = (List<Double>) source.get("coordinates");
List<Number> dbl = (List<Number>) source.get("coordinates");
return new GeoJsonPoint(dbl.get(0).doubleValue(), dbl.get(1).doubleValue());
}
}
@@ -600,7 +607,7 @@ abstract class GeoConverters {
* @author Christoph Strobl
* @since 1.7
*/
static enum DbObjectToGeoJsonPolygonConverter implements Converter<DBObject, GeoJsonPolygon> {
static enum DocumentToGeoJsonPolygonConverter implements Converter<Document, GeoJsonPolygon> {
INSTANCE;
@@ -609,7 +616,7 @@ abstract class GeoConverters {
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@Override
public GeoJsonPolygon convert(DBObject source) {
public GeoJsonPolygon convert(Document source) {
if (source == null) {
return null;
@@ -618,7 +625,7 @@ abstract class GeoConverters {
Assert.isTrue(ObjectUtils.nullSafeEquals(source.get("type"), "Polygon"),
String.format("Cannot convert type '%s' to Polygon.", source.get("type")));
return toGeoJsonPolygon((BasicDBList) source.get("coordinates"));
return toGeoJsonPolygon((List) source.get("coordinates"));
}
}
@@ -626,7 +633,7 @@ abstract class GeoConverters {
* @author Christoph Strobl
* @since 1.7
*/
static enum DbObjectToGeoJsonMultiPolygonConverter implements Converter<DBObject, GeoJsonMultiPolygon> {
static enum DocumentToGeoJsonMultiPolygonConverter implements Converter<Document, GeoJsonMultiPolygon> {
INSTANCE;
@@ -635,7 +642,7 @@ abstract class GeoConverters {
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@Override
public GeoJsonMultiPolygon convert(DBObject source) {
public GeoJsonMultiPolygon convert(Document source) {
if (source == null) {
return null;
@@ -644,11 +651,11 @@ abstract class GeoConverters {
Assert.isTrue(ObjectUtils.nullSafeEquals(source.get("type"), "MultiPolygon"),
String.format("Cannot convert type '%s' to MultiPolygon.", source.get("type")));
BasicDBList dbl = (BasicDBList) source.get("coordinates");
List dbl = (List) source.get("coordinates");
List<GeoJsonPolygon> polygones = new ArrayList<GeoJsonPolygon>();
for (Object polygon : dbl) {
polygones.add(toGeoJsonPolygon((BasicDBList) polygon));
polygones.add(toGeoJsonPolygon((List) polygon));
}
return new GeoJsonMultiPolygon(polygones);
@@ -659,7 +666,7 @@ abstract class GeoConverters {
* @author Christoph Strobl
* @since 1.7
*/
static enum DbObjectToGeoJsonLineStringConverter implements Converter<DBObject, GeoJsonLineString> {
static enum DocumentToGeoJsonLineStringConverter implements Converter<Document, GeoJsonLineString> {
INSTANCE;
@@ -668,7 +675,7 @@ abstract class GeoConverters {
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@Override
public GeoJsonLineString convert(DBObject source) {
public GeoJsonLineString convert(Document source) {
if (source == null) {
return null;
@@ -677,7 +684,7 @@ abstract class GeoConverters {
Assert.isTrue(ObjectUtils.nullSafeEquals(source.get("type"), "LineString"),
String.format("Cannot convert type '%s' to LineString.", source.get("type")));
BasicDBList cords = (BasicDBList) source.get("coordinates");
List cords = (List) source.get("coordinates");
return new GeoJsonLineString(toListOfPoint(cords));
}
@@ -687,7 +694,7 @@ abstract class GeoConverters {
* @author Christoph Strobl
* @since 1.7
*/
static enum DbObjectToGeoJsonMultiPointConverter implements Converter<DBObject, GeoJsonMultiPoint> {
static enum DocumentToGeoJsonMultiPointConverter implements Converter<Document, GeoJsonMultiPoint> {
INSTANCE;
@@ -696,7 +703,7 @@ abstract class GeoConverters {
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@Override
public GeoJsonMultiPoint convert(DBObject source) {
public GeoJsonMultiPoint convert(Document source) {
if (source == null) {
return null;
@@ -705,7 +712,7 @@ abstract class GeoConverters {
Assert.isTrue(ObjectUtils.nullSafeEquals(source.get("type"), "MultiPoint"),
String.format("Cannot convert type '%s' to MultiPoint.", source.get("type")));
BasicDBList cords = (BasicDBList) source.get("coordinates");
List cords = (List) source.get("coordinates");
return new GeoJsonMultiPoint(toListOfPoint(cords));
}
@@ -715,7 +722,7 @@ abstract class GeoConverters {
* @author Christoph Strobl
* @since 1.7
*/
static enum DbObjectToGeoJsonMultiLineStringConverter implements Converter<DBObject, GeoJsonMultiLineString> {
static enum DocumentToGeoJsonMultiLineStringConverter implements Converter<Document, GeoJsonMultiLineString> {
INSTANCE;
@@ -724,7 +731,7 @@ abstract class GeoConverters {
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@Override
public GeoJsonMultiLineString convert(DBObject source) {
public GeoJsonMultiLineString convert(Document source) {
if (source == null) {
return null;
@@ -734,10 +741,10 @@ abstract class GeoConverters {
String.format("Cannot convert type '%s' to MultiLineString.", source.get("type")));
List<GeoJsonLineString> lines = new ArrayList<GeoJsonLineString>();
BasicDBList cords = (BasicDBList) source.get("coordinates");
List cords = (List) source.get("coordinates");
for (Object line : cords) {
lines.add(new GeoJsonLineString(toListOfPoint((BasicDBList) line)));
lines.add(new GeoJsonLineString(toListOfPoint((List) line)));
}
return new GeoJsonMultiLineString(lines);
}
@@ -747,7 +754,7 @@ abstract class GeoConverters {
* @author Christoph Strobl
* @since 1.7
*/
static enum DbObjectToGeoJsonGeometryCollectionConverter implements Converter<DBObject, GeoJsonGeometryCollection> {
static enum DocumentToGeoJsonGeometryCollectionConverter implements Converter<Document, GeoJsonGeometryCollection> {
INSTANCE;
@@ -757,7 +764,7 @@ abstract class GeoConverters {
*/
@SuppressWarnings("rawtypes")
@Override
public GeoJsonGeometryCollection convert(DBObject source) {
public GeoJsonGeometryCollection convert(Document source) {
if (source == null) {
return null;
@@ -768,36 +775,36 @@ abstract class GeoConverters {
List<GeoJson<?>> geometries = new ArrayList<GeoJson<?>>();
for (Object o : (List) source.get("geometries")) {
geometries.add(convertGeometries((DBObject) o));
geometries.add(convertGeometries((Document) o));
}
return new GeoJsonGeometryCollection(geometries);
}
private static GeoJson<?> convertGeometries(DBObject source) {
private static GeoJson<?> convertGeometries(Document source) {
Object type = source.get("type");
if (ObjectUtils.nullSafeEquals(type, "Point")) {
return DbObjectToGeoJsonPointConverter.INSTANCE.convert(source);
return DocumentToGeoJsonPointConverter.INSTANCE.convert(source);
}
if (ObjectUtils.nullSafeEquals(type, "MultiPoint")) {
return DbObjectToGeoJsonMultiPointConverter.INSTANCE.convert(source);
return DocumentToGeoJsonMultiPointConverter.INSTANCE.convert(source);
}
if (ObjectUtils.nullSafeEquals(type, "LineString")) {
return DbObjectToGeoJsonLineStringConverter.INSTANCE.convert(source);
return DocumentToGeoJsonLineStringConverter.INSTANCE.convert(source);
}
if (ObjectUtils.nullSafeEquals(type, "MultiLineString")) {
return DbObjectToGeoJsonMultiLineStringConverter.INSTANCE.convert(source);
return DocumentToGeoJsonMultiLineStringConverter.INSTANCE.convert(source);
}
if (ObjectUtils.nullSafeEquals(type, "Polygon")) {
return DbObjectToGeoJsonPolygonConverter.INSTANCE.convert(source);
return DocumentToGeoJsonPolygonConverter.INSTANCE.convert(source);
}
if (ObjectUtils.nullSafeEquals(type, "MultiPolygon")) {
return DbObjectToGeoJsonMultiPolygonConverter.INSTANCE.convert(source);
return DocumentToGeoJsonMultiPolygonConverter.INSTANCE.convert(source);
}
throw new IllegalArgumentException(String.format("Cannot convert unknown GeoJson type %s", type));
@@ -816,7 +823,7 @@ abstract class GeoConverters {
* @since 1.7
*/
@SuppressWarnings("unchecked")
static List<Point> toListOfPoint(BasicDBList listOfCoordinatePairs) {
static List<Point> toListOfPoint(List listOfCoordinatePairs) {
List<Point> points = new ArrayList<Point>();
@@ -824,7 +831,7 @@ abstract class GeoConverters {
Assert.isInstanceOf(List.class, point);
List<Double> coordinatesList = (List<Double>) point;
List<Number> coordinatesList = (List<Number>) point;
points.add(new GeoJsonPoint(coordinatesList.get(0).doubleValue(), coordinatesList.get(1).doubleValue()));
}
@@ -838,7 +845,7 @@ abstract class GeoConverters {
* @return
* @since 1.7
*/
static GeoJsonPolygon toGeoJsonPolygon(BasicDBList dbList) {
return new GeoJsonPolygon(toListOfPoint((BasicDBList) dbList.get(0)));
static GeoJsonPolygon toGeoJsonPolygon(List dbList) {
return new GeoJsonPolygon(toListOfPoint((List) dbList.get(0)));
}
}

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