0

I'm running a Spring Boot web app with an underlying Neo4j database. In order to be able to view the Neo4j browser (direct web view onto the db), the Neo4j web server is embedded into the application using the following configuration.

@Bean(initMethod = "start", destroyMethod = "stop")
public WrappingNeoServerBootstrapper neo4jWebServer() {
    return new WrappingNeoServerBootstrapper((GraphDatabaseAPI) graphDatabaseService());
}

and by including the following in the maven pom:

<dependency>
    <groupId>org.neo4j.app</groupId>
    <artifactId>neo4j-server</artifactId>
    <classifier>static-web</classifier>
    <version>2.0.2</version>
</dependency>

This all works fine when running from STS (i.e. unpackaged).

When I package the application up using the spring-boot-maven-plugin. This creates the uber-jar correctly containing the neo4j-server-2.0.2-static-web.jar file in the /lib folder of the uber-jar.

When I run the application directly using the uber-jar file and then attempt to hit the http://localhost:7474/browser/ URL for the Neo4j browser, it returns a 404.

The reason for this is that the Jetty DefaultServlet attempts to getResource() from the WebAppContext which, in turn, calls JarFileResource.exists() which tries to operate on the following URL string:

jar:file:/home/dev/myapp/target/myapp-0.0.1-SNAPSHOT.jar!/lib/neo4j-browser-2.0.2.jar!/browser/

Jetty fails to match anything in its resource list as it's looking for a resource called /lib/neo4j-browser-2.0.2.jar!/browser/ as the code, e.g. at http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java#n123 (and a couple of other places) is looking for the first !/ in the string.

I am going to submit a Jetty bug for this with a suggestion that they use String.lastIndexOf("!/") in their code, which will resolve the issue.

In the meantime, apart from producing our oun standard maven assembly, does anyone have any suggestions for how I could get this to work within a Spring Boot uber-jar?

Many thanks.

Dave Hallam
  • 136
  • 8
  • Does it work with Tomcat? – Dave Syer May 01 '14 at 09:11
  • I've not tried with Tomcat as the `CommunityNeoServer` explicitly uses a Jetty 9 web server: ref [CommunityNeoServer](https://github.com/neo4j/neo4j/blob/master/community/server/src/main/java/org/neo4j/server/CommunityNeoServer.java#L94) creates one of [Jetty9WebServer](https://github.com/neo4j/neo4j/blob/master/community/server/src/main/java/org/neo4j/server/web/Jetty9WebServer.java) – Dave Hallam May 01 '14 at 09:32
  • Then I guess it's not a Spring Boot app. Can't you just run it the way the Neo4j guys tell you to? – Dave Syer May 01 '14 at 09:39
  • It is a Spring Boot app - there's a cutdown example project [here](https://github.com/dhallam/spring-data-neo4j-demo) which uses the `SpringApplication` and `EnableAutoConfiguration`, although that isn't demonstrating any `spring-boot-starter-web` controllers or anything at the moment. The Neo4j browser part is just an additional interface to view the database. – Dave Hallam May 01 '14 at 10:02
  • The Spring Boot part provides all the boot components, e.g. `spring-boot-starter-jetty`, `spring-boot-starter-web`, `spring-boot-starter-test`, etc. This isn't a Spring Boot issue - it's a Jetty issue - Spring Boot is behaving as I expect it should. I just wondered if there was a workaround that I could deploy (other than a maven assembly) to still make use of the Spring Boot uber-jar whilst the Jetty issue still exists. I don't think there is - just wanted to ask the question. – Dave Hallam May 01 '14 at 10:05
  • Regarding the running the Neo4j browser separately, I can't as it's an embedded database within the application - for example [this blog post](http://www.markhneedham.com/blog/2013/06/19/neo4j-wrappingneoserverbootstrapper-and-the-case-of-the-webadmin-404/) – Dave Hallam May 01 '14 at 10:19
  • I see. I don't know anything about the Neo server. Is it a servlet (or something similar)? You could probably just register it with your Spring Boot context and forget about running with the embedded server that it provides. – Dave Syer May 01 '14 at 10:37
  • It's more than just a servlet. There are JAXRS extensions, servlets, filters, security, static content, etc. that are setup within the Neo code. It's working with a simple maven assembly so I'll stick with that for now and see what the Jetty guys say. Many thanks for your comments. – Dave Hallam May 01 '14 at 10:50

2 Answers2

1

Spring Boot uber-jars use some special techniques to allow content to be loaded from nested jars. Jetty (quite understandably) assumes that jar URLs will only contain a single ! which unfortunately is not the case here.

Your easiest solution is probably to switch to the maven-shade-plugin. This creates an uber-jar by unpacking all of your dependencies before repacking them into a single jar.

Some other alternatives are suggested in the Spring Boot reference documentation

Phil Webb
  • 8,119
  • 1
  • 37
  • 37
0

If you're using SpringBoot+Maven you can add the following:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <requiresUnpack>
            <dependency>
                <groupId>org.neo4j.app</groupId>
                <artifactId>neo4j-browser</artifactId>
            </dependency>
        </requiresUnpack>
    </configuration>
    <executions>
       ...
</plugin>

Obtained from this gradle suggestion

Community
  • 1
  • 1
Mike Holdsworth
  • 1,088
  • 11
  • 12