Spring Data Neo4j example
In this example we shall demonstrate how to integrate Neo4J, a graph based NoSql database with Spring Data.
1. Introduction
Neo4j is an open source, graph based NoSQL database developed in Java and Scala. Like traditional relational Databases, Neo4J offers support to ACID properties. The graph based databases find their uses in use cases where the focus is strongly on inter-relationship between the entities of the domain like match-making,social networks, routing.
2. Installation
Neo4J can be downloaded from here. For the purpose of this demo we are using the community edition.
The user can install the Neo4j by simply following the steps provided by the installer, downloaded earlier.
3. Project Set-up
We shall use Maven to setup our project. Open Eclipse and create a simple Maven project and check the skip archetype selection checkbox on the dialogue box that appears. Replace the content of the existing pom.xml with the one provided below:
<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.jcg.springNeo4J</groupId>
<artifactId>SpringDataNeo4JExample</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId> org.neo4j </groupId>
<artifactId> neo4j-kernel </artifactId>
<version> 2.1.3 </version>
</dependency>
<dependency>
<groupId> javax.transaction </groupId>
<artifactId> jta </artifactId>
<version> 1.1 </version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.0.0.GA</version>
</dependency>
</dependencies>
</project>
4. Implementation
We start by creating the entity models for our example. Here are the entities:
Account.java
package com.jcg.examples.entity;
import java.io.Serializable;
import org.springframework.data.neo4j.annotation.GraphId;
import org.springframework.data.neo4j.annotation.NodeEntity;
@NodeEntity
public class Account implements Serializable
{
private static final long serialVersionUID = -8860106787025445177L;
@GraphId
private Long accountId;
private String accountType;
private Double balance;
public Long getAccountId()
{
return accountId;
}
public void setAccountId(Long accountId)
{
this.accountId = accountId;
}
public String getAccountType()
{
return accountType;
}
public void setAccountType(String accountType)
{
this.accountType = accountType;
}
public Double getBalance()
{
return balance;
}
public void setBalance(Double balance)
{
this.balance = balance;
}
@Override
public String toString()
{
return "Account [accountId=" + accountId + ", accountType=" + accountType + ", balance=" + balance + "]";
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((accountId == null) ? 0 : accountId.hashCode());
result = prime * result + ((accountType == null) ? 0 : accountType.hashCode());
result = prime * result + ((balance == null) ? 0 : balance.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Account other = (Account) obj;
if (accountId == null)
{
if (other.accountId != null)
return false;
}
else if (!accountId.equals(other.accountId))
return false;
if (accountType == null)
{
if (other.accountType != null)
return false;
}
else if (!accountType.equals(other.accountType))
return false;
if (balance == null)
{
if (other.balance != null)
return false;
}
else if (!balance.equals(other.balance))
return false;
return true;
}
}
Person.java
package com.jcg.examples.entity;
import java.io.Serializable;
import org.springframework.data.neo4j.annotation.Fetch;
import org.springframework.data.neo4j.annotation.GraphId;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.data.neo4j.annotation.RelatedTo;
@NodeEntity
public class Person implements Serializable
{
private static final long serialVersionUID = -5378396373373165919L;
@GraphId
private Long id;
private String personName;
@RelatedTo
@Fetch
private Account account;
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public Account getAccount()
{
return account;
}
public void setAccount(Account account)
{
this.account = account;
}
@Override
public String toString()
{
return "Person [id=" + id + ", account=" + account + "]";
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((account == null) ? 0 : account.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@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 (account == null)
{
if (other.account != null)
return false;
}
else if (!account.equals(other.account))
return false;
if (id == null)
{
if (other.id != null)
return false;
}
else if (!id.equals(other.id))
return false;
return true;
}
public String getPersonName()
{
return personName;
}
public void setPersonName(String personName)
{
this.personName = personName;
}
}
@NodeEntityThis annotation is used to mark the PoJo as Neo4J Entity.@GraphIdThis marks the annotated field as the Node ID. It must be of the typejava.lang.Long. If the field name isid, it need not be annotated.@RelatedToannotation is used to relate to other entities.@FetchIf this tag is present on a relationship property, it eagerly fetches that entity.
Now that the entities are configured, we can create the DAO layer by configuring the basic repositories:
AccountRepo.java
package com.jcg.examples.repo;
import org.springframework.data.neo4j.repository.GraphRepository;
import org.springframework.stereotype.Repository;
import com.jcg.examples.entity.Account;
@Repository
public interface AccountRepo extends GraphRepository
{
}
PersonRepo.java
package com.jcg.examples.repo;
import org.springframework.data.neo4j.repository.GraphRepository;
import org.springframework.stereotype.Repository;
import com.jcg.examples.entity.Person;
@Repository
public interface PersonRepo extends GraphRepository
{
}
Spring Data provides a number of inbuilt method for manipulating the Data. We need not write the queries for basic data manipulation and reading. It is achieved by extending the GraphRepository and declaring the proper Generics as per the PoJo, which in our case is the Person and Account.
In case the Developer is not satisfied with the existing method, he can create his own method by specifying the Query using the @Query annotation.
The Spring IoC Container creates an instance of this Repository and makes it available to be used as a Bean since we have annotated it with the stereotype annotation @Repository and enabled component-scan in the spring configuration xml.
Here’s a trivial implementation of the service layer for Person
PersonService.java
package com.jcg.examples.service;
import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.jcg.examples.entity.Person;
import com.jcg.examples.repo.PersonRepo;
@Service
public class PersonService
{
@Autowired
private PersonRepo personRepo;
@Transactional
public Person save(Person person)
{
return personRepo.save(person);
}
@Transactional
public void delete(Long personId)
{
personRepo.delete(personId);
}
@Transactional
public Person get(Long personId)
{
return personRepo.findOne(personId);
}
@SuppressWarnings("unchecked")
public Collection findAll()
{
return personRepo.findAll().as(Collection.class);
}
public PersonRepo getPersonRepo()
{
return personRepo;
}
public void setPersonRepo(PersonRepo personRepo)
{
this.personRepo = personRepo;
}
}
We have annotated the service methods with @Transactional to wrap around the operations within a transaction boundary.
The last and the most important part is to configure the Spring Container using the spring-configuration.xml :
spring-configuration.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:neo4j="http://www.springframework.org/schema/data/neo4j"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/neo4j http://www.springframework.org/schema/data/neo4j/spring-neo4j.xsd">
<context:component-scan base-package="com.jcg.examples" />
<neo4j:config storeDirectory="C:\\Users\\chandansingh\\Documents\\Neo4j" base-package="com.jcg.examples.entity"/>
<neo4j:repositories base-package="com.jcg.examples.repo"/>
<bean id="applicationTest" class="com.jcg.examples.main.ApplicationTest" />
</beans>
Line-13 : Declares the Neo4J store location and the location of the Neo4J entities.
Line-15 : Scan and initiate the Neo4J repositories.
Now that all is set, let’s run the application and test out the code! Here’s Application class that loads the XML file to instantiate the Spring Container and execute a few queries.
ApplicationTest.java
package com.jcg.examples.main;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import com.jcg.examples.entity.Account;
import com.jcg.examples.entity.Person;
import com.jcg.examples.service.AccountService;
import com.jcg.examples.service.PersonService;
public class ApplicationTest
{
@Autowired
private PersonService personService;
@Autowired
private AccountService accountService;
public static void main(String[] args)
{
ApplicationContext context = new ClassPathXmlApplicationContext(new ClassPathResource("spring-configuration.xml").getPath());
ApplicationTest applicationTest = context.getBean(ApplicationTest.class);
System.out.println("Starting with the Tests..");
Long personId = applicationTest.savePerson();
applicationTest.printPerson(personId);
System.out.println("Finished!");
}
private Long savePerson()
{
Person person = new Person();
person.setPersonName("Chandan Singh");
Account account = new Account();
account.setBalance(212.21);
account.setAccountType("Savings");
person.setAccount(account);
person = personService.save(person);
System.out.println("Saved Person sucessfully!");
return person.getId();
}
private void printPerson(Long personId)
{
System.out.println(personService.get(personId));
}
public PersonService getPersonService()
{
return personService;
}
public void setPersonService(PersonService personService)
{
this.personService = personService;
}
public AccountService getAccountService()
{
return accountService;
}
public void setAccountService(AccountService accountService)
{
this.accountService = accountService;
}
}
Here’s the sample output of the program :
Starting with the Tests.. Saved Person sucessfully! Person [id=6, account=Account [accountId=7, accountType=Savings, balance=212.21]] Finished!
5. Download Source Code
In this example, we studied how we can integrate Neo4J with Spring Data.
You can download the source code of this example here: SpringDataNeo4JExample.zip


