I am using Java
and Gradle
to compile and test my project.
Running gradle -v
outputs the following:
gradle -v
------------------------------------------------------------
Gradle 7.4.2
------------------------------------------------------------
Build time: 2022-03-31 15:25:29 UTC
Revision: 540473b8118064efcc264694cbcaa4b677f61041
Kotlin: 1.5.31
Groovy: 3.0.9
Ant: Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM: 21.0.1 (Microsoft 21.0.1+12-LTS)
OS: Linux 5.15.0-89-generic amd64
The code base works under Java 11
, making use of the following libraries defined in a build.gradle
file Gradle
:
plugins {
id 'org.springframework.boot' version '2.2.0.RELEASE'
id 'io.spring.dependency-management' version '1.0.8.RELEASE'
id 'java-library'
}
group = 'pt.ist.meic'
version = '1.2.0'
sourceCompatibility = '11'
repositories {
mavenCentral()
}
dependencies {
testImplementation(group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: '2.2.2.RELEASE') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testImplementation group: 'org.openjdk.jmh', name: 'jmh-generator-annprocess', version: '1.19'
api group: 'org.openjdk.jmh', name: 'jmh-core', version: '1.19'
api group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.10.0'
api group: 'com.google.api-client', name: 'google-api-client', version: '1.30.9'
implementation 'org.springframework.boot:spring-boot-starter-data-neo4j'
implementation 'org.springframework.boot:spring-boot-starter-data-rest'
}
test {
useJUnitPlatform()
}
Recently I updated several dependencies to the latest versions and have incurred what seem to be deprecation and compatibility issues.
This required that I also set Java 17
as target.
To support this version, I updated Gradle
as well:
gradle -v
------------------------------------------------------------
Gradle 8.4
------------------------------------------------------------
Build time: 2023-10-04 20:52:13 UTC
Revision: e9251e572c9bd1d01e503a0dfdf43aedaeecdc3f
Kotlin: 1.9.10
Groovy: 3.0.17
Ant: Apache Ant(TM) version 1.10.13 compiled on January 4 2023
JVM: 21.0.1 (Microsoft 21.0.1+12-LTS)
OS: Linux 5.15.0-89-generic amd64
This is my updated build.gradle
file.
I am unsure if this is 100% correct as I had to try out different things to get this to compile:
plugins {
id 'org.springframework.boot' version '3.1.5'
id 'io.spring.dependency-management' version '1.1.4'
id 'java-library'
}
version = '1.2.0'
group = 'pt.ist.meic'
description = "PhyloDB Docker Container App"
java {
sourceCompatibility = JavaVersion.VERSION_17
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.neo4j:neo4j-ogm-core:4.0.8'
implementation 'org.neo4j:neo4j-ogm-bolt-driver:4.0.8'
// https://mvnrepository.com/artifact/jakarta.servlet/jakarta.servlet-api
implementation group: 'jakarta.servlet', name: 'jakarta.servlet-api', version: '6.0.0'
// https://mvnrepository.com/artifact/org.springframework/spring-core
implementation group: 'org.springframework', name: 'spring-core', version: '6.1.0'
// https://mvnrepository.com/artifact/org.springframework/spring-web
implementation group: 'org.springframework', name: 'spring-web', version: '6.1.0'
api group: 'org.openjdk.jmh', name: 'jmh-core', version: '1.37'
api group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.16.0'
api group: 'com.google.api-client', name: 'google-api-client', version: '2.2.0'
implementation 'org.springframework.boot:spring-boot-starter-data-neo4j'
implementation 'org.springframework.boot:spring-boot-starter-data-rest'
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0'
testImplementation group: 'org.springframework', name: 'spring-core', version: '6.1.0'
testImplementation group: 'org.springframework', name: 'spring-web', version: '6.1.0'
// https://mvnrepository.com/artifact/org.springframework/spring-context
testImplementation group: 'org.springframework', name: 'spring-context', version: '6.1.0'
testImplementation(group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: '3.1.5') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testImplementation('org.junit.jupiter:junit-jupiter')
testImplementation('org.neo4j:neo4j-ogm-core:4.0.8')
testImplementation('org.neo4j:neo4j-ogm-bolt-driver:4.0.8')
testImplementation group: 'org.openjdk.jmh', name: 'jmh-generator-annprocess', version: '1.37'
}
test {
useJUnitPlatform()
}
Compilation appears to work fine:
gradle bootJar
> Task :compileJava
Note: Some input files use unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
BUILD SUCCESSFUL in 7s
4 actionable tasks: 4 executed
However, when I try to execute the generated JAR file, I get the following error:
java -jar build/libs/phylodb-1.2.0.jar
18:51:24.545 [main] INFO p.i.meic.phylodb.PhylodbApplication - Starting
PhylodbApplication v1.2.0 using Java 21.0.1 with PID 198252
(/home/user/phyloDB-official.git/phylodb/build/libs/phylodb-1.2.0.jar started
by user in /home/user/phyloDB-official.git/phylodb)
18:51:24.547 [main] INFO p.i.meic.phylodb.PhylodbApplication -
No active profile set, falling back to 1 default profile: "default"
18:51:26.485 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat]
18:51:26.486 [main] INFO o.a.catalina.core.StandardEngine -
Starting Servlet engine: [Apache Tomcat/10.1.15]
18:51:26.575 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/]
- Initializing Spring embedded WebApplicationContext
18:51:26.654 [main] INFO o.a.catalina.core.StandardService
- Stopping service [Tomcat]
18:51:26.702 [main] ERROR o.s.boot.SpringApplication -
Application run failed
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'profileService' defined in URL
[jar:file:/home/user/phyloDB-official.git/phylodb/build/libs/phylodb-1.2.0.jar!/BOOT-INF/classes!/pt/ist/meic/phylodb/typing/profile/ProfileService.class]:
Unsatisfied dependency expressed through constructor parameter 0:
Error creating bean with name 'datasetRepository' defined in URL
[jar:file:/home/user/phyloDB-official.git/phylodb/build/libs/phylodb-1.2.0.jar!/BOOT-INF/classes!/pt/ist/meic/phylodb/typing/dataset/DatasetRepository.class]:
Unsatisfied dependency expressed through constructor parameter 0:
Error creating bean with name 'org.neo4j.ogm.session.Session':
Failed to instantiate [org.neo4j.ogm.session.Session]: Specified class is an interface
In particular the following error did not show up with the previous version of Java
and dependencies:
Error creating bean with name 'org.neo4j.ogm.session.Session':
Failed to instantiate [org.neo4j.ogm.session.Session]: Specified class is an interface
... (I omitted the remaining errors)
I am trying to understand what may have caused this problem to emerge.
While it is true that org.neo4j.ogm.session.Session
is a Java interface
, this was working in the past, so I believe there may be something wrong with how the Spring Framework is loading classes.
We are using annotations such as @Repository
, for example in this file which is one of the triggers of the error.
The UserRepository
class in this link has a constructor which receives an instance (implementation) of org.neo4j.ogm.session.Session
as an argument.
For some reason after updating Java
, Gradle
and the dependencies, the Spring Framework is no longer able to create an instance of org.neo4j.ogm.session.Session
, although I don't know how it did it in the previous versions...
I usually work with Maven
but this was done in Gradle
so I aimed to understand how it was designed to work.
I am not sure which one of these packages may be the cause for headaches:
implementation 'org.neo4j:neo4j-ogm-core:4.0.8'
implementation 'org.neo4j:neo4j-ogm-bolt-driver:4.0.8'
implementation group: 'org.springframework', name: 'spring-core', version: '6.1.0'
implementation group: 'org.springframework', name: 'spring-web', version: '6.1.0'
implementation 'org.springframework.boot:spring-boot-starter-data-neo4j'
implementation 'org.springframework.boot:spring-boot-starter-data-rest'
implementation 'org.springframework.boot:spring-boot-starter-web'
Any insight would be much appreciated!
The first thing I spot is that you are jumping from Spring Boot 2.2 directly on 3.1. And, even this sounds harsh, the probably least problem is the Java 17 baseline in this case.
Focussing on the Spring Data Neo4j and Neo4j-OGM dependency: There was a major change in Spring Data Neo4j between version 5 and 6 (happened with Spring Boot 2.4).
This change removed all Neo4j-OGM dependencies from Spring Data Neo4j, even more, SDN was completely rewritten and has its own object mapping now.
Having said this, I am not sure what exactly is causing the exception your are facing. The Spring Boot autoconfiguration for SDN in the newer versions is not aware of any Neo4j-OGM classes and wouldn't touch it. Maybe this does not matter much, let's solve your problem.
You have two options at hand: Either upgrade to the new Spring Data Neo4j stack or stick with the "classic" combination of older Spring Data Neo4j and Neo4j-OGM.
The first one will require, based on you current project, some work. Some features of Neo4j-OGM are not supported in Spring Data Neo4j anymore, like working relationship-centric. Mapping of results is stricter. If you are willing to go this route, there is a migration guide for the boilerplate: https://docs.spring.io/spring-data/neo4j/reference/appendix/migrating.html (since it would completely make this thread explode, https://community.neo4j.com/c/drivers-stacks/spring-data-neo4j-ogm/30 would be the best place to ask project-specific questions during migration).
The other option, sticking with the Neo4j-OGM/SDN combination, is supported by https://github.com/neo4j/neo4j-ogm-spring This is a fork of the initial Spring Data Neo4j 5 to be compatible with the latest versions of Neo4j-OGM and Spring Boot. Please refer to the README for information how to use the custom starter. Also keep in mind that this project is not always up-to-date with the latest releases but maintained on a best-effort base.