Spring Data Neo4j example (original) (raw)

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:

4.0.0 com.jcg.springNeo4J SpringDataNeo4JExample 0.0.1-SNAPSHOT org.springframework.data spring-data-neo4j 4.0.0.RELEASE
 <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>
  

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

}

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

<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" />

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.

Photo of 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.