I am trying out Neo4J OGM for first time from simple example given on its github page and with the help of its manual.
I am running neo4j-community-3.0.0-M05.
I am getting following exception:
Exception in thread "main" java.lang.NullPointerException
at org.neo4j.ogm.session.delegates.LoadOneDelegate.lookup(LoadOneDelegate.java:56)
at org.neo4j.ogm.session.delegates.LoadOneDelegate.load(LoadOneDelegate.java:49)
at org.neo4j.ogm.session.delegates.LoadOneDelegate.load(LoadOneDelegate.java:39)
at org.neo4j.ogm.session.Neo4jSession.load(Neo4jSession.java:137)
at org.neo4j.ogm.session.Capability$LoadOne$load.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:110)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:130)
at Main.main(Main.groovy:24)
The exception occurs on line 24 of Main.groovy. I debugged. It occurs on session.load() call.
I feel that this must be beacuse I must have made some mistake in setting up dependencies. But cant figure it out.
This is my code:
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mahesha999.exp</groupId>
<artifactId>Neo4JTemp</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-core</artifactId>
<version>2.0.4</version>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-http-driver</artifactId>
<version>2.0.4</version>
</dependency>
</dependencies>
</project>
ogm.properties
driver=org.neo4j.ogm.drivers.http.driver.HttpDriver
URI=http://neo4j:password#localhost:7474
Actor.groovy
import org.neo4j.ogm.annotation.NodeEntity
import org.neo4j.ogm.annotation.Relationship
import org.neo4j.ogm.annotation.GraphId
#NodeEntity
public class Actor {
#GraphId
private Long id;
private String name;
#Relationship(type = "ACTS_IN", direction = "OUTGOING")
private Set<Movie> movies = new HashSet<>();
public Actor() { }
public Actor(String name) {
this.name = name;
}
public void actsIn(Movie movie) {
movies<< movie;
movie.getActors() << this;
}
}
Movie.groovy
import org.neo4j.ogm.annotation.NodeEntity
import org.neo4j.ogm.annotation.Relationship
import org.neo4j.ogm.annotation.GraphId
#NodeEntity
public class Movie {
#GraphId
private Long id;
private String title;
private int released;
#Relationship(type = "ACTS_IN", direction = "INCOMING")
List<Actor> actors = [];
public Movie() {}
public Movie(String title, int year) {
this.title = title;
this.released = year;
}
}
Main.groovy
1 import org.neo4j.ogm.session.Session
2 import org.neo4j.ogm.session.SessionFactory
3
4 class Main {
5
6 static main(def args)
7 {
8 //Set up the Session
9 SessionFactory sessionFactory = new SessionFactory("movies.domain");
10 Session session = sessionFactory.openSession();
11
12 Movie movie = new Movie("The Matrix", 1999);
13
14 Actor keanu = new Actor("Keanu Reeves");
15 keanu.actsIn(movie);
16
17 Actor carrie = new Actor("Carrie-Ann Moss");
18 carrie.actsIn(movie);
19
20 //Persist the movie. This persists the actors as well.
21 session.save(movie);
22
23 //Load a movie
24 Movie matrix = session.load(Movie.class, movie.id);
25 for(Actor actor : matrix.getActors()) {
26 System.out.println("Actor: " + actor.name);
27 }
28 }
29 }
The package being scanned (movies.domain) does not seem to contain your entity classes. That's why the entity is not saved, and the id is null.
The OGM reference guide (with tutorial) is here: http://neo4j.com/docs/ogm-manual/current/
And a small sample app: https://github.com/neo4j-examples/neo4j-ogm-university/tree/2.0
Related
I'm trying to run spock tests against a neo4j container using the TestContainers library. Previously, I used the test-harness library to run tests against an embedded neo4j database but the need to migrate to using TestContainers has come up. With test-harness I used a configuration file to include some necessary beans for callback functionality. Without these beans, some unit tests are failing.
Previous test-harness method
#ContextConfiguration(classes = [
Neo4jTestHarnessAutoConfiguration,
Neo4jDriverAutoConfiguration,
Neo4jDataAutoConfiguration,
CustomNeo4jConfiguration
])
#ImportAutoConfiguration(classes = [
Neo4jTestHarnessAutoConfiguration,
Neo4jDriverAutoConfiguration,
Neo4jDataAutoConfiguration
])
#Transactional
trait EmbeddedNeo4j {
// Neo4j embedded database is created in Neo4jTestHarnessAutoConfiguration
}
CustomNeo4jConfiguration
#Configuration
#EntityScan(value = {
"data.neo4j.nodes",
"data.neo4j.relationships",
"data.neo4j.queryresults"
})
#EnableNeo4jRepositories("data.neo4j.repository")
#EnableNeo4jAuditing(auditorAwareRef = "auditorAware")
public class CustomNeo4jConfiguration {
#Bean
public AuditorAware<String> auditorAware(){
return new CustomAuditorAwareImpl();
}
#Bean
public BeforeBindCallback neo4jCustomEntitiesCallback(AuditorAware<String> auditorAware) {
return new CustomNeo4jEntitiesCallback(auditorAware);
}
#Bean
public Neo4jConversions neo4jCustomConversions() {
Set<GenericConverter> additionalConverters = Collections.singleton(new InstantStringConverter());
return new Neo4jConversions(additionalConverters);
}
}
The above method works fine. All tests run properly and all beans are created.
TestContainers attempt
#Testcontainers
#Transactional
trait EmbeddedNeo4j {
#Shared
static final Neo4jContainer<?> neo4jContainer = new Neo4jContainer<>("neo4j:4.3.9")
.withReuse(true)
#DynamicPropertySource
static void neo4jProperties(DynamicPropertyRegistry registry) {
neo4jContainer.start()
registry.add("spring.neo4j.uri", neo4jContainer::getBoltUrl)
registry.add("spring.neo4j.authentication.username", () -> "neo4j")
registry.add("spring.neo4j.authentication.password", neo4jContainer::getAdminPassword)
}
}
With the above, all tests successfully run against the test container. However, any test that needs the functionality of the beans in the CustomNeo4jConfiguration fails.
What I've tried
I've attempted to use the same #ContextConfiguration annotations in various configurations, such as...
#ContextConfiguration(classes = [
Neo4jDriverAutoConfiguration,
Neo4jDataAutoConfiguration,
CustomNeo4jConfiguration
])
#ImportAutoConfiguration(classes = [
Neo4jDriverAutoConfiguration,
Neo4jDataAutoConfiguration
])
#Transactional
trait EmbeddedNeo4j {
TestContainer code here...
However, this fails with the following stack trace:
Failed to load ApplicationContext
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:124)
at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:190)
at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:132)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:248)
at org.spockframework.spring.SpringTestContextManager.prepareTestInstance(SpringTestContextManager.java:56)
at org.spockframework.spring.SpringInterceptor.interceptInitializerMethod(SpringInterceptor.java:43)
at org.spockframework.runtime.extension.AbstractMethodInterceptor.intercept(AbstractMethodInterceptor.java:24)
at org.spockframework.runtime.extension.MethodInvocation.proceed(MethodInvocation.java:101)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$2(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:90)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.spockframework.runtime.model.MethodInfo.invoke(MethodInfo.java:148)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:133)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:414)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'auditFieldRepository' defined in data.neo4j.repository.AuditFieldRepository defined in #EnableNeo4jRepositories declared on CustomNeo4jConfiguration: Cannot resolve reference to bean 'neo4jTemplate' while setting bean property 'neo4jOperations'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'neo4jTemplate' available
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:113)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1707)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1452)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:619)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:936)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:308)
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:132)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
... 64 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'neo4jTemplate' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:874)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1344)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:309)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:330)
... 82 more
I've also attempted in various ways to create the missing beans, but that doesn't feel like the right path to take and that didn't produce any results.
What's the right way to use a #Configuration file with TestContainers?
Appreciate any help!
If I interpret your mixture of Java and Scala code correctly, I would recommend the following approach, but only if you insist on not using #SpringBootTest.
Also: You are using the outdated neo4j-java-driver-spring-boot-starter classes, they aren't needed for a while now in recent Spring Boot and also will potentially break SDN6+.
Please note: You should never import auto configuration classes and use them as ContextConfiguration at the same time. They are only meant to be imported via #ImportAutoConfiguration, but even that is redundant or overly complicated most of the time.
First of all, here's the pom so you get the proper dependencies:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>neowithapoc</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>neowithapoc</name>
<description>neowithapoc</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>1.17.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>neo4j</artifactId>
<version>1.17.3</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Solution 1
Here's a solution that goes into what you have there, with a trait - or in case of pure java - abstract test class:
package com.example.neowithapoc;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration;
import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.containers.Neo4jLabsPlugin;
#TestConfiguration
#ImportAutoConfiguration({
Neo4jAutoConfiguration.class,
Neo4jDataAutoConfiguration.class
})
#EnableTransactionManagement
#EnableNeo4jRepositories(considerNestedRepositories = true)
public abstract class EmbeddedNeo4jConfig {
static final Neo4jContainer<?> neo4j = new Neo4jContainer<>("neo4j:4.4")
.withLabsPlugins(Neo4jLabsPlugin.APOC)
.withReuse(true);
#DynamicPropertySource
static void neo4jProperties(DynamicPropertyRegistry registry) {
neo4j.start();
registry.add("spring.neo4j.uri", neo4j::getBoltUrl);
registry.add("spring.neo4j.authentication.username", () -> "neo4j");
registry.add("spring.neo4j.authentication.password", neo4j::getAdminPassword);
}
}
Use like this:
package com.example.neowithapoc;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.data.neo4j.core.Neo4jTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = EmbeddedNeo4jConfig.class)
public class SomeTest extends EmbeddedNeo4jConfig {
#Test
void whatever(#Autowired Neo4jTemplate template, #Autowired Neo4jClient client) {
assertThat(template).isNotNull();
assertThat(client).isNotNull();
String apoc = client
.query("RETURN apoc.version() AS output")
.fetchAs(String.class)
.first().get();
assertThat(apoc).startsWith("4.4");
}
}
Solution 2
I do prefer this way simpler and less complicated approach:
package com.example.neowithapoc;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.data.neo4j.core.Neo4jTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.transaction.annotation.Transactional;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.containers.Neo4jLabsPlugin;
import org.testcontainers.junit.jupiter.Testcontainers;
#SpringBootTest
#Transactional
#Testcontainers(disabledWithoutDocker = true)
public class SomeSpringBootTest {
static final Neo4jContainer<?> neo4j = new Neo4jContainer<>("neo4j:4.4")
.withLabsPlugins(Neo4jLabsPlugin.APOC)
.withReuse(true);
#DynamicPropertySource
static void neo4jProperties(DynamicPropertyRegistry registry) {
neo4j.start();
registry.add("spring.neo4j.uri", neo4j::getBoltUrl);
registry.add("spring.neo4j.authentication.username", () -> "neo4j");
registry.add("spring.neo4j.authentication.password", neo4j::getAdminPassword);
}
#Test
void whatever(#Autowired Neo4jTemplate template, #Autowired Neo4jClient client) {
assertThat(template).isNotNull();
assertThat(client).isNotNull();
String apoc = client
.query("RETURN apoc.version() AS output")
.fetchAs(String.class)
.first().get();
assertThat(apoc).startsWith("4.4");
}
}
Bonus questions custom conversions
Given the following class:
package com.example.neowithapoc;
public class SomeObject {
private final String value;
public SomeObject(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
It is not an entity and it needs some special treatment during conversions.
It can be converted back and forth like this:
import java.util.Set;
import org.neo4j.driver.Value;
import org.neo4j.driver.Values;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.GenericConverter;
public class SomeObjectConverter implements GenericConverter {
#Override public Set<ConvertiblePair> getConvertibleTypes() {
return Set.of(
new ConvertiblePair(Value.class, SomeObject.class),
new ConvertiblePair(SomeObject.class, Value.class)
);
}
#Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
return Value.class.isAssignableFrom(targetType.getType()) ? Values.NULL : null;
} else if (source instanceof SomeObject someObject) {
return Values.value(someObject.getValue());
} else if (source instanceof Value value) {
return new SomeObject(value.asString());
} else
throw new IllegalArgumentException();
}
}
Configure it with a #TestConfiguration (or on your main config) like this
#TestConfiguration
static class AdditionalBeans {
#Bean
SomeObjectConverter someObjectConverter() {
return new SomeObjectConverter();
}
#Bean
Neo4jConversions neo4jConversions(SomeObjectConverter someObjectConverter) {
return new Neo4jConversions(List.of(someObjectConverter));
}
}
In both cases this class is a static nested class of either EmbeddedNeo4jConfig and SomeSpringBootTest.
In the former you normally would just declare the bean method directly, but as I tried to recreate your "trait" as much as possible in Java and I do extend that class, this is not possible. Tests must not have their own #Bean methods.
After that, test like this
#Node
static class ContainerNode {
#Id #GeneratedValue
Long id;
SomeObject someObject;
public Long getId() {
return id;
}
public SomeObject getSomeObject() {
return someObject;
}
}
#Test
void conversionsShouldWork(#Autowired Neo4jTemplate template) {
var container = template.find(ContainerNode.class)
.matching("CREATE (n:ContainerNode {someObject: 'Hello'}) RETURN n")
.one();
assertThat(container).map(ContainerNode::getSomeObject).map(SomeObject::getValue).hasValue("Hello");
}
will work just fine, also with the repository.
This test here will fail
#Test
void conversionsShouldWork(#Autowired Neo4jClient client) {
var anObject = client.query("RETURN 'whatever'").fetchAs(SomeObject.class).first();
assertThat(anObject).map(SomeObject::getValue).hasValue("whatever");
}
but the Spring Data Neo4j fixed this in 6.3.3 https://github.com/spring-projects/spring-data-neo4j/issues/2594 and you would be able to manually add it to the client like this:
#TestConfiguration
static class AdditionalBeans {
#Bean
SomeObjectConverter someObjectConverter() {
return new SomeObjectConverter();
}
#Bean
Neo4jConversions neo4jConversions(SomeObjectConverter someObjectConverter) {
return new Neo4jConversions(List.of(someObjectConverter));
}
#Bean
public Neo4jClient neo4jClient(
Driver driver,
DatabaseSelectionProvider databaseSelectionProvider,
Neo4jConversions neo4jConversions) {
return Neo4jClient.with(driver)
.withDatabaseSelectionProvider(databaseSelectionProvider)
.withNeo4jConversions(neo4jConversions)
.build();
}
}
Than this test will work just fine:
#Test
void clientConversionsShouldWork(#Autowired Neo4jClient client) {
var anObject = client.query("RETURN 'whatever'").fetchAs(SomeObject.class).first();
assertThat(anObject).map(SomeObject::getValue).hasValue("whatever");
}
I want to use the vaadin gantt chart component and used some of the code examples for a test.
I can create the object but is not readable
public class PlanningView extends VerticalLayout implements View {
// declare parent GUI
private MainUI myUI;
// declare navigator
public Navigator navigator;
// declare menubar
public MenuGenerator menubar;
private TimeZone defaultTimeZone;
private Gantt gantt;
private NativeSelect reso;
private DateField start;
private DateField end;
private SimpleDateFormat dateFormat = new SimpleDateFormat("MMM dd HH:mm:ss zzz yyyy");
public PlanningView(Navigator navigator, MainUI myUI) {
this.myUI = myUI;
this.navigator = navigator;
menubar = new MenuGenerator(this);
VerticalLayout mainlayout = new VerticalLayout();
gantt = new Gantt();
gantt.setWidth(100, Unit.PERCENTAGE);
gantt.setHeight(500, Unit.PIXELS);
gantt.setResizableSteps(true);
gantt.setMovableSteps(true);
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
gantt.setStartDate(cal.getTime());
cal.add(Calendar.YEAR, 1);
gantt.setEndDate(cal.getTime());
cal.setTime(new Date());
Step step1 = new Step("First step");
step1.setStartDate(cal.getTime().getTime());
cal.add(Calendar.MONTH, 2);
step1.setEndDate(cal.getTime().getTime());
gantt.addStep(step1);
mainlayout.addComponents(gantt);
addComponent(mainlayout);
}
#Override
public void enter(ViewChangeEvent arg0) {
// TODO Auto-generated method stub
Notification.show("Planning");
}
public void navigate(String page) {
navigator.navigateTo(page);
}
}
This is what it looks like:
I just had the same issue and after a while, I found the solution.
First, you have to add a addons.scss file to your theme
webapp/VAADIN/themes/mytheme/addons.scss:
/* This file is automatically managed and will be overwritten from time to time. */
/* Do not manually edit this file. */
/* Provided by gantt-addon-1.0.1.jar */
#import "../../../VAADIN/addons/gantt/gantt.scss";
/* Import and include this mixin into your project theme to include the addon themes */
#mixin addons {
#include gantt;
}
Afterward, modify your theme file:
webapp/VAADIN/themes/mytheme/mystyle.scss:
#import "addons.scss";
#import "../../../VAADIN/addons/gantt/gantt-valo.scss";
#include addons;
#include gantt-valo;
Additionally, your widget set needs to inherit from the one of the gantt addon:
<module>
<inherits name="org.tltv.gantt.WidgetSet" />
</module>
As you are using custom client side code, you have to add the client-compiler dependency to your build process:
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-client-compiler</artifactId>
</dependency>
Be aware of the vaadin-maven.plugin, which must be told to compile the widget set:
<plugin>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-maven-plugin</artifactId>
<version>${com.vaadin_version}</version>
<configuration>
<extraJvmArgs>-Xmx1G -Xss1G</extraJvmArgs>
<webappDirectory>${basedir}/src/main/webapp/VAADIN/widgetsets</webappDirectory>
<hostedWebapp>${basedir}/src/main/webapp/VAADIN/widgetsets</hostedWebapp>
<compileReport>true</compileReport>
<strict>true</strict>
</configuration>
<executions>
<execution>
<goals>
<goal>resources</goal>
<goal>update-theme</goal>
<goal>update-widgetset</goal>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
I'm starting to use neo4j-spatial in some of my code. I thought I would be able to integration test neo4j-spatial code by including the spatial server lib as a maven dependency in my project. This has not worked for me though. I can't find any documentation anywhere on this.
How can I get my integration tests to work?
Any tips anyone? :)
Just to give an idea of what I'm doing, I've pasted a segment of my controller, service and repository code below, with the final code posting being my tests that don't work against an embedded TestServer.
Repository
package nz.co.domain.core.repository.location;
import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.neo4j.repository.GraphRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import nz.co.domain.model.pojos.Location;
#Repository
public interface LocationRepository extends GraphRepository<Location> {
#Query("match (n:Location {domainId : {domainId}}) with n call spatial.addNode({layerName}, n) yield node return node;")
public Location indexLocation(#Param("domainId") String locationId, #Param("layerName") String layerName);
#Query("call spatial.withinDistance({layerName},{longitude: {longitude},latitude: {latitude}}, {rangeInKms});")
public Iterable<Location> findLocationsWithinRange(#Param("longitude") String longitude, #Param("latitude") String latitude, #Param("rangeInKms") String rangeInKms, #Param("layerName") String layerName);
#Query("call spatial.addPointLayer({layerName});")
public void createLayer(#Param("layerName") String layerName);
#Query("match ()-[:LAYER]->(n) where n.layer = {layerName} return count(n) > 0;")
public boolean hasLayer(#Param("layerName") String layerName);
public Location findByDomainSpecificId(String domainSpecificId);
public Location findByGooglePlaceId(String googlePlaceId);
}
Service
package nz.co.domain.core.location;
import javax.inject.Inject;
import org.springframework.stereotype.Service;
import nz.co.domain.core.repository.location.LocationRepository;
import nz.co.domain.model.UniqueIDGenerator;
import nz.co.domain.model.pojos.Location;
#Service
public class LocationService {
#Inject
private LocationRepository locationRepository;
public void createLayer(String layerName) {
locationRepository.createLayer(layerName);
}
public Location createLocation(double latitude, double longitude, String googlePlaceId, String layerName) {
Location location = new Location(UniqueIDGenerator.randomID(), googlePlaceId, latitude, longitude);
boolean hasLayer = locationRepository.hasLayer(layerName);
if (!hasLayer) {
locationRepository.createLayer(layerName);
}
Location preExistingLocation = locationRepository.findByGooglePlaceId(googlePlaceId);
if (preExistingLocation == null) {
location = locationRepository.save(location);
location = locationRepository.indexLocation(location.getDomainId(), layerName);
} else {
location = preExistingLocation;
}
return location;
}
public Iterable<Location> findLocationsWithinRange(String latitude, String longitude, String rangeInKms, String layerName) {
return locationRepository.findLocationsWithinRange(longitude, latitude, rangeInKms, layerName);
}
public Location loadLocationByGooglePlaceId(String googlePlaceId) {
return locationRepository.findByGooglePlaceId(googlePlaceId);
}
public Location loadLocationByDomainId(String domainId) {
return locationRepository.findByDomainId(domainId);
}
}
Controller
...
/**
* Add location.
* #param profiletypes
* #param profileId
* #return
*/
#RequestMapping(value = "/{profileType}/{profileId}/location", method = RequestMethod.POST, produces = "application/hal+json")
public HttpEntity<LocationResource> addLocation(#PathVariable String profileType,
#PathVariable String profileId, #RequestBody CreateLocationRequest locationRequest, #ApiIgnore LocationResourceAssembler locationResourceAssembler) {
Profile profile = profileService.loadProfileByDomainId(profileId);
Location location = locationService.createLocation(locationRequest.getLatitude(), locationRequest.getLongitude(), locationRequest.getGooglePlaceId(), profileType + "-layer");
profile.setLocation(location);
profileService.save(profile);
location = locationService.loadLocationByGooglePlaceId(location.getGooglePlaceId());
LocationResource resource = locationResourceAssembler.toResource(location);
return new ResponseEntity<>(resource, HttpStatus.CREATED) ;
}
...
Service test
(It is my tests here that I can't get working as part of a standard build against an embedded TestServer)
package nz.co.domain.core.location;
import javax.inject.Inject;
import org.junit.Ignore;
import org.junit.Test;
import nz.co.domain.core.AbstractTest;
import nz.co.domain.model.pojos.Location;
public class LocationServiceTest extends AbstractTest {
#Inject
private LocationService locationService;
#Test
public void indexLocationTest() {
// The Rogue and Vagabond
Location rogueAndVagabond = locationService.createLocation(51.469150, 7.23212, "ChIJmwfKGdivOG0R9eTCVFOngnU", "test-layer");
/* more test code here */
// Te Papa Museum
Location tePapaMuseum = locationService.createLocation(-41.289964, 174.778354, "ChIJfxn9AdGvOG0RpLRGGO3tRX8", "test-layer");
/* more test code here */
// Porirua Club
Location poriruaClub = locationService.createLocation(-41.136048, 174.836409, "ChIJ9wl16m1TP20R3G3npuEokak", "test-layer");
/* more test code here */
Iterable<Location> findLocationsWithinRange = locationService.findLocationsWithinRange("-41.289964", "longitude", "5", "test-layer");
/* more test code here */
}
}
Spatial functionality is not provided in SDN 4 yet. If you integrate the neo4j-spatial lib then the only option you have at the moment is to use it directly- there will be no repository support etc.
However, spatial integration work is currently in progress, so some basic functionality should be introduced in the next release.
We're using SDN 4.1.2, OGM 2.0.3 and I got my tests working with this setup:
Added the maven dependency using the description on the github page. By the time of writing this comment the necessary addition to the pom.xml was
<repositories>
<repository>
<id>neo4j-contrib-releases</id>
<url>https://raw.github.com/neo4j-contrib/m2/master/releases</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>neo4j-contrib-snapshots</id>
<url>https://raw.github.com/neo4j-contrib/m2/master/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<!-- ... -->
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-spatial</artifactId>
<version>0.19-neo4j-3.0.3</version>
</dependency>
Defining the following abstract classes for all spatial-related tests:
#RunWith(SpringJUnit4ClassRunner::class)
#SpringApplicationConfiguration(classes = arrayOf(Application::class))
#ActiveProfiles("test")
#Transactional
abstract class AbstractIntegrationTests() {}
and
#WebAppConfiguration
abstract class AbstractIntegrationTestsWithProcedures : AbstractIntegrationTests() {
lateinit var databaseService: GraphDatabaseService
val layerName = "layer"
#Before()
open fun before() {
if (ProcedureTestUtil.registeredProcedures.contains(SpatialProcedures::class.java)) {
return
}
val driver = Components.driver()
if (driver is EmbeddedDriver) {
databaseService = driver.graphDatabaseService
ProcedureTestUtil.registerProcedure(databaseService, SpatialProcedures::class.java)
val spatialPlugin = SpatialPlugin()
spatialPlugin.addSimplePointLayer(databaseService, layerName, "latitude", "longitude")
} else {
throw UnsupportedOperationException("Expected an embedded Neo4j instance, but was " + driver.javaClass.name)
}
}
}
and additionally
class ProcedureTestUtil {
companion object {
#JvmStatic
var registeredProcedures: MutableList<Class<*>> = ArrayList()
#JvmStatic
#Throws(KernelException::class)
fun registerProcedure(db: GraphDatabaseService, procedure: Class<*>) {
val proceduresService = (db as GraphDatabaseAPI).dependencyResolver.resolveDependency(Procedures::class.java)
proceduresService.register(procedure)
registeredProcedures.add(procedure)
}
}
}
you should get your tests running if
LocationServiceTest extends AbstractIntegrationTestsWithProcedures.
I hope someone can help me.
I try to send a POST Request with a JSON Body using Retrofit 2.0.
Interface:
public interface Interface {
#POST(/*path*/)
Call<MyResponseObject> sendInt(#Body MyInteger myInt);
}
MyInteger class:
public class MyInteger {
int id;
public MyInteger(int id) {
this.id = id;
}
}
Part of MainActivity:
private Retrofit mRetrofit = null;
private final Interface mService;
...
...
mRetrofit = new Retrofit.Builder()
.baseUrl(/*URL*/)
.addConverterFactory(GsonConverterFactory.create())
.build();
mService = mRetrofit.create(Interface.class);
The call:
MyInteger id = new MyInteger(0);
mService.sendInt(id).enqueue(new Callback<MyResponseObject>() {
#Override
public void onResponse(Call<MyResponseObject> call, Response<MyResponseObject> response) {/*Log something*/}
#Override
public void onFailure(Call<MyResponseObject> call, Throwable t) {}
});
In my Opinion it's like this example:
https://futurestud.io/blog/retrofit-send-objects-in-request-body
But the GsonConverter cant convert MyInteger to JSON..
Here is the Log:
java.lang.IllegalArgumentException: Unable to create #Body converter for class com.??.MyInteger (parameter #1)
for method Interface.sendInt
...
...
Caused by: java.lang.IllegalArgumentException: Could not locate RequestBody converter for class com.??.MyInteger.
Tried:
* retrofit2.BuiltInConverters
* retrofit2.GsonConverterFactory
at retrofit2.Retrofit.nextRequestBodyConverter(Retrofit.java:288)
at retrofit2.Retrofit.requestBodyConverter(Retrofit.java:248)
at retrofit2.RequestFactoryParser.parseParameters(RequestFactoryParser.java:491)
I had the same problem. The root cause was that I was using incompatible libraries.
This combination works for me:
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.0.0-beta4</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-gson</artifactId>
<version>2.0.0-beta4</version>
</dependency>
I'm doing a test movie project to learn neo4j and SDN and here is a problem I'm facing:
As you know movie director may be a producer or a writer or even an actor. In my java class architecture I have Person superclass. And it has children: Producer, Director, Actor and Writer. All these children nodes are on the same level, thus they are incompatible types.
While on the other hand, in neo4j I have nodes that are at the same time Producer, Director and Writer.
So I have a problem when I want to get all directors via repository.findAll() method (or via custom method with Cypher query). Spring tells me:
java.lang.IllegalArgumentException: Can not set java.util.Set field
com.test.db.domain.Producer.producedMovies to
com.test.db.domain.Director
I use Neo4j 2.0.1 and Spring Data Neo4j 3.0.0.RELEASE.
What is the right way to solve such kind of issue?
Update:
Here is the code:
public class App {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("service-beans.xml");
Neo4jTemplate neo4jTemplate = context.getBean(Neo4jTemplate.class);
DirectorRepository repository = context.getBean(DirectorRepository.class);
try (Transaction transaction = neo4jTemplate.getGraphDatabase().beginTx()) {
EndResult<Director> all = repository.findAll_Upd(); //repository.findAll();
Iterator<Director> iterator = all.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
transaction.success();
}
}
}
#Transactional
public interface DirectorRepository extends GraphRepository<Director> {
#Query("match(n:Director) return n")
EndResult<Director> findAll_Upd();
}
#NodeEntity
public class Person implements Comparable<Person> {
#GraphId
Long nodeId;
// #Indexed(unique=true)
String id;
#Indexed(indexType= IndexType.FULLTEXT, indexName = "people")
String name;
private Short born;
private Date birthday;
private String birthplace;
private String biography;
private Integer version;
private Date lastModified;
private String profileImageUrl;
...
}
public class Director extends Person {
#Fetch #RelatedTo(elementClass = Movie.class, type = RelationshipConstants.DIRECTED)
private Set<Movie> directedMovies = new HashSet<>();
}
public class Producer extends Person {
#Fetch #RelatedTo(elementClass = Movie.class, type = RelationshipConstants.PRODUCED)
private Set<Movie> producedMovies = new HashSet<>();
}
public class Actor extends Person {
#RelatedToVia(type = RelationshipConstants.ACTED_IN)
List<Role> roles;
}
#NodeEntity
public class Movie implements Comparable<Movie> {
#GraphId
Long nodeId;
#Indexed(unique = true)
String id;
#Indexed(indexType= IndexType.FULLTEXT, indexName = "search")
String title;
int released;
String tagline;
#Fetch #RelatedTo(type = RelationshipConstants.ACTED_IN, direction = INCOMING)
Set<Actor> actors;
#Fetch #RelatedTo(type = RelationshipConstants.PRODUCED, direction = INCOMING)
Set<Producer> producers;
#RelatedToVia(type = RelationshipConstants.ACTED_IN, direction = INCOMING)
List<Role> roles;
}
And the full Exception:
Exception in thread "main"
org.springframework.data.mapping.model.MappingException: Setting
property producedMovies to null on Rob Reiner [null] at
org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.setProperty(SourceStateTransmitter.java:85)
at
org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.copyEntityStatePropertyValue(SourceStateTransmitter.java:91)
at
org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.access$000(SourceStateTransmitter.java:40)
at
org.springframework.data.neo4j.support.mapping.SourceStateTransmitter$2.doWithAssociation(SourceStateTransmitter.java:61)
at
org.springframework.data.mapping.model.BasicPersistentEntity.doWithAssociations(BasicPersistentEntity.java:291)
at
org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.copyPropertiesFrom(SourceStateTransmitter.java:57)
at
org.springframework.data.neo4j.support.mapping.Neo4jEntityFetchHandler.fetchValue(Neo4jEntityFetchHandler.java:75)
at
org.springframework.data.neo4j.support.mapping.Neo4jEntityFetchHandler.fetch(Neo4jEntityFetchHandler.java:60)
at
org.springframework.data.neo4j.support.mapping.Neo4jEntityConverterImpl$1.doWithAssociation(Neo4jEntityConverterImpl.java:135)
at
org.springframework.data.mapping.model.BasicPersistentEntity.doWithAssociations(BasicPersistentEntity.java:291)
at
org.springframework.data.neo4j.support.mapping.Neo4jEntityConverterImpl.cascadeFetch(Neo4jEntityConverterImpl.java:125)
at
org.springframework.data.neo4j.support.mapping.Neo4jEntityConverterImpl.loadEntity(Neo4jEntityConverterImpl.java:114)
at
org.springframework.data.neo4j.support.mapping.Neo4jEntityConverterImpl.read(Neo4jEntityConverterImpl.java:104)
at
org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister$CachedConverter.read(Neo4jEntityPersister.java:170)
at
org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister.createEntityFromState(Neo4jEntityPersister.java:189)
at
org.springframework.data.neo4j.support.Neo4jTemplate.createEntityFromState(Neo4jTemplate.java:223)
at
org.springframework.data.neo4j.fieldaccess.RelationshipHelper.createEntitySetFromRelationshipEndNodes(RelationshipHelper.java:150)
at
org.springframework.data.neo4j.fieldaccess.RelatedToFieldAccessor.createEntitySetFromRelationshipEndNodes(RelatedToFieldAccessor.java:86)
at
org.springframework.data.neo4j.fieldaccess.RelatedToCollectionFieldAccessorFactory$RelatedToCollectionFieldAccessor.getValue(RelatedToCollectionFieldAccessorFactory.java:76)
at
org.springframework.data.neo4j.fieldaccess.DefaultEntityState.getValue(DefaultEntityState.java:97)
at
org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.copyEntityStatePropertyValue(SourceStateTransmitter.java:90)
at
org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.access$000(SourceStateTransmitter.java:40)
at
org.springframework.data.neo4j.support.mapping.SourceStateTransmitter$2.doWithAssociation(SourceStateTransmitter.java:61)
at
org.springframework.data.mapping.model.BasicPersistentEntity.doWithAssociations(BasicPersistentEntity.java:291)
at
org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.copyPropertiesFrom(SourceStateTransmitter.java:57)
at
org.springframework.data.neo4j.support.mapping.Neo4jEntityConverterImpl.loadEntity(Neo4jEntityConverterImpl.java:112)
at
org.springframework.data.neo4j.support.mapping.Neo4jEntityConverterImpl.read(Neo4jEntityConverterImpl.java:104)
at
org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister$CachedConverter.read(Neo4jEntityPersister.java:170)
at
org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister.createEntityFromState(Neo4jEntityPersister.java:189)
at
org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister.projectTo(Neo4jEntityPersister.java:216)
at
org.springframework.data.neo4j.support.Neo4jTemplate.projectTo(Neo4jTemplate.java:240)
at
org.springframework.data.neo4j.support.conversion.EntityResultConverter.doConvert(EntityResultConverter.java:73)
at
org.springframework.data.neo4j.conversion.DefaultConverter.convert(DefaultConverter.java:44)
at
org.springframework.data.neo4j.support.conversion.EntityResultConverter.convert(EntityResultConverter.java:165)
at
org.springframework.data.neo4j.conversion.QueryResultBuilder$1.convert(QueryResultBuilder.java:103)
at
org.springframework.data.neo4j.conversion.QueryResultBuilder$1.access$300(QueryResultBuilder.java:81)
at
org.springframework.data.neo4j.conversion.QueryResultBuilder$1$1.underlyingObjectToObject(QueryResultBuilder.java:121)
at
org.neo4j.helpers.collection.IteratorWrapper.next(IteratorWrapper.java:47)
at com.test.util.App.main(App.java:34) at
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606) at
com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: java.lang.IllegalArgumentException: Can not set
java.util.Set field com.test.db.domain.Producer.producedMovies to
com.test.db.domain.Director at
sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:164)
at
sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:168)
at
sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:55)
at
sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:75)
at java.lang.reflect.Field.set(Field.java:741) at
org.springframework.util.ReflectionUtils.setField(ReflectionUtils.java:102)
at
org.springframework.data.mapping.model.BeanWrapper.setProperty(BeanWrapper.java:90)
at
org.springframework.data.mapping.model.BeanWrapper.setProperty(BeanWrapper.java:68)
at
org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.setProperty(SourceStateTransmitter.java:83)
... 43 more
Update
I have also tried projectTo () method (projections), but still I get the same exception:
Director director = neo4jTemplate.projectTo(person, Director.class);
I'm not sure on the neo4j mapping - but your java model doesn't match your business description - you more need a Person class with a Set < MovieJob> member- where MovieJob is your abstract class which Actor, Director, Producer are subclasses.