Compare commits

..

106 Commits

Author SHA1 Message Date
Thomas Risberg
00bea23eed preparing for 1.0.0.M4 MongoDB release 2011-09-01 20:32:10 -04:00
Thomas Risberg
c646c1f3b2 Updated changelog for 1.0.0.M4 MongoDB 2011-09-01 20:23:48 -04:00
Thomas Risberg
069f491603 DATADOC-232 added unit tests for multi set and inc updates 2011-09-01 18:56:16 -04:00
Thomas Risberg
e426ba4d43 DATADOC-210 removed Java 6 only method to provide Java 5 compatibility 2011-09-01 18:56:16 -04:00
Mark Pollack
756f886cef DATADOC-7 - Support for map-reduce operations in MongoTemplate 2011-09-01 18:03:32 -04:00
Thomas Risberg
9bb42245bb changed the test for index names since they don't seem to be consistent 2011-09-01 17:52:21 -04:00
Thomas Risberg
c15263a259 updated .gitignore 2011-09-01 17:51:46 -04:00
Mark Pollack
758ee97a8d DATADOC-7 - Support for map-reduce operations in MongoTemplate 2011-09-01 16:34:52 -04:00
Mark Pollack
4f92690f58 DATADOC-255 - Add to MongoOperations and executeCommand with an additional integer options argument
DATADOC-256 - Update to use MongoDB driver version 2.6.5
DATADOC-7 - Support for map-reduce operations in MongoTemplate
2011-09-01 15:33:55 -04:00
Mark Pollack
595ed69820 DATADOC-255 - Add to MongoOperations and executeCommand with an additional integer options argument
DATADOC-256 - Update to use MongoDB driver version 2.6.5
DATADOC-7 - Support for map-reduce operations in MongoTemplate
2011-09-01 15:33:13 -04:00
Oliver Gierke
48bf08afa3 DATADOC-68 - Updated documentation regading geoNear usage with MongoOperations. 2011-09-01 17:32:27 +02:00
Mark Pollack
98bdae4a00 DATADOC-7 (Add initial options class for Map reduce) 2011-09-01 11:19:54 -04:00
Mark Pollack
f08b87d8d6 DATADOC-7 (Add initial options class for Map reduce) 2011-09-01 10:35:12 -04:00
Oliver Gierke
6c3ffeac5f Merge branch 'geo-repo'
* geo-repo:
  DATADOC-68 - Support for geo-near queries at repositories.
2011-09-01 00:33:38 +02:00
Oliver Gierke
490ddc4a0e DATADOC-254 - Reject invalid MongoDB database names.
Only letters, numbers underscores and dashes are now allowed.
2011-09-01 00:29:55 +02:00
Oliver Gierke
ae26f4fea1 DATADOC-68 - Support for geo-near queries at repositories. 2011-09-01 00:28:48 +02:00
Oliver Gierke
e9ea756a3a DATADOC-253 - Upgraded to Spring 3.0.6. 2011-08-31 20:32:30 +02:00
Oliver Gierke
c4c95813b7 DATADOC-199 - Added caching for MongoPersistentProperty.isIdProperty and ….getFieldName.
Continuous field and annotation lookups in those methods have turned out to be some hotspots in performance tests. Added a CachingMongoPersistentProperty that delegates to the actual implementation once and caching it.
2011-08-31 19:41:04 +02:00
Mark Pollack
bfeb1b34c1 DATADOC-170 - Streamlined AbstractMongoEventListener (fix test) 2011-08-30 10:30:23 -04:00
Oliver Gierke
44def7dddb DATADOC-170 - Streamlined AbstractMongoEventListener.
Renamed Abstract{Mapping => Mongo}EventListener. Removed generic typing for the MongoMappingEvent and stick to domain type generification only.
2011-08-29 23:04:43 +02:00
Mark Pollack
df10bb2168 DATADOC-202 - Add a 'DocumentCallbackHandler' so that a callback can process each DBObject returned from a query (cherry-picking from commit 2ddc77c25e09a81ee61b3931337b35ae9a67b6e5) 2011-08-29 14:48:35 -04:00
Mark Pollack
f98607f5dc Add integration tests for mapping events 2011-08-29 11:46:05 -04:00
Oliver Gierke
da23133327 Yet another round of formatting.
Added Eclipse formatter settings.
2011-08-26 20:26:06 +02:00
Oliver Gierke
ce5046c35f DATADOC-63 - Added TypeMapper abstraction to customize how type information is written to a DBObject and retrieved from it.
Added TypeMapper abstraction to allow plugging in a custom implementation. Current type handling logic is now in DefaultTypeMapper which additionally allows customizing the key the type information its stored under or disabling writing type info by setting the key to null.

Added ConfigurableTypeMapper implementation that gets a Map configured to define Strings to be used to store type information.
2011-08-26 20:20:38 +02:00
Oliver Gierke
95245015bc DATADOC-245 - Default to custom target type if raw type is null.
Really only use the custom target type in case it is a real subtype of the basic one. Before that we used the plain custom one which was is lacking generics information potentially available in the basic one.
2011-08-26 13:44:47 +02:00
Oliver Gierke
fc40e6b08c DATADOC-243 - Allow db-factory-ref attribute for converter-element. 2011-08-24 16:51:56 +02:00
Oliver Gierke
eac5cb8c46 DATADOC-247 - BigInteger ids handled properly in QueryMapper.
QueryMapper now tries to convert given ids to ObjectId and String.
2011-08-24 16:31:18 +02:00
Oliver Gierke
54377031bb DATADOC-216 - Added ability to configure a WriteConcern on DB level.
Added WriteConcern property to MongoDbFactory and expose it through the db-factory namespace element.
2011-08-24 09:16:06 +02:00
Oliver Gierke
213963f2ff DATADOC-215 - Allow configuring a WriteConcern per MongoFactoryBean.
Added ability to configure a WriteConcern for an entire MongoFactoryBean and exposed the attribute via the namespace.
2011-08-23 20:47:19 +02:00
Oliver Gierke
0fb21aa2a1 DATADOC-248 - Customized MappingMongoEntityInformation to allow taking a custom collection.
In case a repository query method returns a domain type not assignable to the repository domain type we have to use the repositories domain type to determine the collection but still use the returned domain type to hand to the unmarshalling. Thus, we need to set up a custom MongoEntityInformation to reflect this scenario.

Extended MappingMongoEntityInformation to allow manually defining a custom collection name. EntityInformationCreator was extended accordingly and MongoQueryMethod now sets up the EntityInformation accordingly.
2011-08-23 13:42:32 +02:00
Oliver Gierke
e0da98ec51 DATADOC-217 - Consolidated collection handling when reading.
Extracted readCollectionOrArray(…) method and make sure it's used everywhere a Collection has to be read. Test cases now checks that empty collections are correctly read when using @PersistenceConstructor as well.
2011-08-22 18:15:22 +02:00
Oliver Gierke
7610246a1d Fixed GeoResultsUnitTests. 2011-08-22 17:37:37 +02:00
Oliver Gierke
ce59d893ba DATACMNS-61 - Adapted changes in Spring Data Commons.
Use QueryMethod accessor methods instead of dropped Type enum to determine query execution. Added custom MongoParameters and MongoParameter to allow discovering a Distance parameter for repository queries which will transparently add a 'maxDistance' clause for *Near criterias in query methods. If the given Distance is equipped with a Metric we will rather use $nearSphere over $near.

Added asList() to Point class to circumvent bug in BasicBSONObject.equals(…) which breaks equals(…) comparisons of DBObjects in case they use arrays as values. See [0] for details. Adapted usage of Point objects to use asList() over asArray().

[0] https://jira.mongodb.org/browse/JAVA-416
2011-08-21 16:46:11 +02:00
Oliver Gierke
e130fb5a2d DATACMNS-61 - Adapted changes in Spring Data Commons.
Use QueryMethod accessor methods instead of dropped Type enum to determine query execution. Added custom MongoParameters and MongoParameter to allow discovering a Distance parameter for repository queries which will transparently add a 'maxDistance' clause for *Near criterias in query methods. If the given Distance is equipped with a Metric we will rather use $nearSphere over $near.

Added asList() to Point class to circumvent bug in BasicBSONObject.equals(…) which breaks equals(…) comparisons of DBObjects in case they use arrays as values. See [0] for details. Adapted usage of Point objects to use asList() over asArray().

[0] https://jira.mongodb.org/browse/JAVA-416
2011-08-21 15:18:36 +02:00
Oliver Gierke
fedcbdae4f DATADOC-68 - Added support for geoNear command.
Introduced GeoResult value object as well as NearQuery. NearQuery allows definition of an origin and distances. Introduced a Metric interface and Metrics enum to carry commonly used metrics like kilometers and miles to ease the handling in NearQueries. Introduced Distance value object to capture distances in Metrics.
2011-08-20 17:56:26 +02:00
Oliver Gierke
7cd020ffa7 Removed some compiler warnings. 2011-08-20 13:27:08 +02:00
Oliver Gierke
b01e1a994b DATADOC-245 - MappingMongoConverter now reads nested, untyped Maps correctly.
Added some defaulting code in MappingMongoConverter that converts DBObject instances into Maps in case the raw property type is Object (see getMoreConcreteTargetType()).
2011-08-19 22:43:26 +02:00
Oliver Gierke
dd02338b5e DATADOC-246 - Added DBRef to Mongo simple types.
General overhaul of default setup of custom Mongo simple types. MongoTemplate.doUpdate(…) transparently handles null queries now as well.
2011-08-19 21:28:25 +02:00
Oliver Gierke
7084839df1 DATADOC-194 - Use OSGi valid version loading a class. 2011-08-19 09:33:39 +02:00
Oliver Gierke
09aad4343f DATADOC-241 - Made readMap(…) protected to allow overriding.
Aligned method signatures for reading and writing for consistent parameter order.
2011-08-16 14:25:48 +02:00
Oliver Gierke
c6a97ef407 DATADOC-240, DATADOC-212 - Overhaul of MongoTemplate.doUpdate(…).
Replaced manual ID conversion with delegating to QueryMapper. Added ObjectId as Mongo native type to CustomConversions and added unit tests around its handling.
2011-08-16 13:03:52 +02:00
Oliver Gierke
ceac760d19 DATADOC-236 - MongoQueryCreator now regards the Sort object from the PartTree on query completion. 2011-08-16 10:40:44 +02:00
Oliver Gierke
244e9bc6d8 DATADOC-238 - Reverted change in test case that introduced side effects. 2011-08-16 10:30:50 +02:00
Oliver Gierke
2016aab969 DATADOC-235 - Arbitrary Map values are now converted correctly.
Map values are now handled correctly regardless of the actual Map value type declaration (can be Object in the most open case). We now handle collections as Map value types correctly. BasicDBList instances are now hinted to become Lists by default (if not typed to another collection type by the property). 

Reduced visibility of MappingMongoConverter.addCustomTypeKeyIfNecessary(…) and made createCollectionDBObject(…) safe against null values for the TypeInformation.
2011-08-15 20:54:16 +02:00
Oliver Gierke
35f180f999 DATADOC-238 - Fixed applying pagination for manually defined queries.
BasicQuery accidentally shadowed limit and skip fields of Query and introduced setters instead of builder style mutators. This caused the getters not returning the values set throughout the mutators which essentially turned off pagination for manually defined queries.

Removed the shadowing and created test case. Refactored constructors.
2011-08-15 19:59:08 +02:00
Oliver Gierke
ad8b6fccb4 DATADOC-237 - Index name considers field name if not configured explicitly. 2011-08-14 17:22:50 +02:00
Oliver Gierke
d237ee80c8 DATADOC-239 - Clarify documentation of passed in values for MongoReader. 2011-08-12 20:06:04 +02:00
Oliver Gierke
eb276841dd DATADOC-214 - Cleaned up MongoConverter interface and implementations.
Removed quite some obsolete methods from MongoConverter interface. Renamed maybeConvertObject(…) to convertToMongoType(…). Moved implementation of that method into MappingMongoConverter. Let the implementation transparently use custom Converters as well. Removed SimpleMongoConverter. Switched QueryMapper implementation from using a MongoConverter to use a ConversionService. Removed custom "maybe convert" logic from ConvertingParameterAccessor in favor of MongoWriter.convertToMongo(…).
2011-08-12 15:39:57 +02:00
Mark Pollack
1d51052ab1 Merge pull request #4 from georgecalm/master
DATADOC-231: setting optional deps in the manifest to make the bundle work in an OSGi server
2011-08-02 07:09:46 -07:00
Yuriy Nemtsov
58898e97c2 DATADOC-231 - Making mysema.query & collections15 deps optional in the manifest 2011-07-31 20:46:12 -04:00
Oliver Gierke
a5328da460 Added handling of BigInteger.
Added converter to handle BigInteger values. Adapted id handling to try converting and object to String before taking the id as is. Made custom converter implementations safe against invocations with null.
2011-07-28 13:29:32 +02:00
Oliver Gierke
fd7e41b753 DATADOC-228 - MappingMongoConverter now writes null for map values.
Fixes a NPE that one got when trying to persist a Map containing null as value for entries.
2011-07-28 11:17:47 +02:00
Oliver Gierke
f349f5ea10 DATADOC-226 - Added QuerydslRepositorySupport class to ease implementing repositories using Querydsl predicates. 2011-07-28 11:16:33 +02:00
Oliver Gierke
aa9d69d584 DATADOC-225 - BasicMongoPersistentEntity doesn't reject root entities without id anymore. 2011-07-27 09:55:56 +02:00
Oliver Gierke
764317635c Fixed annotation package pattern for APT processor. 2011-07-27 09:52:13 +02:00
Oliver Gierke
9ed5e6886c DATADOC-224 - Inspect value entity metadata in case it's a subtype of the declared property. 2011-07-26 23:35:05 +02:00
Oliver Gierke
94f36d27fc Upgraded Querydsl APT plugin to 1.0.2. 2011-07-26 21:22:11 +02:00
Oliver Gierke
a5fb4872b7 DATADOC-221 - Potentially convert values of maps on reading. 2011-07-26 21:13:51 +02:00
Oliver Gierke
2f577c9678 Updated Spring Data Commons dependency to 1.2.0.BUILD-SNAPSHOT. 2011-07-25 23:44:38 +02:00
Oliver Gierke
9bcd19866f DATADOC-211 - Guard potential NullPointerException in AbstractMongoConverter.maybeConvertObject(…).
Quickfix, will probably undergo a deeper cleanup as part of DATADOC-214.
2011-07-25 14:37:30 +02:00
Oliver Gierke
2af45518bd Formatting in MappingMongoConverter. 2011-07-22 17:53:04 +02:00
Oliver Gierke
e1daf36ed8 DATADOC-209 - MappingMongoConverter handles collections of enums correctly now. 2011-07-22 17:52:48 +02:00
Oliver Gierke
101064769c DATADOC-207 - Empty custom maps get read correctly.
Eagerly detect the map target type by using the TypeInformation instead of falling back to the raw Map interface.
2011-07-22 10:16:13 +02:00
Oliver Gierke
ac9c804aae DATADOC-206 - Upgraded to Querydsl 2.2.0. 2011-07-21 09:11:22 +02:00
Oliver Gierke
992f09d731 Removed unused imports, polished license headers and suppres some compiler warnings. 2011-07-21 09:07:49 +02:00
Oliver Gierke
4324ed8231 Javadoc cleanups and a few code cleanups. 2011-07-20 19:03:08 +02:00
Oliver Gierke
eebe973209 Added *.sonar4clipseExternals, .springBeans and *.orig to .gitignore.
Removed accidentally checked in .classpath.orig file.
2011-07-20 18:59:14 +02:00
Oliver Gierke
bb01cccac5 Updated architecture description to allow core package to have access to geo. 2011-07-20 18:51:35 +02:00
Oliver Gierke
2bdd49e3b7 Beautify upper version ranges in manifest. 2011-07-14 21:34:32 +02:00
Oliver Gierke
f424b7c760 DATADOC-166 - Check for null on removing objects. 2011-07-14 21:34:11 +02:00
Oliver Gierke
58b9db28a8 Polished Sonargraph architecture description. 2011-07-13 12:42:56 +02:00
Oliver Gierke
3e56210c78 Polished test cases a little. 2011-07-13 12:01:32 +02:00
Oliver Gierke
523612a3a9 DATADOC-175 - Broke up cyclic dependencies and added architecture management file.
Added initial architecture description for Sonargraph. Moved some types around and introduced core package to break up cyclic dependencies.
2011-07-13 11:57:38 +02:00
Jon Brisbin
1604c80d32 DATADOC-176 - Added test case to make sure non-ObjectIds can be used in DBRefs 2011-07-12 10:18:10 -05:00
Jon Brisbin
d27a1ad310 DATADOC-176 - Changed from using ObjectId to using Object for IDs in DBRefs. 2011-07-12 09:33:31 -05:00
Oliver Gierke
d2cca2c52a DATADOC-192 - Tweak Array handling in processing collection-like structures in MappingMongoConverter.
Fixes broken tests.
2011-07-08 13:22:48 +02:00
Oliver Gierke
ce0539a3dc DATADOC-192 - MappingMongoConverter handles collections correctly now.
Replaced hard coded List creation with delegate to Spring's CollectionFactory. Although the List should get converted before setting the value we can prevent that additional step by looking up the correct collection type upfront.
2011-07-08 13:04:25 +02:00
Oliver Gierke
4b4c35b904 DATADOC-191 - Removed 'document' from package names.
Polished template.mf as well by using Maven version placeholders.
2011-07-08 11:25:43 +02:00
Oliver Gierke
f0df16a340 Added more unit tests for Box. 2011-07-08 11:00:06 +02:00
Oliver Gierke
a9670de959 DATADOC-134 - Added test case to show indexes with unique flag work. 2011-07-08 10:23:45 +02:00
Oliver Gierke
2d5f41f65c DATADOC-171 - Convert BigDecimals to String by default.
Unfortunately MongoDB can't handle BigDecimal instances by default thus we have to provide a default serialization. We do by simply serializing it into a String and reading it back. Can be customized to register a custom Converter with the MongoConverter.
2011-07-07 21:35:54 +02:00
Oliver Gierke
2e3f2c602c Made integration test less aggressive in cleaning up to avoid inter-test collisions. 2011-07-07 19:52:16 +02:00
Oliver Gierke
a2687b6688 DATADOC-188 - Allow controlling repository index creation.
Disabled index creation for repository query methods by default. Added property on MongoRepositoryFactoryBean to enable index creation and expose that via 'create-query-indexes' attribute on the namespace.
2011-07-07 13:22:25 +02:00
Oliver Gierke
e89ea320bc Added @NoRepositoryBean to MongoRepository to prevent it being accidentally picked up during class path scanning. 2011-07-07 13:14:48 +02:00
Oliver Gierke
df24218a4f DATADOC-189 - Improved extensibility of MongoRepositoryFactoryBean.
Creation of MongoRepositoryFactory is now delegated into a template method that gets a MongoTemplate handed over.
2011-07-07 10:46:54 +02:00
Oliver Gierke
2d09b8b7d1 DATADOC-186 - Ensure index property order.
Use LinkedHashMap inside Index to make sure properties added are kept in the order of the addition.
2011-07-07 07:45:15 +02:00
Oliver Gierke
dd06973f50 DATADOC-190 - SimpleMongoRepository.exists(…) now works for entities with non-ObjectId id type.
Changed the implementation of the exists(…) method to make sure the query is handed to the QueryMapper to convert the id appropriately before executing the query.
2011-07-06 19:49:11 +02:00
Oliver Gierke
2256ebac1b DATADOC-172 - Allow defining property order for document mapping.
Entities can now use @Field annotation to define the order using the order attribute. We will simply start with the lower values and proceed to the higher ones. Unannotated properties are ordered behind all annotated (and order declared) ones. One might not assume any particular order for fields where the order is not manually defined.

Removed @FieldName as it is superseeded by @Field.
2011-07-06 19:09:24 +02:00
Oliver Gierke
f4373957b3 DATADOC-177 - Sort now preserves order of individual sort properties.
Using a LinkedHashMap now to preserve the order of properties to be sorted upon.
2011-07-06 15:39:22 +02:00
Thomas Risberg
af0cd9049a DATADOC-178 removed System.out.println statement 2011-06-24 12:45:17 -04:00
Thomas Risberg
99edcb82cf reformatted code to use tabs 2011-06-24 11:50:28 -04:00
Thomas Risberg
7a98877e75 DATADOC-181 added destroy() method and DisposableBean interface to call close on Mongo 2011-06-24 11:45:42 -04:00
Oliver Gierke
d856a7cad9 DATACMNS-49, DATADOC-100 - Allow externalizing Mongo repository queries.
Adapted changes in Spring Data Commons for DATACMNS-49. We now automatically pick up classpath*:META-INF/mongo-named-queries.properties to find named queries when using the namespace. See AbstractMongoRepositoryIntegrationTests.findsPeopleByNamedQuery() for sample.
2011-06-23 19:12:22 +02:00
Oliver Gierke
c1b396cca5 Replaced custom implementation over usage of TypeInformation.getActualType(). 2011-06-17 20:28:13 +02:00
Oliver Gierke
2e86012b3f Lowered log level to speed up test execution. 2011-06-13 20:25:36 -07:00
Oliver Gierke
538a62efce Adapted package refactorings in Spring Data Commons. 2011-06-13 20:25:15 -07:00
Oliver Gierke
3573851bfc Polishing.
Removed obsolete methods from MappingMongoConverter exposing internals. Added JavaDoc here and there. Polished GeospatialIndex value object and added some assertions to it. Fixed generics warnings in GeoIndexedAppConfig.
2011-06-13 14:53:07 -07:00
Oliver Gierke
e47ddf4bf2 Polished MonogoPersistentEntityIndexCreator.
Fixed generics warnings and the index key being set to the field name in any case now. setting the index name is now only affecting the name.
2011-06-13 13:25:06 -07:00
Oliver Gierke
c59711a409 Use findOne(…) for single entity queries inside repository abstraction. 2011-06-13 13:24:43 -07:00
Oliver Gierke
b1ab3f6ade DATADOC-162 - Added more test cases around Point class. 2011-06-13 09:53:11 -07:00
Thomas Risberg
fa094eef25 DATADOC-162 fixed formatting in toString method 2011-06-10 09:01:56 -04:00
Oliver Gierke
8ac2ff6b81 DATACMNS-169 - Revised custom converter handling.
Registering custom converts now automatically declares the custom handled types simple by using the SimpleTypeHolder built up by the CustomConversions instance. All the custom converter lookup logic is now in CustomConversions and AbstractMongoConverter uses that over handling it itself.
2011-06-09 16:35:04 -07:00
Oliver Gierke
46d6dffdd4 DATADOC-167 - @Documentation annotation is now inherited into subclasses 2011-06-07 11:42:53 -07:00
Oliver Gierke
06632cc3ae DATACMNS-42 - Fixed some bugs in nested collection handling. 2011-06-06 14:46:06 -07:00
Oliver Gierke
df0427442a DATACMNS-42 - Removed BigInteger as Mongo specific custom type as MappingBeanHelper covers Number implementations already. 2011-06-06 11:10:53 -07:00
Thomas Risberg
eb20aea7fe preparing for snapshot builds 2011-06-02 13:45:25 -04:00
319 changed files with 11569 additions and 5728 deletions

30
.gitignore vendored
View File

@@ -1,13 +1,17 @@
.DS_Store
*.iml
*.ipr
*.iws
target
.springBeans
.ant-targets-build.xml
.settings/
.project
.classpath
src/ant/.ant-targets-upload-dist.xml
atlassian-ide-plugin.xml
/.gradle/
.DS_Store
*.iml
*.ipr
*.iws
*.orig
target
.springBeans
.sonar4clipse
*.sonar4clipseExternals
.ant-targets-build.xml
.settings/
.project
.classpath
src/ant/.ant-targets-upload-dist.xml
atlassian-ide-plugin.xml
/.gradle/
/.idea/

View File

@@ -5,7 +5,7 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-document-dist</artifactId>
<name>Spring Data Document Distribution</name>
<version>1.0.0.M3</version>
<version>1.0.0.M4</version>
<packaging>pom</packaging>
<modules>
<module>spring-data-document-parent</module>

View File

@@ -6,7 +6,7 @@
<artifactId>spring-data-document-parent</artifactId>
<name>Spring Data Document Parent</name>
<url>http://www.springsource.org/spring-data/data-document</url>
<version>1.0.0.M3</version>
<version>1.0.0.M4</version>
<packaging>pom</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -16,8 +16,8 @@
<org.mockito.version>1.8.4</org.mockito.version>
<org.slf4j.version>1.5.10</org.slf4j.version>
<org.codehaus.jackson.version>1.6.1</org.codehaus.jackson.version>
<org.springframework.version>3.0.5.RELEASE</org.springframework.version>
<data.commons.version>1.1.0.M1</data.commons.version>
<org.springframework.version>3.0.6.RELEASE</org.springframework.version>
<data.commons.version>1.2.0.M1</data.commons.version>
<aspectj.version>1.6.11.RELEASE</aspectj.version>
</properties>
<profiles>

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-document-parent</artifactId>
<version>1.0.0.M3</version>
<version>1.0.0.M4</version>
<relativePath>../spring-data-document-parent/pom.xml</relativePath>
</parent>
<artifactId>spring-data-mongodb-cross-store</artifactId>

View File

@@ -11,8 +11,8 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.document.mongodb.CollectionCallback;
import org.springframework.data.document.mongodb.MongoTemplate;
import org.springframework.data.mongodb.core.CollectionCallback;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.persistence.ChangeSet;
import org.springframework.data.persistence.ChangeSetBacked;
import org.springframework.data.persistence.ChangeSetPersister;

View File

@@ -7,10 +7,10 @@ import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.document.mongodb.MongoTemplate;
import org.springframework.data.document.persistence.test.Address;
import org.springframework.data.document.persistence.test.Person;
import org.springframework.data.document.persistence.test.Resume;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

View File

@@ -4,7 +4,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.document.mongodb.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Document;
@Document
public class Resume {

View File

@@ -20,22 +20,22 @@
<mongo:mapping-converter/>
<!-- Mongo config -->
<bean id="mongo" class="org.springframework.data.document.mongodb.MongoFactoryBean">
<bean id="mongo" class="org.springframework.data.mongodb.core.MongoFactoryBean">
<property name="host" value="localhost"/>
<property name="port" value="27017"/>
</bean>
<bean id="mongoDbFactory" class="org.springframework.data.document.mongodb.SimpleMongoDbFactory">
<bean id="mongoDbFactory" class="org.springframework.data.mongodb.core.SimpleMongoDbFactory">
<constructor-arg name="mongo" ref="mongo"/>
<constructor-arg name="databaseName" value="database"/>
</bean>
<bean id="mongoTemplate" class="org.springframework.data.document.mongodb.MongoTemplate">
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
<constructor-arg name="mongoConverter" ref="mappingConverter"/>
</bean>
<bean class="org.springframework.data.document.mongodb.MongoExceptionTranslator"/>
<bean class="org.springframework.data.mongodb.core.MongoExceptionTranslator"/>
<!-- Mongo aspect config -->
<bean class="org.springframework.data.persistence.document.mongodb.MongoDocumentBacking"

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-document-parent</artifactId>
<version>1.0.0.M3</version>
<version>1.0.0.M4</version>
<relativePath>../spring-data-document-parent/pom.xml</relativePath>
</parent>
<artifactId>spring-data-mongodb-log4j</artifactId>

View File

@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry including="**/*.java" kind="src" output="target/classes" path="src/main/java"/>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
<classpathentry including="**/*.java" kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="src" output="target/test-classes" path="target/generated-sources/test-annotations"/>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="org.eclipse.jst.component.nondependency" value=""/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.module.container"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@@ -0,0 +1,116 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<context version="7.0.3.1152">
<scope name="spring-data-mongodb" type="Project">
<element name="Filter" type="TypeFilterReferenceOverridden">
<element name="org.springframework.data.mongodb.**" type="IncludeTypePattern"/>
</element>
<architecture>
<element name="Config" type="Layer">
<element name="Assignment" type="TypeFilter">
<element name="**.config.**" type="IncludeTypePattern"/>
</element>
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Core"/>
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Monitoring"/>
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Repositories"/>
</element>
<element name="Repositories" type="Layer">
<element name="Assignment" type="TypeFilter">
<element name="**.repository.**" type="IncludeTypePattern"/>
</element>
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Core"/>
</element>
<element name="Monitoring" type="Layer">
<element name="Assignment" type="TypeFilter">
<element name="**.monitor.**" type="IncludeTypePattern"/>
</element>
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Core"/>
</element>
<element name="Core" type="Layer">
<element name="Assignment" type="TypeFilter">
<element name="**.core.**" type="IncludeTypePattern"/>
</element>
<element name="Mapping" type="Subsystem">
<element name="Assignment" type="TypeFilter">
<element name="**.mapping.**" type="IncludeTypePattern"/>
</element>
</element>
<element name="Geospatial" type="Subsystem">
<element name="Assignment" type="TypeFilter">
<element name="**.geo.**" type="IncludeTypePattern"/>
</element>
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Mapping"/>
</element>
<element name="Query" type="Subsystem">
<element name="Assignment" type="TypeFilter">
<element name="**.query.**" type="IncludeTypePattern"/>
</element>
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Geospatial"/>
</element>
<element name="Index" type="Subsystem">
<element name="Assignment" type="TypeFilter">
<element name="**.index.**" type="IncludeTypePattern"/>
</element>
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Mapping"/>
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Query"/>
</element>
<element name="Core" type="Subsystem">
<element name="Assignment" type="TypeFilter">
<element name="**.core.**" type="WeakTypePattern"/>
</element>
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Geospatial"/>
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Index"/>
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Mapping"/>
<dependency type="AllowedDependency" toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Query"/>
</element>
</element>
</architecture>
<workspace>
<element name="src/main/java" type="JavaRootDirectory">
<reference name="Project|spring-data-mongodb::BuildUnit|spring-data-mongodb"/>
</element>
<element name="target/classes" type="JavaRootDirectory">
<reference name="Project|spring-data-mongodb::BuildUnit|spring-data-mongodb"/>
</element>
</workspace>
<physical>
<element name="spring-data-mongodb" type="BuildUnit"/>
</physical>
</scope>
<scope name="External" type="External">
<element name="Filter" type="TypeFilter">
<element name="**" type="IncludeTypePattern"/>
<element name="java.**" type="ExcludeTypePattern"/>
<element name="javax.**" type="ExcludeTypePattern"/>
</element>
<architecture>
<element name="Spring" type="Subsystem">
<element name="Assignment" type="TypeFilter">
<element name="org.springframework.**" type="IncludeTypePattern"/>
<element name="org.springframework.data.**" type="ExcludeTypePattern"/>
</element>
</element>
<element name="Spring Data Core" type="Subsystem">
<element name="Assignment" type="TypeFilter">
<element name="org.springframework.data.**" type="IncludeTypePattern"/>
</element>
</element>
<element name="Mongo Java Driver" type="Subsystem">
<element name="Assignment" type="TypeFilter">
<element name="com.mongodb.**" type="IncludeTypePattern"/>
<element name="org.bson.**" type="IncludeTypePattern"/>
</element>
</element>
<element name="Querydsl" type="Subsystem">
<element name="Assignment" type="TypeFilter">
<element name="com.mysema.query.**" type="IncludeTypePattern"/>
</element>
</element>
</architecture>
</scope>
<scope name="Global" type="Global">
<element name="Configuration" type="Configuration"/>
<element name="Filter" type="TypeFilter">
<element name="**" type="IncludeTypePattern"/>
</element>
</scope>
</context>

View File

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

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-document-parent</artifactId>
<version>1.0.0.M3</version>
<version>1.0.0.M4</version>
<relativePath>../spring-data-document-parent/pom.xml</relativePath>
</parent>
<artifactId>spring-data-mongodb</artifactId>
@@ -13,8 +13,8 @@
<name>Spring Data MongoDB Support</name>
<properties>
<mongo.version>2.5.3</mongo.version>
<querydsl.version>2.2.0-beta4</querydsl.version>
<mongo.version>2.6.5</mongo.version>
<querydsl.version>2.2.0</querydsl.version>
</properties>
<dependencies>
@@ -139,7 +139,7 @@
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>maven-apt-plugin</artifactId>
<version>1.0.1</version>
<version>1.0.2</version>
<executions>
<execution>
<phase>generate-test-sources</phase>
@@ -148,7 +148,7 @@
</goals>
<configuration>
<outputDirectory>target/generated-test-sources</outputDirectory>
<processor>org.springframework.data.document.mongodb.repository.MongoAnnotationProcessor</processor>
<processor>org.springframework.data.mongodb.repository.MongoAnnotationProcessor</processor>
</configuration>
</execution>
</executions>

View File

@@ -1,13 +0,0 @@
package org.springframework.data.document.mongodb;
import org.springframework.dao.DataAccessException;
import com.mongodb.DB;
public interface MongoDbFactory {
DB getDb() throws DataAccessException;
DB getDb(String dbName) throws DataAccessException;
}

View File

@@ -1,60 +0,0 @@
package org.springframework.data.document.mongodb;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.data.authentication.UserCredentials;
import org.springframework.util.Assert;
import com.mongodb.DB;
import com.mongodb.Mongo;
public class SimpleMongoDbFactory implements MongoDbFactory {
/**
* Logger, available to subclasses.
*/
protected final Log logger = LogFactory.getLog(getClass());
private Mongo mongo;
private String databaseName;
private String username;
private String password;
/**
* Create an instance of SimpleMongoDbFactory given the Mongo instance and database name
* @param mongo Mongo instance, not null
* @param databaseName Database name, not null
*/
public SimpleMongoDbFactory(Mongo mongo, String databaseName) {
Assert.notNull(mongo, "Mongo must not be null");
Assert.hasText(databaseName, "Database name must not be empty");
this.mongo = mongo;
this.databaseName = databaseName;
}
/**
* Create an instance of SimpleMongoDbFactory given the Mongo instance, database name, and username/password
* @param mongo Mongo instance, not null
* @param databaseName Database name, not null
* @param userCredentials username and password
*/
public SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials userCredentials) {
this(mongo, databaseName);
this.username = userCredentials.getUsername();
this.password = userCredentials.getPassword();
}
public DB getDb() throws DataAccessException {
Assert.notNull(mongo, "Mongo must not be null");
Assert.hasText(databaseName, "Database name must not be empty");
return MongoDbUtils.getDB(mongo, databaseName, username, password == null ? null : password.toCharArray());
}
public DB getDb(String dbName) throws DataAccessException {
Assert.notNull(mongo, "Mongo must not be null");
Assert.hasText(dbName, "Database name must not be empty");
return MongoDbUtils.getDB(mongo, dbName, username, password == null ? null : password.toCharArray());
}
}

View File

@@ -1,101 +0,0 @@
/*
* Copyright (c) 2011 by the original author(s).
*
* 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.document.mongodb.config;
import static org.springframework.data.document.mongodb.config.BeanNames.*;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.authentication.UserCredentials;
import org.springframework.data.document.mongodb.MongoFactoryBean;
import org.springframework.data.document.mongodb.SimpleMongoDbFactory;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
@Override
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) throws BeanDefinitionStoreException {
String id = element.getAttribute("id");
if (!StringUtils.hasText(id)) {
id = DB_FACTORY;
}
return id;
}
@Override
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
BeanDefinitionBuilder dbFactoryBuilder = BeanDefinitionBuilder.genericBeanDefinition(SimpleMongoDbFactory.class);
// UserCredentials
BeanDefinitionBuilder userCredentialsBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserCredentials.class);
String username = element.getAttribute("username");
if (StringUtils.hasText(username)) {
userCredentialsBuilder.addConstructorArgValue(username);
} else {
userCredentialsBuilder.addConstructorArgValue(null);
}
String password = element.getAttribute("password");
if (StringUtils.hasText(password)) {
userCredentialsBuilder.addConstructorArgValue(password);
} else {
userCredentialsBuilder.addConstructorArgValue(null);
}
// host and port
String host = element.getAttribute("host");
if (!StringUtils.hasText(host)) {
host = "localhost";
}
String port = element.getAttribute("port");
if (!StringUtils.hasText(port)) {
port = "27017";
}
// Database name
String dbname = element.getAttribute("dbname");
if (!StringUtils.hasText(dbname)) {
dbname = "db";
}
// com.mongodb.Mongo object
String mongoRef = element.getAttribute("mongo-ref");
if (!StringUtils.hasText(mongoRef)) {
//Create implicit com.mongodb.Mongo object and register under generated name
BeanDefinitionBuilder mongoBuilder = BeanDefinitionBuilder.genericBeanDefinition(MongoFactoryBean.class);
mongoBuilder.addPropertyValue("host", host);
mongoBuilder.addPropertyValue("port", port);
mongoRef = BeanDefinitionReaderUtils.registerWithGeneratedName(mongoBuilder.getBeanDefinition(), parserContext.getRegistry());
}
dbFactoryBuilder.addConstructorArgValue(new RuntimeBeanReference(mongoRef));
dbFactoryBuilder.addConstructorArgValue(dbname);
dbFactoryBuilder.addConstructorArgValue(userCredentialsBuilder.getBeanDefinition());
return dbFactoryBuilder.getRawBeanDefinition();
}
}

View File

@@ -1,97 +0,0 @@
/*
* Copyright (c) 2011 by the original author(s).
*
* 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.document.mongodb.config;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.document.mongodb.MongoOptionsFactoryBean;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
import com.mongodb.ServerAddress;
abstract class ParsingUtils {
/**
* Parses the mongo replica-set element.
* @param parserContext the parser context
* @param element the mongo element
* @param mongoBuilder the bean definition builder to populate
* @return true if parsing actually occured, false otherwise
*/
static boolean parseReplicaSet(ParserContext parserContext, Element element, BeanDefinitionBuilder mongoBuilder) {
String replicaSetString = element.getAttribute("replica-set");
if (StringUtils.hasText(replicaSetString)) {
ManagedList<Object> serverAddresses = new ManagedList<Object>();
String[] replicaSetStringArray = StringUtils.commaDelimitedListToStringArray(replicaSetString);
for (int i = 0; i < replicaSetStringArray.length; i++) {
String[] hostAndPort = StringUtils.delimitedListToStringArray(replicaSetStringArray[i], ":");
BeanDefinitionBuilder defBuilder = BeanDefinitionBuilder.genericBeanDefinition(ServerAddress.class);
defBuilder.addConstructorArgValue(hostAndPort[0]);
defBuilder.addConstructorArgValue(hostAndPort[1]);
serverAddresses.add(defBuilder.getBeanDefinition());
}
if (!serverAddresses.isEmpty()) {
mongoBuilder.addPropertyValue("replicaSetSeeds", serverAddresses);
}
}
return true;
}
/**
* Parses the mongo:options sub-element. Populates the given attribute factory with the proper attributes.
*
* @return true if parsing actually occured, false otherwise
*/
static boolean parseMongoOptions(ParserContext parserContext, Element element, BeanDefinitionBuilder mongoBuilder) {
Element optionsElement = DomUtils.getChildElementByTagName(element, "options");
if (optionsElement == null)
return false;
BeanDefinitionBuilder optionsDefBuilder = BeanDefinitionBuilder
.genericBeanDefinition(MongoOptionsFactoryBean.class);
setPropertyValue(optionsElement, optionsDefBuilder, "connections-per-host", "connectionsPerHost");
setPropertyValue(optionsElement, optionsDefBuilder, "threads-allowed-to-block-for-connection-multiplier",
"threadsAllowedToBlockForConnectionMultiplier");
setPropertyValue(optionsElement, optionsDefBuilder, "max-wait-time", "maxWaitTime");
setPropertyValue(optionsElement, optionsDefBuilder, "connect-timeout", "connectTimeout");
setPropertyValue(optionsElement, optionsDefBuilder, "socket-timeout", "socketTimeout");
setPropertyValue(optionsElement, optionsDefBuilder, "socket-keep-alive", "socketKeepAlive");
setPropertyValue(optionsElement, optionsDefBuilder, "auto-connect-retry", "autoConnectRetry");
setPropertyValue(optionsElement, optionsDefBuilder, "write-number", "writeNumber");
setPropertyValue(optionsElement, optionsDefBuilder, "write-timeout", "writeTimeout");
setPropertyValue(optionsElement, optionsDefBuilder, "write-fsync", "writeFsync");
setPropertyValue(optionsElement, optionsDefBuilder, "slave-ok", "slaveOk");
mongoBuilder.addPropertyValue("mongoOptions", optionsDefBuilder.getBeanDefinition());
return true;
}
static void setPropertyValue(Element element, BeanDefinitionBuilder builder, String attrName, String propertyName) {
String attr = element.getAttribute(attrName);
if (StringUtils.hasText(attr)) {
builder.addPropertyValue(propertyName, attr);
}
}
}

View File

@@ -1,258 +0,0 @@
/*
* Copyright (c) 2011 by the original author(s).
*
* 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.document.mongodb.convert;
import static org.springframework.data.mapping.MappingBeanHelper.isSimpleType;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.core.convert.converter.GenericConverter.ConvertiblePair;
import org.springframework.core.convert.support.ConversionServiceFactory;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.data.document.mongodb.convert.ObjectIdConverters.BigIntegerToObjectIdConverter;
import org.springframework.data.document.mongodb.convert.ObjectIdConverters.ObjectIdToBigIntegerConverter;
import org.springframework.data.document.mongodb.convert.ObjectIdConverters.ObjectIdToStringConverter;
import org.springframework.data.document.mongodb.convert.ObjectIdConverters.StringToObjectIdConverter;
import org.springframework.data.mapping.MappingBeanHelper;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
public abstract class AbstractMongoConverter implements MongoConverter, InitializingBean {
@SuppressWarnings({ "unchecked" })
private static final List<Class<?>> MONGO_TYPES = Arrays.asList(Number.class, Date.class, String.class,
DBObject.class);
protected final GenericConversionService conversionService;
private final Set<ConvertiblePair> customTypeMapping = new HashSet<ConvertiblePair>();
public AbstractMongoConverter(GenericConversionService conversionService) {
this.conversionService = conversionService == null ? ConversionServiceFactory.createDefaultConversionService()
: conversionService;
this.conversionService.removeConvertible(Object.class, String.class);
registerConverter(CustomToStringConverter.INSTANCE);
}
/**
* Add custom {@link Converter} or {@link ConverterFactory} instances to be used that will take presidence over
* metadata driven conversion between of objects to/from DBObject
*
* @param converters
*/
public void setCustomConverters(Set<?> converters) {
if (null != converters) {
for (Object c : converters) {
registerConverter(c);
}
}
}
/**
* Registers converters for {@link ObjectId} handling, removes plain {@link #toString()} converter and promotes the
* configured {@link ConversionService} to {@link MappingBeanHelper}.
*/
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);
}
if (!conversionService.canConvert(ObjectId.class, BigInteger.class)) {
conversionService.addConverter(ObjectIdToBigIntegerConverter.INSTANCE);
}
if (!conversionService.canConvert(BigInteger.class, ObjectId.class)) {
conversionService.addConverter(BigIntegerToObjectIdConverter.INSTANCE);
}
}
/**
* Inspects the given {@link Converter} for the types it can convert and registers the pair for custom type conversion
* in case the target type is a Mongo basic type.
*
* @param converter
*/
private void registerConverter(Object converter) {
if (converter instanceof GenericConverter) {
customTypeMapping.addAll(((GenericConverter) converter).getConvertibleTypes());
} else {
Class<?>[] arguments = GenericTypeResolver.resolveTypeArguments(converter.getClass(), Converter.class);
if (MONGO_TYPES.contains(arguments[1]) || MONGO_TYPES.contains(arguments[0])) {
customTypeMapping.add(new ConvertiblePair(arguments[0], arguments[1]));
}
}
boolean added = false;
if (converter instanceof Converter) {
this.conversionService.addConverter((Converter<?, ?>) converter);
added = true;
}
if (converter instanceof ConverterFactory) {
this.conversionService.addConverterFactory((ConverterFactory<?, ?>) converter);
added = true;
}
if (converter instanceof GenericConverter) {
this.conversionService.addConverter((GenericConverter) converter);
added = true;
}
if (!added) {
throw new IllegalArgumentException("Given set contains element that is neither Converter nor ConverterFactory!");
}
}
protected Class<?> getCustomTarget(Class<?> source, Class<?> expectedTargetType) {
for (ConvertiblePair typePair : customTypeMapping) {
if (typePair.getSourceType().isAssignableFrom(source)) {
Class<?> targetType = typePair.getTargetType();
if (targetType.equals(expectedTargetType) || expectedTargetType == null) {
return targetType;
}
}
}
return null;
}
/*
* (non-Javadoc)
* @see org.springframework.data.document.mongodb.convert.MongoConverter#getConversionService()
*/
public ConversionService getConversionService() {
return conversionService;
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() {
initializeConverters();
}
@SuppressWarnings("unchecked")
public Object maybeConvertObject(Object obj) {
if (obj instanceof Enum<?>) {
return ((Enum<?>) obj).name();
}
if (null != obj && isSimpleType(obj.getClass())) {
// Doesn't need conversion
return obj;
}
if (obj instanceof BasicDBList) {
return maybeConvertList((BasicDBList) obj);
}
if (obj instanceof DBObject) {
DBObject newValueDbo = new BasicDBObject();
for (String vk : ((DBObject) obj).keySet()) {
Object o = ((DBObject) obj).get(vk);
newValueDbo.put(vk, maybeConvertObject(o));
}
return newValueDbo;
}
if (obj instanceof Map) {
Map<Object, Object> m = new HashMap<Object, Object>();
for (Map.Entry<Object, Object> entry : ((Map<Object, Object>) obj).entrySet()) {
m.put(entry.getKey(), maybeConvertObject(entry.getValue()));
}
return m;
}
if (obj instanceof List) {
List<?> l = (List<?>) obj;
List<Object> newList = new ArrayList<Object>();
for (Object o : l) {
newList.add(maybeConvertObject(o));
}
return newList;
}
if (obj.getClass().isArray()) {
return maybeConvertArray((Object[]) obj);
}
DBObject newDbo = new BasicDBObject();
this.write(obj, newDbo);
return newDbo;
}
public Object[] maybeConvertArray(Object[] src) {
Object[] newArr = new Object[src.length];
for (int i = 0; i < src.length; i++) {
newArr[i] = maybeConvertObject(src[i]);
}
return newArr;
}
public BasicDBList maybeConvertList(BasicDBList dbl) {
BasicDBList newDbl = new BasicDBList();
Iterator<?> iter = dbl.iterator();
while (iter.hasNext()) {
Object o = iter.next();
newDbl.add(maybeConvertObject(o));
}
return newDbl;
}
private enum CustomToStringConverter implements GenericConverter {
INSTANCE;
public Set<ConvertiblePair> getConvertibleTypes() {
ConvertiblePair localeToString = new ConvertiblePair(Locale.class, String.class);
ConvertiblePair booleanToString = new ConvertiblePair(Character.class, String.class);
return new HashSet<ConvertiblePair>(Arrays.asList(localeToString, booleanToString));
}
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
return source.toString();
}
}
}

View File

@@ -1,59 +0,0 @@
/*
* Copyright 2010-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb.convert;
import com.mongodb.BasicDBList;
import org.bson.types.ObjectId;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.document.mongodb.MongoReader;
import org.springframework.data.document.mongodb.MongoWriter;
import org.springframework.data.document.mongodb.mapping.MongoPersistentEntity;
import org.springframework.data.document.mongodb.mapping.MongoPersistentProperty;
import org.springframework.data.mapping.model.MappingContext;
public interface MongoConverter extends MongoWriter<Object>, MongoReader<Object> {
/**
* Converts the given {@link ObjectId} to the given target type.
*
* @param <T>
* the actual type to create
* @param id
* the source {@link ObjectId}
* @param targetType
* the target type to convert the {@link ObjectId} to
* @return
*/
public <T> T convertObjectId(ObjectId id, Class<T> targetType);
/**
* Returns the {@link ObjectId} instance for the given id.
*
* @param id
* @return
*/
public ObjectId convertObjectId(Object id);
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> getMappingContext();
Object maybeConvertObject(Object obj);
Object[] maybeConvertArray(Object[] src);
BasicDBList maybeConvertList(BasicDBList dbl);
ConversionService getConversionService();
}

View File

@@ -1,516 +0,0 @@
/*
* Copyright 2010-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb.convert;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Pattern;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.DBRef;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bson.types.CodeWScope;
import org.bson.types.ObjectId;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.CollectionFactory;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.ConversionServiceFactory;
import org.springframework.data.document.mongodb.MongoPropertyDescriptors.MongoPropertyDescriptor;
import org.springframework.data.document.mongodb.mapping.MongoPersistentEntity;
import org.springframework.data.document.mongodb.mapping.MongoPersistentProperty;
import org.springframework.data.document.mongodb.mapping.SimpleMongoMappingContext;
import org.springframework.data.mapping.model.MappingContext;
import org.springframework.util.Assert;
import org.springframework.util.comparator.CompoundComparator;
/**
* Basic {@link MongoConverter} implementation to convert between domain classes and {@link DBObject}s.
*
* @author Mark Pollack
* @author Thomas Risberg
* @author Oliver Gierke
*
* @deprecated since Spring 1.0 M3 in favor of {@link org.springframework.data.document.mongodb.convert.MappingMongoConverter}
* The MappingMongoConverter provides all the functionality of the SimpleMongoConverter and will replace it as the default
* converter used. The SimpleMongoCOnverter will be removed at some point before the GA release.
*/
@Deprecated
public class SimpleMongoConverter extends AbstractMongoConverter implements InitializingBean {
private static final Log LOG = LogFactory.getLog(SimpleMongoConverter.class);
@SuppressWarnings("unchecked")
private static final List<Class<?>> MONGO_TYPES = Arrays.asList(Number.class, Date.class, String.class,
DBObject.class);
private static final Set<String> SIMPLE_TYPES;
static {
Set<String> basics = new HashSet<String>();
basics.add(boolean.class.getName());
basics.add(long.class.getName());
basics.add(short.class.getName());
basics.add(int.class.getName());
basics.add(byte.class.getName());
basics.add(float.class.getName());
basics.add(double.class.getName());
basics.add(char.class.getName());
basics.add(Boolean.class.getName());
basics.add(Long.class.getName());
basics.add(Short.class.getName());
basics.add(Integer.class.getName());
basics.add(Byte.class.getName());
basics.add(Float.class.getName());
basics.add(Double.class.getName());
basics.add(Character.class.getName());
basics.add(String.class.getName());
basics.add(java.util.Date.class.getName());
// basics.add(Time.class.getName());
// basics.add(Timestamp.class.getName());
// basics.add(java.sql.Date.class.getName());
// basics.add(BigDecimal.class.getName());
// basics.add(BigInteger.class.getName());
basics.add(Locale.class.getName());
// basics.add(Calendar.class.getName());
// basics.add(GregorianCalendar.class.getName());
// basics.add(java.util.Currency.class.getName());
// basics.add(TimeZone.class.getName());
// basics.add(Object.class.getName());
basics.add(Class.class.getName());
// basics.add(byte[].class.getName());
// basics.add(Byte[].class.getName());
// basics.add(char[].class.getName());
// basics.add(Character[].class.getName());
// basics.add(Blob.class.getName());
// basics.add(Clob.class.getName());
// basics.add(Serializable.class.getName());
// basics.add(URI.class.getName());
// basics.add(URL.class.getName());
basics.add(DBRef.class.getName());
basics.add(Pattern.class.getName());
basics.add(CodeWScope.class.getName());
basics.add(ObjectId.class.getName());
basics.add(Enum.class.getName());
SIMPLE_TYPES = Collections.unmodifiableSet(basics);
}
private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
/**
* Creates a {@link SimpleMongoConverter}.
*/
public SimpleMongoConverter() {
super(ConversionServiceFactory.createDefaultConversionService());
this.mappingContext = new SimpleMongoMappingContext();
}
/* (non-Javadoc)
* @see org.springframework.data.document.mongodb.convert.MongoConverter#getMappingContext()
*/
public MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> getMappingContext() {
return mappingContext;
}
/*
* (non-Javadoc)
*
* @see org.springframework.data.document.mongodb.MongoWriter#write(java.lang.Object, com.mongodb.DBObject)
*/
@SuppressWarnings("rawtypes")
public void write(Object obj, DBObject dbo) {
MongoBeanWrapper beanWrapper = createWrapper(obj, false);
for (MongoPropertyDescriptor descriptor : beanWrapper.getDescriptors()) {
if (descriptor.isMappable()) {
Object value = beanWrapper.getValue(descriptor);
if (value == null) {
continue;
}
String keyToUse = descriptor.getKeyToMap();
if (descriptor.isEnum()) {
writeValue(dbo, keyToUse, ((Enum) value).name());
} else if (descriptor.isIdProperty() && descriptor.isOfIdType()) {
if (value instanceof String && ObjectId.isValid((String) value)) {
try {
writeValue(dbo, keyToUse, conversionService.convert(value, ObjectId.class));
} catch (ConversionFailedException iae) {
LOG.warn("Unable to convert the String " + value + " to an ObjectId");
writeValue(dbo, keyToUse, value);
}
} else {
// we can't convert this id - use as is
writeValue(dbo, keyToUse, value);
}
} else {
writeValue(dbo, keyToUse, value);
}
} else {
if (!"class".equals(descriptor.getName())) {
LOG.debug("Skipping property " + descriptor.getName() + " as it's not a mappable one.");
}
}
}
}
/**
* Writes the given value to the given {@link DBObject}. Will skip {@literal null} values.
*
* @param dbo
* @param keyToUse
* @param value
*/
private void writeValue(DBObject dbo, String keyToUse, Object value) {
if (!isSimpleType(value.getClass())) {
writeCompoundValue(dbo, keyToUse, value);
} else {
dbo.put(keyToUse, value);
}
}
/**
* Writes the given {@link CompoundComparator} value to the given {@link DBObject}.
*
* @param dbo
* @param keyToUse
* @param value
*/
@SuppressWarnings("unchecked")
private void writeCompoundValue(DBObject dbo, String keyToUse, Object value) {
if (value instanceof Map) {
writeMap(dbo, keyToUse, (Map<String, Object>) value);
return;
}
if (value instanceof Collection) {
// Should write a collection!
writeArray(dbo, keyToUse, ((Collection<Object>) value).toArray());
return;
}
if (value instanceof Object[]) {
// Should write an array!
writeArray(dbo, keyToUse, (Object[]) value);
return;
}
Class<?> customTargetType = getCustomTargetType(value);
if (customTargetType != null) {
dbo.put(keyToUse, conversionService.convert(value, customTargetType));
return;
}
DBObject nestedDbo = new BasicDBObject();
write(value, nestedDbo);
dbo.put(keyToUse, nestedDbo);
}
/**
* Returns whether the {@link ConversionService} has a custom {@link Converter} registered that can convert the given
* object into one of the types supported by MongoDB.
*
* @param obj
* @return
*/
private Class<?> getCustomTargetType(Object obj) {
for (Class<?> mongoType : MONGO_TYPES) {
if (conversionService.canConvert(obj.getClass(), mongoType)) {
return mongoType;
}
}
return null;
}
/**
* Writes the given {@link Map} to the given {@link DBObject}.
*
* @param dbo
* @param mapKey
* @param map
*/
protected void writeMap(DBObject dbo, String mapKey, Map<String, Object> map) {
// TODO support non-string based keys as long as there is a Spring Converter obj->string and (optionally)
// string->obj
DBObject dboToPopulate = null;
// TODO - Does that make sense? If we create a new object here it's content will never make it out of this
// method
if (mapKey != null) {
dboToPopulate = new BasicDBObject();
} else {
dboToPopulate = dbo;
}
if (map != null) {
for (Entry<String, Object> entry : map.entrySet()) {
Object entryValue = entry.getValue();
String entryKey = entry.getKey();
if (!isSimpleType(entryValue.getClass())) {
writeCompoundValue(dboToPopulate, entryKey, entryValue);
} else {
dboToPopulate.put(entryKey, entryValue);
}
}
dbo.put(mapKey, dboToPopulate);
}
}
/**
* Writes the given array to the given {@link DBObject}.
*
* @param dbo
* @param keyToUse
* @param array
*/
protected void writeArray(DBObject dbo, String keyToUse, Object[] array) {
Object[] dboValues;
if (array != null) {
dboValues = new Object[array.length];
int i = 0;
for (Object o : array) {
if (!isSimpleType(o.getClass())) {
DBObject dboValue = new BasicDBObject();
write(o, dboValue);
dboValues[i] = dboValue;
} else {
dboValues[i] = o;
}
i++;
}
dbo.put(keyToUse, dboValues);
}
}
/*
* (non-Javadoc)
*
* @see org.springframework.data.document.mongodb.MongoReader#read(java.lang.Class, com.mongodb.DBObject)
*/
public <S> S read(Class<S> clazz, DBObject source) {
if (source == null) {
return null;
}
Assert.notNull(clazz, "Mapped class was not specified");
S target = BeanUtils.instantiateClass(clazz);
MongoBeanWrapper bw = new MongoBeanWrapper(target, conversionService, true);
for (MongoPropertyDescriptor descriptor : bw.getDescriptors()) {
String keyToUse = descriptor.getKeyToMap();
if (source.containsField(keyToUse)) {
if (descriptor.isMappable()) {
Object value = source.get(keyToUse);
if (!isSimpleType(value.getClass())) {
if (value instanceof Object[]) {
bw.setValue(descriptor, readCollection(descriptor, Arrays.asList((Object[]) value)).toArray());
} else if (value instanceof BasicDBList) {
bw.setValue(descriptor, readCollection(descriptor, (BasicDBList) value));
} else if (value instanceof DBObject) {
bw.setValue(descriptor, readCompoundValue(descriptor, (DBObject) value));
} else {
LOG.warn("Unable to map compound DBObject field " + keyToUse + " to property " + descriptor.getName()
+ ". The field value should have been a 'DBObject.class' but was " + value.getClass().getName());
}
} else {
bw.setValue(descriptor, value);
}
} else {
LOG.warn("Unable to map DBObject field " + keyToUse + " to property " + descriptor.getName() + ". Skipping.");
}
}
}
return target;
}
/**
* Reads the given collection values (that are {@link DBObject}s potentially) into a {@link Collection} of domain
* objects.
*
* @param descriptor
* @param values
* @return
*/
private Collection<Object> readCollection(MongoPropertyDescriptor descriptor, Collection<?> values) {
Class<?> targetCollectionType = descriptor.getPropertyType();
boolean targetIsArray = targetCollectionType.isArray();
@SuppressWarnings("unchecked")
Collection<Object> result = targetIsArray ? new ArrayList<Object>(values.size()) : CollectionFactory
.createCollection(targetCollectionType, values.size());
for (Object o : values) {
if (o instanceof DBObject) {
Class<?> type;
if (targetIsArray) {
type = targetCollectionType.getComponentType();
} else {
type = getGenericParameters(descriptor.getTypeToSet()).get(0);
}
result.add(read(type, (DBObject) o));
} else {
result.add(o);
}
}
return result;
}
/**
* Reads a compound value from the given {@link DBObject} for the given property.
*
* @param pd
* @param dbo
* @return
*/
private Object readCompoundValue(MongoPropertyDescriptor pd, DBObject dbo) {
Assert.isTrue(!pd.isCollection(), "Collections not supported!");
if (pd.isMap()) {
return readMap(pd, dbo, getGenericParameters(pd.getTypeToSet()).get(1));
} else {
return read(pd.getPropertyType(), dbo);
}
}
/**
* Create a {@link Map} instance. Will return a {@link HashMap} by default. Subclasses might want to override this
* method to use a custom {@link Map} implementation.
*
* @return
*/
protected Map<String, Object> createMap() {
return new HashMap<String, Object>();
}
/**
* Reads every key/value pair from the {@link DBObject} into a {@link Map} instance.
*
* @param pd
* @param dbo
* @param targetType
* @return
*/
protected Map<?, ?> readMap(MongoPropertyDescriptor pd, DBObject dbo, Class<?> targetType) {
Map<String, Object> map = createMap();
for (String key : dbo.keySet()) {
Object value = dbo.get(key);
if (!isSimpleType(value.getClass())) {
map.put(key, read(targetType, (DBObject) value));
// Can do some reflection tricks here -
// throw new RuntimeException("User types not supported yet as values for Maps");
} else {
map.put(key, conversionService.convert(value, targetType));
}
}
return map;
}
protected static boolean isSimpleType(Class<?> propertyType) {
if (propertyType == null) {
return false;
}
if (propertyType.isArray()) {
return isSimpleType(propertyType.getComponentType());
}
return SIMPLE_TYPES.contains(propertyType.getName());
}
/**
* Callback to allow customizing creation of a {@link MongoBeanWrapper}.
*
* @param target
* the target object to wrap
* @param fieldAccess
* whether to use field access or property access
* @return
*/
protected MongoBeanWrapper createWrapper(Object target, boolean fieldAccess) {
return new MongoBeanWrapper(target, conversionService, fieldAccess);
}
public List<Class<?>> getGenericParameters(Type genericParameterType) {
List<Class<?>> actualGenericParameterTypes = new ArrayList<Class<?>>();
if (genericParameterType instanceof ParameterizedType) {
ParameterizedType aType = (ParameterizedType) genericParameterType;
Type[] parameterArgTypes = aType.getActualTypeArguments();
for (Type parameterArgType : parameterArgTypes) {
if (parameterArgType instanceof GenericArrayType) {
Class<?> arrayType = (Class<?>) ((GenericArrayType) parameterArgType).getGenericComponentType();
actualGenericParameterTypes.add(Array.newInstance(arrayType, 0).getClass());
} else {
if (parameterArgType instanceof ParameterizedType) {
ParameterizedType paramTypeArgs = (ParameterizedType) parameterArgType;
actualGenericParameterTypes.add((Class<?>) paramTypeArgs.getRawType());
} else {
if (parameterArgType instanceof TypeVariable) {
throw new RuntimeException("Can not map " + ((TypeVariable<?>) parameterArgType).getName());
} else {
if (parameterArgType instanceof Class) {
actualGenericParameterTypes.add((Class<?>) parameterArgType);
} else {
throw new RuntimeException("Can not map " + parameterArgType);
}
}
}
}
}
}
return actualGenericParameterTypes;
}
/* (non-Javadoc)
* @see org.springframework.data.document.mongodb.convert.MongoConverter#convertObjectId(org.bson.types.ObjectId, java.lang.Class)
*/
public <T> T convertObjectId(ObjectId id, Class<T> targetType) {
return conversionService.convert(id, targetType);
}
/* (non-Javadoc)
* @see org.springframework.data.document.mongodb.convert.MongoConverter#convertObjectId(java.lang.Object)
*/
public ObjectId convertObjectId(Object id) {
return conversionService.convert(id, ObjectId.class);
}
}

View File

@@ -1,36 +0,0 @@
/*
* Copyright (c) 2011 by the original author(s).
*
* 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.document.mongodb.mapping;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation to allow defining the name of the field a property should use in a Mongo document. This will cause the
* property annotated being persisted to a field with the configured name as wells as being read from it.
*
* @author Oliver Gierke
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD })
@Documented
public @interface FieldName {
String value();
}

View File

@@ -1,5 +0,0 @@
/**
* MongoDB specific JMX monitoring support.
*/
package org.springframework.data.document.mongodb.monitor;

View File

@@ -1,5 +0,0 @@
/**
* MongoDB core support.
*/
package org.springframework.data.document.mongodb;

View File

@@ -1,5 +0,0 @@
/**
* MongoDB specific query and update support.
*/
package org.springframework.data.document.mongodb.query;

View File

@@ -1,5 +0,0 @@
/**
* MongoDB specific repository implementation.
*/
package org.springframework.data.document.mongodb.repository;

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb;
package org.springframework.data.mongodb;
import org.springframework.dao.DataAccessResourceFailureException;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010 the original author or authors.
* Copyright 2010-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,19 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb;
package org.springframework.data.mongodb;
import org.springframework.dao.InvalidDataAccessApiUsageException;
public class InvalidMongoDbApiUsageException extends InvalidDataAccessApiUsageException {
public InvalidMongoDbApiUsageException(String msg) {
super(msg);
}
private static final long serialVersionUID = 2034770973290508041L;
public InvalidMongoDbApiUsageException(String msg, Throwable cause) {
super(msg, cause);
}
public InvalidMongoDbApiUsageException(String msg) {
super(msg);
}
public InvalidMongoDbApiUsageException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -14,18 +14,16 @@
* limitations under the License.
*/
package org.springframework.data.document.mongodb;
package org.springframework.data.mongodb;
import org.springframework.util.StringUtils;
/**
* Helper class featuring helper methods for working with MongoDb collections.
* <p/>
* <p/>
* Mainly intended for internal use within the framework.
*
*
* @author Thomas Risberg
* @since 1.0
*/
@@ -40,7 +38,7 @@ public abstract class MongoCollectionUtils {
/**
* Obtains the collection name to use for the provided class
*
*
* @param entityClass The class to determine the preferred collection name for
* @return The preferred collection name
*/

View File

@@ -0,0 +1,30 @@
package org.springframework.data.mongodb;
import org.springframework.dao.DataAccessException;
import com.mongodb.DB;
/**
* Interface for factories creating {@link DB} instances.
*
* @author Mark Pollack
*/
public interface MongoDbFactory {
/**
* Creates a default {@link DB} instance.
*
* @return
* @throws DataAccessException
*/
DB getDb() throws DataAccessException;
/**
* Creates a {@link DB} instance to access the database with the given name.
*
* @param dbName must not be {@literal null} or empty.
* @return
* @throws DataAccessException
*/
DB getDb(String dbName) throws DataAccessException;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010 the original author or authors.
* Copyright 2010-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,15 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb;
package org.springframework.data.mongodb;
import org.springframework.dao.UncategorizedDataAccessException;
public class UncategorizedMongoDbException extends UncategorizedDataAccessException {
public UncategorizedMongoDbException(String msg, Throwable cause) {
super(msg, cause);
}
private static final long serialVersionUID = -2336595514062364929L;
public UncategorizedMongoDbException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb.config;
package org.springframework.data.mongodb.config;
import java.util.HashSet;
import java.util.Set;
@@ -26,13 +26,13 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.data.annotation.Persistent;
import org.springframework.data.authentication.UserCredentials;
import org.springframework.data.document.mongodb.MongoDbFactory;
import org.springframework.data.document.mongodb.MongoTemplate;
import org.springframework.data.document.mongodb.SimpleMongoDbFactory;
import org.springframework.data.document.mongodb.convert.MappingMongoConverter;
import org.springframework.data.document.mongodb.mapping.Document;
import org.springframework.data.document.mongodb.mapping.MongoMappingContext;
import org.springframework.data.mapping.context.MappingContextAwareBeanPostProcessor;
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.MappingMongoConverter;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
@@ -46,24 +46,24 @@ public abstract class AbstractMongoConfiguration {
@Bean
public MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongoDbFactory(), mappingMongoConverter());
return new MongoTemplate(mongoDbFactory(), mappingMongoConverter());
}
@Bean
public MongoDbFactory mongoDbFactory() throws Exception {
if (getUserCredentials() == null) {
return new SimpleMongoDbFactory(mongo(), getDatabaseName());
} else {
return new SimpleMongoDbFactory(mongo(), getDatabaseName(), getUserCredentials());
}
public MongoDbFactory mongoDbFactory() throws Exception {
if (getUserCredentials() == null) {
return new SimpleMongoDbFactory(mongo(), getDatabaseName());
} else {
return new SimpleMongoDbFactory(mongo(), getDatabaseName(), getUserCredentials());
}
}
public String getMappingBasePackage() {
return "";
}
public UserCredentials getUserCredentials() {
return null;
return null;
}
@Bean
@@ -71,13 +71,15 @@ public abstract class AbstractMongoConfiguration {
MongoMappingContext mappingContext = new MongoMappingContext();
String basePackage = getMappingBasePackage();
if (StringUtils.hasText(basePackage)) {
ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(false);
ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(
false);
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Document.class));
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Persistent.class));
Set<Class<?>> initialEntitySet = new HashSet<Class<?>>();
for (BeanDefinition candidate : componentProvider.findCandidateComponents(basePackage)) {
initialEntitySet.add(ClassUtils.forName(candidate.getBeanClassName(), mappingContext.getClass().getClassLoader()));
initialEntitySet.add(ClassUtils.forName(candidate.getBeanClassName(), mappingContext.getClass()
.getClassLoader()));
}
mappingContext.setInitialEntitySet(initialEntitySet);
}
@@ -93,7 +95,7 @@ public abstract class AbstractMongoConfiguration {
/**
* Hook that allows post-processing after the MappingMongoConverter has been successfully created.
*
*
* @param converter
*/
protected void afterMappingMongoConverterCreation(MappingMongoConverter converter) {

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.document.mongodb.config;
package org.springframework.data.mongodb.config;
/**
* @author Jon Brisbin <jbrisbin@vmware.com>

View File

@@ -14,9 +14,9 @@
* limitations under the License.
*/
package org.springframework.data.document.mongodb.config;
package org.springframework.data.mongodb.config;
import static org.springframework.data.document.mongodb.config.BeanNames.*;
import static org.springframework.data.mongodb.config.BeanNames.*;
import java.util.List;
import java.util.Set;
@@ -30,6 +30,7 @@ import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedSet;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
@@ -37,11 +38,12 @@ import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.data.annotation.Persistent;
import org.springframework.data.document.mongodb.convert.MappingMongoConverter;
import org.springframework.data.document.mongodb.mapping.Document;
import org.springframework.data.document.mongodb.mapping.MongoMappingContext;
import org.springframework.data.document.mongodb.mapping.MongoPersistentEntityIndexCreator;
import org.springframework.data.mapping.context.MappingContextAwareBeanPostProcessor;
import org.springframework.data.mongodb.core.convert.CustomConversions;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
@@ -65,19 +67,8 @@ public class MappingMongoConverterParser extends AbstractBeanDefinitionParser {
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
BeanDefinitionRegistry registry = parserContext.getRegistry();
String ctxRef = element.getAttribute("mapping-context-ref");
if (!StringUtils.hasText(ctxRef)) {
BeanDefinitionBuilder mappingContextBuilder = BeanDefinitionBuilder
.genericBeanDefinition(MongoMappingContext.class);
Set<String> classesToAdd = getInititalEntityClasses(element, mappingContextBuilder);
if (classesToAdd != null) {
mappingContextBuilder.addPropertyValue("initialEntitySet", classesToAdd);
}
registry.registerBeanDefinition(MAPPING_CONTEXT, mappingContextBuilder.getBeanDefinition());
ctxRef = MAPPING_CONTEXT;
}
BeanDefinition conversionsDefinition = getCustomConversions(element, parserContext);
String ctxRef = potentiallyCreateMappingContext(element, parserContext, conversionsDefinition);
try {
registry.getBeanDefinition(POST_PROCESSOR);
@@ -93,12 +84,15 @@ public class MappingMongoConverterParser extends AbstractBeanDefinitionParser {
if (!StringUtils.hasText(dbFactoryRef)) {
dbFactoryRef = DB_FACTORY;
}
// Converter
BeanDefinitionBuilder converterBuilder = BeanDefinitionBuilder.genericBeanDefinition(MappingMongoConverter.class);
converterBuilder.addConstructorArgReference(dbFactoryRef);
converterBuilder.addConstructorArgReference(ctxRef);
if (conversionsDefinition != null) {
converterBuilder.addPropertyValue("customConversions", conversionsDefinition);
}
try {
registry.getBeanDefinition(INDEX_HELPER);
@@ -106,26 +100,70 @@ public class MappingMongoConverterParser extends AbstractBeanDefinitionParser {
if (!StringUtils.hasText(dbFactoryRef)) {
dbFactoryRef = DB_FACTORY;
}
BeanDefinitionBuilder indexHelperBuilder = BeanDefinitionBuilder.genericBeanDefinition(MongoPersistentEntityIndexCreator.class);
BeanDefinitionBuilder indexHelperBuilder = BeanDefinitionBuilder
.genericBeanDefinition(MongoPersistentEntityIndexCreator.class);
indexHelperBuilder.addConstructorArgValue(new RuntimeBeanReference(ctxRef));
indexHelperBuilder.addConstructorArgValue(new RuntimeBeanReference(dbFactoryRef));
registry.registerBeanDefinition(INDEX_HELPER, indexHelperBuilder.getBeanDefinition());
}
return converterBuilder.getBeanDefinition();
}
private String potentiallyCreateMappingContext(Element element, ParserContext parserContext,
BeanDefinition conversionsDefinition) {
String ctxRef = element.getAttribute("mapping-context-ref");
if (!StringUtils.hasText(ctxRef)) {
BeanDefinitionBuilder mappingContextBuilder = BeanDefinitionBuilder
.genericBeanDefinition(MongoMappingContext.class);
Set<String> classesToAdd = getInititalEntityClasses(element, mappingContextBuilder);
if (classesToAdd != null) {
mappingContextBuilder.addPropertyValue("initialEntitySet", classesToAdd);
}
if (conversionsDefinition != null) {
AbstractBeanDefinition simpleTypesDefinition = new GenericBeanDefinition();
simpleTypesDefinition.setFactoryBeanName("customConversions");
simpleTypesDefinition.setFactoryMethodName("getSimpleTypeHolder");
mappingContextBuilder.addPropertyValue("simpleTypeHolder", simpleTypesDefinition);
}
parserContext.getRegistry().registerBeanDefinition(MAPPING_CONTEXT, mappingContextBuilder.getBeanDefinition());
ctxRef = MAPPING_CONTEXT;
}
return ctxRef;
}
private BeanDefinition getCustomConversions(Element element, ParserContext parserContext) {
List<Element> customConvertersElements = DomUtils.getChildElementsByTagName(element, "custom-converters");
if (customConvertersElements.size() == 1) {
Element customerConvertersElement = customConvertersElements.get(0);
ManagedList<BeanMetadataElement> converterBeans = new ManagedList<BeanMetadataElement>();
List<Element> listenerElements = DomUtils.getChildElementsByTagName(customerConvertersElement, "converter");
if (listenerElements != null) {
for (Element listenerElement : listenerElements) {
List<Element> converterElements = DomUtils.getChildElementsByTagName(customerConvertersElement, "converter");
if (converterElements != null) {
for (Element listenerElement : converterElements) {
converterBeans.add(parseConverter(listenerElement, parserContext));
}
}
converterBuilder.addPropertyValue("customConverters", converterBeans);
BeanDefinitionBuilder conversionsBuilder = BeanDefinitionBuilder.rootBeanDefinition(CustomConversions.class);
conversionsBuilder.addConstructorArgValue(converterBeans);
AbstractBeanDefinition conversionsBean = conversionsBuilder.getBeanDefinition();
conversionsBean.setSource(parserContext.extractSource(element));
parserContext.getRegistry().registerBeanDefinition("customConversions", conversionsBean);
return conversionsBean;
}
return converterBuilder.getBeanDefinition();
return null;
}
public Set<String> getInititalEntityClasses(Element element, BeanDefinitionBuilder builder) {

View File

@@ -0,0 +1,123 @@
/*
* Copyright (c) 2011 by the original author(s).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.config;
import static org.springframework.data.mongodb.config.BeanNames.*;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.authentication.UserCredentials;
import org.springframework.data.mongodb.core.MongoFactoryBean;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
import com.mongodb.Mongo;
/**
* {@link BeanDefinitionParser} to parse {@code db-factory} elements into {@link BeanDefinition}s.
*
* @author Jon Brisbin
* @author Oliver Gierke
*/
public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
@Override
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
throws BeanDefinitionStoreException {
String id = element.getAttribute("id");
if (!StringUtils.hasText(id)) {
id = DB_FACTORY;
}
return id;
}
@Override
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
String mongoRef = element.getAttribute("mongo-ref");
if (!StringUtils.hasText(mongoRef)) {
mongoRef = registerMongoBeanDefinition(element, parserContext);
}
// Database name
String dbname = element.getAttribute("dbname");
if (!StringUtils.hasText(dbname)) {
dbname = "db";
}
BeanDefinitionBuilder dbFactoryBuilder = BeanDefinitionBuilder.genericBeanDefinition(SimpleMongoDbFactory.class);
dbFactoryBuilder.addConstructorArgValue(new RuntimeBeanReference(mongoRef));
dbFactoryBuilder.addConstructorArgValue(dbname);
BeanDefinition userCredentials = getUserCredentialsBeanDefinition(element);
if (userCredentials != null) {
dbFactoryBuilder.addConstructorArgValue(userCredentials);
}
ParsingUtils.setPropertyValue(element, dbFactoryBuilder, "write-concern", "writeConcern");
return dbFactoryBuilder.getBeanDefinition();
}
/**
* Registers a default {@link BeanDefinition} of a {@link Mongo} instance and returns the name under which the
* {@link Mongo} instance was registered under.
*
* @param element must not be {@literal null}.
* @param parserContext must not be {@literal null}.
* @return
*/
private String registerMongoBeanDefinition(Element element, ParserContext parserContext) {
BeanDefinitionBuilder mongoBuilder = BeanDefinitionBuilder.genericBeanDefinition(MongoFactoryBean.class);
ParsingUtils.setPropertyValue(element, mongoBuilder, "host");
ParsingUtils.setPropertyValue(element, mongoBuilder, "port");
return BeanDefinitionReaderUtils.registerWithGeneratedName(mongoBuilder.getBeanDefinition(),
parserContext.getRegistry());
}
/**
* Returns a {@link BeanDefinition} for a {@link UserCredentials} object.
*
* @param element
* @return the {@link BeanDefinition} or {@literal null} if neither username nor password given.
*/
private BeanDefinition getUserCredentialsBeanDefinition(Element element) {
String username = element.getAttribute("username");
String password = element.getAttribute("password");
if (!StringUtils.hasText(username) && !StringUtils.hasText(password)) {
return null;
}
BeanDefinitionBuilder userCredentialsBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserCredentials.class);
userCredentialsBuilder.addConstructorArgValue(StringUtils.hasText(username) ? username : null);
userCredentialsBuilder.addConstructorArgValue(StringUtils.hasText(password) ? password : null);
return userCredentialsBuilder.getBeanDefinition();
}
}

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb.config;
package org.springframework.data.mongodb.config;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
@@ -21,8 +21,8 @@ import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.document.mongodb.MongoAdmin;
import org.springframework.data.document.mongodb.monitor.*;
import org.springframework.data.mongodb.core.MongoAdmin;
import org.springframework.data.mongodb.monitor.*;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;

View File

@@ -14,29 +14,25 @@
* limitations under the License.
*/
package org.springframework.data.document.mongodb.config;
package org.springframework.data.mongodb.config;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.document.mongodb.MongoFactoryBean;
import org.springframework.data.document.mongodb.MongoOptionsFactoryBean;
import org.springframework.data.mongodb.core.MongoFactoryBean;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
import com.mongodb.ServerAddress;
/**
* Parser for &lt;mongo;gt; definitions. If no name
*
*
* @author Mark Pollack
*/
public class MongoParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
return MongoFactoryBean.class;
}
@@ -47,16 +43,13 @@ public class MongoParser extends AbstractSingleBeanDefinitionParser {
ParsingUtils.setPropertyValue(element, builder, "port", "port");
ParsingUtils.setPropertyValue(element, builder, "host", "host");
ParsingUtils.setPropertyValue(element, builder, "write-concern", "writeConcern");
ParsingUtils.parseMongoOptions(parserContext, element, builder);
ParsingUtils.parseReplicaSet(parserContext, element, builder);
}
@Override
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
throws BeanDefinitionStoreException {
@@ -66,6 +59,4 @@ public class MongoParser extends AbstractSingleBeanDefinitionParser {
}
return name;
}
}

View File

@@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb.config;
package org.springframework.data.mongodb.config;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.data.document.mongodb.config.SimpleMongoRepositoryConfiguration.MongoRepositoryConfiguration;
import org.springframework.data.mongodb.config.SimpleMongoRepositoryConfiguration.MongoRepositoryConfiguration;
import org.springframework.data.repository.config.AbstractRepositoryConfigDefinitionParser;
import org.w3c.dom.Element;
@@ -49,5 +49,6 @@ public class MongoRepositoryConfigParser extends
BeanDefinitionRegistry registry, Object beanSource) {
builder.addPropertyReference("template", context.getMongoTemplateRef());
builder.addPropertyValue("createIndexesForQueryMethods", context.getCreateQueryIndexes());
}
}

View File

@@ -13,13 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb.config;
package org.springframework.data.mongodb.config;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
/**
* {@link org.springframework.beans.factory.xml.NamespaceHandler} for Mongo DB based repositories.
*
*
* @author Oliver Gierke
*/
public class MongoRepositoryNamespaceHandler extends NamespaceHandlerSupport {

View File

@@ -0,0 +1,112 @@
/*
* Copyright (c) 2011 by the original author(s).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.config;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.mongodb.core.MongoOptionsFactoryBean;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
import com.mongodb.ServerAddress;
abstract class ParsingUtils {
/**
* Parses the mongo replica-set element.
*
* @param parserContext the parser context
* @param element the mongo element
* @param mongoBuilder the bean definition builder to populate
* @return true if parsing actually occured, false otherwise
*/
static boolean parseReplicaSet(ParserContext parserContext, Element element, BeanDefinitionBuilder mongoBuilder) {
String replicaSetString = element.getAttribute("replica-set");
if (StringUtils.hasText(replicaSetString)) {
ManagedList<Object> serverAddresses = new ManagedList<Object>();
String[] replicaSetStringArray = StringUtils.commaDelimitedListToStringArray(replicaSetString);
for (String element2 : replicaSetStringArray) {
String[] hostAndPort = StringUtils.delimitedListToStringArray(element2, ":");
BeanDefinitionBuilder defBuilder = BeanDefinitionBuilder.genericBeanDefinition(ServerAddress.class);
defBuilder.addConstructorArgValue(hostAndPort[0]);
defBuilder.addConstructorArgValue(hostAndPort[1]);
serverAddresses.add(defBuilder.getBeanDefinition());
}
if (!serverAddresses.isEmpty()) {
mongoBuilder.addPropertyValue("replicaSetSeeds", serverAddresses);
}
}
return true;
}
/**
* Parses the mongo:options sub-element. Populates the given attribute factory with the proper attributes.
*
* @return true if parsing actually occured, false otherwise
*/
static boolean parseMongoOptions(ParserContext parserContext, Element element, BeanDefinitionBuilder mongoBuilder) {
Element optionsElement = DomUtils.getChildElementByTagName(element, "options");
if (optionsElement == null) {
return false;
}
BeanDefinitionBuilder optionsDefBuilder = BeanDefinitionBuilder
.genericBeanDefinition(MongoOptionsFactoryBean.class);
setPropertyValue(optionsElement, optionsDefBuilder, "connections-per-host", "connectionsPerHost");
setPropertyValue(optionsElement, optionsDefBuilder, "threads-allowed-to-block-for-connection-multiplier",
"threadsAllowedToBlockForConnectionMultiplier");
setPropertyValue(optionsElement, optionsDefBuilder, "max-wait-time", "maxWaitTime");
setPropertyValue(optionsElement, optionsDefBuilder, "connect-timeout", "connectTimeout");
setPropertyValue(optionsElement, optionsDefBuilder, "socket-timeout", "socketTimeout");
setPropertyValue(optionsElement, optionsDefBuilder, "socket-keep-alive", "socketKeepAlive");
setPropertyValue(optionsElement, optionsDefBuilder, "auto-connect-retry", "autoConnectRetry");
setPropertyValue(optionsElement, optionsDefBuilder, "write-number", "writeNumber");
setPropertyValue(optionsElement, optionsDefBuilder, "write-timeout", "writeTimeout");
setPropertyValue(optionsElement, optionsDefBuilder, "write-fsync", "writeFsync");
setPropertyValue(optionsElement, optionsDefBuilder, "slave-ok", "slaveOk");
mongoBuilder.addPropertyValue("mongoOptions", optionsDefBuilder.getBeanDefinition());
return true;
}
static void setPropertyValue(Element element, BeanDefinitionBuilder builder, String attrName, String propertyName) {
String attr = element.getAttribute(attrName);
if (StringUtils.hasText(attr)) {
builder.addPropertyValue(propertyName, attr);
}
}
/**
* Sets the property with the given attribute name on the given {@link BeanDefinitionBuilder} to the value of the
* attribute with the given name.
*
* @param element must not be {@literal null}.
* @param builder must not be {@literal null}.
* @param attrName must not be {@literal null} or empty.
*/
static void setPropertyValue(Element element, BeanDefinitionBuilder builder, String attrName) {
String attr = element.getAttribute(attrName);
if (StringUtils.hasText(attr)) {
builder.addPropertyValue(attrName, attr);
}
}
}

View File

@@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb.config;
package org.springframework.data.mongodb.config;
import org.springframework.data.document.mongodb.repository.MongoRepositoryFactoryBean;
import org.springframework.data.mongodb.repository.MongoRepositoryFactoryBean;
import org.springframework.data.repository.config.AutomaticRepositoryConfigInformation;
import org.springframework.data.repository.config.ManualRepositoryConfigInformation;
import org.springframework.data.repository.config.RepositoryConfig;
@@ -34,6 +34,7 @@ public class SimpleMongoRepositoryConfiguration
RepositoryConfig<SimpleMongoRepositoryConfiguration.MongoRepositoryConfiguration, SimpleMongoRepositoryConfiguration> {
private static final String MONGO_TEMPLATE_REF = "mongo-template-ref";
private static final String CREATE_QUERY_INDEXES = "create-query-indexes";
private static final String DEFAULT_MONGO_TEMPLATE_REF = "mongoTemplate";
/**
@@ -47,7 +48,7 @@ public class SimpleMongoRepositoryConfiguration
}
/**
* Returns the bean name of the {@link org.springframework.data.document.mongodb.MongoTemplate} to be referenced.
* Returns the bean name of the {@link org.springframework.data.mongodb.core.core.MongoTemplate} to be referenced.
*
* @return
*/
@@ -57,6 +58,17 @@ public class SimpleMongoRepositoryConfiguration
return StringUtils.hasText(templateRef) ? templateRef : DEFAULT_MONGO_TEMPLATE_REF;
}
/**
* Returns whether to create indexes for query methods.
*
* @return
*/
public boolean getCreateQueryIndexes() {
String createQueryIndexes = getSource().getAttribute(CREATE_QUERY_INDEXES);
return StringUtils.hasText(createQueryIndexes) ? Boolean.parseBoolean(createQueryIndexes) : false;
}
/*
* (non-Javadoc)
*
@@ -69,6 +81,14 @@ public class SimpleMongoRepositoryConfiguration
return new AutomaticMongoRepositoryConfiguration(interfaceName, this);
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfig#getNamedQueriesLocation()
*/
public String getNamedQueriesLocation() {
return "classpath*:META-INF/mongo-named-queries.properties";
}
/*
* (non-Javadoc)
*
@@ -90,6 +110,8 @@ public class SimpleMongoRepositoryConfiguration
SingleRepositoryConfigInformation<SimpleMongoRepositoryConfiguration> {
String getMongoTemplateRef();
boolean getCreateQueryIndexes();
}
/**
@@ -114,7 +136,7 @@ public class SimpleMongoRepositoryConfiguration
/*
* (non-Javadoc)
*
* @see org.springframework.data.document.mongodb.repository.config.
* @see org.springframework.data.mongodb.repository.config.
* SimpleMongoRepositoryConfiguration
* .MongoRepositoryConfiguration#getMongoTemplateRef()
*/
@@ -122,6 +144,15 @@ public class SimpleMongoRepositoryConfiguration
return getAttribute(MONGO_TEMPLATE_REF);
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.config.SimpleMongoRepositoryConfiguration.MongoRepositoryConfiguration#getCreateQueryIndexes()
*/
public boolean getCreateQueryIndexes() {
String attribute = getAttribute(CREATE_QUERY_INDEXES);
return attribute == null ? false : Boolean.parseBoolean(attribute);
}
}
/**
@@ -146,7 +177,7 @@ public class SimpleMongoRepositoryConfiguration
/*
* (non-Javadoc)
*
* @see org.springframework.data.document.mongodb.repository.config.
* @see org.springframework.data.mongodb.repository.config.
* SimpleMongoRepositoryConfiguration
* .MongoRepositoryConfiguration#getMongoTemplateRef()
*/
@@ -154,5 +185,12 @@ public class SimpleMongoRepositoryConfiguration
return getParent().getMongoTemplateRef();
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.config.SimpleMongoRepositoryConfiguration.MongoRepositoryConfiguration#getCreateQueryIndexes()
*/
public boolean getCreateQueryIndexes() {
return getParent().getCreateQueryIndexes();
}
}
}

View File

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

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb;
package org.springframework.data.mongodb.core;
import com.mongodb.DBCollection;
import com.mongodb.MongoException;

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb;
package org.springframework.data.mongodb.core;
/**
* Provides a simple wrapper to encapsulate the variety of settings you can use when creating a collection.
@@ -31,13 +31,10 @@ public class CollectionOptions {
/**
* Constructs a new <code>CollectionOptions</code> instance.
*
* @param size
* the collection size in bytes, this data space is preallocated
* @param maxDocuments
* the maximum number of documents in the collection.
* @param capped
* true to created a "capped" collection (fixed size with auto-FIFO behavior based on insertion order), false
* otherwise.
* @param size the collection size in bytes, this data space is preallocated
* @param maxDocuments the maximum number of documents in the collection.
* @param capped true to created a "capped" collection (fixed size with auto-FIFO behavior based on insertion order),
* false otherwise.
*/
public CollectionOptions(Integer size, Integer maxDocuments, Boolean capped) {
super();

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb;
package org.springframework.data.mongodb.core;
import com.mongodb.DBCursor;

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb;
package org.springframework.data.mongodb.core;
import com.mongodb.DB;
import com.mongodb.MongoException;

View File

@@ -1,4 +1,4 @@
package org.springframework.data.document.mongodb;
package org.springframework.data.mongodb.core;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2010-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core;
import 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.
*
* @author Mark Pollack
*
*/
public interface DocumentCallbackHandler {
void processDocument(DBObject dbObject) throws MongoException, DataAccessException;
}

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb;
package org.springframework.data.mongodb.core;
import com.mongodb.DB;
import com.mongodb.Mongo;
@@ -45,7 +45,7 @@ public class MongoAdmin implements MongoAdminOperations {
}
/* (non-Javadoc)
* @see org.springframework.data.document.mongodb.MongoAdminOperations#dropDatabase(java.lang.String)
* @see org.springframework.data.mongodb.core.core.MongoAdminOperations#dropDatabase(java.lang.String)
*/
@ManagedOperation
public void dropDatabase(String databaseName) {
@@ -53,7 +53,7 @@ public class MongoAdmin implements MongoAdminOperations {
}
/* (non-Javadoc)
* @see org.springframework.data.document.mongodb.MongoAdminOperations#createDatabase(java.lang.String)
* @see org.springframework.data.mongodb.core.core.MongoAdminOperations#createDatabase(java.lang.String)
*/
@ManagedOperation
public void createDatabase(String databaseName) {
@@ -61,7 +61,7 @@ public class MongoAdmin implements MongoAdminOperations {
}
/* (non-Javadoc)
* @see org.springframework.data.document.mongodb.MongoAdminOperations#getDatabaseStats(java.lang.String)
* @see org.springframework.data.mongodb.core.core.MongoAdminOperations#getDatabaseStats(java.lang.String)
*/
@ManagedOperation
public String getDatabaseStats(String databaseName) {
@@ -71,8 +71,7 @@ public class MongoAdmin implements MongoAdminOperations {
/**
* Sets the username to use to connect to the Mongo database
*
* @param username
* The username to use
* @param username The username to use
*/
public void setUsername(String username) {
this.username = username;
@@ -81,8 +80,7 @@ public class MongoAdmin implements MongoAdminOperations {
/**
* Sets the password to use to authenticate with the Mongo database.
*
* @param password
* The password to use
* @param password The password to use
*/
public void setPassword(String password) {

View File

@@ -1,4 +1,4 @@
package org.springframework.data.document.mongodb;
package org.springframework.data.mongodb.core;
import org.springframework.jmx.export.annotation.ManagedOperation;

View File

@@ -13,13 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb;
package org.springframework.data.mongodb.core;
import com.mongodb.DB;
import com.mongodb.Mongo;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.data.mongodb.CannotGetMongoDbConnectionException;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
@@ -48,10 +48,8 @@ public abstract class MongoDbUtils {
/**
* Obtains a {@link DB} connection for the given {@link Mongo} instance and database name
*
* @param mongo
* The {@link Mongo} instance
* @param databaseName
* The database name
* @param mongo The {@link Mongo} instance
* @param databaseName The database name
* @return The {@link DB} connection
*/
public static DB getDB(Mongo mongo, String databaseName) {
@@ -61,14 +59,10 @@ public abstract class MongoDbUtils {
/**
* Obtains a {@link DB} connection for the given {@link Mongo} instance and database name
*
* @param mongo
* The {@link Mongo} instance
* @param databaseName
* The database name
* @param username
* The username to authenticate with
* @param password
* The password to authenticate with
* @param mongo The {@link Mongo} instance
* @param databaseName The database name
* @param username The username to authenticate with
* @param password The password to authenticate with
* @return The {@link DB} connection
*/
public static DB getDB(Mongo mongo, String databaseName, String username, char[] password) {
@@ -140,10 +134,8 @@ public abstract class MongoDbUtils {
* Return whether the given DB instance is transactional, that is, bound to the current thread by Spring's transaction
* facilities.
*
* @param db
* the DB to check
* @param mongo
* the Mongo instance that the DB was created with (may be <code>null</code>)
* @param db the DB to check
* @param mongo the Mongo instance that the DB was created with (may be <code>null</code>)
* @return whether the DB is transactional
*/
public static boolean isDBTransactional(DB db, Mongo mongo) {
@@ -157,8 +149,7 @@ public abstract class MongoDbUtils {
/**
* Perform actual closing of the Mongo DB object, catching and logging any cleanup exceptions thrown.
*
* @param db
* the DB to close (may be <code>null</code>)
* @param db the DB to close (may be <code>null</code>)
*/
public static void closeDB(DB db) {
if (db != null) {

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb;
package org.springframework.data.mongodb.core;
public interface MongoDocumentWriter {

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb;
package org.springframework.data.mongodb.core;
import com.mongodb.MongoException;
import com.mongodb.MongoException.CursorNotFound;
@@ -23,21 +23,18 @@ import com.mongodb.MongoInternalException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.mongodb.UncategorizedMongoDbException;
/**
* Simple {@link PersistenceExceptionTranslator} for Mongo. Convert the given runtime exception to an appropriate
* exception from the {@code org.springframework.dao} hierarchy. Return {@literal null} if no translation is
* appropriate: any other exception may have resulted from user code, and should not be translated.
*
* @param ex
* runtime exception that occurred
* @author Oliver Gierke
* @return the corresponding DataAccessException instance, or {@literal null} if the exception should not be translated
*/
public class MongoExceptionTranslator implements PersistenceExceptionTranslator {

View File

@@ -14,39 +14,40 @@
* limitations under the License.
*/
package org.springframework.data.document.mongodb;
package org.springframework.data.mongodb.core;
import java.util.List;
import com.mongodb.Mongo;
import com.mongodb.MongoOptions;
import com.mongodb.ServerAddress;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.util.Assert;
import org.springframework.data.mongodb.CannotGetMongoDbConnectionException;
import com.mongodb.Mongo;
import com.mongodb.MongoOptions;
import com.mongodb.ServerAddress;
import com.mongodb.WriteConcern;
/**
* Convenient factory for configuring MongoDB.
*
* @author Thomas Risberg
* @author Graeme Rocher
* @author Oliver Gierke
* @since 1.0
*/
public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, PersistenceExceptionTranslator {
public class MongoFactoryBean implements FactoryBean<Mongo>, PersistenceExceptionTranslator {
/**
* Logger, available to subclasses.
*/
protected final Log logger = LogFactory.getLog(getClass());
private Mongo mongo;
private MongoOptions mongoOptions;
private String host;
private Integer port;
private WriteConcern writeConcern;
private List<ServerAddress> replicaSetSeeds;
private List<ServerAddress> replicaPair;
@@ -72,8 +73,13 @@ public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, P
this.port = port;
}
public PersistenceExceptionTranslator getExceptionTranslator() {
return exceptionTranslator;
/**
* Sets the {@link WriteConcern} to be configured for the {@link Mongo} instance to be created.
*
* @param writeConcern
*/
public void setWriteConcern(WriteConcern writeConcern) {
this.writeConcern = writeConcern;
}
public void setExceptionTranslator(PersistenceExceptionTranslator exceptionTranslator) {
@@ -81,49 +87,64 @@ public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, P
}
public Mongo getObject() throws Exception {
Assert.notNull(mongo, "Mongo must not be null");
Mongo mongo;
if (host == null) {
logger.debug("Property host not specified. Using default configuration");
mongo = new Mongo();
} else {
ServerAddress defaultOptions = new ServerAddress();
if (mongoOptions == null) {
mongoOptions = new MongoOptions();
}
if (replicaPair != null) {
if (replicaPair.size() < 2) {
throw new CannotGetMongoDbConnectionException("A replica pair must have two server entries");
}
mongo = new Mongo(replicaPair.get(0), replicaPair.get(1), mongoOptions);
} else if (replicaSetSeeds != null) {
mongo = new Mongo(replicaSetSeeds, mongoOptions);
} else {
String mongoHost = host != null ? host : defaultOptions.getHost();
mongo = port != null ? new Mongo(new ServerAddress(mongoHost, port), mongoOptions) : new Mongo(mongoHost,
mongoOptions);
}
}
if (writeConcern != null) {
mongo.setWriteConcern(writeConcern);
}
return mongo;
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
*/
public Class<? extends Mongo> getObjectType() {
return Mongo.class;
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
*/
public boolean isSingleton() {
return false;
}
public void afterPropertiesSet() throws Exception {
// apply defaults - convenient when used to configure for tests
// in an application context
if (mongo == null) {
if (host == null) {
logger.warn("Property host not specified. Using default configuration");
mongo = new Mongo();
} else {
ServerAddress defaultOptions = new ServerAddress();
if (mongoOptions == null)
mongoOptions = new MongoOptions();
if (replicaPair != null) {
if (replicaPair.size() < 2) {
throw new CannotGetMongoDbConnectionException("A replica pair must have two server entries");
}
mongo = new Mongo(replicaPair.get(0), replicaPair.get(1), mongoOptions);
} else if (replicaSetSeeds != null) {
mongo = new Mongo(replicaSetSeeds, mongoOptions);
} else {
String mongoHost = host != null ? host : defaultOptions.getHost();
if (port != null) {
mongo = new Mongo(new ServerAddress(mongoHost, port), mongoOptions);
} else {
mongo = new Mongo(mongoHost, mongoOptions);
}
}
}
}
return true;
}
/*
* (non-Javadoc)
* @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
*/
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
return exceptionTranslator.translateExceptionIfPossible(ex);
}

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb;
package org.springframework.data.mongodb.core;
import java.util.Collection;
import java.util.List;
@@ -24,9 +24,15 @@ import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.WriteResult;
import org.springframework.data.document.mongodb.index.IndexDefinition;
import org.springframework.data.document.mongodb.query.Query;
import org.springframework.data.document.mongodb.query.Update;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.data.mongodb.core.geo.GeoResult;
import org.springframework.data.mongodb.core.geo.GeoResults;
import org.springframework.data.mongodb.core.index.IndexDefinition;
import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions;
import org.springframework.data.mongodb.core.mapreduce.MapReduceResults;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
/**
* Interface that specifies a basic set of MongoDB operations. Implemented by {@link MongoTemplate}. Not often used but
@@ -51,8 +57,7 @@ public interface MongoOperations {
* 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.
* @param jsonCommand a MongoDB command expressed as a JSON string.
*/
CommandResult executeCommand(String jsonCommand);
@@ -60,20 +65,48 @@ public interface MongoOperations {
* 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 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
*/
CommandResult executeCommand(DBObject command, int options);
/**
* Execute a MongoDB query and iterate over the query results on a per-document basis with a DocumentCallbackHandler.
*
* @param query the query class that specifies the criteria used to find a record and also an optional fields
* specification
* @param collectionName name of the collection to retrieve the objects from
* @param dch the handler that will extract results, one document at a time
*/
void executeQuery(Query query, String collectionName, DocumentCallbackHandler dch);
/**
* Execute a MongoDB query and iterate over the query results on a per-document basis with a DocumentCallbackHandler using the
* provided CursorPreparer.
* @param query the query class that specifies the criteria used to find a record and also an optional fields
* specification
* @param collectionName name of the collection to retrieve the objects from
* @param dch the handler that will extract results, one document at a time
* @param preparer allows for customization of the DBCursor used when iterating over the result set, (apply limits,
* skips and so on).
*/
void executeQuery(Query query, String collectionName, DocumentCallbackHandler dch, CursorPreparer preparer);
/**
* Executes a {@link DbCallback} 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.
* @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 or <tt>null</tt>
*/
<T> T execute(DbCallback<T> action);
@@ -83,12 +116,9 @@ public interface MongoOperations {
* <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
* @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> T execute(Class<?> entityClass, CollectionCallback<T> action);
@@ -98,12 +128,9 @@ public interface MongoOperations {
* <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.
* @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> T execute(String collectionName, CollectionCallback<T> action);
@@ -115,10 +142,8 @@ public interface MongoOperations {
* <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
* @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>
*/
<T> T executeInSession(DbCallback<T> action);
@@ -126,8 +151,7 @@ public interface MongoOperations {
/**
* Create an uncapped collection with a name based on the provided entity class.
*
* @param entityClass
* class that determines the collection to create
* @param entityClass class that determines the collection to create
* @return the created collection
*/
<T> DBCollection createCollection(Class<T> entityClass);
@@ -135,10 +159,8 @@ public interface MongoOperations {
/**
* Create a collect 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.
* @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);
@@ -146,8 +168,7 @@ public interface MongoOperations {
/**
* Create an uncapped collection with the provided name.
*
* @param collectionName
* name of the collection
* @param collectionName name of the collection
* @return the created collection
*/
DBCollection createCollection(String collectionName);
@@ -155,10 +176,8 @@ public interface MongoOperations {
/**
* Create a collect with the provided name and options.
*
* @param collectionName
* name of the collection
* @param collectionOptions
* options to use when creating the collection.
* @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);
@@ -175,8 +194,7 @@ public interface MongoOperations {
* <p/>
* Translate any exceptions as necessary.
*
* @param collectionName
* name of the collection
* @param collectionName name of the collection
* @return an existing collection or a newly created one.
*/
DBCollection getCollection(String collectionName);
@@ -186,8 +204,7 @@ public interface MongoOperations {
* <p/>
* Translate any exceptions as necessary.
*
* @param entityClass
* class that determines the name of the collection
* @param entityClass class that determines the name of the collection
* @return true if a collection with the given name is found, false otherwise.
*/
<T> boolean collectionExists(Class<T> entityClass);
@@ -197,8 +214,7 @@ public interface MongoOperations {
* <p/>
* Translate any exceptions as necessary.
*
* @param collectionName
* name of the collection
* @param collectionName name of the collection
* @return true if a collection with the given name is found, false otherwise.
*/
boolean collectionExists(String collectionName);
@@ -208,8 +224,7 @@ public interface MongoOperations {
* <p/>
* Translate any exceptions as necessary.
*
* @param entityClass
* class that determines the collection to drop/delete.
* @param entityClass class that determines the collection to drop/delete.
*/
<T> void dropCollection(Class<T> entityClass);
@@ -218,8 +233,7 @@ public interface MongoOperations {
* <p/>
* Translate any exceptions as necessary.
*
* @param collectionName
* name of the collection to drop/delete.
* @param collectionName name of the collection to drop/delete.
*/
void dropCollection(String collectionName);
@@ -232,8 +246,7 @@ public interface MongoOperations {
* 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 parameterized type of the returned list
* @param entityClass the parameterized type of the returned list
* @return the converted collection
*/
<T> List<T> findAll(Class<T> entityClass);
@@ -247,21 +260,90 @@ public interface MongoOperations {
* 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 parameterized type of the returned list.
* @param collectionName
* name of the collection to retrieve the objects from
* @param entityClass the parameterized type of the returned list.
* @param collectionName name of the collection to retrieve the objects from
* @return the converted collection
*/
<T> List<T> findAll(Class<T> entityClass, String collectionName);
/**
* Execute a map-reduce operation. The map-reduce operation will be formed with an output type of INLINE
* @param inputCollectionName the collection where the map-reduce will read from
* @param mapFunction The JavaScript map function
* @param reduceFunction The JavaScript reduce function
* @param mapReduceOptions Options that specify detailed map-reduce behavior
* @param entityClass The parameterized type of the returned list
* @return The results of the map reduce operation
*/
<T> MapReduceResults<T> mapReduce(String inputCollectionName, String mapFunction, String reduceFunction, Class<T> entityClass );
/**
* Execute a map-reduce operation that takes additional map-reduce options.
* @param inputCollectionName the collection where the map-reduce will read from
* @param mapFunction The JavaScript map function
* @param reduceFunction The JavaScript reduce function
* @param mapReduceOptions Options that specify detailed map-reduce behavior
* @param entityClass The parameterized type of the returned list
* @return The results of the map reduce operation
*/
<T> MapReduceResults<T> mapReduce(String inputCollectionName, String mapFunction, String reduceFunction, MapReduceOptions mapReduceOptions, Class<T> entityClass );
/**
* Execute a map-reduce operation that takes a query. The map-reduce operation will be formed with an output type of INLINE
* @param query The query to use to select the data for the map phase
* @param inputCollectionName the collection where the map-reduce will read from
* @param mapFunction The JavaScript map function
* @param reduceFunction The JavaScript reduce function
* @param mapReduceOptions Options that specify detailed map-reduce behavior
* @param entityClass The parameterized type of the returned list
* @return The results of the map reduce operation
*/
<T> MapReduceResults<T> mapReduce(Query query, String inputCollectionName, String mapFunction, String reduceFunction, Class<T> entityClass );
/**
* Execute a map-reduce operation that takes a query and additional map-reduce options
* @param query The query to use to select the data for the map phase
* @param inputCollectionName the collection where the map-reduce will read from
* @param mapFunction The JavaScript map function
* @param reduceFunction The JavaScript reduce function
* @param mapReduceOptions Options that specify detailed map-reduce behavior
* @param entityClass The parameterized type of the returned list
* @return The results of the map reduce operation
*/
<T> MapReduceResults<T> mapReduce(Query query, String inputCollectionName, String mapFunction, String reduceFunction, MapReduceOptions mapReduceOptions, Class<T> entityClass );
/**
* Ensure that an index for the provided {@link IndexDefinition} exists for the collection indicated by the entity class.
* If not it will be created.
* Returns {@link GeoResult} for all entities matching the given {@link NearQuery}. Will consider entity mapping
* information to determine the collection the query is ran against.
*
* @param near must not be {@literal null}.
* @param entityClass must not be {@literal null}.
* @return
*/
<T> GeoResults<T> geoNear(NearQuery near, Class<T> entityClass);
/**
* Returns {@link GeoResult} for all entities matching the given {@link NearQuery}.
*
* @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> GeoResults<T> geoNear(NearQuery near, Class<T> entityClass, String collectionName);
/**
* 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
* @param entityClass
* class that determines the collection to use
* @param entityClass class that determines the collection to use
*/
void ensureIndex(IndexDefinition indexDefinition, Class<?> entityClass);
@@ -274,8 +356,8 @@ public interface MongoOperations {
void ensureIndex(IndexDefinition indexDefinition, 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.
* 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 SimpleMongoConverter will be used.
@@ -283,11 +365,9 @@ public interface MongoOperations {
* 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
* @param query the query class that specifies the criteria used to find a record and also an optional fields
* specification
* @param entityClass
* the parameterized type of the returned list.
* @param entityClass the parameterized type of the returned list.
* @return the converted object
*/
<T> T findOne(Query query, Class<T> entityClass);
@@ -301,13 +381,11 @@ public interface MongoOperations {
* <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
*
* @param query the query class that specifies the criteria used to find a record and also an optional fields
* specification
* @param entityClass
* the parameterized type of the returned list.
* @param collectionName
* name of the collection to retrieve the objects from
* @param entityClass the parameterized type of the returned list.
* @param collectionName name of the collection to retrieve the objects from
*
* @return the converted object
*/
@@ -322,11 +400,9 @@ public interface MongoOperations {
* 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
* @param query the query class that specifies the criteria used to find a record and also an optional fields
* specification
* @param entityClass
* the parameterized type of the returned list.
* @param entityClass the parameterized type of the returned list.
* @return the List of converted objects
*/
<T> List<T> find(Query query, Class<T> entityClass);
@@ -339,13 +415,11 @@ public interface MongoOperations {
* <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
*
* @param query the query class that specifies the criteria used to find a record and also an optional fields
* specification
* @param entityClass
* the parameterized type of the returned list.
* @param collectionName
* name of the collection to retrieve the objects from
* @param entityClass the parameterized type of the returned list.
* @param collectionName name of the collection to retrieve the objects from
*
* @return the List of converted objects
*/
@@ -359,16 +433,13 @@ public interface MongoOperations {
* <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
*
* @param query the query class that specifies the criteria used to find a record and also an optional fields
* specification
* @param entityClass
* the parameterized type of the returned list.
* @param preparer
* allows for customization of the DBCursor used when iterating over the result set, (apply limits, skips and
* so on).
* @param collectionName
* name of the collection to retrieve the objects from
* @param entityClass the parameterized type of the returned list.
* @param preparer allows for customization of the DBCursor used when iterating over the result set, (apply limits,
* skips and so on).
* @param collectionName name of the collection to retrieve the objects from
*
* @return the List of converted objects.
*/
@@ -384,9 +455,10 @@ public interface MongoOperations {
* @return the document with the given id mapped onto the given target class.
*/
<T> 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
@@ -397,20 +469,18 @@ public interface MongoOperations {
<T> T findById(Object id, 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.
* 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}.
* 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
* 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 parameterized type of the returned list.
* @param query the query class that specifies the criteria used to find a record and also an optional fields
* specification
* @param entityClass the parameterized type of the returned list.
* @return the converted object
*/
<T> T findAndRemove(Query query, Class<T> entityClass);
@@ -424,13 +494,11 @@ public interface MongoOperations {
* <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
*
* @param query the query class that specifies the criteria used to find a record and also an optional fields
* specification
* @param entityClass
* the parameterized type of the returned list.
* @param collectionName
* name of the collection to retrieve the objects from
* @param entityClass the parameterized type of the returned list.
* @param collectionName name of the collection to retrieve the objects from
*
* @return the converted object
*/
@@ -450,8 +518,7 @@ public interface MongoOperations {
* <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 objectToSave the object to store in the collection.
*/
void insert(Object objectToSave);
@@ -462,44 +529,39 @@ public interface MongoOperations {
* configured otherwise, an instance of SimpleMongoConverter 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
*
* @param objectToSave the object to store in the collection
* @param collectionName name of the collection to store the object in
*/
void insert(Object objectToSave, String collectionName);
/**
* Insert a Collection of objects into a collection in a single batch write to the database.
*
* @param batchToSave
* the list of objects to save.
* @param entityClass
* class that determines the collection to use
* @param batchToSave the list of objects to save.
* @param entityClass class that determines the collection to use
*/
void insert(Collection<? extends Object> batchToSave, Class<?> entityClass);
/**
* Insert a list 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
*
* @param batchToSave the list of objects to save.
* @param collectionName name of the collection to store the object in
*/
void insert(Collection<? extends Object> batchToSave, String collectionName);
/**
* Insert a mixed Collection of objects into a database collection determining the
* collection name to use based on the class.
* Insert a mixed Collection of objects into a database collection determining the collection name to use based on the
* class.
*
* @param collectionToSave
* the list of objects to save.
* @param collectionToSave the list of objects to save.
*/
void insertAll(Collection<? extends Object> 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'.
* 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 SimpleMongoConverter will be used.
@@ -510,8 +572,7 @@ public interface MongoOperations {
* See <a href="http://static.springsource.org/spring/docs/3.0.x/reference/validation.html#core-convert">Spring 3 Type
* Conversion"</a> for more details.
*
* @param objectToSave
* the object to store in the collection
* @param objectToSave the object to store in the collection
*/
void save(Object objectToSave);
@@ -527,58 +588,53 @@ public interface MongoOperations {
* property type will be handled by Spring's BeanWrapper class that leverages Spring 3.0's new Type Cobnversion API.
* See <a href="http://static.springsource.org/spring/docs/3.0.x/reference/validation.html#core-convert">Spring 3 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
*
* @param objectToSave the object to store in the collection
* @param collectionName name of the collection to store the object in
*/
void save(Object objectToSave, String collectionName);
/**
* Updates the first object that is found in the collection of the entity class that matches the query document with
* 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
*
* @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
*/
WriteResult 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
*
* @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
*/
WriteResult updateFirst(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
* 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
*
* @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
*/
WriteResult 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
*
* @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
*/
WriteResult updateMulti(Query query, Update update, String collectionName);
@@ -590,10 +646,8 @@ public interface MongoOperations {
void remove(Object object);
/**
* 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.
* 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 <T>
* @param query
@@ -602,13 +656,18 @@ public interface MongoOperations {
<T> void remove(Query query, Class<T> entityClass);
/**
* 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
* 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
*/
void remove(Query query, String collectionName);
/**
* Returns the underlying {@link MongoConverter}.
*
* @return
*/
MongoConverter getConverter();
}

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb;
package org.springframework.data.mongodb.core;
import com.mongodb.MongoOptions;
@@ -55,47 +55,44 @@ public class MongoOptionsFactoryBean implements FactoryBean<MongoOptions>, Initi
* socket timeout. 0 is default and infinite
*/
private int socketTimeout = MONGO_OPTIONS.socketTimeout;
/**
* This controls whether or not to have socket keep alive
* turned on (SO_KEEPALIVE).
*
* defaults to false
*/
public boolean socketKeepAlive = MONGO_OPTIONS.socketKeepAlive;
/**
* This controls whether or not to have socket keep alive turned on (SO_KEEPALIVE).
*
* defaults to false
*/
public boolean socketKeepAlive = MONGO_OPTIONS.socketKeepAlive;
/**
* this controls whether or not on a connect, the system retries automatically
*/
private boolean autoConnectRetry = MONGO_OPTIONS.autoConnectRetry;
/**
* This specifies the number of servers to wait for on the write operation, and exception raising behavior.
*
* Defaults to 0.
*/
private int writeNumber;
/**
* This controls timeout for write operations in milliseconds.
*
* Defaults to 0 (indefinite). Greater than zero is number of milliseconds to wait.
*/
private int writeTimeout;
/**
* This controls whether or not to fsync.
*
* Defaults to false.
*/
private boolean writeFsync;
/**
* Specifies if the driver is allowed to read from secondaries
* or slaves.
*
* Defaults to false
* This specifies the number of servers to wait for on the write operation, and exception raising behavior.
*
* Defaults to 0.
*/
private int writeNumber;
/**
* This controls timeout for write operations in milliseconds.
*
* Defaults to 0 (indefinite). Greater than zero is number of milliseconds to wait.
*/
private int writeTimeout;
/**
* This controls whether or not to fsync.
*
* Defaults to false.
*/
private boolean writeFsync;
/**
* Specifies if the driver is allowed to read from secondaries or slaves.
*
* Defaults to false
*/
private boolean slaveOk = MONGO_OPTIONS.slaveOk;
@@ -135,60 +132,64 @@ public class MongoOptionsFactoryBean implements FactoryBean<MongoOptions>, Initi
public void setSocketTimeout(int socketTimeout) {
this.socketTimeout = socketTimeout;
}
/**
* This controls whether or not to have socket keep alive
*
* @param socketKeepAlive
*/
public void setSocketKeepAlive(boolean socketKeepAlive) {
this.socketKeepAlive = socketKeepAlive;
}
/**
* This specifies the number of servers to wait for on the write operation, and exception raising behavior.
* The 'w' option to the getlasterror command. Defaults to 0.
* <ul>
* <li>-1 = don't even report network errors </li>
* <li> 0 = default, don't call getLastError by default </li>
* <li> 1 = basic, call getLastError, but don't wait for slaves</li>
* <li> 2+= wait for slaves </li>
* </ul>
* @param writeNumber the number of servers to wait for on the write operation, and exception raising behavior.
*/
public void setWriteNumber(int writeNumber) {
this.writeNumber = writeNumber;
}
public void setSocketKeepAlive(boolean socketKeepAlive) {
this.socketKeepAlive = socketKeepAlive;
}
/**
* This controls timeout for write operations in milliseconds. The 'wtimeout' option to the getlasterror command.
*
* @param writeTimeout Defaults to 0 (indefinite). Greater than zero is number of milliseconds to wait.
* This specifies the number of servers to wait for on the write operation, and exception raising behavior. The 'w'
* option to the getlasterror command. Defaults to 0.
* <ul>
* <li>-1 = don't even report network errors</li>
* <li>0 = default, don't call getLastError by default</li>
* <li>1 = basic, call getLastError, but don't wait for slaves</li>
* <li>2+= wait for slaves</li>
* </ul>
*
* @param writeNumber the number of servers to wait for on the write operation, and exception raising behavior.
*/
public void setWriteTimeout(int writeTimeout) {
this.writeTimeout = writeTimeout;
}
public void setWriteNumber(int writeNumber) {
this.writeNumber = writeNumber;
}
/**
* This controls whether or not to fsync. The 'fsync' option to the getlasterror command. Defaults to false.
* @param writeFsync to fsync on write (true), otherwise false.
*/
public void setWriteFsync(boolean writeFsync) {
this.writeFsync = writeFsync;
}
/**
* This controls timeout for write operations in milliseconds. The 'wtimeout' option to the getlasterror command.
*
* @param writeTimeout Defaults to 0 (indefinite). Greater than zero is number of milliseconds to wait.
*/
public void setWriteTimeout(int writeTimeout) {
this.writeTimeout = writeTimeout;
}
/**
/**
* This controls whether or not to fsync. The 'fsync' option to the getlasterror command. Defaults to false.
*
* @param writeFsync to fsync on write (true), otherwise false.
*/
public void setWriteFsync(boolean writeFsync) {
this.writeFsync = writeFsync;
}
/**
* this controls whether or not on a connect, the system retries automatically
*/
public void setAutoConnectRetry(boolean autoConnectRetry) {
this.autoConnectRetry = autoConnectRetry;
}
/**
* Specifies if the driver is allowed to read from secondaries or slaves. Defaults to false.
* Specifies if the driver is allowed to read from secondaries or slaves. Defaults to false.
*
* @param slaveOk true if the driver should read from secondaries or slaves.
*/
public void setSlaveOk(boolean slaveOk) {
this.slaveOk = slaveOk;
this.slaveOk = slaveOk;
}
public void afterPropertiesSet() {
@@ -198,8 +199,8 @@ public class MongoOptionsFactoryBean implements FactoryBean<MongoOptions>, Initi
MONGO_OPTIONS.connectTimeout = connectTimeout;
MONGO_OPTIONS.socketTimeout = socketTimeout;
MONGO_OPTIONS.socketKeepAlive = socketKeepAlive;
MONGO_OPTIONS.autoConnectRetry = autoConnectRetry;
MONGO_OPTIONS.slaveOk = slaveOk;
MONGO_OPTIONS.autoConnectRetry = autoConnectRetry;
MONGO_OPTIONS.slaveOk = slaveOk;
MONGO_OPTIONS.w = writeNumber;
MONGO_OPTIONS.wtimeout = writeTimeout;
MONGO_OPTIONS.fsync = writeFsync;

View File

@@ -1,4 +1,4 @@
package org.springframework.data.document.mongodb;
package org.springframework.data.mongodb.core;
import org.springframework.transaction.support.ResourceHolder;
import org.springframework.transaction.support.ResourceHolderSynchronization;

View File

@@ -13,46 +13,48 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb.query;
package org.springframework.data.mongodb.core;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import org.bson.types.BasicBSONList;
import org.bson.types.ObjectId;
import org.springframework.core.convert.ConversionException;
import org.springframework.data.document.mongodb.convert.MongoConverter;
import org.springframework.data.document.mongodb.mapping.MongoPersistentEntity;
import org.springframework.data.mapping.model.PersistentEntity;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.util.Assert;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* A helper class to encapsulate any modifications of a Query object before it gets submitted to the database.
*
*
* @author Jon Brisbin <jbrisbin@vmware.com>
* @author Oliver Gierke
*/
public class QueryMapper {
private final MongoConverter converter;
private final ConversionService conversionService;
/**
* Creates a new {@link QueryMapper} with the given {@link MongoConverter}.
*
* @param converter
* Creates a new {@link QueryMapper} with the given {@link ConversionService}.
*
* @param conversionService must not be {@literal null}.
*/
public QueryMapper(MongoConverter converter) {
Assert.notNull(converter);
this.converter = converter;
public QueryMapper(ConversionService conversionService) {
Assert.notNull(conversionService);
this.conversionService = conversionService;
}
/**
* Replaces the property keys used in the given {@link DBObject} with the appropriate keys by using the
* {@link PersistentEntity} metadata.
*
*
* @param query
* @param entity
* @return
@@ -78,33 +80,22 @@ public class QueryMapper {
String inKey = valueDbo.containsField("$in") ? "$in" : "$nin";
List<Object> ids = new ArrayList<Object>();
for (Object id : (Object[]) valueDbo.get(inKey)) {
if (null != converter && !(id instanceof ObjectId)) {
try {
ObjectId oid = converter.convertObjectId(id);
ids.add(oid);
} catch (ConversionException ignored) {
ids.add(id);
}
} else {
ids.add(id);
}
ids.add(convertId(id));
}
valueDbo.put(inKey, ids.toArray(new Object[ids.size()]));
} else {
value = getMappedObject((DBObject) value, entity);
}
} else if (null != converter) {
try {
value = converter.convertObjectId(value);
} catch (ConversionException ignored) {
}
} else {
value = convertId(value);
}
newKey = "_id";
} else if (key.startsWith("$") && key.endsWith("or")) {
// $or/$nor
BasicBSONList conditions = (BasicBSONList) value;
BasicBSONList newConditions = new BasicBSONList();
Iterator iter = conditions.iterator();
Iterator<Object> iter = conditions.iterator();
while (iter.hasNext()) {
newConditions.add(getMappedObject((DBObject) iter.next(), entity));
}
@@ -117,4 +108,28 @@ public class QueryMapper {
return newDbo;
}
/**
* Converts the given raw id value into either {@link ObjectId} or {@link String}.
*
* @param id
* @return
*/
@SuppressWarnings("unchecked")
public Object convertId(Object id) {
for (Class<?> type : Arrays.asList(ObjectId.class, String.class)) {
if (id.getClass().isAssignableFrom(type)) {
return id;
}
try {
return conversionService.convert(id, type);
} catch (ConversionException e) {
// Ignore
}
}
return id;
}
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright 2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.dao.DataAccessException;
import org.springframework.data.authentication.UserCredentials;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.util.Assert;
import com.mongodb.DB;
import com.mongodb.Mongo;
import com.mongodb.WriteConcern;
/**
* Factory to create {@link DB} instances from a {@link Mongo} instance.
*
* @author Mark Pollack
* @author Oliver Gierke
*/
public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
protected final Log logger = LogFactory.getLog(getClass());
private final Mongo mongo;
private final String databaseName;
private String username;
private String password;
private WriteConcern writeConcern;
/**
* Create an instance of {@link SimpleMongoDbFactory} given the {@link Mongo} instance and database name.
*
* @param mongo Mongo instance, must not be {@literal null}.
* @param databaseName database name, not be {@literal null}.
*/
public SimpleMongoDbFactory(Mongo mongo, String databaseName) {
Assert.notNull(mongo, "Mongo 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 = mongo;
this.databaseName = databaseName;
}
/**
* Create an instance of SimpleMongoDbFactory given the Mongo instance, database name, and username/password
*
* @param mongo Mongo instance, must not be {@literal null}.
* @param databaseName Database name, must not be {@literal null}.
* @param userCredentials username and password must not be {@literal null}.
*/
public SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials userCredentials) {
this(mongo, databaseName);
this.username = userCredentials.getUsername();
this.password = userCredentials.getPassword();
}
/**
* Configures the {@link WriteConcern} to be used on the {@link DB} instance being created.
*
* @param writeConcern the writeConcern to set
*/
public void setWriteConcern(WriteConcern writeConcern) {
this.writeConcern = writeConcern;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.MongoDbFactory#getDb()
*/
public DB getDb() throws DataAccessException {
return getDb(databaseName);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.MongoDbFactory#getDb(java.lang.String)
*/
public DB getDb(String dbName) throws DataAccessException {
Assert.hasText(dbName, "Database name must not be empty.");
DB db = MongoDbUtils.getDB(mongo, dbName, username, password == null ? null : password.toCharArray());
if (writeConcern != null) {
db.setWriteConcern(writeConcern);
}
return db;
}
/**
* Clean up the Mongo instance.
*/
public void destroy() throws Exception {
mongo.close();
}
}

View File

@@ -1,4 +1,4 @@
package org.springframework.data.document.mongodb;
package org.springframework.data.mongodb.core;
public enum WriteResultChecking {
NONE, LOG, EXCEPTION

View File

@@ -0,0 +1,107 @@
/*
* Copyright (c) 2011 by the original author(s).
*
* 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.math.BigInteger;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.ConversionServiceFactory;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.data.mongodb.core.convert.MongoConverters.BigIntegerToObjectIdConverter;
import org.springframework.data.mongodb.core.convert.MongoConverters.BigIntegerToStringConverter;
import org.springframework.data.mongodb.core.convert.MongoConverters.ObjectIdToBigIntegerConverter;
import org.springframework.data.mongodb.core.convert.MongoConverters.ObjectIdToStringConverter;
import org.springframework.data.mongodb.core.convert.MongoConverters.StringToBigIntegerConverter;
import org.springframework.data.mongodb.core.convert.MongoConverters.StringToObjectIdConverter;
/**
* Base class for {@link MongoConverter} implementations. Sets up a {@link GenericConversionService} and populates basic
* converters. Allows registering {@link CustomConversions}.
*
* @author Jon Brisbin <jbrisbin@vmware.com>
* @author Oliver Gierke ogierke@vmware.com
*/
public abstract class AbstractMongoConverter implements MongoConverter, InitializingBean {
protected final GenericConversionService conversionService;
protected CustomConversions conversions = new CustomConversions();
/**
* Creates a new {@link AbstractMongoConverter} using the given {@link GenericConversionService}.
*
* @param conversionService
*/
public AbstractMongoConverter(GenericConversionService conversionService) {
this.conversionService = conversionService == null ? ConversionServiceFactory.createDefaultConversionService()
: conversionService;
this.conversionService.removeConvertible(Object.class, String.class);
}
/**
* Registers the given custom conversions with the converter.
*
* @param conversions
*/
public void setCustomConversions(CustomConversions conversions) {
this.conversions = conversions;
}
/**
* Registers additional converters that will be available when using the {@link ConversionService} directly (e.g. for
* id conversion). These converters are not custom conversions as they'd introduce unwanted conversions (e.g.
* ObjectId-to-String).
*/
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);
}
if (!conversionService.canConvert(ObjectId.class, BigInteger.class)) {
conversionService.addConverter(ObjectIdToBigIntegerConverter.INSTANCE);
}
if (!conversionService.canConvert(BigInteger.class, ObjectId.class)) {
conversionService.addConverter(BigIntegerToObjectIdConverter.INSTANCE);
}
if (!conversionService.canConvert(BigInteger.class, String.class)) {
conversionService.addConverter(BigIntegerToStringConverter.INSTANCE);
}
if (!conversionService.canConvert(String.class, BigInteger.class)) {
conversionService.addConverter(StringToBigIntegerConverter.INSTANCE);
}
conversions.registerConvertersIn(conversionService);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.core.convert.MongoConverter#getConversionService()
*/
public ConversionService getConversionService() {
return conversionService;
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() {
initializeConverters();
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright 2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.convert;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert;
/**
* {@link TypeMapper} allowing to configure a {@link Map} containing {@link Class} to {@link String} mappings that will
* be used to map the values found under the configured type key (see {@link DefaultTypeMapper#setTypeKey(String)}. This
* allows declarative type mapping in a Spring config file for example.
*
* @author Oliver Gierke
*/
public class ConfigurableTypeMapper extends DefaultTypeMapper {
private final Map<TypeInformation<?>, String> typeMap;
private boolean handleUnmappedClasses = false;
/**
* Creates a new {@link ConfigurableTypeMapper} for the given type map.
*
* @param sourceTypeMap must not be {@literal null}.
*/
public ConfigurableTypeMapper(Map<? extends Class<?>, String> sourceTypeMap) {
Assert.notNull(sourceTypeMap);
this.typeMap = new HashMap<TypeInformation<?>, String>(sourceTypeMap.size());
for (Entry<? extends Class<?>, String> entry : sourceTypeMap.entrySet()) {
TypeInformation<?> key = ClassTypeInformation.from(entry.getKey());
String value = entry.getValue();
if (typeMap.containsValue(value)) {
throw new IllegalArgumentException(String.format(
"Detected mapping ambiguity! String %s cannot be mapped to more than one type!", value));
}
this.typeMap.put(key, value);
}
}
/**
* Configures whether to try to handle unmapped classes by simply writing the class' name or loading the class as
* specified in the superclass. Defaults to {@literal false}.
*
* @param handleUnmappedClasses the handleUnmappedClasses to set
*/
public void setHandleUnmappedClasses(boolean handleUnmappedClasses) {
this.handleUnmappedClasses = handleUnmappedClasses;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.convert.DefaultTypeMapper#getTypeInformation(java.lang.String)
*/
@Override
protected TypeInformation<?> getTypeInformation(String value) {
for (Entry<TypeInformation<?>, String> entry : typeMap.entrySet()) {
if (entry.getValue().equals(value)) {
return entry.getKey();
}
}
return handleUnmappedClasses ? super.getTypeInformation(value) : null;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.convert.DefaultTypeMapper#getTypeString(org.springframework.data.util.TypeInformation)
*/
@Override
protected String getTypeString(TypeInformation<?> typeInformation) {
String key = typeMap.get(typeInformation);
return key != null ? key : handleUnmappedClasses ? super.getTypeString(typeInformation) : null;
}
}

View File

@@ -0,0 +1,298 @@
/*
* Copyright (c) 2011 by the original author(s).
*
* 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.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.bson.types.ObjectId;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.core.convert.converter.GenericConverter.ConvertiblePair;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.mongodb.core.convert.MongoConverters.BigDecimalToStringConverter;
import org.springframework.data.mongodb.core.convert.MongoConverters.StringToBigDecimalConverter;
import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes;
import org.springframework.util.Assert;
import com.mongodb.DBObject;
/**
* Value object to capture custom conversion. That is essentially a {@link List} of converters and some additional logic
* around them. The converters are pretty much builds up two sets of types which Mongo basic types {@see #MONGO_TYPES}
* can be converted into and from. These types will be considered simple ones (which means they neither need deeper
* inspection nor nested conversion. Thus the {@link CustomConversions} also act as factory for {@link SimpleTypeHolder}
* .
*
* @author Oliver Gierke
*/
public class CustomConversions {
@SuppressWarnings({ "unchecked" })
private static final List<Class<?>> MONGO_TYPES = Arrays.asList(Number.class, Date.class, ObjectId.class,
String.class, DBObject.class);
private final Set<ConvertiblePair> readingPairs;
private final Set<ConvertiblePair> writingPairs;
private final Set<Class<?>> customSimpleTypes;
private final SimpleTypeHolder simpleTypeHolder;
private final List<Object> converters;
/**
* Creates an empty {@link CustomConversions} object.
*/
CustomConversions() {
this(new ArrayList<Object>());
}
/**
* Creates a new {@link CustomConversions} instance registering the given converters.
*
* @param converters
*/
public CustomConversions(List<?> converters) {
Assert.notNull(converters);
this.readingPairs = new HashSet<ConvertiblePair>();
this.writingPairs = new HashSet<ConvertiblePair>();
this.customSimpleTypes = new HashSet<Class<?>>();
this.converters = new ArrayList<Object>();
this.converters.add(CustomToStringConverter.INSTANCE);
this.converters.add(BigDecimalToStringConverter.INSTANCE);
this.converters.add(StringToBigDecimalConverter.INSTANCE);
this.converters.addAll(converters);
for (Object c : this.converters) {
registerConversion(c);
}
this.simpleTypeHolder = new SimpleTypeHolder(customSimpleTypes, MongoSimpleTypes.HOLDER);
}
/**
* Returns the underlying {@link SimpleTypeHolder}.
*
* @return
*/
public SimpleTypeHolder getSimpleTypeHolder() {
return simpleTypeHolder;
}
/**
* Returns whether the given type is considered to be simple.
*
* @param type
* @return
*/
public boolean isSimpleType(Class<?> type) {
return simpleTypeHolder.isSimpleType(type);
}
/**
* Populates the given {@link GenericConversionService} with the convertes registered.
*
* @param conversionService
*/
public void registerConvertersIn(GenericConversionService conversionService) {
for (Object converter : converters) {
boolean added = false;
if (converter instanceof Converter) {
conversionService.addConverter((Converter<?, ?>) converter);
added = true;
}
if (converter instanceof ConverterFactory) {
conversionService.addConverterFactory((ConverterFactory<?, ?>) converter);
added = true;
}
if (converter instanceof GenericConverter) {
conversionService.addConverter((GenericConverter) converter);
added = true;
}
if (!added) {
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}.
*
* @param converter
*/
private void registerConversion(Object converter) {
if (converter instanceof GenericConverter) {
GenericConverter genericConverter = (GenericConverter) converter;
for (ConvertiblePair pair : genericConverter.getConvertibleTypes()) {
register(pair);
}
} else if (converter instanceof Converter) {
Class<?>[] arguments = GenericTypeResolver.resolveTypeArguments(converter.getClass(), Converter.class);
register(new ConvertiblePair(arguments[0], arguments[1]));
} else {
throw new IllegalArgumentException("Unsupported Converter type!");
}
}
/**
* Registers the given {@link ConvertiblePair} as reading or writing pair depending on the type sides being basic
* Mongo types.
*
* @param pair
*/
private void register(ConvertiblePair pair) {
if (isMongoBasicType(pair.getSourceType())) {
readingPairs.add(pair);
customSimpleTypes.add(pair.getTargetType());
}
if (isMongoBasicType(pair.getTargetType())) {
writingPairs.add(pair);
customSimpleTypes.add(pair.getSourceType());
}
}
/**
* Returns the target type to convert to in case we have a custom conversion registered to convert the given source
* type into a Mongo native one.
*
* @param source must not be {@literal null}
* @return
*/
public Class<?> getCustomWriteTarget(Class<?> source) {
return getCustomWriteTarget(source, null);
}
/**
* Returns the target type we can write an onject of the given source type to. The returned type might be a subclass
* oth the given expected type though. If {@code expexctedTargetType} is {@literal null} we will simply return the
* first target type matching or {@literal null} if no conversion can be found.
*
* @param source must not be {@literal null}
* @param expectedTargetType
* @return
*/
public Class<?> getCustomWriteTarget(Class<?> source, Class<?> expectedTargetType) {
Assert.notNull(source);
return getCustomTarget(source, expectedTargetType, writingPairs);
}
/**
* Returns whether we have a custom conversion registered to write into a Mongo native type. The returned type might
* be a subclass oth the given expected type though.
*
* @param source must not be {@literal null}
* @return
*/
public boolean hasCustomWriteTarget(Class<?> source) {
return hasCustomWriteTarget(source, null);
}
/**
* Returns whether we have a custom conversion registered to write an object of the given source type into an object
* of the given Mongo native target type.
*
* @param source must not be {@literal null}.
* @param expectedTargetType
* @return
*/
public boolean hasCustomWriteTarget(Class<?> source, Class<?> expectedTargetType) {
return getCustomWriteTarget(source, expectedTargetType) != null;
}
/**
* Returns whether we have a custom conversion registered to read the given source into the given target type.
*
* @param source must not be {@literal null}
* @param expectedTargetType must not be {@literal null}
* @return
*/
public boolean hasCustomReadTarget(Class<?> source, Class<?> expectedTargetType) {
Assert.notNull(source);
Assert.notNull(expectedTargetType);
return getCustomTarget(source, expectedTargetType, readingPairs) != null;
}
/**
* Inspects the given {@link ConvertiblePair} for ones that have a source compatible type as source. Additionally
* checks assignabilty of the target type if one is given.
*
* @param source must not be {@literal null}
* @param expectedTargetType
* @param pairs must not be {@literal null}
* @return
*/
private static Class<?> getCustomTarget(Class<?> source, Class<?> expectedTargetType, Iterable<ConvertiblePair> pairs) {
Assert.notNull(source);
Assert.notNull(pairs);
for (ConvertiblePair typePair : pairs) {
if (typePair.getSourceType().isAssignableFrom(source)) {
Class<?> targetType = typePair.getTargetType();
if (expectedTargetType == null || targetType.isAssignableFrom(expectedTargetType)) {
return targetType;
}
}
}
return null;
}
/**
* Returns whether the given type is a type that Mongo can handle basically.
*
* @param type
* @return
*/
private static boolean isMongoBasicType(Class<?> type) {
return MONGO_TYPES.contains(type);
}
private enum CustomToStringConverter implements GenericConverter {
INSTANCE;
public Set<ConvertiblePair> getConvertibleTypes() {
ConvertiblePair localeToString = new ConvertiblePair(Locale.class, String.class);
ConvertiblePair booleanToString = new ConvertiblePair(Character.class, String.class);
return new HashSet<ConvertiblePair>(Arrays.asList(localeToString, booleanToString));
}
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
return source.toString();
}
}
}

View File

@@ -0,0 +1,147 @@
/*
* Copyright 2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.convert;
import java.util.List;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import com.mongodb.BasicDBList;
import com.mongodb.DBObject;
/**
* Default implementation of {@link TypeMapper} 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} conversion and back
* is done in {@link #getTypeString(TypeInformation)} or {@link #getTypeInformation(String)} respectively.
*
* @author Oliver Gierke
*/
public class DefaultTypeMapper implements TypeMapper {
public static final String DEFAULT_TYPE_KEY = "_class";
@SuppressWarnings("rawtypes")
private static final TypeInformation<List> LIST_TYPE_INFORMATION = ClassTypeInformation.from(List.class);
private String typeKey = DEFAULT_TYPE_KEY;
/**
* Sets the key to store the type information under. If set to {@literal null} no type information will be stored in
* the document.
*
* @param typeKey the typeKey to set
*/
public void setTypeKey(String typeKey) {
this.typeKey = typeKey;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.convert.TypeMapper#isTypeKey(java.lang.String)
*/
public boolean isTypeKey(String key) {
return typeKey == null ? false : typeKey.equals(key);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.convert.TypeMapper#readType(com.mongodb.DBObject)
*/
public TypeInformation<?> readType(DBObject dbObject) {
if (dbObject instanceof BasicDBList) {
return LIST_TYPE_INFORMATION;
}
if (typeKey == null) {
return null;
}
Object classToBeUsed = dbObject.get(typeKey);
if (classToBeUsed == null) {
return null;
}
return getTypeInformation(classToBeUsed.toString());
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.convert.TypeMapper#writeType(java.lang.Class, com.mongodb.DBObject)
*/
public void writeType(Class<?> type, DBObject dbObject) {
writeType(ClassTypeInformation.from(type), dbObject);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.convert.TypeMapper#writeType(java.lang.Class, com.mongodb.DBObject)
*/
public void writeType(TypeInformation<?> info, DBObject dbObject) {
Assert.notNull(info);
if (typeKey == null) {
return;
}
String string = getTypeString(info);
if (string != null) {
dbObject.put(typeKey, getTypeString(info));
}
}
/**
* Turn the given type information into the String representation that shall be stored inside the {@link DBObject}. If
* the returned String is {@literal null} no type information will be stored. Default implementation simply returns
* the fully-qualified class name.
*
* @param typeInformation must not be {@literal null}.
* @return the String representation to be stored or {@literal null} if no type information shall be stored.
*/
protected String getTypeString(TypeInformation<?> typeInformation) {
return typeInformation.getType().getName();
}
/**
* Returns the {@link TypeInformation} that shall be used when the given {@link String} value is found as type hint.
* The default implementation will simply interpret the given value as fully-qualified class name and try to load the
* class. Will return {@literal null} in case the given {@link String} is empty. Will not be called in case no
* {@link String} was found for the configured type key at all.
*
* @param value the type to load, must not be {@literal null}.
* @return the type to be used for the given {@link String} representation or {@literal null} if nothing found or the
* class cannot be loaded.
*/
protected TypeInformation<?> getTypeInformation(String value) {
if (!StringUtils.hasText(value)) {
return null;
}
try {
return ClassTypeInformation.from(ClassUtils.forName(value, null));
} catch (ClassNotFoundException e) {
return null;
}
}
}

View File

@@ -14,9 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.document.mongodb.convert;
import static org.springframework.data.mapping.MappingBeanHelper.*;
package org.springframework.data.mongodb.core.convert;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
@@ -24,7 +22,9 @@ import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -44,18 +44,18 @@ import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.core.CollectionFactory;
import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.support.ConversionServiceFactory;
import org.springframework.data.document.mongodb.MongoDbFactory;
import org.springframework.data.document.mongodb.mapping.MongoPersistentEntity;
import org.springframework.data.document.mongodb.mapping.MongoPersistentProperty;
import org.springframework.data.mapping.Association;
import org.springframework.data.mapping.AssociationHandler;
import org.springframework.data.mapping.BeanWrapper;
import org.springframework.data.mapping.PreferredConstructor;
import org.springframework.data.mapping.PropertyHandler;
import org.springframework.data.mapping.model.Association;
import org.springframework.data.mapping.model.MappingContext;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.BeanWrapper;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mapping.model.ParameterValueProvider;
import org.springframework.data.mapping.model.PreferredConstructor;
import org.springframework.data.mapping.model.SpELAwareParameterValueProvider;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
import org.springframework.expression.Expression;
@@ -68,62 +68,95 @@ import org.springframework.util.StringUtils;
/**
* {@link MongoConverter} that uses a {@link MappingContext} to do sophisticated mapping of domain objects to
* {@link DBObject}.
*
*
* @author Jon Brisbin <jbrisbin@vmware.com>
* @author Oliver Gierke
*/
public class MappingMongoConverter extends AbstractMongoConverter implements ApplicationContextAware {
public class MappingMongoConverter extends AbstractMongoConverter implements ApplicationContextAware,
TypeMapperProvider {
public static final String CUSTOM_TYPE_KEY = "_class";
@SuppressWarnings("rawtypes")
private static final TypeInformation<Map> MAP_TYPE_INFORMATION = ClassTypeInformation.from(Map.class);
private static final List<Class<?>> VALID_ID_TYPES = Arrays.asList(new Class<?>[] { ObjectId.class, String.class,
BigInteger.class, byte[].class });
private static final List<Class<?>> VALID_ID_TYPES = Arrays.asList(new Class<?>[]{ObjectId.class, String.class,
BigInteger.class, byte[].class});
protected static final Log log = LogFactory.getLog(MappingMongoConverter.class);
protected final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
protected final SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
protected final MongoDbFactory mongoDbFactory;
protected ApplicationContext applicationContext;
protected boolean useFieldAccessOnly = true;
protected MongoDbFactory mongoDbFactory;
protected TypeMapper typeMapper = new DefaultTypeMapper();
/**
* Creates a new {@link MappingMongoConverter} given the new {@link MongoDbFactory} and {@link MappingContext}.
*
* @param mongoDbFactory
* @param mappingContext
*
* @param mongoDbFactory must not be {@literal null}.
* @param mappingContext must not be {@literal null}.
*/
public MappingMongoConverter(MongoDbFactory mongoDbFactory, MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
public MappingMongoConverter(MongoDbFactory mongoDbFactory,
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
super(ConversionServiceFactory.createDefaultConversionService());
Assert.notNull(mappingContext);
Assert.notNull(mongoDbFactory);
Assert.notNull(mappingContext);
this.mongoDbFactory = mongoDbFactory;
this.mappingContext = mappingContext;
}
/**
* Configures the {@link TypeMapper} to be used to add type information to {@link DBObject}s created by the converter
* and how to lookup type information from {@link DBObject}s when reading them. Uses a {@link DefaultTypeMapper} by
* default. Setting this to {@literal null} will reset the {@link TypeMapper} to the default one.
*
* @param typeMapper the typeMapper to set
*/
public void setTypeMapper(TypeMapper typeMapper) {
this.typeMapper = typeMapper == null ? new DefaultTypeMapper() : typeMapper;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.convert.MongoConverter#getTypeMapper()
*/
public TypeMapper getTypeMapper() {
return this.typeMapper;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.core.convert.MongoConverter#getMappingContext()
*/
public MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> getMappingContext() {
return mappingContext;
}
public void setMongoDbFactory(MongoDbFactory mongoDbFactory) {
this.mongoDbFactory = mongoDbFactory;
}
public boolean isUseFieldAccessOnly() {
return useFieldAccessOnly;
}
/**
* Configures whether to use field access only for entity mapping. Setting this to true will force the
* {@link MongoConverter} to not go through getters or setters even if they are present for getting and setting
* property values.
*
* @param useFieldAccessOnly
*/
public void setUseFieldAccessOnly(boolean useFieldAccessOnly) {
this.useFieldAccessOnly = useFieldAccessOnly;
}
public <T> T convertObjectId(ObjectId id, Class<T> targetType) {
return conversionService.convert(id, targetType);
}
public ObjectId convertObjectId(Object id) {
return conversionService.convert(id, ObjectId.class);
/*
* (non-Javadoc)
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.core.MongoReader#read(java.lang.Class, com.mongodb.DBObject)
*/
public <S extends Object> S read(Class<S> clazz, final DBObject dbo) {
return read(ClassTypeInformation.from(clazz), dbo);
}
@@ -137,31 +170,17 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
TypeInformation<? extends S> typeToUse = getMoreConcreteTargetType(dbo, type);
Class<? extends S> rawType = typeToUse.getType();
Class<?> customTarget = getCustomTarget(rawType, DBObject.class);
if (customTarget != null) {
if (conversions.hasCustomReadTarget(dbo.getClass(), rawType)) {
return conversionService.convert(dbo, rawType);
}
if (typeToUse.isCollectionLike() && dbo instanceof BasicDBList) {
List<Object> l = new ArrayList<Object>();
BasicDBList dbList = (BasicDBList) dbo;
for (Object o : dbList) {
if (o instanceof DBObject) {
return (S) readCollectionOrArray(typeToUse, (BasicDBList) dbo);
}
Object newObj = read(typeToUse.getComponentType(), (DBObject) o);
Class<?> rawComponentType = typeToUse.getComponentType().getType();
if (newObj.getClass().isAssignableFrom(rawComponentType)) {
l.add(newObj);
} else {
l.add(conversionService.convert(newObj, rawComponentType));
}
} else {
l.add(o);
}
}
return conversionService.convert(l, rawType);
if (typeToUse.isMap()) {
return (S) readMap(typeToUse, dbo);
}
// Retrieve persistent entity info
@@ -181,7 +200,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
spelCtx.setBeanResolver(new BeanFactoryResolver(applicationContext));
}
if (!(dbo instanceof BasicDBList)) {
String[] keySet = dbo.keySet().toArray(new String[]{});
String[] keySet = dbo.keySet().toArray(new String[] {});
for (String key : keySet) {
spelCtx.setVariable(key, dbo.get(key));
}
@@ -210,8 +229,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
return read(type, ((DBRef) obj).fetch());
} else if (obj instanceof BasicDBList) {
BasicDBList objAsDbList = (BasicDBList) obj;
List<?> l = unwrapList(objAsDbList, type);
return conversionService.convert(l, rawType);
return conversionService.convert(readCollectionOrArray(type, objAsDbList), rawType);
} else if (obj instanceof DBObject) {
return read(type, ((DBObject) obj));
} else if (null != obj && obj.getClass().isAssignableFrom(rawType)) {
@@ -269,8 +287,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
/**
* Root entry method into write conversion. Adds a type discriminator to the {@link DBObject}. Shouldn't be called for
* nested conversions.
*
* @see org.springframework.data.document.mongodb.MongoWriter#write(java.lang.Object, com.mongodb.DBObject)
*
* @see org.springframework.data.mongodb.core.core.convert.MongoWriter#write(java.lang.Object, com.mongodb.DBObject)
*/
public void write(final Object obj, final DBObject dbo) {
@@ -278,10 +296,10 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
return;
}
boolean handledByCustomConverter = getCustomTarget(obj.getClass(), DBObject.class) != null;
boolean handledByCustomConverter = conversions.getCustomWriteTarget(obj.getClass(), DBObject.class) != null;
if (!handledByCustomConverter) {
dbo.put(CUSTOM_TYPE_KEY, obj.getClass().getName());
typeMapper.writeType(ClassTypeInformation.from(obj.getClass()), dbo);
}
writeInternal(obj, dbo);
@@ -289,7 +307,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
/**
* Internal write conversion method which should be used for nested invocations.
*
*
* @param obj
* @param dbo
*/
@@ -300,7 +318,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
return;
}
Class<?> customTarget = getCustomTarget(obj.getClass(), DBObject.class);
Class<?> customTarget = conversions.getCustomWriteTarget(obj.getClass(), DBObject.class);
if (customTarget != null) {
DBObject result = conversionService.convert(obj, DBObject.class);
@@ -333,10 +351,10 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
final MongoPersistentProperty idProperty = entity.getIdProperty();
if (!dbo.containsField("_id") && null != idProperty) {
Object idObj = null;
Class<?>[] targetClasses = new Class<?>[]{ObjectId.class, Object.class};
for (Class<?> targetClasse : targetClasses) {
Class<?>[] targetClasses = new Class<?>[] { ObjectId.class, String.class, Object.class };
for (Class<?> targetClass : targetClasses) {
try {
idObj = wrapper.getProperty(idProperty, targetClasse, useFieldAccessOnly);
idObj = wrapper.getProperty(idProperty, targetClass, useFieldAccessOnly);
if (null != idObj) {
break;
}
@@ -373,10 +391,10 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
throw new MappingException(e.getMessage(), e);
}
if (null != propertyObj) {
if (!isSimpleType(propertyObj.getClass())) {
writePropertyInternal(prop, propertyObj, dbo);
if (!conversions.isSimpleType(propertyObj.getClass())) {
writePropertyInternal(propertyObj, dbo, prop);
} else {
writeSimpleInternal(prop.getFieldName(), propertyObj, dbo);
writeSimpleInternal(propertyObj, dbo, prop.getFieldName());
}
}
}
@@ -395,18 +413,14 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
throw new MappingException(e.getMessage(), e);
}
if (null != propertyObj) {
writePropertyInternal(inverseProp, propertyObj, dbo);
writePropertyInternal(propertyObj, dbo, inverseProp);
}
}
});
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@SuppressWarnings({"unchecked"})
protected void writePropertyInternal(MongoPersistentProperty prop, Object obj, DBObject dbo) {
@SuppressWarnings({ "unchecked" })
protected void writePropertyInternal(Object obj, DBObject dbo, MongoPersistentProperty prop) {
if (obj == null) {
return;
@@ -415,14 +429,16 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
String name = prop.getFieldName();
if (prop.isCollection()) {
DBObject collectionInternal = writeCollectionInternal(prop, obj);
DBObject collectionInternal = createCollection(asCollection(obj), prop);
dbo.put(name, collectionInternal);
return;
}
TypeInformation<?> type = prop.getTypeInformation();
if (prop.isMap()) {
BasicDBObject mapDbObj = new BasicDBObject();
writeMapInternal((Map<Object, Object>) obj, mapDbObj, prop.getTypeInformation());
writeMapInternal((Map<Object, Object>) obj, mapDbObj, type);
dbo.put(name, mapDbObj);
return;
}
@@ -436,7 +452,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
}
// Lookup potential custom target type
Class<?> basicTargetType = getCustomTarget(obj.getClass(), null);
Class<?> basicTargetType = conversions.getCustomWriteTarget(obj.getClass(), null);
if (basicTargetType != null) {
dbo.put(name, conversionService.convert(obj, basicTargetType));
@@ -444,53 +460,93 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
}
BasicDBObject propDbObj = new BasicDBObject();
addCustomTypeKeyIfNecessary(prop.getTypeInformation(), obj, propDbObj);
writeInternal(obj, propDbObj, mappingContext.getPersistentEntity(prop.getTypeInformation()));
addCustomTypeKeyIfNecessary(type, obj, propDbObj);
MongoPersistentEntity<?> entity = isSubtype(prop.getType(), obj.getClass()) ? mappingContext
.getPersistentEntity(obj.getClass()) : mappingContext.getPersistentEntity(type);
writeInternal(obj, propDbObj, entity);
dbo.put(name, propDbObj);
}
@SuppressWarnings("unchecked")
protected DBObject writeCollectionInternal(MongoPersistentProperty property, Object obj) {
private boolean isSubtype(Class<?> left, Class<?> right) {
return left.isAssignableFrom(right) && !left.equals(right);
}
/**
* Returns given object as {@link Collection}. Will return the {@link Collection} as is if the source is a
* {@link Collection} already, will convert an array into a {@link Collection} or simply create a single element
* collection for everything else.
*
* @param source
* @return
*/
private static Collection<?> asCollection(Object source) {
if (source instanceof Collection) {
return (Collection<?>) source;
}
return source.getClass().isArray() ? CollectionUtils.arrayToList(source) : Collections.singleton(source);
}
/**
* Writes the given {@link Collection} using the given {@link MongoPersistentProperty} information.
*
* @param collection must not be {@literal null}.
* @param property must not be {@literal null}.
*
* @return
*/
protected DBObject createCollection(Collection<?> collection, MongoPersistentProperty property) {
if (!property.isDbReference()) {
return createCollectionDBObject(collection, property.getTypeInformation());
}
BasicDBList dbList = new BasicDBList();
Class<?> type = property.getType();
Collection<Object> coll = type.isArray() ? CollectionUtils.arrayToList(obj) : (Collection<Object>) obj;
TypeInformation<?> componentType = property.getTypeInformation().getComponentType();
for (Object element : coll) {
for (Object element : collection) {
if (element == null) {
continue;
}
TypeInformation<?> valueType = ClassTypeInformation.from(element.getClass());
DBRef dbRef = createDBRef(element, property.getDBRef());
dbList.add(dbRef);
}
if (property.isDbReference()) {
DBRef dbRef = createDBRef(element, property.getDBRef());
dbList.add(dbRef);
} else if (type.isArray() && isSimpleType(property.getComponentType())) {
dbList.add(element);
} else if (element instanceof List) {
List<?> propObjColl = (List<?>) element;
while (valueType.isCollectionLike()) {
valueType = valueType.getComponentType();
}
if (isSimpleType(valueType.getType())) {
dbList.add(propObjColl);
} else {
BasicDBList propNestedDbList = new BasicDBList();
for (Object propNestedObjItem : propObjColl) {
BasicDBObject propDbObj = new BasicDBObject();
writeInternal(propNestedObjItem, propDbObj);
propNestedDbList.add(propDbObj);
}
dbList.add(propNestedDbList);
}
} else if (isSimpleType(element.getClass())) {
dbList.add(element);
return dbList;
}
/**
* Creates a new {@link BasicDBList} from the given {@link Collection}.
*
* @param source the collection to create a {@link BasicDBList} for, must not be {@literal null}.
* @param type the {@link TypeInformation} to consider or {@literal null} if unknown.
* @return
*/
private BasicDBList createCollectionDBObject(Collection<?> source, TypeInformation<?> type) {
BasicDBList dbList = new BasicDBList();
TypeInformation<?> componentType = type == null ? null : type.getComponentType();
for (Object element : source) {
if (element == null) {
continue;
}
Class<?> elementType = element.getClass();
if (conversions.isSimpleType(elementType)) {
dbList.add(getPotentiallyConvertedSimpleWrite(element));
} else if (element instanceof Collection || elementType.isArray()) {
dbList.add(createCollectionDBObject(asCollection(element), componentType));
} else {
BasicDBObject propDbObj = new BasicDBObject();
writeInternal(element, propDbObj, mappingContext.getPersistentEntity(valueType));
writeInternal(element, propDbObj,
mappingContext.getPersistentEntity(ClassTypeInformation.from(element.getClass())));
addCustomTypeKeyIfNecessary(componentType, element, propDbObj);
dbList.add(propDbObj);
}
@@ -503,12 +559,14 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
for (Map.Entry<Object, Object> entry : obj.entrySet()) {
Object key = entry.getKey();
Object val = entry.getValue();
if (isSimpleType(key.getClass())) {
if (conversions.isSimpleType(key.getClass())) {
// Don't use conversion service here as removal of ObjectToString converter results in some primitive types not
// being convertable
String simpleKey = key.toString();
if (isSimpleType(val.getClass())) {
writeSimpleInternal(simpleKey, val, dbo);
if (val == null || conversions.isSimpleType(val.getClass())) {
writeSimpleInternal(val, dbo, simpleKey);
} else if (val instanceof Collection) {
dbo.put(simpleKey, createCollectionDBObject((Collection<?>) val, propertyType.getMapValueType()));
} else {
DBObject newDbo = new BasicDBObject();
writeInternal(val, newDbo);
@@ -524,74 +582,97 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
/**
* Adds custom type information to the given {@link DBObject} if necessary. That is if the value is not the same as
* the one given. This is usually the case if you store a subtype of the actual declared type of the property.
*
*
* @param type
* @param value
* @param dbObject
* @param value must not be {@literal null}.
* @param dbObject must not be {@literal null}.
*/
public void addCustomTypeKeyIfNecessary(TypeInformation<?> type, Object value, DBObject dbObject) {
protected void addCustomTypeKeyIfNecessary(TypeInformation<?> type, Object value, DBObject dbObject) {
if (type == null) {
return;
}
Class<?> reference = getValueType(type).getType();
Class<?> reference = type.getActualType().getType();
boolean notTheSameClass = !value.getClass().equals(reference);
if (notTheSameClass) {
dbObject.put(CUSTOM_TYPE_KEY, value.getClass().getName());
}
}
/**
* Returns the type type information of the actual value to be stored. That is, for maps it will return the map value
* type, for collections it will return the component type as well as the given type if it is a non-collection or
* non-map one.
*
* @param type
* @return
*/
public TypeInformation<?> getValueType(TypeInformation<?> type) {
if (type.isMap()) {
return type.getMapValueType();
} else if (type.isCollectionLike()) {
return type.getComponentType();
} else {
return type;
typeMapper.writeType(value.getClass(), dbObject);
}
}
/**
* Writes the given simple value to the given {@link DBObject}. Will store enum names for enum values.
*
* @param key
*
* @param value
* @param dbObject
* @param dbObject must not be {@literal null}.
* @param key must not be {@literal null}.
*/
private void writeSimpleInternal(String key, Object value, DBObject dbObject) {
Class<?> customTarget = getCustomTarget(value.getClass(), null);
Object valueToSet = null;
if (customTarget != null) {
valueToSet = conversionService.convert(value, customTarget);
} else {
valueToSet = value.getClass().isEnum() ? ((Enum<?>) value).name() : value;
}
dbObject.put(key, valueToSet);
private void writeSimpleInternal(Object value, DBObject dbObject, String key) {
dbObject.put(key, getPotentiallyConvertedSimpleWrite(value));
}
protected DBRef createDBRef(Object target, org.springframework.data.document.mongodb.mapping.DBRef dbref) {
/**
* Checks whether we have a custom conversion registered for the given value into an arbitrary simple Mongo type.
* Returns the converted value if so. If not, we perform special enum handling or simply return the value as is.
*
* @param value
* @return
*/
private Object getPotentiallyConvertedSimpleWrite(Object value) {
if (value == null) {
return null;
}
Class<?> customTarget = conversions.getCustomWriteTarget(value.getClass(), null);
if (customTarget != null) {
return conversionService.convert(value, customTarget);
} else {
return value.getClass().isEnum() ? ((Enum<?>) value).name() : value;
}
}
/**
* Checks whether we have a custom conversion for the given simple object. Converts the given value if so, applies
* {@link Enum} handling or returns the value as is.
*
* @param value
* @param target must not be {@literal null}.
* @return
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
private Object getPotentiallyConvertedSimpleRead(Object value, Class<?> target) {
Assert.notNull(target);
if (value == null) {
return null;
}
if (conversions.hasCustomReadTarget(value.getClass(), target)) {
return conversionService.convert(value, target);
}
if (target.isEnum()) {
return Enum.valueOf((Class<Enum>) target, value.toString());
}
return value;
}
protected DBRef createDBRef(Object target, org.springframework.data.mongodb.core.mapping.DBRef dbref) {
MongoPersistentEntity<?> targetEntity = mappingContext.getPersistentEntity(target.getClass());
if (null == targetEntity || null == targetEntity.getIdProperty()) {
return null;
}
MongoPersistentProperty idProperty = targetEntity.getIdProperty();
ObjectId id = null;
Object id = null;
BeanWrapper<MongoPersistentEntity<Object>, Object> wrapper = BeanWrapper.create(target, conversionService);
try {
id = wrapper.getProperty(idProperty, ObjectId.class, useFieldAccessOnly);
id = wrapper.getProperty(idProperty, Object.class, useFieldAccessOnly);
if (null == id) {
throw new MappingException("Cannot create a reference to an object with a NULL id.");
}
@@ -611,8 +692,9 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
return new DBRef(db, collection, id);
}
protected Object getValueInternal(MongoPersistentProperty prop, DBObject dbo, StandardEvaluationContext ctx, String spelExpr) {
@SuppressWarnings("unchecked")
protected Object getValueInternal(MongoPersistentProperty prop, DBObject dbo, StandardEvaluationContext ctx,
String spelExpr) {
Object o;
if (null != spelExpr) {
@@ -620,106 +702,119 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
o = x.getValue(ctx);
} else {
Object dbObj = dbo.get(prop.getFieldName());
Object sourceValue = dbo.get(prop.getFieldName());
if (dbObj == null) {
if (sourceValue == null) {
return null;
}
Class<?> propertyType = prop.getType();
Class<?> customTarget = getCustomTarget(dbObj.getClass(), propertyType);
if (customTarget != null) {
return conversionService.convert(dbObj, propertyType);
if (conversions.hasCustomReadTarget(sourceValue.getClass(), propertyType)) {
return conversionService.convert(sourceValue, propertyType);
}
if (dbObj instanceof DBRef) {
dbObj = ((DBRef) dbObj).fetch();
if (sourceValue instanceof DBRef) {
sourceValue = ((DBRef) sourceValue).fetch();
}
if (dbObj instanceof DBObject) {
if (sourceValue instanceof DBObject) {
if (prop.isMap()) {
return readMap(prop.getTypeInformation(), (DBObject) dbObj);
} else if (prop.isArray() && dbObj instanceof BasicDBObject && ((DBObject) dbObj).keySet().size() == 0) {
return readMap(prop.getTypeInformation(), (DBObject) sourceValue);
} else if (prop.isArray() && sourceValue instanceof BasicDBObject
&& ((DBObject) sourceValue).keySet().size() == 0) {
// It's empty
return Array.newInstance(prop.getComponentType(), 0);
} else if (prop.isCollection() && dbObj instanceof BasicDBList) {
BasicDBList dbObjList = (BasicDBList) dbObj;
List<Object> items = new LinkedList<Object>();
for (int i = 0; i < dbObjList.size(); i++) {
Object dbObjItem = dbObjList.get(i);
if (dbObjItem instanceof DBRef) {
items.add(read(prop.getComponentType(), ((DBRef) dbObjItem).fetch()));
} else if (dbObjItem instanceof DBObject) {
items.add(read(prop.getComponentType(), (DBObject) dbObjItem));
} else {
items.add(dbObjItem);
}
}
List<Object> itemsToReturn = new LinkedList<Object>();
for (Object obj : items) {
itemsToReturn.add(obj);
}
return itemsToReturn;
} else if (prop.isCollection() && sourceValue instanceof BasicDBList) {
return readCollectionOrArray((TypeInformation<? extends Collection<?>>) prop.getTypeInformation(),
(BasicDBList) sourceValue);
}
Class<?> toType = findTypeToBeUsed((DBObject) dbObj);
TypeInformation<?> toType = findTypeToBeUsed((DBObject) sourceValue);
// It's a complex object, have to read it in
if (toType != null) {
dbo.removeField(CUSTOM_TYPE_KEY);
o = read(toType, (DBObject) dbObj);
// TODO: why do we remove the type?
// dbo.removeField(CUSTOM_TYPE_KEY);
o = read(toType, (DBObject) sourceValue);
} else {
o = read(mappingContext.getPersistentEntity(prop.getTypeInformation()), (DBObject) dbObj);
o = read(mappingContext.getPersistentEntity(prop.getTypeInformation()), (DBObject) sourceValue);
}
} else {
o = dbObj;
o = sourceValue;
}
}
return o;
}
/**
* Reads the given {@link BasicDBList} into a collection of the given {@link TypeInformation}.
*
* @param targetType must not be {@literal null}.
* @param sourceValue must not be {@literal null}.
* @return the converted {@link Collections}, will never be {@literal null}.
*/
@SuppressWarnings("unchecked")
private Collection<?> readCollectionOrArray(TypeInformation<?> targetType, BasicDBList sourceValue) {
Assert.notNull(targetType);
Collection<Object> items = targetType.getType().isArray() ? new ArrayList<Object>() : CollectionFactory
.createCollection(targetType.getType(), sourceValue.size());
for (int i = 0; i < sourceValue.size(); i++) {
Object dbObjItem = sourceValue.get(i);
if (dbObjItem instanceof DBRef) {
items.add(read(targetType.getComponentType(), ((DBRef) dbObjItem).fetch()));
} else if (dbObjItem instanceof DBObject) {
items.add(read(targetType.getComponentType(), (DBObject) dbObjItem));
} else {
items.add(getPotentiallyConvertedSimpleRead(dbObjItem, targetType.getComponentType().getType()));
}
}
return items;
}
/**
* Reads the given {@link DBObject} into a {@link Map}. will recursively resolve nested {@link Map}s as well.
*
* @param type the {@link Map} {@link TypeInformation} to be used to unmarshall this {@link DBObject}.
* @param dbObject
*
* @return
*/
@SuppressWarnings("unchecked")
private Map<Object, Object> readMap(TypeInformation<?> type, DBObject dbObject) {
Assert.notNull(type);
Assert.isTrue(type.isMap());
protected Map<Object, Object> readMap(TypeInformation<?> type, DBObject dbObject) {
Assert.notNull(dbObject);
Class<?> customMapType = findTypeToBeUsed(dbObject);
Class<?> mapType = customMapType == null ? Map.class : customMapType;
Class<?> mapType = getMoreConcreteTargetType(dbObject, type).getType();
Map<Object, Object> map = CollectionFactory.createMap(mapType, dbObject.keySet().size());
Map<String, Object> sourceMap = dbObject.toMap();
for (Entry<String, Object> entry : sourceMap.entrySet()) {
if (entry.getKey().equals(CUSTOM_TYPE_KEY)) {
if (typeMapper.isTypeKey(entry.getKey())) {
continue;
}
Class<?> keyType = type.getComponentType().getType();
Object key = conversionService.convert(entry.getKey(), keyType);
Object key = entry.getKey();
if (null != entry.getValue() && entry.getValue() instanceof DBObject) {
DBObject valueSource = (DBObject) entry.getValue();
TypeInformation<?> valueType = type.getMapValueType();
Object value = valueType.isMap() ? readMap(valueType, valueSource) : read(valueType, valueSource);
map.put(key, value);
TypeInformation<?> keyTypeInformation = type.getComponentType();
if (keyTypeInformation != null) {
Class<?> keyType = keyTypeInformation.getType();
key = conversionService.convert(entry.getKey(), keyType);
}
Object value = entry.getValue();
TypeInformation<?> valueType = type.getMapValueType();
if (value instanceof DBObject) {
map.put(key, read(valueType, (DBObject) value));
} else {
map.put(key, entry.getValue());
valueType = valueType == null ? MAP_TYPE_INFORMATION : valueType;
map.put(key, getPotentiallyConvertedSimpleRead(value, valueType.getType()));
}
}
return map;
}
@@ -727,44 +822,47 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
* Returns the type to be used to convert the DBObject given to. Will return {@literal null} if there's not type hint
* found in the {@link DBObject} or the type hint found can't be converted into a {@link Class} as the type might not
* be available.
*
*
* @param dbObject
* @return the type to be used for converting the given {@link DBObject} into or {@literal null} if there's no type
* found.
*/
protected Class<?> findTypeToBeUsed(DBObject dbObject) {
Object classToBeUsed = dbObject.get(CUSTOM_TYPE_KEY);
protected TypeInformation<?> findTypeToBeUsed(DBObject dbObject) {
return typeMapper.readType(dbObject);
}
if (classToBeUsed == null) {
return null;
private Class<?> getDefaultedTypeToBeUsed(DBObject dbObject) {
TypeInformation<?> result = findTypeToBeUsed(dbObject);
if (result != null) {
return result.getType();
}
try {
return Class.forName(classToBeUsed.toString());
} catch (ClassNotFoundException e) {
return null;
}
return dbObject instanceof BasicDBList ? List.class : Map.class;
}
/**
* Inspects the a custom class definition stored inside the given {@link DBObject} and returns that in case it's a
* subtype of the given basic one.
*
*
* @param dbObject
* @param basicType
* @return
*/
@SuppressWarnings("unchecked")
private <S> TypeInformation<? extends S> getMoreConcreteTargetType(DBObject dbObject, TypeInformation<S> basicType) {
Class<?> documentsTargetType = findTypeToBeUsed(dbObject);
Class<S> rawType = basicType.getType();
boolean isMoreConcreteCustomType = documentsTargetType != null && rawType.isAssignableFrom(documentsTargetType);
Class<?> documentsTargetType = getDefaultedTypeToBeUsed(dbObject);
Class<S> rawType = basicType == null ? null : basicType.getType();
boolean isMoreConcreteCustomType = rawType == null ? true : rawType.isAssignableFrom(documentsTargetType)
&& !rawType.equals(documentsTargetType);
return isMoreConcreteCustomType ? (TypeInformation<? extends S>) ClassTypeInformation.from(documentsTargetType)
: basicType;
}
protected <T> List<?> unwrapList(BasicDBList dbList, TypeInformation<T> targetType) {
List<Object> rootList = new LinkedList<Object>();
List<Object> rootList = new ArrayList<Object>();
for (int i = 0; i < dbList.size(); i++) {
Object obj = dbList.get(i);
if (obj instanceof BasicDBList) {
@@ -777,4 +875,78 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
}
return rootList;
}
@SuppressWarnings("unchecked")
public Object convertToMongoType(Object obj) {
if (obj == null) {
return null;
}
Class<?> target = conversions.getCustomWriteTarget(getClass());
if (target != null) {
return conversionService.convert(obj, target);
}
if (null != obj && conversions.isSimpleType(obj.getClass())) {
// Doesn't need conversion
return getPotentiallyConvertedSimpleWrite(obj);
}
if (obj instanceof BasicDBList) {
return maybeConvertList((BasicDBList) obj);
}
if (obj instanceof DBObject) {
DBObject newValueDbo = new BasicDBObject();
for (String vk : ((DBObject) obj).keySet()) {
Object o = ((DBObject) obj).get(vk);
newValueDbo.put(vk, convertToMongoType(o));
}
return newValueDbo;
}
if (obj instanceof Map) {
Map<Object, Object> m = new HashMap<Object, Object>();
for (Map.Entry<Object, Object> entry : ((Map<Object, Object>) obj).entrySet()) {
m.put(entry.getKey(), convertToMongoType(entry.getValue()));
}
return m;
}
if (obj instanceof List) {
List<?> l = (List<?>) obj;
List<Object> newList = new ArrayList<Object>();
for (Object o : l) {
newList.add(convertToMongoType(o));
}
return newList;
}
if (obj.getClass().isArray()) {
return maybeConvertArray((Object[]) obj);
}
DBObject newDbo = new BasicDBObject();
this.write(obj, newDbo);
return newDbo;
}
public Object[] maybeConvertArray(Object[] src) {
Object[] newArr = new Object[src.length];
for (int i = 0; i < src.length; i++) {
newArr[i] = convertToMongoType(src[i]);
}
return newArr;
}
public BasicDBList maybeConvertList(BasicDBList dbl) {
BasicDBList newDbl = new BasicDBList();
Iterator<?> iter = dbl.iterator();
while (iter.hasNext()) {
Object o = iter.next();
newDbl.add(convertToMongoType(o));
}
return newDbl;
}
}

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb.convert;
package org.springframework.data.mongodb.core.convert;
import static org.springframework.beans.PropertyAccessorFactory.forBeanPropertyAccess;
import static org.springframework.beans.PropertyAccessorFactory.forDirectFieldAccess;
@@ -22,8 +22,7 @@ import org.springframework.beans.BeanWrapper;
import org.springframework.beans.ConfigurablePropertyAccessor;
import org.springframework.beans.NotWritablePropertyException;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.document.mongodb.MongoPropertyDescriptors;
import org.springframework.data.document.mongodb.MongoPropertyDescriptors.MongoPropertyDescriptor;
import org.springframework.data.mongodb.core.convert.MongoPropertyDescriptors.MongoPropertyDescriptor;
import org.springframework.util.Assert;
/**

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2010-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.convert;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
/**
* Central Mongo specific converter interface which combines {@link MongoWriter} and {@link MongoReader}.
*
* @author Oliver Gierke
*/
public interface MongoConverter extends MongoWriter<Object>, MongoReader<Object> {
/**
* Returns the underlying {@link MappingContext} used by the converter.
*
* @return never {@literal null}
*/
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> getMappingContext();
/**
* Returns the underlying {@link ConversionService} used by the converter.
*
* @return never {@literal null}.
*/
ConversionService getConversionService();
}

View File

@@ -13,24 +13,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb.convert;
package org.springframework.data.mongodb.core.convert;
import java.math.BigDecimal;
import java.math.BigInteger;
import org.bson.types.ObjectId;
import org.springframework.core.convert.converter.Converter;
import org.springframework.util.StringUtils;
/**
* Wrapper class to contain useful {@link ObjectId}-to-something-and-back converters.
* Wrapper class to contain useful converters for the usage with Mongo.
*
* @author Oliver Gierke
*/
abstract class ObjectIdConverters {
abstract class MongoConverters {
/**
* Private constructor to prevent instantiation.
*/
private ObjectIdConverters() {
private MongoConverters() {
}
@@ -43,7 +45,7 @@ abstract class ObjectIdConverters {
INSTANCE;
public String convert(ObjectId id) {
return id.toString();
return id == null ? null : id.toString();
}
}
@@ -56,7 +58,7 @@ abstract class ObjectIdConverters {
INSTANCE;
public ObjectId convert(String source) {
return new ObjectId(source);
return StringUtils.hasText(source) ? new ObjectId(source) : null;
}
}
@@ -69,7 +71,7 @@ abstract class ObjectIdConverters {
INSTANCE;
public BigInteger convert(ObjectId source) {
return new BigInteger(source.toString(), 16);
return source == null ? null : new BigInteger(source.toString(), 16);
}
}
@@ -82,7 +84,39 @@ abstract class ObjectIdConverters {
INSTANCE;
public ObjectId convert(BigInteger source) {
return new ObjectId(source.toString(16));
return source == null ? null : new ObjectId(source.toString(16));
}
}
public static enum BigDecimalToStringConverter implements Converter<BigDecimal, String> {
INSTANCE;
public String convert(BigDecimal source) {
return source == null ? null : source.toString();
}
}
public static enum StringToBigDecimalConverter implements Converter<String, BigDecimal> {
INSTANCE;
public BigDecimal convert(String source) {
return StringUtils.hasText(source) ? new BigDecimal(source) : null;
}
}
public static enum BigIntegerToStringConverter implements Converter<BigInteger, String> {
INSTANCE;
public String convert(BigInteger source) {
return source == null ? null : source.toString();
}
}
public static enum StringToBigIntegerConverter implements Converter<String, BigInteger> {
INSTANCE;
public BigInteger convert(String source) {
return StringUtils.hasText(source) ? new BigInteger(source) : null;
}
}
}

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb;
package org.springframework.data.mongodb.core.convert;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;

View File

@@ -13,15 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb;
package org.springframework.data.mongodb.core.convert;
import com.mongodb.DBObject;
/**
* A MongoWriter is responsible for converting a native MongoDB DBObject to an object of type T.
*
* @param <T>
* the type of the object to convert from a DBObject
* @param <T> the type of the object to convert from a DBObject
* @author Mark Pollack
* @author Thomas Risberg
* @author Oliver Gierke
@@ -33,11 +32,9 @@ public interface MongoReader<T> {
* starting point for marshalling the {@link DBObject} into it. So in case there's no real valid data inside
* {@link DBObject} for the given type, just return an empty instance of the given type.
*
* @param clazz
* the type of the return value
* @param dbo
* theDBObject
* @return the converted object
* @param clazz the type of the return value. Will never be {@literal null}.
* @param dbo the {@link DBObject} to convert into a domain object. Might be {@literal null}.
* @return the converted object. Might be {@literal null}.
*/
<S extends T> S read(Class<S> clazz, DBObject dbo);
}

View File

@@ -13,28 +13,34 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb;
package org.springframework.data.mongodb.core.convert;
import com.mongodb.DBObject;
/**
* A MongoWriter is responsible for converting an object of type T to the native MongoDB representation DBObject.
*
* @param <T>
* the type of the object to convert to a DBObject
* @param <T> the type of the object to convert to a DBObject
* @author Mark Pollack
* @author Thomas Risberg
* @author Oliver Gierke
*/
public interface MongoWriter<T> {
/**
* Write the given object of type T to the native MongoDB object representation DBObject.
*
* @param t
* The object to convert to a DBObject
* @param dbo
* The DBObject to use for writing.
* @param t The object to convert to a DBObject
* @param dbo The DBObject to use for writing.
*/
void write(T t, DBObject dbo);
/**
* Converts the given object into one Mongo will be able to store natively. If the given object can already be stored
* as is, no conversion will happen.
*
* @param obj
* @return
*/
Object convertToMongoType(Object obj);
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.convert;
import org.springframework.data.util.TypeInformation;
import com.mongodb.DBObject;
/**
* Interface to define strategies how to store type information in a {@link DBObject}.
*
* @author Oliver Gierke
*/
public interface TypeMapper {
/**
* Returns whether the given key is the key being used as type key.
*
* @param key
* @return
*/
boolean isTypeKey(String key);
/**
* Reads the {@link TypeInformation} from the given {@link DBObject}.
*
* @param dbObject must not be {@literal null}.
* @return
*/
TypeInformation<?> readType(DBObject dbObject);
/**
* Writes type information for the given type into the given {@link DBObject}.
*
* @param type must not be {@literal null}.
* @param dbObject must not be {@literal null}.
*/
void writeType(Class<?> type, DBObject dbObject);
/**
* Writes type information for the given {@link TypeInformation} into the given {@link DBObject}.
*
* @param type must not be {@literal null}.
* @param dbObject must not be {@literal null}.
*/
void writeType(TypeInformation<?> type, DBObject dbObject);
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.convert;
/**
* Interfaces for components being able to provide a {@link TypeMapper}.
*
* @author Oliver Gierke
*/
public interface TypeMapperProvider {
/**
* Returns the {@link TypeMapper}.
*
* @return the {@link TypeMapper} or {@literal null} if none available.
*/
TypeMapper getTypeMapper();
}

View File

@@ -13,8 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb.geo;
package org.springframework.data.mongodb.core.geo;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.util.Assert;
/**
@@ -25,7 +26,9 @@ import org.springframework.util.Assert;
*/
public class Box {
@Field(order = 10)
private final Point first;
@Field(order = 20)
private final Point second;
public Box(Point lowerLeft, Point upperRight) {

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb.geo;
package org.springframework.data.mongodb.core.geo;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.util.Assert;

View File

@@ -0,0 +1,145 @@
/*
* Copyright 2010-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.geo;
import org.springframework.util.ObjectUtils;
/**
* Value object to represent distances in a given metric.
*
* @author Oliver Gierke
*/
public class Distance {
private final double value;
private final Metric metric;
/**
* Creates a new {@link Distance}.
*
* @param value
*/
public Distance(double value) {
this(value, Metrics.NEUTRAL);
}
/**
* Creates a new {@link Distance} with the given {@link Metric}.
*
* @param value
* @param metric
*/
public Distance(double value, Metric metric) {
this.value = value;
this.metric = metric == null ? Metrics.NEUTRAL : metric;
}
/**
* @return the value
*/
public double getValue() {
return value;
}
/**
* Returns the normalized value regarding the underlying {@link Metric}.
*
* @return
*/
public double getNormalizedValue() {
return value / metric.getMultiplier();
}
/**
* @return the metric
*/
public Metric getMetric() {
return metric;
}
/**
* Adds the given distance to the current one. The resulting {@link Distance} will be in the same metric as the
* current one.
*
* @param other
* @return
*/
public Distance add(Distance other) {
double newNormalizedValue = getNormalizedValue() + other.getNormalizedValue();
return new Distance(newNormalizedValue * metric.getMultiplier(), metric);
}
/**
* Adds the given {@link Distance} to the current one and forces the result to be in a given {@link Metric}.
*
* @param other
* @param metric
* @return
*/
public Distance add(Distance other, Metric metric) {
double newLeft = getNormalizedValue() * metric.getMultiplier();
double newRight = other.getNormalizedValue() * metric.getMultiplier();
return new Distance(newLeft + newRight, metric);
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || !getClass().equals(obj.getClass())) {
return false;
}
Distance that = (Distance) obj;
return this.value == that.value && ObjectUtils.nullSafeEquals(this.metric, that.metric);
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int result = 17;
result += 31 * Double.doubleToLongBits(value);
result += 31 * ObjectUtils.nullSafeHashCode(metric);
return result;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(value);
if (metric != Metrics.NEUTRAL) {
builder.append(" ").append(metric.toString());
}
return builder.toString();
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.geo;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
/**
* Custom {@link Page} to carry the average distance retrieved from the {@link GeoResults} the {@link GeoPage} is set up
* from.
*
* @author Oliver Gierke
*/
public class GeoPage<T> extends PageImpl<GeoResult<T>> {
private static final long serialVersionUID = 23421312312412L;
private final Distance averageDistance;
/**
* Creates a new {@link GeoPage} from the given {@link GeoResults}.
*
* @param content must not be {@literal null}.
*/
public GeoPage(GeoResults<T> results) {
super(results.getContent());
this.averageDistance = results.getAverageDistance();
}
/**
* Creates a new {@link GeoPage} from the given {@link GeoResults}, {@link Pageable} and total.
*
* @param results must not be {@literal null}.
* @param pageable must not be {@literal null}.
* @param total
*/
public GeoPage(GeoResults<T> results, Pageable pageable, long total) {
super(results.getContent(), pageable, total);
this.averageDistance = results.getAverageDistance();
}
/**
* Returns the average distance of the underlying results.
*
* @return the averageDistance
*/
public Distance getAverageDistance() {
return averageDistance;
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright 2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.geo;
import org.springframework.util.Assert;
/**
* Calue object capturing some arbitrary object plus a distance.
*
* @author Oliver Gierke
*/
public class GeoResult<T> {
private final T content;
private final Distance distance;
/**
* Creates a new {@link GeoResult} for the given content and distance.
*
* @param content must not be {@literal null}.
* @param distance must not be {@literal null}.
*/
public GeoResult(T content, Distance distance) {
Assert.notNull(content);
Assert.notNull(distance);
this.content = content;
this.distance = distance;
}
/**
* Returns the actual content object.
*
* @return the content
*/
public T getContent() {
return content;
}
/**
* Returns the distance the actual content object has from the origin.
*
* @return the distance
*/
public Distance getDistance() {
return distance;
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || !getClass().equals(obj.getClass())) {
return false;
}
GeoResult<?> that = (GeoResult<?>) obj;
return this.content.equals(that.content) && this.distance.equals(that.distance);
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int result = 17;
result += 31 * distance.hashCode();
result += 31 * content.hashCode();
return result;
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return String.format("GeoResult [content: %s, distance: %s, ]", content.toString(), distance.toString());
}
}

View File

@@ -0,0 +1,145 @@
/*
* Copyright 2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.geo;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Value object to capture {@link GeoResult}s as well as the average distance they have.
*
* @author Oliver Gierke
*/
public class GeoResults<T> implements Iterable<GeoResult<T>> {
private final List<GeoResult<T>> results;
private final Distance averageDistance;
/**
* Creates a new {@link GeoResults} instance manually calculating the average distance from the distance values of the
* given {@link GeoResult}s.
*
* @param results must not be {@literal null}.
*/
public GeoResults(List<GeoResult<T>> results) {
this(results, (Metric) null);
}
public GeoResults(List<GeoResult<T>> results, Metric metric) {
this(results, calculateAverageDistance(results, metric));
}
/**
* Creates a new {@link GeoResults} instance from the given {@link GeoResult}s and average distance.
*
* @param results must not be {@literal null}.
* @param averageDistance
*/
@PersistenceConstructor
public GeoResults(List<GeoResult<T>> results, Distance averageDistance) {
Assert.notNull(results);
this.results = results;
this.averageDistance = averageDistance;
}
/**
* Returns the average distance of all {@link GeoResult}s in this list.
*
* @return the averageDistance
*/
public Distance getAverageDistance() {
return averageDistance;
}
/*
* (non-Javadoc)
* @see java.lang.Iterable#iterator()
*/
public Iterator<GeoResult<T>> iterator() {
return results.iterator();
}
/**
* Returns the actual
*
* @return
*/
public List<GeoResult<T>> getContent() {
return Collections.unmodifiableList(results);
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || !getClass().equals(obj.getClass())) {
return false;
}
GeoResults<?> that = (GeoResults<?>) obj;
return this.results.equals(that.results) && this.averageDistance == that.averageDistance;
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int result = 17;
result += 31 * results.hashCode();
result += 31 * averageDistance.hashCode();
return result;
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return String.format("GeoResults: [averageDistance: %s, results: %s]", averageDistance.toString(),
StringUtils.collectionToCommaDelimitedString(results));
}
private static Distance calculateAverageDistance(List<? extends GeoResult<?>> results, Metric metric) {
if (results.isEmpty()) {
return new Distance(0, null);
}
double averageDistance = 0;
for (GeoResult<?> result : results) {
averageDistance += result.getDistance().getValue();
}
return new Distance(averageDistance / results.size(), metric);
}
}

View File

@@ -0,0 +1,16 @@
package org.springframework.data.mongodb.core.geo;
/**
* Interface for {@link Metric}s that can be applied to a base scale.
*
* @author Oliver Gierke
*/
public interface Metric {
/**
* Returns the multiplier to calculate metrics values from a base scale.
*
* @return
*/
double getMultiplier();
}

View File

@@ -0,0 +1,27 @@
package org.springframework.data.mongodb.core.geo;
import org.springframework.data.mongodb.core.query.NearQuery;
/**
* Commonly used {@link Metrics} for {@link NearQuery}s.
*
* @author Oliver Gierke
*/
public enum Metrics implements Metric {
KILOMETERS(6378.137), MILES(3963.191), NEUTRAL(1);
private final double multiplier;
private Metrics(double multiplier) {
this.multiplier = multiplier;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.geo.Metric#getMultiplier()
*/
public double getMultiplier() {
return multiplier;
}
}

View File

@@ -13,9 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb.geo;
package org.springframework.data.mongodb.core.geo;
import java.util.Arrays;
import java.util.List;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.util.Assert;
/**
@@ -26,7 +30,9 @@ import org.springframework.util.Assert;
*/
public class Point {
@Field(order = 10)
private final double x;
@Field(order = 20)
private final double y;
@PersistenceConstructor
@@ -53,6 +59,10 @@ public class Point {
return new double[] { x, y };
}
public List<Double> asList() {
return Arrays.asList(x, y);
}
@Override
public int hashCode() {
final int prime = 31;
@@ -88,6 +98,6 @@ public class Point {
@Override
public String toString() {
return String.format("Point [latitude=%d, longitude=%d]", x, y);
return String.format("Point [latitude=%f, longitude=%f]", x, y);
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.document.mongodb.index;
package org.springframework.data.mongodb.core.index;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.document.mongodb.index;
package org.springframework.data.mongodb.core.index;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.document.mongodb.index;
package org.springframework.data.mongodb.core.index;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -13,27 +13,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb.query;
package org.springframework.data.mongodb.core.index;
import org.springframework.data.document.mongodb.index.IndexDefinition;
import org.springframework.util.Assert;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* Value object to capture data to create a geo index.
*
* @author Jon Brisbin
* @author Oliver Gierke
*/
public class GeospatialIndex implements IndexDefinition {
private String keyField;
private final String field;
private String name;
private Integer min = null;
private Integer max = null;
private Integer bits = null;
public GeospatialIndex(String key) {
keyField = key;
/**
* Creates a new {@link GeospatialIndex} for the given field.
*
* @param field must not be empty or {@literal null}.
*/
public GeospatialIndex(String field) {
Assert.hasText(field);
this.field = field;
}
public GeospatialIndex named(String name) {
@@ -58,7 +66,7 @@ public class GeospatialIndex implements IndexDefinition {
public DBObject getIndexKeys() {
DBObject dbo = new BasicDBObject();
dbo.put(keyField, "2d");
dbo.put(field, "2d");
return dbo;
}
@@ -82,7 +90,8 @@ public class GeospatialIndex implements IndexDefinition {
return dbo;
}
/* (non-Javadoc)
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override

View File

@@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb.query;
package org.springframework.data.mongodb.core.index;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.data.document.mongodb.index.IndexDefinition;
import org.springframework.data.mongodb.core.query.Order;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
@@ -29,7 +29,7 @@ public class Index implements IndexDefinition {
RETAIN, DROP
}
private Map<String, Order> fieldSpec = new HashMap<String, Order>();
private final Map<String, Order> fieldSpec = new LinkedHashMap<String, Order>();
private String name;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.document.mongodb.index;
package org.springframework.data.mongodb.core.index;
import com.mongodb.DBObject;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.document.mongodb.index;
package org.springframework.data.mongodb.core.index;
/**
* @author Jon Brisbin <jbrisbin@vmware.com>

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.document.mongodb.index;
package org.springframework.data.mongodb.core.index;
/**
* @author Jon Brisbin <jbrisbin@vmware.com>

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.document.mongodb.index;
package org.springframework.data.mongodb.core.index;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -14,14 +14,21 @@
* limitations under the License.
*/
package org.springframework.data.document.mongodb.mapping.event;
package org.springframework.data.mongodb.core.index;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.document.mongodb.mapping.MongoPersistentEntityIndexCreator;
import org.springframework.data.mapping.event.MappingContextEvent;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
/**
* An implementation of ApplicationEventPublisher that will only fire MappingContextEvents for use by the index creator when
* MongoTemplate is used 'stand-alone', that is not declared inside a Spring ApplicationContext.
*
* Declare MongoTemplate inside an ApplicationContext to enable the publishing of all persistence events such as
* {@link AfterLoadEvent}, {@link AfterSaveEvent}, etc.
*
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
public class MongoMappingEventPublisher implements ApplicationEventPublisher {
@@ -32,10 +39,11 @@ public class MongoMappingEventPublisher implements ApplicationEventPublisher {
this.indexCreator = indexCreator;
}
@SuppressWarnings("unchecked")
public void publishEvent(ApplicationEvent event) {
if (event instanceof MappingContextEvent) {
indexCreator.onApplicationEvent((MappingContextEvent<?, ?>) event);
indexCreator
.onApplicationEvent((MappingContextEvent<MongoPersistentEntity<MongoPersistentProperty>, MongoPersistentProperty>) event);
}
}
}

View File

@@ -14,10 +14,11 @@
* limitations under the License.
*/
package org.springframework.data.document.mongodb.mapping;
package org.springframework.data.mongodb.core.index;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -27,34 +28,38 @@ import com.mongodb.util.JSON;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.data.document.mongodb.MongoDbFactory;
import org.springframework.data.document.mongodb.index.CompoundIndex;
import org.springframework.data.document.mongodb.index.CompoundIndexes;
import org.springframework.data.document.mongodb.index.GeoSpatialIndexed;
import org.springframework.data.document.mongodb.index.IndexDirection;
import org.springframework.data.document.mongodb.index.Indexed;
import org.springframework.data.document.mongodb.query.GeospatialIndex;
import org.springframework.data.mapping.PropertyHandler;
import org.springframework.data.mapping.event.MappingContextEvent;
import org.springframework.data.mapping.model.PersistentProperty;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Component that inspects {@link BasicMongoPersistentEntity} instances contained in the given
* {@link MongoMappingContext} for indexing metadata and ensures the indexes to be available.
*
*
* @author Jon Brisbin <jbrisbin@vmware.com>
* @author Oliver Gierke
*/
public class MongoPersistentEntityIndexCreator implements ApplicationListener<MappingContextEvent> {
public class MongoPersistentEntityIndexCreator implements
ApplicationListener<MappingContextEvent<MongoPersistentEntity<MongoPersistentProperty>, MongoPersistentProperty>> {
private static final Log log = LogFactory.getLog(MongoPersistentEntityIndexCreator.class);
private Set<Class<?>> classesSeen = Collections.newSetFromMap(new ConcurrentHashMap<Class<?>, Boolean>());
private final Map<Class<?>, Boolean> classesSeen = new ConcurrentHashMap<Class<?>, Boolean>();
private final MongoDbFactory mongoDbFactory;
/**
* Creats a new {@link MongoPersistentEntityIndexCreator} for the given {@link MongoMappingContext} and
* {@link MongoDbFactory}.
*
* @param mappingContext must not be {@@iteral null}
* @param mongoDbFactory must not be {@@iteral null}
*/
public MongoPersistentEntityIndexCreator(MongoMappingContext mappingContext, MongoDbFactory mongoDbFactory) {
Assert.notNull(mongoDbFactory);
@@ -66,16 +71,18 @@ public class MongoPersistentEntityIndexCreator implements ApplicationListener<Ma
}
}
/* (non-Javadoc)
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
*/
public void onApplicationEvent(MappingContextEvent event) {
checkForIndexes((MongoPersistentEntity<?>) event.getPersistentEntity());
/*
* (non-Javadoc)
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
*/
public void onApplicationEvent(
MappingContextEvent<MongoPersistentEntity<MongoPersistentProperty>, MongoPersistentProperty> event) {
checkForIndexes(event.getPersistentEntity());
}
protected void checkForIndexes(final MongoPersistentEntity<?> entity) {
final Class<?> type = entity.getType();
if (!classesSeen.contains(type)) {
if (!classesSeen.containsKey(type)) {
if (log.isDebugEnabled()) {
log.debug("Analyzing class " + type + " for index information.");
}
@@ -96,14 +103,14 @@ public class MongoPersistentEntityIndexCreator implements ApplicationListener<Ma
}
}
entity.doWithProperties(new PropertyHandler() {
public void doWithPersistentProperty(PersistentProperty persistentProperty) {
entity.doWithProperties(new PropertyHandler<MongoPersistentProperty>() {
public void doWithPersistentProperty(MongoPersistentProperty persistentProperty) {
Field field = persistentProperty.getField();
if (field.isAnnotationPresent(Indexed.class)) {
Indexed index = field.getAnnotation(Indexed.class);
String name = index.name();
if ("".equals(name)) {
name = field.getName();
if (!StringUtils.hasText(name)) {
name = persistentProperty.getFieldName();
} else {
if (!name.equals(field.getName()) && index.unique() && !index.sparse()) {
// Names don't match, and sparse is not true. This situation will generate an error on the server.
@@ -122,12 +129,13 @@ public class MongoPersistentEntityIndexCreator implements ApplicationListener<Ma
GeoSpatialIndexed index = field.getAnnotation(GeoSpatialIndexed.class);
GeospatialIndex indexObject = new GeospatialIndex(StringUtils.hasText(index.name()) ? index.name() : field
.getName());
GeospatialIndex indexObject = new GeospatialIndex(persistentProperty.getFieldName());
indexObject.withMin(index.min()).withMax(index.max());
indexObject.named(StringUtils.hasText(index.name()) ? index.name() : field.getName());
String collection = StringUtils.hasText(index.collection()) ? index.collection() : entity.getCollection();
mongoDbFactory.getDb().getCollection(collection).ensureIndex(indexObject.getIndexKeys(), indexObject.getIndexOptions());
mongoDbFactory.getDb().getCollection(collection)
.ensureIndex(indexObject.getIndexKeys(), indexObject.getIndexOptions());
if (log.isDebugEnabled()) {
log.debug(String.format("Created %s for entity %s in collection %s! ", indexObject, entity.getType(),
@@ -137,18 +145,12 @@ public class MongoPersistentEntityIndexCreator implements ApplicationListener<Ma
}
});
classesSeen.add(type);
classesSeen.put(type, true);
}
}
protected void ensureIndex(String collection,
final String name,
final String def,
final IndexDirection direction,
final boolean unique,
final boolean dropDups,
final boolean sparse) {
protected void ensureIndex(String collection, final String name, final String def, final IndexDirection direction,
final boolean unique, final boolean dropDups, final boolean sparse) {
DBObject defObj;
if (null != def) {
defObj = (DBObject) JSON.parse(def);
@@ -157,7 +159,7 @@ public class MongoPersistentEntityIndexCreator implements ApplicationListener<Ma
defObj.put(name, (direction == IndexDirection.ASCENDING ? 1 : -1));
}
DBObject opts = new BasicDBObject();
// opts.put("name", name + "_idx");
opts.put("name", name);
opts.put("dropDups", dropDups);
opts.put("sparse", sparse);
opts.put("unique", unique);

View File

@@ -14,12 +14,13 @@
* limitations under the License.
*/
package org.springframework.data.document.mongodb.mapping;
package org.springframework.data.mongodb.core.mapping;
import org.springframework.data.document.mongodb.MongoCollectionUtils;
import org.springframework.data.mapping.BasicPersistentEntity;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mapping.model.PersistentEntity;
import java.util.Comparator;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.model.BasicPersistentEntity;
import org.springframework.data.mongodb.MongoCollectionUtils;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.StringUtils;
@@ -34,7 +35,6 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
MongoPersistentEntity<T> {
private final String collection;
private final boolean isRootEntity;
/**
* Creates a new {@link BasicMongoPersistentEntity} with the given {@link TypeInformation}. Will default the
@@ -44,7 +44,7 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
*/
public BasicMongoPersistentEntity(TypeInformation<T> typeInformation) {
super(typeInformation);
super(typeInformation, MongoPersistentPropertyComparator.INSTANCE);
Class<?> rawType = typeInformation.getType();
String fallback = MongoCollectionUtils.getPreferredCollectionName(rawType);
@@ -52,10 +52,8 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
if (rawType.isAnnotationPresent(Document.class)) {
Document d = rawType.getAnnotation(Document.class);
this.collection = StringUtils.hasText(d.collection()) ? d.collection() : fallback;
this.isRootEntity = true;
} else {
this.collection = fallback;
this.isRootEntity = false;
}
}
@@ -68,13 +66,30 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
return collection;
}
/* (non-Javadoc)
* @see org.springframework.data.mapping.BasicPersistentEntity#verify()
/**
* {@link Comparator} implementation inspecting the {@link MongoPersistentProperty}'s order.
*
* @author Oliver Gierke
*/
@Override
public void verify() {
if (isRootEntity && idProperty == null) {
throw new MappingException(String.format("Root entity %s has to have an id property!", getType().getName()));
static enum MongoPersistentPropertyComparator implements Comparator<MongoPersistentProperty> {
INSTANCE;
/*
* (non-Javadoc)
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
*/
public int compare(MongoPersistentProperty o1, MongoPersistentProperty o2) {
if (o1.getFieldOrder() == Integer.MAX_VALUE) {
return 1;
}
if (o2.getFieldOrder() == Integer.MAX_VALUE) {
return -1;
}
return o1.getFieldOrder() - o2.getFieldOrder();
}
}
}

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.document.mongodb.mapping;
package org.springframework.data.mongodb.core.mapping;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
@@ -21,16 +21,19 @@ import java.math.BigInteger;
import java.util.HashSet;
import java.util.Set;
import com.mongodb.DBObject;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bson.types.ObjectId;
import org.springframework.data.mapping.AnnotationBasedPersistentProperty;
import org.springframework.data.mapping.model.Association;
import org.springframework.data.mapping.Association;
import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.util.StringUtils;
import com.mongodb.DBObject;
/**
* Mongo specific {@link org.springframework.data.mapping.model.PersistentProperty} implementation.
*
* Mongo specific {@link org.springframework.data.mapping.PersistentProperty} implementation.
*
* @author Oliver Gierke
*/
public class BasicMongoPersistentProperty extends AnnotationBasedPersistentProperty<MongoPersistentProperty> implements
@@ -38,6 +41,7 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
private static final Log LOG = LogFactory.getLog(BasicMongoPersistentProperty.class);
private static final String ID_FIELD_NAME = "_id";
private static final Set<Class<?>> SUPPORTED_ID_TYPES = new HashSet<Class<?>>();
private static final Set<String> SUPPORTED_ID_PROPERTY_NAMES = new HashSet<String>();
@@ -52,16 +56,18 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
/**
* Creates a new {@link BasicMongoPersistentProperty}.
*
*
* @param field
* @param propertyDescriptor
* @param owner
* @param simpleTypeHolder
*/
public BasicMongoPersistentProperty(Field field, PropertyDescriptor propertyDescriptor, MongoPersistentEntity<?> owner) {
super(field, propertyDescriptor, owner);
public BasicMongoPersistentProperty(Field field, PropertyDescriptor propertyDescriptor,
MongoPersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {
super(field, propertyDescriptor, owner, simpleTypeHolder);
if (isIdProperty() && field.isAnnotationPresent(FieldName.class)) {
LOG.warn(String.format("Invalid usage of %s on id property. Field name will not be considered!", FieldName.class));
if (isIdProperty() && getFieldName() != ID_FIELD_NAME) {
LOG.warn("Customizing field name for id property not allowed! Custom name will not be considered!");
}
}
@@ -75,7 +81,7 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
/**
* Also considers fields as id that are of supported id type and name.
*
*
* @see #SUPPORTED_ID_PROPERTY_NAMES
* @see #SUPPORTED_ID_TYPES
*/
@@ -87,22 +93,31 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
// We need to support a wider range of ID types than just the ones that can be converted to an ObjectId
return SUPPORTED_ID_PROPERTY_NAMES.contains(field.getName());
//return SUPPORTED_ID_TYPES.contains(field.getType()) && SUPPORTED_ID_PROPERTY_NAMES.contains(field.getName());
}
/**
* Returns the key to be used to store the value of the property inside a Mongo {@link DBObject}.
*
*
* @return
*/
public String getFieldName() {
if (isIdProperty()) {
return "_id";
return ID_FIELD_NAME;
}
FieldName annotation = getField().getAnnotation(FieldName.class);
return annotation != null ? annotation.value() : getName();
org.springframework.data.mongodb.core.mapping.Field annotation = getField().getAnnotation(
org.springframework.data.mongodb.core.mapping.Field.class);
return annotation != null && StringUtils.hasText(annotation.value()) ? annotation.value() : field.getName();
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.core.mapping.MongoPersistentProperty#getFieldOrder()
*/
public int getFieldOrder() {
org.springframework.data.mongodb.core.mapping.Field annotation = getField().getAnnotation(
org.springframework.data.mongodb.core.mapping.Field.class);
return annotation != null ? annotation.order() : Integer.MAX_VALUE;
}
/* (non-Javadoc)
@@ -114,14 +129,14 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
}
/* (non-Javadoc)
* @see org.springframework.data.document.mongodb.mapping.MongoPersistentProperty#isDbReference()
* @see org.springframework.data.mongodb.core.core.mapping.MongoPersistentProperty#isDbReference()
*/
public boolean isDbReference() {
return getField().isAnnotationPresent(DBRef.class);
}
/* (non-Javadoc)
* @see org.springframework.data.document.mongodb.mapping.MongoPersistentProperty#getDBRef()
* @see org.springframework.data.mongodb.core.core.mapping.MongoPersistentProperty#getDBRef()
*/
public DBRef getDBRef() {
return getField().getAnnotation(DBRef.class);

View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) 2011 by the original author(s).
*
* 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.mapping;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import org.springframework.data.mapping.model.SimpleTypeHolder;
/**
* {@link MongoPersistentProperty} caching access to {@link #isIdProperty()} and {@link #getFieldName()}.
*
* @author Oliver Gierke
*/
public class CachingMongoPersistentProperty extends BasicMongoPersistentProperty {
private Boolean isIdProperty;
private String fieldName;
/**
* Creates a new {@link CachingMongoPersistentProperty}.
*
* @param field
* @param propertyDescriptor
* @param owner
* @param simpleTypeHolder
*/
public CachingMongoPersistentProperty(Field field, PropertyDescriptor propertyDescriptor,
MongoPersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {
super(field, propertyDescriptor, owner, simpleTypeHolder);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.BasicMongoPersistentProperty#isIdProperty()
*/
@Override
public boolean isIdProperty() {
if (this.isIdProperty == null) {
this.isIdProperty = super.isIdProperty();
}
return this.isIdProperty;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.BasicMongoPersistentProperty#getFieldName()
*/
@Override
public String getFieldName() {
if (this.fieldName == null) {
this.fieldName = super.getFieldName();
}
return super.getFieldName();
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.document.mongodb.mapping;
package org.springframework.data.mongodb.core.mapping;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -14,9 +14,10 @@
* limitations under the License.
*/
package org.springframework.data.document.mongodb.mapping;
package org.springframework.data.mongodb.core.mapping;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@@ -27,12 +28,13 @@ import org.springframework.data.annotation.Persistent;
* Identifies a domain object to be persisted to MongoDB.
*
* @author Jon Brisbin <jbrisbin@vmware.com>
* @author Oliver Gierke ogierke@vmware.com
*/
@Persistent
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
public @interface Document {
String collection() default "";
}

View File

@@ -0,0 +1,29 @@
package org.springframework.data.mongodb.core.mapping;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Annotation to define custom metadata for document fields.
*
* @author Oliver Gierke
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Field {
/**
* The key to be used to store the field inside the document.
*
* @return
*/
String value() default "";
/**
* The order in which various fields shall be stored. Has to be a positive integer.
*
* @return the order the field shall have in the document or -1 if undefined.
*/
int order() default Integer.MAX_VALUE;
}

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