Integrating Spring with MongoDB

Hi all from past few weeks i was doing research on NoSql, so in the research i found that NoSql has been categorized into three types “Document Database”,”Column Database”,”Graph Based Database”. I have chose two database to integrate with spring one is MongoDB(Document based database) and the other is Apache Cassandra (Column Family Database). In this post i am going to explain how to integrate MongoDB with Spring. In later posts i will explain how to integrate Spring with Cassandra.

Note : before start reading this post please install MongoDB, based on your OS compatibility.

Let us talk about mongodb a little bit before we dive into the tutorial.
MongoDB is cross-platform document oriented database that provide high reliability and scalability, this works on concepts of documents and collections.

A document is a set of key-value pairs. Documents have dynamic schema. Dynamic schema means that documents in the same collection do not need to have the same set of fields or structure, and common fields in a collection’s documents may hold different types of data.

A collection is set of documents, this collection can exist in single or multi-node cluster database. A document with in a collection can have different fields.

the project structure looks as below.
mongo-proj-struct

let us see the pom.xml configuration. This project is compatible with java 8 specification.
pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.spark.springdata.mongodb</groupId>
	<artifactId>SpringDataMongoDB</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>SpringDataMongoDB</name>
	<description>SpringDataMongoDB</description>

	<properties>
		<spring-version>3.2.8.RELEASE</spring-version>
	</properties>

	<!-- Spring framework -->

	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring-version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring-version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>${spring-version}</version>
		</dependency>

		<!-- mongodb java driver -->
		<dependency>
			<groupId>org.mongodb</groupId>
			<artifactId>mongo-java-driver</artifactId>
			<version>2.11.0</version>
		</dependency>

		<!-- Spring data mongodb -->
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-mongodb</artifactId>
			<version>1.2.0.RELEASE</version>
		</dependency>

		<dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib</artifactId>
			<version>2.2.2</version>
		</dependency>

		<!-- oracle and mysql -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.6</version>
		</dependency>

		<dependency>
			<groupId>com.oracle</groupId>
			<artifactId>ojdbc14</artifactId>
			<version>14.0.0</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.2</version>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

Now let us take a look at the Spring configuration file application-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cache="http://www.springframework.org/schema/cache"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee"
	xmlns:lang="http://www.springframework.org/schema/lang" xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:task="http://www.springframework.org/schema/task" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:util="http://www.springframework.org/schema/util"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.2.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
		http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
		http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
		http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.2.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
		http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd">

	<context:property-placeholder location="classpath:jdbc.properties" />

	<bean id="orclDataSource" class="oracle.jdbc.pool.OracleDataSource"
		destroy-method="close">
		<property name="URL" value="${orcl.jdbc.url}" />
		<property name="user" value="${orcl.jdbc.username}" />
		<property name="password" value="${orcl.jdbc.password}" />
		<property name="connectionCachingEnabled" value="true" />
	</bean>

	<bean name="mysqlDataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="${mysql.jdbc.driver}" />
		<property name="url" value="${mysql.jdbc.url}" />
		<property name="username" value="${mysql.jdbc.user}" />
		<property name="password" value="${mysql.jdbc.password}" />
	</bean>

	<context:component-scan base-package="com.spark.spring.data" />

	<!-- Factory bean that creates the Mongo instance -->
	<bean id="mongo" class="org.springframework.data.mongodb.core.MongoFactoryBean">
		<property name="host" value="localhost" />
	</bean>

	<!-- MongoTemplate for connecting and quering the documents in the database -->
	<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
		<constructor-arg name="mongo" ref="mongo" />
		<constructor-arg name="databaseName" value="person" />
	</bean>
	
	<bean id="personService" class="com.spark.spring.data.service.PersonService">
	    <constructor-arg name="mongoTemplate" ref="mongoTemplate"/>
	</bean>
</beans>

Now let us look at the Utility class that will help us to load the configuration file and fetch the different bean objects.

/**
 * 
 */
package com.spark.spring.data.util;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import javax.sql.DataSource;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.mongodb.core.MongoTemplate;

/**
 * @author PavanKumar Mantha
 * 
 */
public class SpringDataUtil {

	private static Future<ApplicationContext> applicationContext;

	static {
		ExecutorService executorService = Executors.newFixedThreadPool(1);
		applicationContext = executorService
				.submit(new Callable<ApplicationContext>() {
					public ApplicationContext call() throws Exception {
						return new ClassPathXmlApplicationContext(
								"application-context.xml");
					}

				});
	}

	/**
	 * @return
	 */
	public static ApplicationContext getContext() {
		try {
			return applicationContext.get();
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
	}

	/**
	 * @return
	 */
	public static DataSource getOracleDataSource() {
		try {
			return (DataSource) getContext().getBean("orclDataSource");
		} catch (Exception e) {
			throw new RuntimeException();
		}
	}

	/**
	 * @return
	 */
	public static DataSource getMysqleDataSource() {
		try {
			return (DataSource) getContext().getBean("mysqlDataSource");
		} catch (Exception e) {
			throw new RuntimeException();
		}
	}

	/**
	 * @param beanName
	 * @return
	 */
	public static Object getObject(String beanName) {
		return getContext().getBean(beanName);
	}

	public static MongoTemplate getMongoTemplate(){
		return (MongoTemplate) getContext().getBean("mongoTemplate");
	}
	
}

Let us create the domain objects in order to hold the data and these are the objects that gets persisted as documents inside mongodb.
Person.java

/**
 * 
 */
package com.spark.spring.data.document.obj;

import java.util.List;
import java.util.Set;

import org.springframework.data.annotation.Id;

/**
 * @author PavanKumar Mantha
 *
 */
public class Person {

	@Id
	private int id;
	private String firstName;
	private String lastName;
	private Set<String> phoneNumbers;
	private List<Address> address;

	/**
	 * @return the id
	 */
	public int getId() {
		return id;
	}

	/**
	 * @param id
	 *            the id to set
	 */
	public void setId(int id) {
		this.id = id;
	}

	/**
	 * @return the firstName
	 */
	public String getFirstName() {
		return firstName;
	}

	/**
	 * @param firstName
	 *            the firstName to set
	 */
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	/**
	 * @return the lastName
	 */
	public String getLastName() {
		return lastName;
	}

	/**
	 * @param lastName
	 *            the lastName to set
	 */
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	/**
	 * @return the phoneNumbers
	 */
	public Set<String> getPhoneNumbers() {
		return phoneNumbers;
	}

	/**
	 * @param phoneNumbers
	 *            the phoneNumbers to set
	 */
	public void setPhoneNumbers(Set<String> phoneNumbers) {
		this.phoneNumbers = phoneNumbers;
	}

	/**
	 * @return the address
	 */
	public List<Address> getAddress() {
		return address;
	}

	/**
	 * @param address
	 *            the address to set
	 */
	public void setAddress(List<Address> address) {
		this.address = address;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((address == null) ? 0 : address.hashCode());
		result = prime * result
				+ ((firstName == null) ? 0 : firstName.hashCode());
		result = prime * result + id;
		result = prime * result
				+ ((lastName == null) ? 0 : lastName.hashCode());
		result = prime * result
				+ ((phoneNumbers == null) ? 0 : phoneNumbers.hashCode());
		return result;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) obj;
		if (address == null) {
			if (other.address != null)
				return false;
		} else if (!address.equals(other.address))
			return false;
		if (firstName == null) {
			if (other.firstName != null)
				return false;
		} else if (!firstName.equals(other.firstName))
			return false;
		if (id != other.id)
			return false;
		if (lastName == null) {
			if (other.lastName != null)
				return false;
		} else if (!lastName.equals(other.lastName))
			return false;
		if (phoneNumbers == null) {
			if (other.phoneNumbers != null)
				return false;
		} else if (!phoneNumbers.equals(other.phoneNumbers))
			return false;
		return true;
	}
	
	

}

Adddress.java

/**
 * 
 */
package com.spark.spring.data.document.obj;

import org.springframework.data.annotation.Id;

/**
 * @author Sony
 *
 */
public class Address {

	@Id
	private int id;
	private String doorNo;
	private String street;
	private String city;
	private String country;
	private String zipcode;

	/**
	 * @return the id
	 */
	public int getId() {
		return id;
	}

	/**
	 * @param id
	 *            the id to set
	 */
	public void setId(int id) {
		this.id = id;
	}

	/**
	 * @return the doorNo
	 */
	public String getDoorNo() {
		return doorNo;
	}

	/**
	 * @param doorNo
	 *            the doorNo to set
	 */
	public void setDoorNo(String doorNo) {
		this.doorNo = doorNo;
	}

	/**
	 * @return the street
	 */
	public String getStreet() {
		return street;
	}

	/**
	 * @param street
	 *            the street to set
	 */
	public void setStreet(String street) {
		this.street = street;
	}

	/**
	 * @return the city
	 */
	public String getCity() {
		return city;
	}

	/**
	 * @param city
	 *            the city to set
	 */
	public void setCity(String city) {
		this.city = city;
	}

	/**
	 * @return the country
	 */
	public String getCountry() {
		return country;
	}

	/**
	 * @param country
	 *            the country to set
	 */
	public void setCountry(String country) {
		this.country = country;
	}

	/**
	 * @return the zipcode
	 */
	public String getZipcode() {
		return zipcode;
	}

	/**
	 * @param zipcode
	 *            the zipcode to set
	 */
	public void setZipcode(String zipcode) {
		this.zipcode = zipcode;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((city == null) ? 0 : city.hashCode());
		result = prime * result + ((country == null) ? 0 : country.hashCode());
		result = prime * result + ((doorNo == null) ? 0 : doorNo.hashCode());
		result = prime * result + ((street == null) ? 0 : street.hashCode());
		result = prime * result + ((zipcode == null) ? 0 : zipcode.hashCode());
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Address other = (Address) obj;
		if (city == null) {
			if (other.city != null)
				return false;
		} else if (!city.equals(other.city))
			return false;
		if (country == null) {
			if (other.country != null)
				return false;
		} else if (!country.equals(other.country))
			return false;
		if (doorNo == null) {
			if (other.doorNo != null)
				return false;
		} else if (!doorNo.equals(other.doorNo))
			return false;
		if (street == null) {
			if (other.street != null)
				return false;
		} else if (!street.equals(other.street))
			return false;
		if (zipcode == null) {
			if (other.zipcode != null)
				return false;
		} else if (!zipcode.equals(other.zipcode))
			return false;
		return true;
	}

}

Once the document objects are ready in hand let us start writing the service implementation. Please observe service class the MongoTemplate (Similar to JdbcTemplate) of SpringFramework gets injected as constructor argument and this is responsible of doing different operations on database.
PersonService.java

/**
 * 
 */
package com.spark.spring.data.service;

import java.util.List;

import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import com.spark.spring.data.document.obj.Person;

/**
 * @author PavanKumar Mantha
 * 
 */
public class PersonService {

	private MongoTemplate mongoTemplate;
	private static final String COLLECTION_NAME = "person";

	/**
	 * @param mongoTemplate
	 */
	public PersonService(MongoTemplate mongoTemplate) {
		this.mongoTemplate = mongoTemplate;
	}
	
	public void setMongoTemplateObject(MongoTemplate mongoTemplate) {
		this.mongoTemplate = mongoTemplate;
	}

	/**
	 * @param person
	 * @return
	 */
	public boolean addPerson(Person person) {
		boolean status = false;
		try {
			if (!mongoTemplate.collectionExists(Person.class)) {
				mongoTemplate.createCollection(Person.class);
			}
			mongoTemplate.insert(person, COLLECTION_NAME);
			status = true;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return status;
	}

	/**
	 * @return
	 */
	public List<Person> listPerson() {
		return mongoTemplate.findAll(Person.class, COLLECTION_NAME);
	}

	/**
	 * @param person
	 */
	public void deletePerson(Person person) {
		mongoTemplate.remove(person, COLLECTION_NAME);
	}
	
	/**
	 * 
	 */
	public void deleteAll() {
		mongoTemplate.getDb().dropDatabase();
	}
	
	/**
	 * @param id
	 * @return
	 */
	public Person findPersonById(String id){
		//BasicQuery query = new BasicQuery("{Name:'"+name+"'}");
		
		Query query = new Query();
		query.addCriteria(Criteria.where("_id").is(id));
		
		Person person = mongoTemplate.findOne(query, Person.class);
		return person;
	}
	
	/**
	 * @param id
	 * @return
	 */
	public boolean deletePersonById(String id){
		Person person = findPersonById(id);
		boolean status = false; 
		try {
			mongoTemplate.remove(person, COLLECTION_NAME);
			status = true;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return status;
	}

	/**
	 * @param person
	 */
	public void updatePerson(Person person) {
		mongoTemplate.save(person, COLLECTION_NAME);
	}
}

Once the service class is ready in hand it’s time for us to test this class, before running the test class make sure your mongodb is up and running.
SpringMongoTest.java

/**
 * 
 */
package com.spark.spring.data.mongo.test;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;

import org.springframework.data.mongodb.core.MongoTemplate;

import com.spark.spring.data.document.obj.Address;
import com.spark.spring.data.document.obj.Person;
import com.spark.spring.data.service.PersonService;
import com.spark.spring.data.util.SpringDataUtil;

/**
 * @author PavanKumar Mantha
 * 
 */
public class SpringMongoTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Person person = new Person();
		
		Address residenceAddress = new Address();
		residenceAddress.setId(1);
		residenceAddress.setDoorNo("7-48/4");
		residenceAddress.setStreet("Shankar Nagar");
		residenceAddress.setCity("Hyderabad");
		residenceAddress.setCountry("India");
		residenceAddress.setZipcode("500098");
		
		Address officeAddress = new Address();
		officeAddress.setId(2);
		officeAddress.setDoorNo("Ness Technologies");
		officeAddress.setStreet("Maximus 2B, Raheja Mind Space, HitechCity");
		officeAddress.setCity("Hyderabad");
		officeAddress.setCountry("India");
		officeAddress.setZipcode("500098");
		
		List<Address> addresses = new ArrayList<>();
		addresses.add(residenceAddress);
		addresses.add(officeAddress);
		
		person.setId(1);
		person.setFirstName("Kameswara Pavan Kumar");
		person.setLastName("Mantha");
		Set<String> phoneNumbers = new HashSet<>();
		phoneNumbers.add("9949493991");
		phoneNumbers.add("9603434035");
		person.setPhoneNumbers(phoneNumbers);
		person.setAddress(addresses);
		
		PersonService personService = (PersonService) SpringDataUtil
				.getObject("personService");

		personService.deleteAll();
		
		if(personService.addPerson(person)){
			System.out.println("Person Added");
		}

	}
}

if every thing goes well and good then we should see some thing as below as output in mongo database.
mongodb-output

Happy Coding, Happy MongoDB 🙂

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s