Spring Framework class resolution with latest neo4j-ogm-core/neo4j-ogm-bolt-driver

31 Views Asked by At

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!

1

There are 1 best solutions below

0
On

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.