├── .gitignore ├── README.md ├── pom.xml └── v4.1.1 ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── ambergarden │ │ └── samples │ │ └── neo4j │ │ ├── GraphDBConfiguration.java │ │ ├── entities │ │ ├── Book.java │ │ ├── Person.java │ │ ├── base │ │ │ ├── AbstractEntity.java │ │ │ ├── DescriptiveEntity.java │ │ │ └── NamedEntity.java │ │ └── relationships │ │ │ └── WriterOf.java │ │ └── repositories │ │ ├── BookRepository.java │ │ └── PersonRepository.java └── resources │ └── META-INF │ └── spring │ └── db │ └── dal-neo4j-context.xml └── test ├── java └── com │ └── ambergarden │ └── samples │ └── neo4j │ └── repositories │ ├── BookRepositoryTest.java │ └── PersonRepositoryTest.java └── resources └── spring └── dal-test-context.xml /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .settings 3 | .project 4 | .classpath 5 | *.iml 6 | *~ 7 | \#*# 8 | build 9 | target 10 | .springBeans -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spring Data Neo4J Sample Project 2 | This is a small project which shows how to use Spring Data Neo4J. 3 | 4 | Neo4J is a well-known graph database. Spring Data Neo4J is a Spring project which allows users to use annotations and Spring Data conventions to operate Neo4J. It is always a good choice if you want to use Neo4J in a Spring-based project. 5 | 6 | They both grow rapidly. As a result, toturals and samples for Spring Neo4J quickly turns to be outdated. 7 | 8 | In this repository, we will try to demonstrate the usage, in a versionized style. 9 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | com.ambergarden.samples.neo4j 6 | parent 7 | pom 8 | ${project.version} 9 | 10 | 11 | v4.1.1 12 | 13 | 14 | 15 | 0.1.0-BUILD-SNAPSHOT 16 | 1.7 17 | 4.2.5.RELEASE 18 | 4.1.1.RELEASE 19 | 2.0.1 20 | 4.9 21 | 22 | 23 | -------------------------------------------------------------------------------- /v4.1.1/pom.xml: -------------------------------------------------------------------------------- 1 |  2 | 4 | 4.0.0 5 | 6 | 7 | com.ambergarden.samples.neo4j 8 | parent 9 | ${project.version} 10 | ../ 11 | 12 | 13 | version-4.1.1 14 | jar 15 | 16 | 17 | 18 | org.neo4j 19 | neo4j-ogm-embedded-driver 20 | ${ogm.version} 21 | 22 | 23 | org.springframework 24 | spring-test 25 | ${spring.version} 26 | 27 | 28 | junit 29 | junit 30 | ${junit.version} 31 | 32 | 33 | org.springframework.data 34 | spring-data-neo4j 35 | ${spring.data.neo4j.version} 36 | 37 | 38 | -------------------------------------------------------------------------------- /v4.1.1/src/main/java/com/ambergarden/samples/neo4j/GraphDBConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.ambergarden.samples.neo4j; 2 | 3 | import org.neo4j.ogm.session.SessionFactory; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.data.neo4j.config.Neo4jConfiguration; 7 | import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; 8 | import org.springframework.transaction.annotation.EnableTransactionManagement; 9 | 10 | /** 11 | * Spring JavaConfig configuration class to setup a Spring container and infrastructure components. 12 | */ 13 | @Configuration 14 | @EnableNeo4jRepositories(basePackages = "com.ambergarden.samples.neo4j.repositories") 15 | @EnableTransactionManagement 16 | public class GraphDBConfiguration extends Neo4jConfiguration { 17 | 18 | @Bean 19 | public org.neo4j.ogm.config.Configuration getConfiguration() { 20 | org.neo4j.ogm.config.Configuration config = 21 | new org.neo4j.ogm.config.Configuration(); 22 | // TODO: Temporary uses the embedded driver. We need to switch to http 23 | // driver. Then we can horizontally scale neo4j 24 | config.driverConfiguration() 25 | .setDriverClassName("org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver") 26 | .setURI("file:/D:/neo4j/graph.db/"); 27 | return config; 28 | } 29 | 30 | @Override 31 | @Bean 32 | public SessionFactory getSessionFactory() { 33 | // Return the session factory which also includes the persistent entities 34 | return new SessionFactory(getConfiguration(), "com.ambergarden.samples.neo4j.entities"); 35 | } 36 | } -------------------------------------------------------------------------------- /v4.1.1/src/main/java/com/ambergarden/samples/neo4j/entities/Book.java: -------------------------------------------------------------------------------- 1 | package com.ambergarden.samples.neo4j.entities; 2 | 3 | import java.util.Set; 4 | 5 | import org.neo4j.ogm.annotation.NodeEntity; 6 | import org.neo4j.ogm.annotation.Relationship; 7 | 8 | import com.ambergarden.samples.neo4j.entities.base.DescriptiveEntity; 9 | import com.ambergarden.samples.neo4j.entities.relationships.WriterOf; 10 | 11 | /** 12 | * Entity which represents a book 13 | */ 14 | @NodeEntity 15 | public class Book extends DescriptiveEntity { 16 | @Relationship(type="WRITER_OF", direction=Relationship.INCOMING) 17 | private Set writers; 18 | 19 | @Relationship(type="READER_OF", direction=Relationship.INCOMING) 20 | private Set readers; 21 | 22 | public Set getWriters() { 23 | return writers; 24 | } 25 | 26 | public void setWriters(Set writers) { 27 | this.writers = writers; 28 | } 29 | 30 | public Set getReaders() { 31 | return readers; 32 | } 33 | 34 | public void setReaders(Set readers) { 35 | this.readers = readers; 36 | } 37 | } -------------------------------------------------------------------------------- /v4.1.1/src/main/java/com/ambergarden/samples/neo4j/entities/Person.java: -------------------------------------------------------------------------------- 1 | package com.ambergarden.samples.neo4j.entities; 2 | 3 | import java.util.Set; 4 | 5 | import org.neo4j.ogm.annotation.NodeEntity; 6 | import org.neo4j.ogm.annotation.Relationship; 7 | 8 | import com.ambergarden.samples.neo4j.entities.base.NamedEntity; 9 | import com.ambergarden.samples.neo4j.entities.relationships.WriterOf; 10 | 11 | /** 12 | * Entity which represents a person 13 | */ 14 | @NodeEntity 15 | public class Person extends NamedEntity { 16 | @Relationship(type="WRITER_OF") 17 | private Set writings; 18 | 19 | @Relationship(type="READER_OF") 20 | private Set books; 21 | 22 | public Set getWritings() { 23 | return writings; 24 | } 25 | 26 | public void setWritings(Set writings) { 27 | this.writings = writings; 28 | } 29 | 30 | public Set getBooks() { 31 | return books; 32 | } 33 | 34 | public void setBooks(Set books) { 35 | this.books = books; 36 | } 37 | } -------------------------------------------------------------------------------- /v4.1.1/src/main/java/com/ambergarden/samples/neo4j/entities/base/AbstractEntity.java: -------------------------------------------------------------------------------- 1 | package com.ambergarden.samples.neo4j.entities.base; 2 | 3 | import org.neo4j.ogm.annotation.GraphId; 4 | 5 | /** 6 | * The abstract entity which contains the basic fields such 7 | * as id, hashCode and equals function 8 | */ 9 | public abstract class AbstractEntity { 10 | 11 | @GraphId 12 | private Long id; 13 | 14 | public Long getId() { 15 | return id; 16 | } 17 | 18 | public void setId(Long id) { 19 | this.id = id; 20 | } 21 | 22 | @Override 23 | public boolean equals(Object obj) { 24 | if (this == obj) { 25 | return true; 26 | } 27 | 28 | if (obj == null) { 29 | return false; 30 | } 31 | 32 | if (getClass() != obj.getClass()) { 33 | return false; 34 | } 35 | 36 | if (this.id == null) { 37 | // For newly created entity, id will be null 38 | return false; 39 | } 40 | 41 | AbstractEntity entity = (AbstractEntity) obj; 42 | return this.id.equals(entity.id); 43 | } 44 | 45 | @Override 46 | public int hashCode() { 47 | return id == null ? super.hashCode() : id.hashCode(); 48 | } 49 | } -------------------------------------------------------------------------------- /v4.1.1/src/main/java/com/ambergarden/samples/neo4j/entities/base/DescriptiveEntity.java: -------------------------------------------------------------------------------- 1 | package com.ambergarden.samples.neo4j.entities.base; 2 | 3 | import org.neo4j.ogm.annotation.NodeEntity; 4 | 5 | /** 6 | * The abstract entity which represents an entity with a description 7 | */ 8 | @NodeEntity 9 | public abstract class DescriptiveEntity extends NamedEntity { 10 | private String description; 11 | 12 | public String getDescription() { 13 | return description; 14 | } 15 | 16 | public void setDescription(String description) { 17 | this.description = description; 18 | } 19 | } -------------------------------------------------------------------------------- /v4.1.1/src/main/java/com/ambergarden/samples/neo4j/entities/base/NamedEntity.java: -------------------------------------------------------------------------------- 1 | package com.ambergarden.samples.neo4j.entities.base; 2 | 3 | import org.neo4j.ogm.annotation.NodeEntity; 4 | 5 | /** 6 | * The abstract entity which represents an entity with a name 7 | */ 8 | @NodeEntity 9 | public abstract class NamedEntity extends AbstractEntity { 10 | private String name; 11 | 12 | public String getName() { 13 | return name; 14 | } 15 | 16 | public void setName(String name) { 17 | this.name = name; 18 | } 19 | } -------------------------------------------------------------------------------- /v4.1.1/src/main/java/com/ambergarden/samples/neo4j/entities/relationships/WriterOf.java: -------------------------------------------------------------------------------- 1 | package com.ambergarden.samples.neo4j.entities.relationships; 2 | 3 | import java.util.Date; 4 | 5 | import org.neo4j.ogm.annotation.EndNode; 6 | import org.neo4j.ogm.annotation.RelationshipEntity; 7 | import org.neo4j.ogm.annotation.StartNode; 8 | 9 | import com.ambergarden.samples.neo4j.entities.Book; 10 | import com.ambergarden.samples.neo4j.entities.Person; 11 | import com.ambergarden.samples.neo4j.entities.base.AbstractEntity; 12 | 13 | @RelationshipEntity(type="WRITER_OF") 14 | public class WriterOf extends AbstractEntity { 15 | @StartNode 16 | private Person writer; 17 | 18 | @EndNode 19 | private Book book; 20 | 21 | private Date startDate; 22 | 23 | private Date endDate; 24 | 25 | public Person getWriter() { 26 | return writer; 27 | } 28 | 29 | public void setWriter(Person writer) { 30 | this.writer = writer; 31 | } 32 | 33 | public Book getBook() { 34 | return book; 35 | } 36 | 37 | public void setBook(Book book) { 38 | this.book = book; 39 | } 40 | 41 | public Date getStartDate() { 42 | return startDate; 43 | } 44 | 45 | public void setStartDate(Date startDate) { 46 | this.startDate = startDate; 47 | } 48 | 49 | public Date getEndDate() { 50 | return endDate; 51 | } 52 | 53 | public void setEndDate(Date endDate) { 54 | this.endDate = endDate; 55 | } 56 | } -------------------------------------------------------------------------------- /v4.1.1/src/main/java/com/ambergarden/samples/neo4j/repositories/BookRepository.java: -------------------------------------------------------------------------------- 1 | package com.ambergarden.samples.neo4j.repositories; 2 | 3 | import org.springframework.data.neo4j.repository.GraphRepository; 4 | 5 | import com.ambergarden.samples.neo4j.entities.Book; 6 | 7 | /** 8 | * The repository to perform CRUD operations on book entities 9 | */ 10 | public interface BookRepository extends GraphRepository { 11 | } -------------------------------------------------------------------------------- /v4.1.1/src/main/java/com/ambergarden/samples/neo4j/repositories/PersonRepository.java: -------------------------------------------------------------------------------- 1 | package com.ambergarden.samples.neo4j.repositories; 2 | 3 | import org.springframework.data.neo4j.repository.GraphRepository; 4 | 5 | import com.ambergarden.samples.neo4j.entities.Person; 6 | 7 | /** 8 | * The repository to perform CRUD operations on person entities 9 | */ 10 | public interface PersonRepository extends GraphRepository { 11 | } -------------------------------------------------------------------------------- /v4.1.1/src/main/resources/META-INF/spring/db/dal-neo4j-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 12 | 13 | -------------------------------------------------------------------------------- /v4.1.1/src/test/java/com/ambergarden/samples/neo4j/repositories/BookRepositoryTest.java: -------------------------------------------------------------------------------- 1 | package com.ambergarden.samples.neo4j.repositories; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNotNull; 5 | import static org.junit.Assert.assertNull; 6 | 7 | import java.util.Date; 8 | import java.util.HashSet; 9 | import java.util.Set; 10 | 11 | import org.junit.Test; 12 | import org.junit.runner.RunWith; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.test.context.ContextConfiguration; 15 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 16 | 17 | import com.ambergarden.samples.neo4j.entities.Book; 18 | import com.ambergarden.samples.neo4j.entities.Person; 19 | import com.ambergarden.samples.neo4j.entities.relationships.WriterOf; 20 | 21 | @RunWith(SpringJUnit4ClassRunner.class) 22 | @ContextConfiguration({ "classpath*:/spring/dal-test-context.xml" }) 23 | public class BookRepositoryTest { 24 | private static String TEST_PERSON_NAME_1 = "Person1"; 25 | 26 | private static String TEST_BOOK_NAME_1 = "Book1"; 27 | private static String TEST_BOOK_NAME_2 = "Book2"; 28 | 29 | @Autowired 30 | private PersonRepository personRepository; 31 | 32 | @Autowired 33 | private BookRepository bookRepository; 34 | 35 | @Test 36 | public void testCRUDBook() { 37 | Book book = new Book(); 38 | book.setName(TEST_BOOK_NAME_1); 39 | book = bookRepository.save(book); 40 | assertNotNull(book); 41 | assertNotNull(book.getId()); 42 | assertEquals(TEST_BOOK_NAME_1, book.getName()); 43 | 44 | Long originalId = book.getId(); 45 | book.setName(TEST_BOOK_NAME_2); 46 | book = bookRepository.save(book); 47 | assertEquals(originalId, book.getId()); 48 | assertEquals(TEST_BOOK_NAME_2, book.getName()); 49 | 50 | bookRepository.delete(book); 51 | book = bookRepository.findOne(originalId); 52 | assertNull(book); 53 | } 54 | 55 | @Test 56 | public void testCRUDRelationships() { 57 | Person person1 = new Person(); 58 | person1.setName(TEST_PERSON_NAME_1); 59 | person1 = personRepository.save(person1); 60 | 61 | // Test create with readers 62 | Set readers = new HashSet(); 63 | readers.add(person1); 64 | 65 | Set books = new HashSet(); 66 | Book book1 = new Book(); 67 | books.add(book1); 68 | person1.setBooks(books); 69 | 70 | book1.setName(TEST_BOOK_NAME_1); 71 | book1.setReaders(readers); 72 | book1 = bookRepository.save(book1); 73 | assertNotNull(book1); 74 | assertNotNull(book1.getReaders()); 75 | assertEquals(1, book1.getReaders().size()); 76 | 77 | // Test add readers 78 | Book book2 = new Book(); 79 | book2.setName(TEST_BOOK_NAME_2); 80 | book2 = bookRepository.save(book2); 81 | assertNotNull(book2); 82 | assertNull(book2.getReaders()); 83 | 84 | readers = new HashSet(); 85 | readers.add(person1); 86 | person1.getBooks().add(book2); 87 | book2.setReaders(readers); 88 | book2 = bookRepository.save(book2); 89 | assertNotNull(book2.getReaders()); 90 | assertEquals(1, book2.getReaders().size()); 91 | 92 | // Verify that the person entity is in sync 93 | person1 = personRepository.findOne(person1.getId()); 94 | assertNotNull(person1.getBooks()); 95 | assertEquals(2, person1.getBooks().size()); 96 | 97 | // Test remove readers 98 | book2.setReaders(null); 99 | person1.getBooks().remove(book2); 100 | book2 = bookRepository.save(book2); 101 | 102 | person1 = personRepository.findOne(person1.getId()); 103 | assertNotNull(person1.getBooks()); 104 | assertEquals(1, person1.getBooks().size()); 105 | 106 | // Test remove all readers 107 | book1.setReaders(null); 108 | person1.getBooks().remove(book1); 109 | book1 = bookRepository.save(book1); 110 | 111 | person1 = personRepository.findOne(person1.getId()); 112 | assertNull(person1.getBooks()); 113 | } 114 | 115 | @Test 116 | public void testRichRelationship() { 117 | Date timestamp = new Date(); 118 | Person person1 = new Person(); 119 | person1.setName(TEST_PERSON_NAME_1); 120 | person1 = personRepository.save(person1); 121 | 122 | // Test create with writers 123 | Book book1 = new Book(); 124 | Set writings = new HashSet(); 125 | person1.setWritings(writings); 126 | 127 | WriterOf writer = new WriterOf(); 128 | writer.setBook(book1); 129 | writer.setWriter(person1); 130 | writer.setStartDate(timestamp); 131 | writer.setEndDate(timestamp); 132 | writings.add(writer); 133 | 134 | book1.setName(TEST_BOOK_NAME_1); 135 | book1.setWriters(writings); 136 | book1 = bookRepository.save(book1); 137 | assertNotNull(book1); 138 | assertNotNull(book1.getWriters()); 139 | assertEquals(1, book1.getWriters().size()); 140 | 141 | for (WriterOf writerOf : book1.getWriters()) { 142 | assertNotNull(writerOf.getStartDate()); 143 | assertNotNull(writerOf.getEndDate()); 144 | } 145 | } 146 | 147 | @Test 148 | public void testCRUDRelationshipEntities() { 149 | Person person1 = new Person(); 150 | person1.setName(TEST_PERSON_NAME_1); 151 | person1 = personRepository.save(person1); 152 | 153 | // Test create with writers 154 | Book book1 = new Book(); 155 | Set writings = new HashSet(); 156 | person1.setWritings(writings); 157 | 158 | WriterOf writer = new WriterOf(); 159 | writer.setBook(book1); 160 | writer.setWriter(person1); 161 | writings.add(writer); 162 | 163 | book1.setName(TEST_BOOK_NAME_1); 164 | book1.setWriters(writings); 165 | book1 = bookRepository.save(book1); 166 | assertNotNull(book1); 167 | assertNotNull(book1.getWriters()); 168 | assertEquals(1, book1.getWriters().size()); 169 | 170 | // Test add readers 171 | Book book2 = new Book(); 172 | book2.setName(TEST_BOOK_NAME_2); 173 | book2 = bookRepository.save(book2); 174 | assertNotNull(book2); 175 | assertNull(book2.getReaders()); 176 | 177 | writings = new HashSet(); 178 | writer = new WriterOf(); 179 | writer.setBook(book2); 180 | writer.setWriter(person1); 181 | writings.add(writer); 182 | 183 | book2.setWriters(writings); 184 | book2 = bookRepository.save(book2); 185 | assertNotNull(book2.getWriters()); 186 | assertEquals(1, book2.getWriters().size()); 187 | 188 | // Verify that the person entity is in sync 189 | person1 = personRepository.findOne(person1.getId()); 190 | assertNotNull(person1.getWritings()); 191 | assertEquals(2, person1.getWritings().size()); 192 | 193 | // Test remove writers 194 | person1.getWritings().removeAll(book1.getWriters()); 195 | person1.getWritings().removeAll(book2.getWriters()); 196 | book2.setWriters(null); 197 | book2 = bookRepository.save(book2); 198 | book1.setWriters(null); 199 | book1 = bookRepository.save(book1); 200 | 201 | person1 = personRepository.findOne(person1.getId()); 202 | assertNull(person1.getWritings()); 203 | } 204 | } -------------------------------------------------------------------------------- /v4.1.1/src/test/java/com/ambergarden/samples/neo4j/repositories/PersonRepositoryTest.java: -------------------------------------------------------------------------------- 1 | package com.ambergarden.samples.neo4j.repositories; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNotNull; 5 | import static org.junit.Assert.assertNull; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.test.context.ContextConfiguration; 11 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 12 | 13 | import com.ambergarden.samples.neo4j.entities.Person; 14 | 15 | @RunWith(SpringJUnit4ClassRunner.class) 16 | @ContextConfiguration({ "classpath*:/spring/dal-test-context.xml" }) 17 | public class PersonRepositoryTest { 18 | private static String TEST_PERSON_NAME_1 = "Person1"; 19 | private static String TEST_PERSON_NAME_2 = "Person2"; 20 | 21 | @Autowired 22 | private PersonRepository personRepository; 23 | 24 | @Test 25 | public void testCRUDPerson() { 26 | Person person = new Person(); 27 | person.setName(TEST_PERSON_NAME_1); 28 | person = personRepository.save(person); 29 | assertNotNull(person); 30 | assertNotNull(person.getId()); 31 | assertEquals(TEST_PERSON_NAME_1, person.getName()); 32 | 33 | Long originalId = person.getId(); 34 | person.setName(TEST_PERSON_NAME_2); 35 | person = personRepository.save(person); 36 | assertEquals(originalId, person.getId()); 37 | assertEquals(TEST_PERSON_NAME_2, person.getName()); 38 | 39 | personRepository.delete(person); 40 | person = personRepository.findOne(originalId); 41 | assertNull(person); 42 | } 43 | } -------------------------------------------------------------------------------- /v4.1.1/src/test/resources/spring/dal-test-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | --------------------------------------------------------------------------------