Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Making Things Better: Migrating Spring Data Neo4j 3.x to 4.0 - The Basics

DZone's Guide to

Making Things Better: Migrating Spring Data Neo4j 3.x to 4.0 - The Basics

Migrating to Spring Data Neo4j's latest version, 4.0, is easy but requires a little effort. This series takes us through the process with an actual example, highlighting several differences and improvements.

· Database Zone
Free Resource

Learn how to create flexible schemas in a relational database using SQL for JSON.

A long time ago, in a graph far, far away, I wrote a blog post detailing how I used Spring Data Neo4j (SDN) to create a video game exploration tool/store, leveraging GiantBomb.com's API and the power of Neo4j with Spring and Spring MVC (hop in my time machine and check it out here).

(Personal note: I still feel that my homage to the Babbage's software store chain, Von Neumann's, is ostensibly the greatest name for a software store since Babbage's shut down years ago.)

In this series, we will focus only on those aspects of the exploration tool that pertain to making use of Spring Data Neo4j 4.0, i.e. code that performs the import from GiantBomb.com's API isn't detailed, unless you folks want it.

But, Why?

Great question!

In a nutshell, while SDN 3.x was (and is) an excellent integration tool for combining the power of Neo4j with the expressiveness of Spring Data, it was not without its flaws.  Originally designed to be used with Neo4j in "embedded mode," the SDN crew adapted the integration tool to be used with Neo4j in "server mode" when Neo eventually introduced that feature.

Unfortunately, as cool as the server mode is, the integration did not perform as well as was hoped.  One look at the debug logs of an SDN-enabled application with Neo4j running as a server reveals just how chatty SDN really was.  

Although performance did incrementally improve with subsequent releases, it still was not on par with SDN running against Neo4j in embedded mode--something which did not sit very well with those looking to separate their data tier from their application tier.

When faced with such issues, the SDN team did what most engineers love/prefer/pray to do:

Rewrite from the Ground Up!

The SDN team did what any good team of engineers would do: They took the best features of the "old" SDN and the lessons learned from developing and maintaining SDN, and created a stronger, faster implementation of Spring Data Neo4j, with a focus on Neo4j running in "server mode".

Enter Spring Data Neo4j 4.0!

Image title

(*Cue fanfare and confetti*)

Now, the SDN team has made available as part of their documentation a migration guide to ease the transition for those who have previously used Spring Data Neo4j 3.x and earlier.  Check it out here.  

This also happens to be the target audience for this post (what a coincidence!), so we will be covering some specific points that I encountered in migrating Von Neumann's Store from Spring Data Neo4j 3.x to 4.0.

Please refrain from feeding the animals during the tour and keep your arms inside your browser at all times.

The Basics

Dependencies

This project makes use of Spring 4.2.2, so be sure that you have the latest and greatest Spring release going.

While I've yet to make the switch to Gradle, I do hear good things.  That said, Von Neumann's Store is Maven-based, like all my favorite Spring-based projects.  So, what do we need in our POM in order to pull down Spring Data Neo4j 4.0?

        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-neo4j</artifactId>
            <version>4.0.0.RELEASE</version>
        </dependency>

(Of course, feel free to tokenize the version.)

It's just that simple!  I've omitted any other Spring dependencies for the sake of brevity, but I can assure you the overall POM file for this project is very straight-forward and pretty short.

Configuration

Currently, one big difference with SDN 4.0 is the lack of XML-based configuration.  The SDN team plans to rectify this situation in the future.

So, that means we are left with Java-based configuration for the time being.  But, given that the original Von Neumann's is old-school, XML-based configuration was used!  Rut roh!

Surely this must be a common pattern faced for migrating.  (It is, and don't call me "Surely".)

Not to fear!  As most Spring developers know, you can mix XML- and Java-based configurations.

So how might this look?

Let's first examine a few key lines from the start of our web.xml file:

<web-app>
  <!-- web-app attributes and name spaces left out for the sake of brevity -->

  <context-param> 
      <param-name>contextClass</param-name>
      <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>     
  </context-param>

  <context-param> 
      <param-name>contextConfigLocation</param-name> 
      <param-value>com.vonneumanns.config.StoreConfiguration</param-value> 
  </context-param>

  <listener> 
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  ...
  </web-app>
  1. The first stanza brings in some annotation support for our configuration class, as well as support for some other features needed by our Spring MVC application.

  2. The second stanza tells the application where to find our Java-based configuration which contains our Spring Data Neo4j configuration (we talk about this more below).

  3. The third stanza is the standard bootstrapping for startup/shutdown of Spring MVC's root WebApplicationContext.

Looking at the servlet portion of our web.xml file:

<servlet>
<servlet-name>vonneumannsweb</servlet-name> 
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param> 
<param-name>contextConfigLocation</param-name> 
<param-value>/WEB-INF/resources/vonneumannsweb-servlet.xml</param-value>
</init-param> 
<load-on-startup>1</load-on-startup>
    ...
</servlet>

Here we are simply letting Spring know the location of our XML-based configuration, which, in this case, contains only a reference to load any resources for Spring MVC and a reference to import beans from the old Von Neumann's XML configuration.

Get to the Actual Configuration!

Image title

Ok, ok.  Geeze, give a developer a break!

So, the first thing of note is that all that has been done with the old XML-based configuration is the removal of all SDN-based dependencies.  In fact, all we are left with is this:

<?xml version="1.0"?>
<beans>
    <!-- once again, attributes and namespace definitions left out for brevity -->

    <context:annotation-config/>

    <context:component-scan base-package="com.vonneumanns.controllers"/>

    <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/> 

    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass"
            value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
    </bean> 
</beans>

Pretty standard stuff.

Now let's have a look at the Java-based configuration and the parts relevant to SDN 4.0:

@Configuration
@EnableNeo4jRepositories(basePackages = "com.vonneumanns.repositories")
@EnableTransactionManagement
@ComponentScan(excludeFilters = @Filter(type=FilterType.ANNOTATION, value={org.springframework.stereotype.Controller.class}),
        basePackages = "com.vonneumanns")
public class StoreConfiguration extends Neo4jConfiguration {
    private final String NEO4J_USERNAME = "neo4j";
    private final String NEO4J_PASSWORD = "madgraph3r"; // the '3' makes it 1337

    @Bean
    public Neo4jServer neo4jServer() {
        return new RemoteServer("http://neo4j-server:7474", this.NEO4J_USERNAME, this.NEO4J_PASSWORD);
    }

    @Bean
    public SessionFactory getSessionFactory() {        
        return new SessionFactory("com.vonneumanns.entities");
    }

    @Bean
    @Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
    public Session getSession() throws Exception {
        return super.getSession();
    }

    ...
}

Honestly, not a lot going on here, which is great!  Let's go over the configuration, shall we?

The Annotations

@Configuration
@EnableNeo4jRepositories(basePackages = "com.bhsconsultants.vonneumanns.repositories")
@EnableTransactionManagement
@ComponentScan(excludeFilters = @Filter(type=FilterType.ANNOTATION, value={org.springframework.stereotype.Controller.class}),
        basePackages = "com.bhsconsultants.vonneumanns")
  • @Configuration is your standard Spring annotation for denoting a—wait for it—configuration class.

  • @EnableNeo4jRepositories tells the configuration to allow us to use SDN's implementation of Spring Data's handy-dandy repository interfaces.  These repositories are similar to the ones from previous versions of SDN, and we will discuss them in a subsequent post.

  • @EnableTransactionManagement is crucial for enabling our favorite enterprise database feature, ACID compliance.  SDN will inject its transaction manager into the Spring container automatically for use by SDN queries.

  • @ComponentScan isn't specific to SDN, but is necessary in this application.  Why?  Because we have @Controller-annotated classes in packages other than the ones SDN is going to use, namely the package that contains the Spring MVC controllers.  You will have issues if you try to use @ComponentScan indiscriminantly in such a project.  I found out the hard way (with some less-than-helpful error messages).

Class Definition

Groovy!  On to the class definition:

public class StoreConfiguration extends Neo4jConfiguration {
  ...
}


We need to extend the Neo4jConfiguration class as it gives us a number of default configuration options that we cannot live without.  How thoughtful!

Methods

Now we get to the meat and potatoes of the configuration.  Let's examine each method in the configuration class individually.

    @Bean
    public Neo4jServer neo4jServer() {
        return new RemoteServer("http://morpheus:7474", this.NEO4J_USERNAME, this.NEO4J_PASSWORD);
    }

This method tells SDN where the Neo4j server is located.  Note that at this time, SDN 4.0 only supports Neo4j operating in "server mode", i.e. "embedded mode" is not an option for use with SDN 4.0.  Future releases of SDN are likely to rectify this.

We simply feed the RemoteServer constructor the URI of the server, and any credentials needed to log on (as of Neo4j 2.3, login credentials are required by default; you can manually disable them in the Neo4j configuration itself if necessary, but I would not advise it).

    @Bean
    public SessionFactory getSessionFactory() {        
        return new SessionFactory("com.vonneumanns.entities");
    }

    @Bean
    @Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
    public Session getSession() throws Exception {
        return super.getSession();
    }

What's this?  Sessions?  A session factory?  In SDN?  For what?

This concept of a "session" is new to Spring Data Neo4j.  We will take a look at sessions in a later post, but, for now (and especially for web-based applications), it is necessary to implement this session factory getter.

In getSessionFactory(), we pass in to the SessionFactory constructor the package containing the POJO entities that represent those entities used in our graph.

In getSession(), we simply return the default session from the Neo4jConfiguration class.  We will also discuss the concept of scope for these sessions in a later post.

(If you're wondering, sessions really are not necessary—or even used—when you are developing an application that is not web-based, so you can omit the session getter all together.)

Conclusion

And that is it for the basics!  Well, at least as far as dependencies and configuration go.

In the next post, we will discuss sessions a bit more, and have a look at what else is new or different (or the same!) as previous versions of Spring Data Neo4j.

Thanks for reading!

Create flexible schemas using dynamic columns for semi-structured data. Learn how.

Topics:
spring data neo4j ,java ,neo4j ,integration ,spring ,spring data

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}