This document provides an overview of how SpringSource is making it easier for Java and Grails developers to build MongoDB applications. It begins with an introduction to the presenter and agenda. It then provides background on the Spring framework and how Spring Data and MongoDB simplify data access and integration. The document introduces Grails and demonstrates how to use Grails with MongoDB, including examples of domain classes, repositories, and relationships. It concludes by discussing future ideas for tighter integration between Spring and MongoDB.
SQL Database Design For Developers at php[tek] 2024
SpringSource and MongoDB: Making Java and Grails MongoDB Apps Easier
1. SpringSource and MongoDB
Chris Richardson
Author of POJOs in Action
Founder of CloudFoundry.com
Chris.Richardson@SpringSource.Com
@crichardson
2. Presentation Goal
How SpringSource is
making it easier for
Java and Grails
developers to build
MongoDB applications
Slide 2
3. About Chris
• Grew up in England and live in Oakland, CA
• Over 25+ years of software development
experience including 14 years of Java
• Speaker at JavaOne, SpringOne, NFJS,
JavaPolis, Spring Experience, etc.
• Organize the Oakland JUG and the Groovy
Grails meetup
http://www.theregister.co.uk/2009/08/19/springsource_cloud_foundry/
Slide 3
4. Agenda
o Introduction to Spring
o Spring Data and MongoDB
o Introduction to Grails
o Using Grails with MongoDB
Slide 4
5. The Spring framework
o Rapid evolution
n Spring 1.0 – March 2004
n Spring 2.0 – October 2006
n Spring 2.5 – December 2007
n Spring 3.0 – December 2009
n …
n Complete backward compatibility
o De facto standard programming
model for enterprise Java
o Two million+ developers
Slide 5
6. The Spring framework ecosystem
Framework Description
Spring framework The foundation
Spring.NET .NET port of the Spring framework
Spring Security (a.k.a. Acegi) Extensible framework providing authentication,
authorization and instance-level security
Spring Web Flow An excellent framework for building multi-page flows
Spring Web Services Contract-first, document–centric SOAP web services
Spring Dynamic Modules for OSGI Deploy Spring applications on OSGI
Spring Batch Powerful batch processing framework
Spring Integration Implements enterprise integration patterns
Spring BlazeDS integration Support for Adobe BlazeDS
Spring AMQP AMQP messaging, i.e. RabbitMQ
Spring Gemfire Simplify Gemfire application development
…
Slide 6
7. Spring programming model
Dependency Injection:
resolves inter-component Benefits:
dependencies, • Improved developer
metadata-driven productivity
• Higher quality code
• Portability across
application servers
POJO
Aspect-Oriented
Programming:
Portable Service modular
Abstractions: implementation of
Transactions, data cross cutting
access, … concerns
Slide 7
8. Portable service abstractions
o Portable service
abstractions
insulate developer Business
Logic
from low-level
programming Infrastructure code
o Less code Spring
o Simpler code Transactions
Security
Data access
o Increased
…
productivity
o Portable code Runtime Environment
Slide 8
9. Spring JDBC example
@Repository
class ActorDaoImpl implements ActorDao {
SimpleJdbcTemplate hides
@Autowired the low-level, messy
private SimpleJdbcTemplate simpleJdbcTemplate; details of using JDBC
public Actor findActor(String specialty, int age) {
String sql = "select id, first_name, last_name from T_ACTOR" +
" where specialty = ? and age = ?";
RowMapper<Actor> mapper = new RowMapper<Actor>() {
public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {
Actor actor = new Actor();
actor.setId(rs.getLong("id"));
actor.setFirstName(rs.getString("first_name"));
actor.setLastName(rs.getString("last_name"));
return actor;
}
};
return simpleJdbcTemplate.queryForObject(sql, mapper, specialty, age);
}
Slide 9
10. Externalized database configuration
@Configuration
public class AppConfig {
private @Value("#{jdbcProperties.url}") String jdbcUrl;
private @Value("#{jdbcProperties.username}") String username;
private @Value("#{jdbcProperties.password}") String password;
@Bean
public SimpleJdbcTemplate jdbcTemplate() {
return new SimpleJdbcTemplate (dataSource());
}
@Bean
public DataSource dataSource() {
return new DriverManagerDataSource(jdbcUrl, username, password);
}
}
Reads DB
configuration
<context:component-scan base-package="..."/> from file
<util:properties id="jdbcProperties" location="…/jdbc.properties"/>
Slide 10
11. Spring DataAccessException
o Base class for
exceptions thrown by DataAccess
Exception
DAOs
o Consistent exception Concurrency
Failure
Exception
...
handling across
Hibernate, JPA, JDBC, Optimistic
LockingFailure
etc. Exception Pessimistic
LockingFailure
Exception
o Unchecked exception
o Extensible exception CannotSerialize
mapping: CannotAcquire
LockException
Transaction
Exception
SqlExceptionTranslator
11
12. Agenda
o Introduction to the Spring framework
o Spring Data and MongoDB
o Introduction to Grails
o Using Grails with MongoDB
Slide 12
13. Spring Data Project Goals
o Bring classic Spring value propositions
to a wide range of NoSQL databases:
n Productivity
n Programming model consistency: E.g.
<NoSQL>Template classes
n “Portability”
o Many entry points to use
n Auto-generated repository implementations
n Opinionated APIs (Think JdbcTemplate)
n Object Mapping (Java and GORM)
n Cross Store Persistence Programming model
n Productivity support in Roo and Grails
Slide 13
14. MongoDB API usage patterns
o Create and store Mongo singleton
o Externalized server details
o Inserts/Updates
n Map application POJO è DBObject
n mongo.getDatabase(…).getCollection(…)
n Partial document updates
o Queries
n mongo.getDatabase(…).getCollection(…)
n Iterate through Cursor
n Map DBObject è application POJO
Ø Higher-level than JDBC but still repetitive,
…
Slide 14
15. Spring Data - MongoDB
o MongoTemplate
o Generic repository implementation
o Querydsl integration
o Cross-store persistence
Slide 15
17. Example entity
public class Restaurant {
private String id;
private String name;
private List<MenuItem> menuItems;
public Restaurant() {
} public class MenuItem {
private String name;
public Restaurant(String name) { private double price;
this.name = name;
… public MenuItem() {
} }
public String getName() { return name; } public MenuItem(String name,
double price) {
this.name = name;
public void setName(String name) {
this.price = price;
this.name = name;
} }
…getters and setters… …getters and setters…
Slide 17
18. Example data access code
@Repository
public class RestaurantRepository {
@Autowired
private MongoTemplate mongoTemplate;
public static final String RESTAURANTS_COLLECTION = "restaurants2";
public void add(Restaurant restaurant) {
mongoTemplate.save(RESTAURANTS_COLLECTION, restaurant);
}
public List<Restaurant> findRestaurantsByName(String restaurantName) {
return mongoTemplate.find(RESTAURANTS_COLLECTION,
new Query(where("name").is(restaurantName)),
Restaurant.class);
}
Slide 18
20. Spring MongoDB Example - Config
@Configuration public class MongoDbExampleConfig {
private @Value("#{mongoDbProperties.databaseName}") String mongoDbDatabase;
private @Value("#{mongoDbProperties.host}") String mongoDbHost;
@Bean public Mongo mongo() throws Exception { Singleton
return new Mongo(mongoDbHost);
}
@Bean public MongoTemplate mongoTemplate(Mongo mongo) {
return new MongoTemplate(mongo, mongoDbDatabase);
}…
<beans>
<context:annotation-config/>
External Config
<context:component-scan
base-package="net.chrisrichardson.mongodb.example"/>
mongodb.properties: <util:properties id="mongoDbProperties"
location="mongodb.properties"/>
databaseName=demo1
</beans>
host=192.168.253.150
Slide 20
21. Spring MongoDB Example Test
public class MongoDbExampleTest {
@Autowired private RestaurantRepository restaurantRepository;
@Test public void test() {
Restaurant ajanta = makeAjantaRestaurant();
restaurantRepository.add(ajanta);
List<Restaurant> results =
restaurantRepository.findRestaurantsByName("Ajanta");
assertRestaurantFound(ajanta, results);
}
private Restaurant makeAjantaRestaurant() {
Restaurant ajanta = new Restaurant("Ajanta");
ajanta.add(new MenuItem("Tandoori Portobello Mushrooms", 5.50));
ajanta.add(new MenuItem("Duck Curry Kerala", 15.00));
return ajanta;
}
…
Slide 21
22. Update example
@Repository
public class RestaurantRepository {
public void addMenuItem(String restaurantId,
MenuItem newMenuItem) {
DBObject dbo = new BasicDBObject();
mongoTemplate.getConverter().write(newMenuItem, dbo);
mongoTemplate.updateFirst(RESTAURANTS_COLLECTION,
new Query(where("_id").is(new ObjectId(restaurantId))),
new Update().push("menuItems", dbo));
}
Atomic, in-place update of document
Slide 22
23. Callbacks – access driver API with
exception translation
@Test
public void testDbCallback() { Exceptions are
Restaurant ajanta = makeAjantaRestaurant(); translated
restaurantRepository.add(ajanta);
assertCollectionExists("restaurants2");
}
private Void assertCollectionExists(final String collectionName) {
return mongoTemplate.execute(new DbCallback<Void>(){
@Override
public Void doInDB(DB db) {
Set<String> collectionNames = db.getCollectionNames();
Assert.assertTrue("Missing from " +
collectionNames,
collectionNames.contains(collectionName));
return null;
}});
}
Slide 23
24. Generic Mongo Repositories
o Generic Repositories support
n Basic CRUD methods
n Dynamic finders
n Pagination and sorting
o You define interface that extends
Repository interface
o Spring Data generates Mongo-specific
implementation at runtime
Slide 24
25. Example Mongo Generic Repository
public class Person {
private ObjectId id;
private String firstname;
private String lastname;
… getters and setters
}
interface PersonRepository
extends MongoRepository<Person, ObjectId> {
List<Person> findByLastname(String lastName);
}
Person p = new Person("John", "Doe");
personRepository.save(p);
Person p2 = personRepository.findOne(p.getId());
List<Person> johnDoes = personRepository.findByLastname("Doe");
assertEquals(1, johnDoes.size());
Slide 25
26. Example Mongo Repository config
<bean>
<mongo:repositories
base-package="net.chrisrichardson.mongodb.example.mongorepository"
mongo-template-ref="mongoTemplate" />
</beans>
Scans classpath looking for
subtypes of MongoRepository
in the base package
Slide 26
27. Richer mapping Annotations define mapping:
@Document, @Id, @Indexed,
@PersistanceConstructor,
@Document @CompoundIndex, @DBRef,
public class Person { @GeoSpatialIndexed, @Value
@Id Map fields instead of properties è
private ObjectId id; no getters or setters required
private String firstname;
Non-default constructor
@Indexed
private String lastname; Index generation
@PersistenceConstructor
public Person(String firstname, String lastname) {
this.firstname = firstname;
this.lastname = lastname;
}
….
}
Slide 27
28. Richer mapping configuration
@Configuration
public class MongoExampleConfig extends AbstractMongoConfiguration
{
…
@Override
public MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongo(),
mongoDbDatabase, null,
mappingMongoConverter());
}
@Override
public String getMappingBasePackage() {
return Person.class.getPackage().getName();
}
}
Slide 28
29. Support for the QueryDSL project
Generated from Type-safe
domain model class composable queries
QPerson person = QPerson.person;
Predicate predicate =
person.homeAddress.street1.eq("1 High Street")
.and(person.firstname.eq("John"))
List<Person> people = personRepository.findAll(predicate);
assertEquals(1, people.size());
assertPersonEquals(p, people.get(0));
Slide 29
30. Cross-store/polyglot persistence
Person person = new Person(…);
@Entity
public class Person { entityManager.persist(person);
// In Database
@Id private Long id; Person p2 = entityManager.find(…)
private String firstname;
private String lastname;
// In MongoDB
@RelatedDocument private Address address;
{ "_id" : ObjectId(”….."),
"_entity_id" : NumberLong(1),
"_entity_class" : "net.. Person",
"_entity_field_name" : "address",
"zip" : "94611", "street1" : "1 High Street", …}
Slide 30
31. Spring MongoDB – Future Ideas
o MongoTemplate
n Support common map-reduce operations
from Mongo Cookbook
n GridFS integration
o Tighter integration with Spring MVC
for activity monitoring
n See current example code on github
Slide 31
32. Agenda
o Introduction to Spring
o Spring Data and MongoDB
o Introduction to Grails
o Using Grails with MongoDB
Slide 32
33. Grails
o Open-source web application framework
o Uses Groovy – dynamic programming language
for the JVM
o Builds on mature frameworks such as Spring
Slide 33
34. GORM = Grails Object Relational Mapping
o Uses convention over configuration
n Defaults for which classes to persist
n Defaults for their O/R mapping
o Leverages the meta-object protocol
n Adds persistence methods and properties to
domain classes
n No equivalent of Hibernate Session
n Avoids the need for dependency injection
n Eliminates many DAO cookie-cutter methods
Slide 34
35. Database access made easy
customer
class Customer { <<table>>
String name id <<pk>>
} version
name
Customer c = new Customer("John Doe")
if (!c.save())
fail "validation failed: ${c.errors}" GORM adds
Methods and
Customer c2 = Customer.get(c.id) properties to class
at runtime
c2.delete()
assertNull Customer.get(c.id)
def customers = Customer.findAllByName(“Fred”)
Slide 35
36. Relationships don’t have to be difficult
customer
class Customer { <<table>>
String name id <<pk>>
static hasMany = [ accounts : Account] version
} name
class Account {
account
static belongsTo = [customer: Customer] <<table>>
double balance
id <<pk>>
} version
customer <<fk>>
Customer c = <…> balance
Account a = new Account(…)
c.addToAccounts(a)
assertSame c, a.customer
assertTrue c.accounts.contains(a)
Slide 36
37. When the defaults aren’t right
class Customer {
static transients = ["networth"]
static mapping = {
id column: 'customer_id' crc_customer
<<table>>
table 'crc_customer'
columns { customer_id <<pk>>
version
name column: 'customer_name' customer_name
}
}
def getNetworth() { …}
…
}
Slide 37
38. Agenda
o Introduction to Spring
o Spring Data and MongoDB
o Introduction to Grails
o Using Grails with MongoDB
Slide 38
39. GORM for MongoDB
o Extends GORM to support MongoDB
o Announced Nov 2010
o Currently 1.0M5
o Builds on
n Spring Data for MongoDB
n Spring Data Mapping
Slide 39
40. GORM/MongoDB example
grails uninstall-plugin hibernate
grails install-plugin mongodb
class Customer {
String name Unchanged
Address address
static hasMany = [ accounts : Account]
static embedded = ['address']
} class Address {
String street
class Account { String city
static belongsTo = [customer: Customer] String state
double balance String zip
} }
DataSource.groovy
mongo {
host = "localhost"
}
Slide 40
42. Cloud Foundry supports Mongo
o MongoDB is one of the provided services
è Deploy your MongoDB applications in
seconds
Slide 42
43. Summary
o Polyglot persistence is here to stay
o Spring Data is here to help you
o GORM let’s you use the familiar and
powerful GORM API with MongoDB
o Deploy your Mongo application on
CloudFoundry.com
o More info at
n http://www.springframework.org/spring-data
n http://www.cloudfoundry.com/
Slide 43
44. Next steps
Checkout Spring Data
Consider contributing
Deploy on CloudFoundry.com
My contact information
chris.richardson@springsource.com
Twitter: @crichardson
Slide 44