Graphs in the Cloud: Spring + Neo4j on Heroku

Last week I hosted a webinar about running Java apps on Heroku that use the Spring Framework and the Neo4j graph database. Here is the recording of that webinar:

In the webinar I began by deploying a copy of the Spring MVC + Hibernate template app from on Heroku. Then I made a few modifications to the app to switch the persistence from Hibernate / JPA to Neo4j. You can get the full source code on GitHub.

Here is a quick recap of what I did to switch the template app to use Neo4j:

  1. Added the Neo4j Heroku Add-on:
    heroku addons:add neo4j
  2. Added the Spring Data Neo4j dependencies (optionally you can remove the unused JPA dependencies) to the “pom.xml” Maven build descriptor:
  3. Modified the “src/main/java/com/example/service/” interface to use the Neo4j GraphRepository:
    package com.example.service;
    import com.example.model.Person;
    public interface PersonService extends GraphRepository<Person> {
  4. Removed the unneeded “src/main/java/com/example/service/” DAO.
  5. Modified the “src/main/java/com/example/model/” POJO to be a @NodeEntity (instead of JPA Entity) and switched the “id” primary key property to be a Long annotated as a @GraphId:
    package com.example.model;
    public class Person {
        private Long id;
        // the rest is omitted
  6. Modified the “src/main/java/com/example/controller/” Spring MVC controller to use the new “PersonService”, take a Long parameter in the “deletePerson” method, and make the “deletePerson” and “addPerson” methods transactional:
    package com.example.controller;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.transaction.annotation.Transactional;
    import org.springframework.web.bind.annotation.ModelAttribute;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import com.example.model.Person;
    import com.example.service.PersonService;
    import java.util.Map;
    public class PersonController {
        private PersonService personService;
        public String listPeople(Map<String, Object> map) {
            map.put("person", new Person());
            map.put("peopleList", personService.findAll().iterator());
            return "people";
        @RequestMapping(value = "/add", method = RequestMethod.POST)
        public String addPerson(@ModelAttribute("person") Person person) {
            return "redirect:/people/";
        public String deletePerson(@PathVariable("personId") Long personId) {
            return "redirect:/people/";
  7. Then I modified the “src/main/resources/applicationContext.xml” Spring config file to use a file for local Neo4j storage in the “default” profile and then in the “prod” profile the “NEO4J_REST_URL”, “NEO4J_LOGIN”, and “NEO4J_PASSWORD” environment variables are used to connect to the Neo4j Heroku add-on service:
    <?xml  version="1.0" encoding="UTF-8"?>
    <beans xmlns=""
        <context:annotation-config />
        <context:spring-configured />
        <context:component-scan base-package="com.example" />
        <neo4j:repositories base-package="com.example.service"/>
        <bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
            <property name="prefix" value="/WEB-INF/jsp/" />
            <property name="suffix" value=".jsp" />
        <tx:annotation-driven />
        <beans profile="default">
            <neo4j:config storeDirectory="target/neo4j-db"/>
        <beans profile="prod">
            <bean class="" id="graphDatabaseService">
                <constructor-arg index="0" value="#{systemEnvironment['NEO4J_REST_URL']}"/>
                <constructor-arg index="1" value="#{systemEnvironment['NEO4J_LOGIN']}"/>
                <constructor-arg index="2" value="#{systemEnvironment['NEO4J_PASSWORD']}"/>
            <neo4j:config graphDatabaseService="graphDatabaseService"/>
  8. After testing my changes locally (which actually didn’t work in my webinar due to a problem with Eclipse) I committed my changes to the git repo and pushed them to Heroku:
    git push heroku master

If you want to just skip to a working example on the cloud, simply follow the instructions in the project README.

Hopefully that helps you get started with Neo4j and Java applications on the cloud!

BTW: If you watched the webinar, you probably noticed that my Maven and Eclipse were misbehaving. Turns out that M2E didn’t read my Maven config and all I had to do was right-click on the project, select Maven, and then Update Project Configuration. That got everything back in sync. My excuse for not being able to figure that out during the demo… I usually use IntelliJ IDEA. :)