diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/AbstractMongoConfiguration.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/AbstractMongoConfiguration.java index e516e62bc..1f84f70f8 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/AbstractMongoConfiguration.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/AbstractMongoConfiguration.java @@ -25,6 +25,7 @@ import org.springframework.context.annotation.ClassPathScanningCandidateComponen 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; @@ -38,27 +39,37 @@ import org.springframework.util.StringUtils; @Configuration public abstract class AbstractMongoConfiguration { - public abstract String defaultDatabaseName(); + public abstract String getDatabaseName(); @Bean public abstract Mongo mongo() throws Exception; @Bean - public abstract MongoTemplate mongoTemplate() throws Exception; - - @Bean - public MongoDbFactory mongoDbFactory() throws Exception { - return new SimpleMongoDbFactory(mongo(), defaultDatabaseName()); + public MongoTemplate mongoTemplate() throws Exception { + return new MongoTemplate(mongoDbFactory(), mappingMongoConverter()); } - public String mappingBasePackage() { + @Bean + 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; + } @Bean public MongoMappingContext mongoMappingContext() throws ClassNotFoundException, LinkageError { MongoMappingContext mappingContext = new MongoMappingContext(); - String basePackage = mappingBasePackage(); + String basePackage = getMappingBasePackage(); if (StringUtils.hasText(basePackage)) { ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(false); componentProvider.addIncludeFilter(new AnnotationTypeFilter(Document.class)); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/GeoSpatialAppConfig.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/GeoSpatialAppConfig.java index 80c4829b1..4dfaf3634 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/GeoSpatialAppConfig.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/GeoSpatialAppConfig.java @@ -26,7 +26,7 @@ import org.springframework.data.document.mongodb.mapping.event.MongoMappingEvent public class GeoSpatialAppConfig extends AbstractMongoConfiguration { @Override - public String defaultDatabaseName() { + public String getDatabaseName() { return "database"; } @@ -35,18 +35,13 @@ public class GeoSpatialAppConfig extends AbstractMongoConfiguration { return new Mongo("localhost"); } - @Bean - public MongoTemplate mongoTemplate() throws Exception { - return new MongoTemplate(mongoDbFactory()); - } - @Bean public LoggingEventListener mappingEventsListener() { return new LoggingEventListener(); } @Override - public String mappingBasePackage() { + public String getMappingBasePackage() { return "org.springframework.data.document.mongodb"; } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/TestMongoConfiguration.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/TestMongoConfiguration.java index b76b5cad6..a48b14bc4 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/TestMongoConfiguration.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/TestMongoConfiguration.java @@ -12,7 +12,7 @@ import org.springframework.data.document.mongodb.convert.MappingMongoConverter; public class TestMongoConfiguration extends AbstractMongoConfiguration { @Override - public String defaultDatabaseName() { + public String getDatabaseName() { return "database"; } @@ -21,13 +21,8 @@ public class TestMongoConfiguration extends AbstractMongoConfiguration { return new Mongo("localhost", 27017); } - @Bean - public MongoTemplate mongoTemplate() throws Exception { - return new MongoTemplate(mongoDbFactory()); - } - @Override - public String mappingBasePackage() { + public String getMappingBasePackage() { return "org.springframework.data.document.mongodb.mapping"; } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/GeoIndexedAppConfig.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/GeoIndexedAppConfig.java index f0327f198..5eb6abeb6 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/GeoIndexedAppConfig.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/GeoIndexedAppConfig.java @@ -4,6 +4,8 @@ import com.mongodb.Mongo; import org.springframework.context.annotation.Bean; import org.springframework.data.document.mongodb.MongoTemplate; import org.springframework.data.document.mongodb.config.AbstractMongoConfiguration; +import org.springframework.data.document.mongodb.mapping.event.LoggingEventListener; +import org.springframework.data.document.mongodb.mapping.event.MongoMappingEvent; public class GeoIndexedAppConfig extends AbstractMongoConfiguration { @@ -11,7 +13,7 @@ public class GeoIndexedAppConfig extends AbstractMongoConfiguration { public static String GEO_COLLECTION = "geolocation"; @Override - public String defaultDatabaseName() { + public String getDatabaseName() { return GEO_DB; } @@ -20,13 +22,13 @@ public class GeoIndexedAppConfig extends AbstractMongoConfiguration { return new Mongo("localhost"); } - @Bean - public MongoTemplate mongoTemplate() throws Exception { - return new MongoTemplate(mongoDbFactory()); - } - public String getMappingBasePackage() { return "org.springframework.data.document.mongodb.mapping"; } + + @Bean + public LoggingEventListener mappingEventsListener() { + return new LoggingEventListener(); + } } diff --git a/src/docbkx/reference/mapping.xml b/src/docbkx/reference/mapping.xml index 057f8856a..53a294ab8 100644 --- a/src/docbkx/reference/mapping.xml +++ b/src/docbkx/reference/mapping.xml @@ -1,8 +1,8 @@ - - Mapping support + + Mapping Rich maping support is provided by the MongoMappingConverter. @@ -23,15 +23,15 @@ SimpleMongoConverter has been deprecated in Spring Data MongoDB M3 as all of its functionality has been subsumed into - MappingMongoConverter. + MappingMongoConverter. -
- Convetion based Mapping +
+ Convention based Mapping - MongoMappingConverter has a few conventions for mapping objects to - documents when no additional mapping metadata is provided. The conventions - are: + MongoMappingConverter has a few conventions + for mapping objects to documents when no additional mapping metadata is + provided. The conventions are: @@ -53,7 +53,8 @@ - Public JavaBean properties + The fields of an object are used to convert to and from fields + in the document. Public JavaBean properties are not used. @@ -70,54 +71,57 @@ Mongo requires that you have an '_id' field for all documents. If you don't provide one the driver will assign a ObjectId with a generated - value. When using the MongoMappingConverter there - are certain rules that govern how properties from the Java class is - mapped to this '_id' field. + value. The "_id" field can be of any type the, other than arrays, so + long as it is unique. The driver naturally supports all primitive types + and Dates. When using the MongoMappingConverter + there are certain rules that govern how properties from the Java class + is mapped to this '_id' field. - The following outlines what property will be mapped to the '_id' + The following outlines what field will be mapped to the '_id' document field: - A property or field annotated with - @Id + A field annotated with @Id (org.springframework.data.annotation.Id) will be mapped to the '_id' field. - A property or field without an annotation but named + A field without an annotation but named id will be mapped to the '_id' field. The following outlines what type conversion, if any, will be done - on the property mapped to the _id document field when using the - MappingMongoConverter, the default for - MongoTemplate. + on the property mapped to the _id document field. - An id property or field declared as a String in the Java class - will be converted to and stored as an ObjectId if possible using a - Spring Converter<String, ObjectId>. Valid conversion rules are - delegated to the Mongo Java driver. If it cannot be converted to an - ObjectId, then the value will be stored as a string in the - database. + If a field named 'id' is declared as a String or BigInteger in + the Java class it will be converted to and stored as an ObjectId if + possible. ObjectId as a field type is also valid. If you specify a + value for 'id' in your application, the conversion to an ObjectId is + delected to the MongoDBdriver. If the specified 'id' value cannot be + converted to an ObjectId, then the value will be stored as is in the + document's _id field. - An id property or field declared as BigInteger in the Java - class will be converted to and stored as an ObjectId using a Spring - Converter<BigInteger, ObjectId>. + If a field named ' id' id field is not declared as a String, + BigInteger, or ObjectID in the Java class then you should assign it + a value in your application so it can be stored 'as-is' in the + document's _id field. + + + + If no field named 'id' is present in the Java class then an + implicit '_id' file will be generated by the driver but not mapped + to a property or field of the Java class. - If no field or property specified above is present in the Java - class then an implicit '_id' file will be generated by the driver but - not mapped to a property or field of the Java class. - When querying and updating MongoTemplate will use the converter to handle conversions of the Query and Update objects @@ -127,13 +131,22 @@
-
- MongoDB Mapping Configuration +
+ Mapping Configuration - You can configure the MongoMappingConverter as well as Mongo and - MongoTemplate eithe using Java or XML based metadata. + Unless explicitly configured, an instance of + MongoMappingConverter is created by default when + creating a MongoTemplate. You can create your own + instance of the MappingMongoConverter so as to tell + it where to scan the classpath at startup your domain classes in order to + extract metadata and construct indexes. Also, by creating your own + instance you can register Spring converters to use for mapping specific + classes to and from the database. - Here is an example using Spring's Java based configuration + You can configure the MongoMappingConverter + as well as com.mongodb.Mongo and MongoTemplate + either using Java or XML based metadata. Here is an example using Spring's + Java based configuration @Configuration class to configure MongoDB mapping support @@ -145,34 +158,60 @@ public class GeoSpatialAppConfig extends AbstractMongoConfiguration { public Mongo mongo() throws Exception { return new Mongo("localhost"); } - - @Bean - public MongoTemplate mongoTemplate() throws Exception { - return new MongoTemplate(mongo(), "geospatial", "newyork", mappingMongoConverter()); - } - - // specify which package to scan for @Document objects. - public String getMappingBasePackage() { - return "org.springframework.data.document.mongodb"; + + @Override + public String getDatabaseName() { + return "database"; + } + + @Override + public String getMappingBasePackage() { + return "com.bigbank.domain"; + } + + // the following are optional + + @Override + protected void afterMappingMongoConverterCreation(MappingMongoConverter converter) { + Set<Converter<?, ?>> converterList = new HashSet<Converter<?, ?>>(); + converterList.add(new org.springframework.data.document.mongodb.PersonReadConverter()); + converterList.add(new org.springframework.data.document.mongodb.PersonWriteConverter()); + converter.setCustomConverters(converterList); } - // optional @Bean public LoggingEventListener<MongoMappingEvent> mappingEventsListener() { return new LoggingEventListener<MongoMappingEvent>(); } + } AbstractMongoConfiguration requires you to - implement methods that define a Mongo as well as a - MongoTemplate object to the container. + implement methods that define a com.mongodb.Mongo + as well as provide a database name. AbstractMongoConfiguration also has a method you can override named 'getMappingBasePackage' which - tells the configuration where to scan for classes annotated with the + tells the converter where to scan for classes annotated with the @org.springframework.data.document.mongodb.mapping.Document annotation. + You can add additional converters to the converter by overriding the + method afterMappingMongoConverterCreation. Also shown in the above example + is a LoggingEventListener which logs + MongoMappingEvents that are posted onto Spring's + ApplicationContextEvent + infrastructure. + + + AbstractMongoConfiguration will create a MongoTemplate instance + and registered with the container under the name 'mongoTemplate'. + + + You can also override the method UserCredentials + getUserCredentials() to provide the username and password + information to connect to the database. + Spring's Mongo namespace enables you to easily enable mapping functionality in XML @@ -192,7 +231,16 @@ public class GeoSpatialAppConfig extends AbstractMongoConfiguration { <mongo:mongo host="localhost" port="27017"/> <!-- by default look for a Mongo object named 'mongo' - default name used for the converter is 'mappingConverter' --> - <mongo:mapping-converter base-package="com.mycompany.domain"/> + <mongo:mapping-converter base-package="com.bigbank.domain"> + <mongo:custom-converters> + <mongo:converter ref="readConverter"/> + <mongo:converter> + <bean class="org.springframework.data.document.mongodb.PersonWriteConverter"/> + </mongo:converter> + </mongo:custom-converters> + </mongo:mapping-converter> + + <bean id="readConverter" class="org.springframework.data.document.mongodb.PersonReadConverter"/> <!-- set the mapping converter to be used by the MongoTemplate --> <bean id="mongoTemplate" class="org.springframework.data.document.mongodb.MongoTemplate"> @@ -202,20 +250,20 @@ public class GeoSpatialAppConfig extends AbstractMongoConfiguration { <constructor-arg name="mongoConverter" ref="mappingConverter"/> </bean> + <bean class="org.springframework.data.document.mongodb.mapping.event.LoggingEventListener"/> </beans - This sets up the right objects in the ApplicationContext to perform - the full gamut of mapping operations. The base-package - property tells it where to scan for classes annotated with the + The base-package property tells it where to scan for + classes annotated with the @org.springframework.data.document.mongodb.mapping.Document annotation.
-
- Mapping Framework Usage +
+ Metadata based Mapping To take full advantage of the object mapping functionality inside the Spring Data/MongoDB support, you should annotate your mapped objects @@ -240,9 +288,12 @@ public class Person { @Id private ObjectId id; + @Indexed private Integer ssn; + private String firstName; + @Indexed private String lastName; @@ -258,11 +309,11 @@ public class Person { document, making searches faster. -
+
Mapping annotation overview - The MappingMongoConverter relies on metadata to drive the mapping - of objects to documents. An overview of the annotations is provided + The MappingMongoConverter can use metadata to drive the mapping of + objects to documents. An overview of the annotations is provided below @@ -381,25 +432,20 @@ public class Person<T extends Address> {
-
- Id fields - - The @Id annotation is applied to fields. MongoDB lets you store - any type as the _id field in the database, including long and string. It - is of course common to use ObjectId for this purpose. If the value on - the @Id field is not null, it is stored into the database as-is. If it - is null, then the converter will assume you want to store an ObjectId in - the database. For this to work the field type should be either ObjectId, - String, or BigInteger. -
- -
+
Compound Indexes Compound indexes are also supported. They are defined at the class - level, rather than on indidvidual properties. Here's an example that - creates a compound index of lastName in ascending order and - age in descending order: + level, rather than on indidvidual properties. + + + Compound indexes are very important to improve the performance + of queries that involve criteria on multiple fields + + + Here's an example that creates a compound index of + lastName in ascending order and age in + descending order: Example Compound Index Usage package com.mycompany.domain; @@ -421,7 +467,7 @@ public class Person {
-
+
Using DBRefs The mapping framework doesn't have to store child objects embedded @@ -474,7 +520,7 @@ public class Person {
-
+
Mapping Framework Events Events are fired throughout the lifecycle of the mapping process. @@ -486,15 +532,18 @@ public class Person { will cause them to be invoked whenever the event is dispatched.
-
+
Overriding Mapping with explicit Converters When storing and querying your objects it is convenient to have a MongoConverter instance handle the mapping of all Java types to DBObjects. However, sometimes you may want the MongoConverter's do most of the work - but allow you to selectivly handle the conversion for a particular type. - To do this, register one or more one or more + but allow you to selectivly handle the conversion for a particular type + or to optimize performance. + + To selectivly handle the conversion yourself, register one or more + one or more org.springframework.core.convert.converter.Converter instances with the MongoConverter. @@ -512,7 +561,37 @@ public class Person { purpose. The method afterMappingMongoConverterCreation in AbstractMongoConfiguration can be overriden to - configure a MappingMongoConverter. + configure a MappingMongoConverter. The examples here at the begining of this chapter show how to + perform the configuration using Java and XML. + + Below is an example of a Spring Converter implementation that + converts from a DBObject to a Person POJO. + + public class PersonReadConverter implements Converter<DBObject, Person> { + + public Person convert(DBObject source) { + Person p = new Person((ObjectId) source.get("_id"), (String) source.get("name")); + p.setAge((Integer) source.get("age")); + return p; + } + +} + + Here is an example that converts from a Person to a + DBObject. + + public class PersonWriteConverter implements Converter<Person, DBObject> { + + public DBObject convert(Person source) { + DBObject dbo = new BasicDBObject(); + dbo.put("_id", source.getId()); + dbo.put("name", source.getFirstName()); + dbo.put("age", source.getAge()); + return dbo; + } + +}
diff --git a/src/docbkx/reference/mongodb.xml b/src/docbkx/reference/mongodb.xml index ae6858c1a..c09d5cb5e 100644 --- a/src/docbkx/reference/mongodb.xml +++ b/src/docbkx/reference/mongodb.xml @@ -296,6 +296,61 @@ public class MongoApp {
+ +
+ Migrating from M2 to M3 + + There were several API changes introduced in the M3 release. To + upgrade from M2 to M3 you will need to make. For a full listing of API + changes please refer to this JDiff + Report. + + The major changes are with respect to MongoTemplate + + + + Constructors have changed on + MongoTemplate. MongoTemplate(Mongo, + String, String) and MongoTemplate(Mongo, String, + String, MongoConverter) were removed. + MongoTemplate(Mongo, String, UserCredentials), + MongoTemplate(MongoDbFactory), MongoTemplate(MongoDbFactory, + MongoConverter) were added. These changes will also effect + usage of wiring up MongoTemplate in + <bean/> XML defintions. + + + + MongoTemplate no longer takes a default + collection name. The collection name is now either specified when + the method is invoked or inferred from the Java class, either the + class name or via mapping metadata. + + + + Removed MongoTemplate methods that use + MongoReader and + MongoWriter. As an alternative + register a Spring converter with the MappingMongoConverter. See + here for + details. + + + + MongoTemplate's update method + arguements from (Query, Update) + to(Class<?>, Query, Update)was updateFirst + takes a java.lang.Class argument as the first + argument. + + + + Added findById methods to + MongoTemplate. + + +
@@ -628,7 +683,7 @@ public class MongoConfiguration { <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/> </bean> - +
@@ -1035,7 +1090,7 @@ DEBUG work.data.document.mongodb.MongoTemplate: 376 - Dropped collection [databa this case the collection name will be determined by name (not fully qualfied) of the class. You may also call the save operation with a specific collection name. The collection to store the object can be - overriden using mapping metadata. + overriden using mapping metadata. When inserting or saving, if the Id property is not set, the assumption is that its value will be autogenerated by the database. As @@ -1826,7 +1881,7 @@ List<Venue> venues = In order to have more fine grained control over the mapping process you can register Spring converters with the MongoConverter implementations such as the - MappingMongoConverter. + MappingMongoConverter. The MappingMongoConverter checks to see if there are any Spring converters that can handle a specific class before