2

I want to access a Neo4j DB from my Play Framework application in addition to a MySQL DB. The MySQL access is working properly. In preparation to code for accessing Neo4j via Bolt, I have:

Added a reference to the Driver in the project build.sbt:

libraryDependencies ++= Seq(
  jdbc,
  cache,
  ws,
  specs2 % Test,
  "org.mindrot" % "jbcrypt" % "0.3m",
  "mysql" % "mysql-connector-java" % "5.1.38",
  "org.neo4j" % "neo4j-bolt" % "3.0.1"
)

and I restarted activator and watched it apparently resolve/retrieve the dependency that I can now find in ~/.ivy2/...

I have also placed a reference to my database in the application.conf as seen in this snippet:

db.default = {
  driver: com.mysql.jdbc.Driver
  url: "jdbc:mysql://127.0.0.1/borg"
  username: "borg"
  password: "XXXXX"
}

# Bolt port # defaults to 7687 I hope
db.neo4j = {
  driver: org.neo4j.jdbc.Driver
  url: "jdbc:neo4j:bolt://neo.myco.com"
  username: "neo4j"
  password: "XX"
}

I have not yet written any Scala code to attempt accessing the DB. Simply adding this specification to application.conf causes the application to fail when anything is retrieved from the site with messages as seen in the following stacktrace. I note a message about "Driver not found [org.neo4j.jdbc.Driver}]", which curiously has a right brace in a peculiar location. I wonder if that is a red herring. Any insights or experience out there?

CreationException: Unable to create injector, see the following errors: 

1) Error in custom provider, Configuration error: Configuration error[Cannot connect to database [neo4j]]
  while locating play.api.db.DBApiProvider
  while locating play.api.db.DBApi for field
    at play.api.db.NamedDatabaseProvider.dbApi(DBModule.scala:80)
  while locating play.api.db.NamedDatabaseProvider
  at com.google.inject.util.Providers$GuicifiedProviderWithDependencies.initialize(Providers.java:149)
  at play.api.db.DBModule$$anonfun$namedDatabaseBindings$1.apply(DBModule.scala:34):
Binding(interface play.api.db.Database qualified with QualifierInstance(@play.db.NamedDatabase(value=default)) to ProviderTarget(play.api.db.NamedDatabaseProvider@746bce08)) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1) 
Caused by: Configuration error: Configuration error[Cannot connect to database [neo4j]]
    at play.api.Configuration$.configError(Configuration.scala:178)
    at play.api.Configuration.reportError(Configuration.scala:829)
    at play.api.db.DefaultDBApi$$anonfun$connect$1.apply(DefaultDBApi.scala:48)
    at play.api.db.DefaultDBApi$$anonfun$connect$1.apply(DefaultDBApi.scala:42)
    at scala.collection.immutable.List.foreach(List.scala:381)
    at play.api.db.DefaultDBApi.connect(DefaultDBApi.scala:42)
    at play.api.db.DBApiProvider.get$lzycompute(DBModule.scala:72)
    at play.api.db.DBApiProvider.get(DBModule.scala:62)
    at play.api.db.DBApiProvider.get(DBModule.scala:58)
    at com.google.inject.internal.ProviderInternalFactory.provision(ProviderInternalFactory.java:81)
    at com.google.inject.internal.BoundProviderFactory.provision(BoundProviderFactory.java:72)
    at com.google.inject.internal.ProviderInternalFactory.circularGet(ProviderInternalFactory.java:61)
    at com.google.inject.internal.BoundProviderFactory.get(BoundProviderFactory.java:62)
    at com.google.inject.internal.SingleFieldInjector.inject(SingleFieldInjector.java:54)
    at com.google.inject.internal.MembersInjectorImpl.injectMembers(MembersInjectorImpl.java:132)
    at com.google.inject.internal.MembersInjectorImpl$1.call(MembersInjectorImpl.java:93)
    at com.google.inject.internal.MembersInjectorImpl$1.call(MembersInjectorImpl.java:80)
    at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1103)
    at com.google.inject.internal.MembersInjectorImpl.injectAndNotify(MembersInjectorImpl.java:80)
    at com.google.inject.internal.MembersInjectorImpl.injectMembers(MembersInjectorImpl.java:62)
    at com.google.inject.internal.InjectorImpl.injectMembers(InjectorImpl.java:984)
    at com.google.inject.util.Providers$GuicifiedProviderWithDependencies.initialize(Providers.java:149)
    at com.google.inject.util.Providers$GuicifiedProviderWithDependencies$$FastClassByGuice$$2a7177aa.invoke(<generated>)
    at com.google.inject.internal.cglib.reflect.$FastMethod.invoke(FastMethod.java:53)
    at com.google.inject.internal.SingleMethodInjector$1.invoke(SingleMethodInjector.java:57)
    at com.google.inject.internal.SingleMethodInjector.inject(SingleMethodInjector.java:91)
    at com.google.inject.internal.MembersInjectorImpl.injectMembers(MembersInjectorImpl.java:132)
    at com.google.inject.internal.MembersInjectorImpl$1.call(MembersInjectorImpl.java:93)
    at com.google.inject.internal.MembersInjectorImpl$1.call(MembersInjectorImpl.java:80)
    at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1092)
    at com.google.inject.internal.MembersInjectorImpl.injectAndNotify(MembersInjectorImpl.java:80)
    at com.google.inject.internal.Initializer$InjectableReference.get(Initializer.java:174)
    at com.google.inject.internal.Initializer.injectAll(Initializer.java:108)
    at com.google.inject.internal.InternalInjectorCreator.injectDynamically(InternalInjectorCreator.java:174)
    at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:110)
    at com.google.inject.Guice.createInjector(Guice.java:96)
    at com.google.inject.Guice.createInjector(Guice.java:73)
    at com.google.inject.Guice.createInjector(Guice.java:62)
    at play.api.inject.guice.GuiceBuilder.injector(GuiceInjectorBuilder.scala:126)
    at play.api.inject.guice.GuiceApplicationBuilder.build(GuiceApplicationBuilder.scala:93)
    at play.api.inject.guice.GuiceApplicationLoader.load(GuiceApplicationLoader.scala:21)
    at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1$$anonfun$2.apply(DevServerStart.scala:153)
    at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1$$anonfun$2.apply(DevServerStart.scala:150)
    at play.utils.Threads$.withContextClassLoader(Threads.scala:21)
    at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1.apply(DevServerStart.scala:150)
    at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1.apply(DevServerStart.scala:121)
    at scala.Option.map(Option.scala:146)
    at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1.apply(DevServerStart.scala:121)
    at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1.apply(DevServerStart.scala:119)
    at scala.util.Success.flatMap(Try.scala:231)
    at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1.apply(DevServerStart.scala:119)
    at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1.apply(DevServerStart.scala:111)
    at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24)
    at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24)
    at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402)
    at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
    at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
    at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1689)
    at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157) 
Caused by: Configuration error: Configuration error[Driver not found: [org.neo4j.jdbc.Driver}]]
    at play.api.Configuration$.configError(Configuration.scala:178)
    at play.api.PlayConfig.reportError(Configuration.scala:1048)
    at play.api.db.DefaultDatabase$$anonfun$driver$1.apply(Databases.scala:115)
    at play.api.db.DefaultDatabase$$anonfun$driver$1.apply(Databases.scala:109)
    at scala.Option.map(Option.scala:146)
    at play.api.db.DefaultDatabase.driver$lzycompute(Databases.scala:109)
    at play.api.db.DefaultDatabase.driver(Databases.scala:108)
    at play.api.db.DefaultDatabase.dataSource$lzycompute(Databases.scala:123)
    at play.api.db.DefaultDatabase.dataSource(Databases.scala:122)
    at play.api.db.DefaultDatabase.getConnection(Databases.scala:143)
    at play.api.db.DefaultDatabase.getConnection(Databases.scala:139)
    at play.api.db.DefaultDBApi$$anonfun$connect$1.apply(DefaultDBApi.scala:44) 
    ... 56 more 
Caused by: @70ombh24b: Cannot load Driver
    at play.utils.Reflect$.createInstance(Reflect.scala:137)
    at play.api.db.DefaultDatabase$$anonfun$driver$1.apply(Databases.scala:111) 
    ... 65 more 
Caused by: java.lang.ClassNotFoundException: org.neo4j.jdbc.Driver
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)
    at play.utils.Reflect$.getClass(Reflect.scala:142)
    at play.utils.Reflect$.createInstance(Reflect.scala:131) 
    ... 66 more
Bill Michaelson
  • 376
  • 2
  • 11
  • 1
    AFAIK Neo4j Bolt does not imply JDBC support - it's just a binary protocol to query Neo4j. There does seem to be a [JDBC Neo4j Bolt driver](https://github.com/neo4j-contrib/neo4j-jdbc) but that's a different dependency to the one you've provided ("org.neo4j"` % "neo4j-jdbc" % "3.0"). Play's database support is based around traditional RMDBSs, but you could try adding the `neo4j-jdbc` dependency instead. – Mikesname Jul 25 '16 at 18:45
  • @Mikesname, yes, it was my intention to use the support at the site you referenced and I can see now that I referenced the wrong dependency. So I have added the appropriate dependency, and as a caution included all of: "org.neo4j" % "neo4j-jdbc" % "3.0", "org.neo4j" % "neo4j-jdbc-bolt" % "3.0", "org.neo4j" % "neo4j-bolt" % "3.0.1" Yet I still see the same driver not found error. – Bill Michaelson Jul 25 '16 at 20:28
  • Follow up. I examined the jdbc-bolt jar and changed my URL to conform to a class I found: driver: org.neo4j.jdbc.bolt.BoltDriver But I'm probably barking up the wrong tree (class). Connection pool creation fails with: Caused by: java.sql.SQLException: JDBC4 Connection.isValid() method not supported, connection test query must be configured – Bill Michaelson Jul 25 '16 at 20:47
  • 1
    I haven't looked into this, but I suspect there may be some SQL-ish assumptions being made in the Play DB support that don't translate to Neo4j. If that's the case, you can still use the Neo4j Bolt JDBC driver in your code, but you should instantiate the connection yourself rather than relying on Play to do it for you (which is the case for most NoSQL DBs.) – Mikesname Jul 25 '16 at 20:52
  • I had considered doing that only to have more transparent access to examples of working code. I've located work-arounds for HikariCP that suppress the isValid() call attempt, but it isn't clear how to accomplish the same thing by configuration within Play. Alas... :( I'm still hazy on how/whether I can establish a persistent Connection in Play or if I will be stuck building it for every HTTP request. Too many things to learn at once. – Bill Michaelson Jul 25 '16 at 21:34
  • So I added this line to my neo4j section in application.conf at it stopped choking: > hikaricp.connectionTestQuery: "match (n)" This according to [https://github.com/brettwooldridge/HikariCP] – Bill Michaelson Jul 25 '16 at 21:48
  • Good-o. I might check this out tomorrow. For your test query you might want to use `RETURN true` or some similarly simply Cypher. – Mikesname Jul 25 '16 at 22:20
  • Yes, point taken. I actually changed it to `return n limit 1`, but all it wanted was a transaction. It didn't have to be valid! – Bill Michaelson Jul 26 '16 at 15:30

0 Answers0