Goals For Java developers who use the Spring Framework or Spring Boot, this guide introduces Spring integration but emphasizes the Spring Data Neo4j library. The library provides convenient access to Neo4j including object mapping, Spring Data repositories, conversion, transaction handling,… Read more →

Goals
For Java developers who use the Spring Framework or Spring Boot, this guide introduces Spring integration but emphasizes the Spring Data Neo4j library. The library provides convenient access to Neo4j including object mapping, Spring Data repositories, conversion, transaction handling, etc.
Prerequisites
You should be familiar with graph database concepts and the property graph model. Having installed Neo4j and tried out the Cypher query language helps too. You should also be familiar with Spring. Knowing Spring Data and Spring Boot are both great additions to your toolbox, as well. When developing with Neo4j, please use JDK 8 and your favorite IDE.
Intermediate

Neo4j for Spring Users

sdn

Neo4j offers a rich set of possibilities for developers using Spring. If you are looking to use Neo4j on the JVM in general, check out our Java Developer’s Guide.

If you want to benefit from full-fledged Object Mapping and the other helpful support that comes with Spring Data, use Spring Data Neo4j.

Neo4j’s Spring Data integration was the founding project of the Spring Data efforts, started by Rod Johnson and Emil Eifrem. It integrates tightly with the Spring Framework and offers Object-Graph Mapping (OGM) on top of Neo4j.

It is based on the Neo4j-OGM a plain Java Object-Graph-Mapper and integrates in the Spring Data infrastructure, including Spring Data repository and annotated object-mapping support.

Spring Data Neo4j is also supported by Spring Boot. You can use the Spring Initializr page to get started with Spring Data Neo4j immediately.

Spring Data Neo4j

Though Spring Data Neo4j has been around for a long time, Neo4j’s APIs and usage evolved quickly from an embedded Java-only database to a server solution with mostly Cypher interactions. At that point, we made the decision that a clean slate and reimplementation of the library was the best approach to embrace the modern Neo4j architecture. In a joint effort with our partner GraphAware, the all-new Spring Data Neo4j library was developed and tested by existing users.

To use Spring Data Neo4j, all you need is the Spring Data Neo4j dependencies and a few annotations to use the object-graph mapping. Then, you can annotate your entities and define Spring-Data-Repositories as convenient interfaces to your persistence layer.

Features

  • Spring Boot Integration
  • annotation-based object-graph mapping
  • interface-based repository support with annotated and derived finder methods
  • fast class metadata scanning
  • optimized management of data loading and change tracking for minimal data transfers
  • multiple transports: binary protocol, HTTP, and embedded
  • persistence lifecycle events

Quickstart

Spring Boot takes on much of the responsibility of application configuration and bootstrap, so we have chosen to take advantage of that assistance in our project, as well. The example project code for Spring Data Neo4j is checked in to GitHub. You can clone the repository and run the code along with this guide, or you can build the project from the ground up from the Spring Initializr page. For this approach, you can follow along with a blog post for step-by-step instructions.

The dependency for Spring Data Neo4j needs to be added in order to use the capabilities.

Spring-Data-Neo4j dependency
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-neo4j</artifactId>
    </dependency>
</dependencies>

The entities outline our main objects in the application. In our graph, they will be the nodes.

GraphModel

There is a Person entity and a Movie entity, so a domain class for each is needed. In each case, the class is annotated with @NodeEntity to use these objects as nodes in the graph. Each contains an id field that is annotated as the id and populated with a value generated by the database (@GeneratedValue). After the id, additional fields are set up to hold different information we want to capture about the object.

The last few lines of each class map the relationship between the nodes. Reference fields in both the Person and Movie classes are annotated with @Relationship and the type of relationship as ACTED_IN. The direction property is outgoing by default, so we must specify that the relationship is incoming on the Movie node. To capture additional attributes about the relationship between the two entities, a new relationship entity called Role is created for Person to be connected to Movie by the Role he/she played. This class, we annotate as a relationship entity and specify the name of the relationship (ACTED_IN). The Role class also has an id field that is managed by the database and a list to contain the possible roles that a person could play in a movie (could be more than one). Finally, annotations are added to mark the Person and Movie nodes as start- and end-nodes for the relationship. We now have our graph structure mapped in our application. This is the object-graph mapping (OGM) piece.

Entities
@NodeEntity
public class Person {

   @Id @GeneratedValue private Long id;
   private String name;
   private int born;

   @Relationship(type = "ACTED_IN")
   private List<Movie> movies = new ArrayList<>();
}

@NodeEntity
public class Movie {

   @Id @GeneratedValue private Long id;
   private String title;
   private int released;
   private String tagline;

   @JsonIgnoreProperties("movie")
   @Relationship(type = "ACTED_IN", direction = Relationship.INCOMING)
   private List<Role> roles;
}

@RelationshipEntity(type = "ACTED_IN")
public class Role {

    @Id @GeneratedValue private Long id;
	private List<String> roles = new ArrayList<>();

	@StartNode
	private Person person;

	@EndNode
	private Movie movie;
}

The repository interface allows the developer to create methods and queries needed for retrieving the data from the database.

The interface extends the Neo4jRepository, which extends the Spring CRUDRepository for persisting and retrieving data. With the CRUDRepository, a lot of CRUD methods (such as findOne, findAll, save, delete, etc.) come already out-of-the-box. So, without even having to specify any method, basic data access is provided.

In the following sample, you see two different kinds of custom methods. Some are defined in a specific pattern so that the queries can be derived for us (like the findByTitle method). Others must be specifically written and annotated with @Query. For more information, see the Spring Data Neo4j page and choose the latest documentation link on the right side of the page.

Declare a repository interface
public interface MovieRepository extends Neo4jRepository<Movie, Long> {

    Movie findByTitle(@Param("title") String title);

    Collection<Movie> findByTitleLike(@Param("title") String title);

    @Query("MATCH (m:Movie)<-[r:ACTED_IN]-(a:Person) RETURN m,r,a LIMIT {limit}")
    Collection<Movie> graph(@Param("limit") int limit);
}

The next section of code uses our repository methods in the MovieService class. The class starts by annotating it as a regular service with @Service. Then, the MovieService class injects the MovieRepository using a constructor.

Annotating these methods with @Transactional and read-only allows the smart client to efficiently route and execute the statements. In each method, the specified method is queried from the MovieRepository interface and results are returned to the service caller.

Use repository
@Service
public class MovieService {

    private final MovieRepository movieRepository;
    public MovieService(MovieRepository movieRepository) {
        this.movieRepository = movieRepository;
    }

    @Transactional(readOnly = true)
    public Movie findByTitle(String title) {
        return movieRepository.findByTitle(title);
    }

    @Transactional(readOnly = true)
    public Collection<Movie> findByTitleLike(String title) {
        return movieRepository.findByTitleLike(title);
    }

    @Transactional(readOnly = true)
    public Map<String, Object>  graph(int limit) {
        Collection<Movie> result = movieRepository.graph(limit);
        return toD3Format(result);
    }
}

For a more thorough walkthrough of the code, see the resources linked below. We also provide a number of example projects using Spring Data Neo4j, Spring Boot, and web frameworks like Angular.js on GitHub.