From fd8ba7a43f3dbd16d603ac5166b8d25cb7ddd56d Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Wed, 11 Oct 2023 11:41:24 +0200 Subject: [PATCH] Polish "Add smoketests for relevant Neo4j features" See gh-190 --- STATUS.adoc | 4 +- .../neo4j/DataNeo4jApplicationAotTests.java | 25 +++--- .../data/neo4j/DatabaseInitializer.java | 12 +-- .../data/neo4j/ImperativeTestRunner.java | 27 +++---- .../java/com/example/data/neo4j/Movie.java | 39 +++++++--- .../example/data/neo4j/MovieRepository.java | 4 +- .../com/example/data/neo4j/ParentNode.java | 6 +- .../java/com/example/data/neo4j/Person.java | 10 +-- .../data/neo4j/ReactiveMovieRepository.java | 4 +- .../data/neo4j/ReactiveTestRunner.java | 45 ++++------- ...dsForMissingTypeHintsAndSB37574Config.java | 76 ------------------- 11 files changed, 84 insertions(+), 168 deletions(-) delete mode 100644 data/data-neo4j/src/main/java/com/example/data/neo4j/WorkaroundsForMissingTypeHintsAndSB37574Config.java diff --git a/STATUS.adoc b/STATUS.adoc index 78ae1842..96abaf82 100644 --- a/STATUS.adoc +++ b/STATUS.adoc @@ -361,8 +361,8 @@ h|nativeTest | |data-neo4j -|image:https://ci.spring.io/api/v1/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-3.2.x/jobs/data-neo4j-app-test/badge[link=https://ci.spring.io/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-3.2.x/jobs/data-neo4j-app-test] -|image:https://ci.spring.io/api/v1/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-3.2.x/jobs/data-neo4j-native-app-test/badge[link=https://ci.spring.io/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-3.2.x/jobs/data-neo4j-native-app-test] +|image:https://ci.spring.io/api/v1/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-3.0.x/jobs/data-neo4j-app-test/badge[link=https://ci.spring.io/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-3.0.x/jobs/data-neo4j-app-test] +|image:https://ci.spring.io/api/v1/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-3.0.x/jobs/data-neo4j-native-app-test/badge[link=https://ci.spring.io/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-3.0.x/jobs/data-neo4j-native-app-test] | | diff --git a/data/data-neo4j/src/appTest/java/neo4j/DataNeo4jApplicationAotTests.java b/data/data-neo4j/src/appTest/java/neo4j/DataNeo4jApplicationAotTests.java index 510a5c77..1ebbaa01 100644 --- a/data/data-neo4j/src/appTest/java/neo4j/DataNeo4jApplicationAotTests.java +++ b/data/data-neo4j/src/appTest/java/neo4j/DataNeo4jApplicationAotTests.java @@ -30,18 +30,16 @@ class DataNeo4jApplicationAotTests { @Test void annotatedTypesShouldHaveBeenRegistered(AssertableOutput output) { - var expectedLines = List.of("All types are present: ChildNode", - "Id has been populated from DB: \\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}"); + List expectedLines = List.of("All types are present: ChildNode", "Id has been populated from DB: \\d+"); assertExpectedLines(output, expectedLines); } @Test void externallyGeneratedFieldsShouldBePopulated(AssertableOutput output) { - var expectedLines = List.of("Generated id is present: \\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}", - "CreatedAt is present: true", "CreatedBy is present: true", "UpdatedAt is absent: false", - "UpdatedBy is absent: false", "Version is 0", "UpdatedAt is now present: true", - "UpdatedBy is now present: true", "Version is now 1"); + List expectedLines = List.of("Generated id is present: \\d+", "CreatedAt is present: true", + "CreatedBy is present: true", "UpdatedAt is absent: false", "UpdatedBy is absent: false", + "Version is 0", "UpdatedAt is now present: true", "UpdatedBy is now present: true", "Version is now 1"); assertExpectedLines(output, expectedLines); } @@ -49,14 +47,14 @@ class DataNeo4jApplicationAotTests { @Test void internallyGeneratedIdsShouldBePopulated(AssertableOutput output) { Awaitility.await().atMost(Duration.ofSeconds(10)).untilAsserted(() -> { - assertThat(output).hasLineMatching("Internal element id is present: \\d:[\\w\\-]+:\\d") - .hasLineMatching("\\[Reactive\\] Internal element id is present: \\d:[\\w\\-]+:\\d"); + assertThat(output).hasLineMatching("Internal element id is present: \\d+") + .hasLineMatching("\\[Reactive\\] Internal element id is present: \\d+"); }); } @Test void cypherDSLIntegrationShouldWork(AssertableOutput output) { - var expectedLines = List.of("Loaded 1 movies", "With 1 actors, first named An Actor"); + List expectedLines = List.of("Loaded 1 movies", "With 1 actors, first named An Actor"); assertExpectedLines(output, expectedLines); } @@ -70,11 +68,10 @@ class DataNeo4jApplicationAotTests { @Test void qbeShouldWork(AssertableOutput output) { - Awaitility.await().atMost(Duration.ofSeconds(10)).untilAsserted(() -> { - assertThat(output).hasLineMatching("Found one movie by example with id \\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}") - .hasLineMatching( - "\\[Reactive\\] Found one movie by example with id \\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}"); - }); + Awaitility.await() + .atMost(Duration.ofSeconds(10)) + .untilAsserted(() -> assertThat(output).hasLineMatching("Found one movie by example with id \\d+") + .hasLineMatching("\\[Reactive\\] Found one movie by example with id \\d+")); } } diff --git a/data/data-neo4j/src/main/java/com/example/data/neo4j/DatabaseInitializer.java b/data/data-neo4j/src/main/java/com/example/data/neo4j/DatabaseInitializer.java index 0f4b3d03..e188850b 100644 --- a/data/data-neo4j/src/main/java/com/example/data/neo4j/DatabaseInitializer.java +++ b/data/data-neo4j/src/main/java/com/example/data/neo4j/DatabaseInitializer.java @@ -16,6 +16,8 @@ package com.example.data.neo4j; import org.neo4j.driver.Driver; +import org.neo4j.driver.Session; +import org.neo4j.driver.Transaction; import org.springframework.context.SmartLifecycle; import org.springframework.stereotype.Component; @@ -32,14 +34,14 @@ public class DatabaseInitializer implements SmartLifecycle { @Override public void start() { - if (running) { + if (this.running) { return; } - try (var session = driver.session(); var tx = session.beginTransaction()) { + try (Session session = this.driver.session(); Transaction tx = session.beginTransaction()) { tx.run("MATCH (n:ParentLabel:ChildLabel) DETACH DELETE n"); - tx.run("CREATE (:ParentLabel:ChildLabel {id: randomUuid(), name: 'BothLabelsMustBeManagedTypes'})"); - tx.run("CREATE (:Movie {id: randomUuid(), version: 0, title: 'A movie', updatedBy: 'A person', updatedAt: localdatetime()}) <-[:ACTED_IN]-(:Person {name: 'An Actor'})"); + tx.run("CREATE (:ParentLabel:ChildLabel {id: 1, name: 'BothLabelsMustBeManagedTypes'})"); + tx.run("CREATE (:Movie {id: 1, version: 0, title: 'A movie', updatedBy: 'A person', updatedAt: localdatetime()}) <-[:ACTED_IN]-(:Person {name: 'An Actor'})"); tx.commit(); this.running = true; } @@ -51,7 +53,7 @@ public class DatabaseInitializer implements SmartLifecycle { @Override public boolean isRunning() { - return running; + return this.running; } } diff --git a/data/data-neo4j/src/main/java/com/example/data/neo4j/ImperativeTestRunner.java b/data/data-neo4j/src/main/java/com/example/data/neo4j/ImperativeTestRunner.java index db24962e..bc9b7c6f 100644 --- a/data/data-neo4j/src/main/java/com/example/data/neo4j/ImperativeTestRunner.java +++ b/data/data-neo4j/src/main/java/com/example/data/neo4j/ImperativeTestRunner.java @@ -17,8 +17,10 @@ package com.example.data.neo4j; import java.util.ArrayList; import java.util.Map; +import java.util.Optional; import org.neo4j.cypherdsl.core.Cypher; +import org.neo4j.cypherdsl.core.Property; import org.springframework.boot.CommandLineRunner; import org.springframework.data.domain.Example; import org.springframework.data.neo4j.core.Neo4jTemplate; @@ -43,7 +45,6 @@ public class ImperativeTestRunner implements CommandLineRunner { @Override public void run(String... args) { - annotatedTypesShouldHaveBeenRegistered(); externallyGeneratedFieldsShouldBePopulated(); internallyGeneratedIdsShouldBePopulated(); @@ -52,19 +53,18 @@ public class ImperativeTestRunner implements CommandLineRunner { } private void qbeShouldWork() { - log("---- Neo4j Query By Example (QBE) ----"); - var optionalMovie = movieRepository.findOne(Example.of(new Movie("A movie"))); + Optional optionalMovie = this.movieRepository.findOne(Example.of(new Movie("A movie"))); optionalMovie.ifPresent((movie) -> { log("Found one movie by example with id %s", movie.getId()); }); } private void cypherDSLIntegrationShouldWork() { - log("---- Neo4j Cypher-DSL integration and relationship population ----"); - var title = Cypher.node("Movie").named("movie").property("title"); - var movies = new ArrayList<>(movieRepository.findAll(title.contains(Cypher.literalOf("A movie")))); + Property title = Cypher.node("Movie").named("movie").property("title"); + ArrayList movies = new ArrayList<>( + this.movieRepository.findAll(title.contains(Cypher.literalOf("A movie")))); log("Loaded %d movies", movies.size()); if (!(movies.isEmpty() || movies.get(0).getActors().isEmpty())) { @@ -74,19 +74,17 @@ public class ImperativeTestRunner implements CommandLineRunner { } private void internallyGeneratedIdsShouldBePopulated() { - log("---- Neo4j internally generated values ----"); - var person = new Person(); + Person person = new Person(); person.setName("Jane Doe"); - person = neo4jTemplate.save(person); + person = this.neo4jTemplate.save(person); log("Internal element id is present: %s", person.getId()); } private void externallyGeneratedFieldsShouldBePopulated() { - log("---- Neo4j externally generated values ----"); - var movie = transactionTemplate - .execute(tx -> movieRepository.save(new Movie("One Flew Over the Cuckoos Nest"))); + Movie movie = this.transactionTemplate + .execute(tx -> this.movieRepository.save(new Movie("One Flew Over the Cuckoos Nest"))); log("Generated id is present: %s", movie.getId()); log("CreatedAt is present: %s", DataNeo4jApplication.FIXED_DATE.equals(movie.getCreatedAt())); @@ -96,7 +94,7 @@ public class ImperativeTestRunner implements CommandLineRunner { log("Version is %d", movie.getVersion()); movie.setTitle("One Flew Over the Cuckoo's Nest"); - var updatedMovie = transactionTemplate.execute(tx -> movieRepository.save(movie)); + Movie updatedMovie = this.transactionTemplate.execute(tx -> this.movieRepository.save(movie)); log("UpdatedAt is now present: %s", DataNeo4jApplication.FIXED_DATE.equals(updatedMovie.getUpdatedAt())); log("UpdatedBy is now present: %s", "Some person".equals(updatedMovie.getUpdatedBy())); @@ -104,10 +102,9 @@ public class ImperativeTestRunner implements CommandLineRunner { } private void annotatedTypesShouldHaveBeenRegistered() { - log("---- Neo4j Managed types ----"); - var optionalResult = this.neo4jTemplate.findOne("MATCH (t:ParentLabel {name: $name}) RETURN t", + Optional optionalResult = this.neo4jTemplate.findOne("MATCH (t:ParentLabel {name: $name}) RETURN t", Map.of("name", "BothLabelsMustBeManagedTypes"), ParentNode.class); optionalResult.ifPresent(node -> { diff --git a/data/data-neo4j/src/main/java/com/example/data/neo4j/Movie.java b/data/data-neo4j/src/main/java/com/example/data/neo4j/Movie.java index e6dc4ac8..f768f1d9 100644 --- a/data/data-neo4j/src/main/java/com/example/data/neo4j/Movie.java +++ b/data/data-neo4j/src/main/java/com/example/data/neo4j/Movie.java @@ -17,7 +17,6 @@ package com.example.data.neo4j; import java.time.LocalDateTime; import java.util.List; -import java.util.UUID; import org.springframework.data.annotation.CreatedBy; import org.springframework.data.annotation.CreatedDate; @@ -35,7 +34,7 @@ public class Movie { @Id @GeneratedValue - private final UUID id; + private final Long id; @Version private final Long version; @@ -62,7 +61,7 @@ public class Movie { } @PersistenceCreator - Movie(UUID id, Long version, String title, List actors, LocalDateTime createdAt, String createdBy, + Movie(Long id, Long version, String title, List actors, LocalDateTime createdAt, String createdBy, LocalDateTime updatedAt, String updatedBy) { this.id = id; this.version = version; @@ -74,16 +73,16 @@ public class Movie { this.updatedBy = updatedBy; } - public UUID getId() { - return id; + public Long getId() { + return this.id; } public Long getVersion() { - return version; + return this.version; } public String getTitle() { - return title; + return this.title; } public void setTitle(String title) { @@ -91,23 +90,39 @@ public class Movie { } public List getActors() { - return actors; + return this.actors; } public LocalDateTime getCreatedAt() { - return createdAt; + return this.createdAt; } public String getCreatedBy() { - return createdBy; + return this.createdBy; } public LocalDateTime getUpdatedAt() { - return updatedAt; + return this.updatedAt; } public String getUpdatedBy() { - return updatedBy; + return this.updatedBy; + } + + public void setCreatedAt(LocalDateTime createdAt) { + this.createdAt = createdAt; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public void setUpdatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + } + + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; } } diff --git a/data/data-neo4j/src/main/java/com/example/data/neo4j/MovieRepository.java b/data/data-neo4j/src/main/java/com/example/data/neo4j/MovieRepository.java index 85fb4f7b..865f2466 100644 --- a/data/data-neo4j/src/main/java/com/example/data/neo4j/MovieRepository.java +++ b/data/data-neo4j/src/main/java/com/example/data/neo4j/MovieRepository.java @@ -15,13 +15,11 @@ */ package com.example.data.neo4j; -import java.util.UUID; - import org.springframework.data.neo4j.repository.Neo4jRepository; import org.springframework.data.neo4j.repository.support.CypherdslConditionExecutor; import org.springframework.data.repository.query.QueryByExampleExecutor; public interface MovieRepository - extends Neo4jRepository, CypherdslConditionExecutor, QueryByExampleExecutor { + extends Neo4jRepository, CypherdslConditionExecutor, QueryByExampleExecutor { } diff --git a/data/data-neo4j/src/main/java/com/example/data/neo4j/ParentNode.java b/data/data-neo4j/src/main/java/com/example/data/neo4j/ParentNode.java index 14deb868..7dfe674e 100644 --- a/data/data-neo4j/src/main/java/com/example/data/neo4j/ParentNode.java +++ b/data/data-neo4j/src/main/java/com/example/data/neo4j/ParentNode.java @@ -16,8 +16,6 @@ package com.example.data.neo4j; -import java.util.UUID; - import org.springframework.data.neo4j.core.schema.GeneratedValue; import org.springframework.data.neo4j.core.schema.Id; import org.springframework.data.neo4j.core.schema.Node; @@ -32,11 +30,11 @@ public abstract sealed class ParentNode permits ParentNode.ChildNode { @Id @GeneratedValue - private UUID id; + private Long id; private String name; - public UUID getId() { + public Long getId() { return this.id; } diff --git a/data/data-neo4j/src/main/java/com/example/data/neo4j/Person.java b/data/data-neo4j/src/main/java/com/example/data/neo4j/Person.java index 6fc32ab9..666de0e7 100644 --- a/data/data-neo4j/src/main/java/com/example/data/neo4j/Person.java +++ b/data/data-neo4j/src/main/java/com/example/data/neo4j/Person.java @@ -22,20 +22,20 @@ public class Person { @Id @GeneratedValue - private String id; + private Long id; private String name; - public String getId() { - return id; + public Long getId() { + return this.id; } - public void setId(String id) { + public void setId(Long id) { this.id = id; } public String getName() { - return name; + return this.name; } public void setName(String name) { diff --git a/data/data-neo4j/src/main/java/com/example/data/neo4j/ReactiveMovieRepository.java b/data/data-neo4j/src/main/java/com/example/data/neo4j/ReactiveMovieRepository.java index 4b4bad09..aabee815 100644 --- a/data/data-neo4j/src/main/java/com/example/data/neo4j/ReactiveMovieRepository.java +++ b/data/data-neo4j/src/main/java/com/example/data/neo4j/ReactiveMovieRepository.java @@ -15,13 +15,11 @@ */ package com.example.data.neo4j; -import java.util.UUID; - import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository; import org.springframework.data.neo4j.repository.support.ReactiveCypherdslConditionExecutor; import org.springframework.data.repository.query.ReactiveQueryByExampleExecutor; -public interface ReactiveMovieRepository extends ReactiveNeo4jRepository, +public interface ReactiveMovieRepository extends ReactiveNeo4jRepository, ReactiveCypherdslConditionExecutor, ReactiveQueryByExampleExecutor { } diff --git a/data/data-neo4j/src/main/java/com/example/data/neo4j/ReactiveTestRunner.java b/data/data-neo4j/src/main/java/com/example/data/neo4j/ReactiveTestRunner.java index a29c1262..b0630e50 100644 --- a/data/data-neo4j/src/main/java/com/example/data/neo4j/ReactiveTestRunner.java +++ b/data/data-neo4j/src/main/java/com/example/data/neo4j/ReactiveTestRunner.java @@ -15,9 +15,12 @@ */ package com.example.data.neo4j; +import java.util.List; import java.util.Map; +import java.util.Optional; import org.neo4j.cypherdsl.core.Cypher; +import org.neo4j.cypherdsl.core.Property; import org.neo4j.driver.Driver; import org.springframework.boot.CommandLineRunner; import org.springframework.data.domain.Example; @@ -29,25 +32,21 @@ import org.springframework.transaction.reactive.TransactionalOperator; @Component public class ReactiveTestRunner implements CommandLineRunner { - private final Driver driver; - private final ReactiveNeo4jTemplate neo4jTemplate; private final TransactionalOperator transactionalOperator; private final ReactiveMovieRepository movieRepository; - public ReactiveTestRunner(Driver driver, ReactiveNeo4jTemplate neo4jTemplate, + public ReactiveTestRunner(ReactiveNeo4jTemplate neo4jTemplate, ReactiveTransactionManager reactiveTransactionManager, ReactiveMovieRepository movieRepository) { - this.driver = driver; this.neo4jTemplate = neo4jTemplate; this.transactionalOperator = TransactionalOperator.create(reactiveTransactionManager); this.movieRepository = movieRepository; } @Override - public void run(String... args) throws Exception { - + public void run(String... args) { annotatedTypesShouldHaveBeenRegistered(); externallyGeneratedFieldsShouldBePopulated(); internallyGeneratedIdsShouldBePopulated(); @@ -56,19 +55,19 @@ public class ReactiveTestRunner implements CommandLineRunner { } private void qbeShouldWork() { - log("---- [Reactive] Neo4j Query By Example (QBE) ----"); - var optionalMovie = movieRepository.findOne(Example.of(new Movie("A movie"))).blockOptional(); + Optional optionalMovie = this.movieRepository.findOne(Example.of(new Movie("A movie"))).blockOptional(); optionalMovie.ifPresent((movie) -> { log("[Reactive] Found one movie by example with id %s", movie.getId()); }); } private void cypherDSLIntegrationShouldWork() { - log("---- [Reactive] Neo4j Cypher-DSL integration and relationship population ----"); - var title = Cypher.node("Movie").named("movie").property("title"); - var movies = movieRepository.findAll(title.contains(Cypher.literalOf("A movie"))).collectList().block(); + Property title = Cypher.node("Movie").named("movie").property("title"); + List movies = this.movieRepository.findAll(title.contains(Cypher.literalOf("A movie"))) + .collectList() + .block(); log("[Reactive] Loaded %d movies", movies.size()); if (!(movies.isEmpty() || movies.get(0).getActors().isEmpty())) { @@ -78,19 +77,17 @@ public class ReactiveTestRunner implements CommandLineRunner { } private void internallyGeneratedIdsShouldBePopulated() { - log("---- [Reactive] Neo4j internally generated values ----"); - var person = new Person(); + Person person = new Person(); person.setName("Jane Doe"); - person = neo4jTemplate.save(person).block(); + person = this.neo4jTemplate.save(person).block(); log("[Reactive] Internal element id is present: %s", person.getId()); } private void externallyGeneratedFieldsShouldBePopulated() { - log("---- [Reactive] Neo4j externally generated values ----"); - var movie = movieRepository.save(new Movie("One Flew Over the Cuckoos Nest")) - .as(transactionalOperator::transactional) + Movie movie = this.movieRepository.save(new Movie("One Flew Over the Cuckoos Nest")) + .as(this.transactionalOperator::transactional) .block(); log("[Reactive] Generated id is present: %s", movie.getId()); @@ -101,7 +98,7 @@ public class ReactiveTestRunner implements CommandLineRunner { log("[Reactive] Version is %d", movie.getVersion()); movie.setTitle("One Flew Over the Cuckoo's Nest"); - var updatedMovie = movieRepository.save(movie).as(transactionalOperator::transactional).block(); + Movie updatedMovie = this.movieRepository.save(movie).as(this.transactionalOperator::transactional).block(); log("[Reactive] UpdatedAt is now present: %s", DataNeo4jApplication.FIXED_DATE.equals(updatedMovie.getUpdatedAt())); @@ -110,10 +107,9 @@ public class ReactiveTestRunner implements CommandLineRunner { } private void annotatedTypesShouldHaveBeenRegistered() { - log("---- [Reactive] Neo4j Managed types ----"); - var optionalResult = this.neo4jTemplate + Optional optionalResult = this.neo4jTemplate .findOne("MATCH (t:ParentLabel {name: $name}) RETURN t", Map.of("name", "BothLabelsMustBeManagedTypes"), ParentNode.class) .blockOptional(); @@ -124,15 +120,6 @@ public class ReactiveTestRunner implements CommandLineRunner { }); } - private void initializeDatabase(String... args) { - try (var session = driver.session(); var tx = session.beginTransaction()) { - tx.run("MATCH (n:ParentLabel:ChildLabel) DETACH DELETE n"); - tx.run("CREATE (:ParentLabel:ChildLabel {id: randomUuid(), name: 'BothLabelsMustBeManagedTypes'})"); - tx.run("CREATE (:Movie {id: randomUuid(), version: 0, title: 'A movie', updatedBy: 'A person', updatedAt: localdatetime()}) <-[:ACTED_IN]-(:Person {name: 'An Actor'})"); - tx.commit(); - } - } - private void log(Object value) { log(String.valueOf(value), new Object[0]); } diff --git a/data/data-neo4j/src/main/java/com/example/data/neo4j/WorkaroundsForMissingTypeHintsAndSB37574Config.java b/data/data-neo4j/src/main/java/com/example/data/neo4j/WorkaroundsForMissingTypeHintsAndSB37574Config.java deleted file mode 100644 index 9e15bf79..00000000 --- a/data/data-neo4j/src/main/java/com/example/data/neo4j/WorkaroundsForMissingTypeHintsAndSB37574Config.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2023 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.example.data.neo4j; - -import java.util.List; -import java.util.Set; - -import org.springframework.aot.hint.MemberCategory; -import org.springframework.aot.hint.RuntimeHints; -import org.springframework.aot.hint.RuntimeHintsRegistrar; -import org.springframework.aot.hint.TypeReference; -import org.springframework.boot.autoconfigure.domain.EntityScanner; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ImportRuntimeHints; -import org.springframework.data.neo4j.aot.Neo4jManagedTypes; -import org.springframework.data.neo4j.core.convert.Neo4jConversions; -import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext; -import org.springframework.data.neo4j.core.schema.Node; -import org.springframework.data.neo4j.core.schema.RelationshipProperties; -import org.springframework.data.neo4j.repository.query.CypherdslConditionExecutorImpl; -import org.springframework.data.neo4j.repository.query.ReactiveCypherdslConditionExecutorImpl; - -/** - * See https://github.com/spring-projects/spring-data-neo4j/issues/2798 Only needed until - * https://github.com/spring-projects/spring-boot/pull/37574 is resolved Otherwise the - * abscence of {@link ParentNode.ChildNode} will cause application startup failure - */ -@Configuration(proxyBeanMethods = false) -@ImportRuntimeHints(WorkaroundsForMissingTypeHintsAndSB37574Config.MissingRuntimeHints.class) -public class WorkaroundsForMissingTypeHintsAndSB37574Config { - - @Bean - public Neo4jManagedTypes neo4jManagedTypes(ApplicationContext applicationContext) throws ClassNotFoundException { - Set> initialEntityClasses = new EntityScanner(applicationContext).scan(Node.class, - RelationshipProperties.class); - return Neo4jManagedTypes.fromIterable(initialEntityClasses); - } - - @Bean - public Neo4jMappingContext neo4jMappingContext(Neo4jManagedTypes managedTypes, Neo4jConversions neo4jConversions) { - - Neo4jMappingContext context = new Neo4jMappingContext(neo4jConversions); - context.setManagedTypes(managedTypes); - return context; - } - - public static class MissingRuntimeHints implements RuntimeHintsRegistrar { - - @Override - public void registerHints(RuntimeHints hints, ClassLoader classLoader) { - hints.reflection() - .registerTypes( - List.of(TypeReference.of(CypherdslConditionExecutorImpl.class), - TypeReference.of(ReactiveCypherdslConditionExecutorImpl.class)), - builder -> builder.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, - MemberCategory.INVOKE_PUBLIC_METHODS)); - } - - } - -} \ No newline at end of file