spring

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;
		}
		
}

  • @NodeEntity This annotation is used to mark the PoJo as Neo4J Entity.
  • @GraphId This marks the annotated field as the Node ID. It must be of the type java.lang.Long. If the field name is id, it need not be annotated.
  • @RelatedTo annotation is used to relate to other entities.
  • @Fetch If 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.

Download
You can download the source code of this example here: SpringDataNeo4JExample.zip

Chandan Singh

Chandan holds a degree in Computer Engineering and is a passionate software programmer. He has good experience in Java/J2EE Web-Application development for Banking and E-Commerce Domains.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button