Bootstrapping Neo4j With Spring-Data – Without XML
May 12, 2013 9 Comments
With the maturing of Spring-Data I started porting all my personal projects to use Spring Data for bootstrapping. I also wanted to get rid of XML, which proved a little more tricky as I expected.
Dependencies
Let’s start with the required dependencies:
Update: Added a missing validator-dependency
<properties> <spring-core.version>3.2.0.RELEASE</spring-core.version> </properties> <dependencies> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-neo4j</artifactId> <version>2.2.1.RELEASE</version> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-asm</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.neo4j.app</groupId> <artifactId>neo4j-server</artifactId> <version>1.8.1</version> </dependency> <dependency> <groupId>org.neo4j.app</groupId> <artifactId>neo4j-server</artifactId> <classifier>static-web</classifier> <version>1.8.1</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring-core.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring-core.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring-core.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring-core.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring-core.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>${spring-core.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring-core.version}</version> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.2.2</version> </dependency> </dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>4.3.0.Final</version> </dependency>
We need/want to override the spring dependencies pulled in via Spring Data with a newer one. We also need to explicitly remove spring-asm as newer versions of Spring don’t need it.
The neo4j-dependencies are required to give us the Neo4j-WebServer.
Repositories
I created a small demo-Entity based on the Neo4j-Annotation provided by Spring-Data.
@NodeEntity public class Component { @GraphId Long id; @Indexed(unique = true) String simpleName; @RelatedTo(type = “Component”) Set<Component> relatedTo = new HashSet<Component>(); … … }
Next I added a repository to handle the class (oh, the beauty of Spring-Data-Repositories).
public interface ComponentRepository extends GraphRepository<Component>{ }
That’s it.
Configuration
To get it all up and running the only thing required is @Configuration-Annotated class which extends Neo4jConfiguration.
@EnableTransactionManagement @Configuration @EnableNeo4jRepositories(basePackages = “de.codepitbull.neo4j”) public class CustomNeo4jConfig extends Neo4jConfiguration { private static final String DB_PATH = "target/neo4j"; @Bean public EmbeddedGraphDatabase graphDatabaseService() { return new EmbeddedGraphDatabase(DB_PATH); } @Bean public WrappingNeoServerBootstrapper neo4jWebServer() { WrappingNeoServerBootstrapper server = new WrappingNeoServerBootstrapper(graphDatabaseService()); server.start(); return server; } }
Using this config we are getting not only an embedded Neo4J instance but also a nice query-interface (including the Neo4J-Shell) running at localhost:7474.
Nice, that’s it 🙂
Create a main-Class, fire up the context and see the magic happen.
public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(CustomNeo4jConfig.class); context.start(); context.getBean(WrappingNeoServerBootstrapper.class); context.registerShutdownHook(); } }
Using Converters
After playing around with Neo4J you will run into the need for using converters (everything that goes into the graph has to be converted to a String). This proved to be a little more tricky than I had expected.
Normally you only have to register a new ConversionServiceFactoryBean to provide additional back and forth conversions. Registering this been in the same @Configuration we just created will be followed by a “circular dependency”-problem.
I am not sure why this is happening but I simply moved it into a separate @Configuration _ which uses @Import_ to include the Neo4J-Configuration and things started working.
Obviously you will also have to replace CustomNeo4jConfig.class in your Main-class with MainConfiguration.class.
@Configuration @Import(CustomNeo4jConfig.class) public class MainConfiguration { @Bean public ConversionServiceFactoryBean conversionService() { Set converters = Sets.newHashSet(); converters.add(new ConstructorListConverter()); ConversionServiceFactoryBean bean = new ConversionServiceFactoryBean(); bean.setConverters(converters); return bean; } }
Conclusion
I love it, nothing more to say.