- add dependency
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-neo4j</artifactId> </dependency>
add Friend class
import lombok.Data; import lombok.experimental.Accessors; import org.bson.types.ObjectId; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.MongoId;
@Document(collection = "friend")
@Data
@Accessors(chain = true)
public class Friend {
@MongoId
private ObjectId id;
}
- startup exception
springboot 2.4.1 has no problem starting If the type of the id field of the Friend class is changed to String, the startup is OK **Test project address is https://github.com/star4j/test.git
Comment From: wilkinsona
This is the failure:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'neo4jMappingContext' defined in class path resource [org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.class]: Invocation of init method failed; nested exception is org.springframework.data.mapping.MappingException: The property 'null' is not mapped to a Graph property!
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1788) ~[spring-beans-5.3.3.jar:5.3.3]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:609) ~[spring-beans-5.3.3.jar:5.3.3]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:531) ~[spring-beans-5.3.3.jar:5.3.3]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.3.jar:5.3.3]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.3.jar:5.3.3]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.3.jar:5.3.3]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.3.jar:5.3.3]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944) ~[spring-beans-5.3.3.jar:5.3.3]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:923) ~[spring-context-5.3.3.jar:5.3.3]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:588) ~[spring-context-5.3.3.jar:5.3.3]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:144) ~[spring-boot-2.4.2.jar:2.4.2]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:767) [spring-boot-2.4.2.jar:2.4.2]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759) [spring-boot-2.4.2.jar:2.4.2]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:426) [spring-boot-2.4.2.jar:2.4.2]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:326) [spring-boot-2.4.2.jar:2.4.2]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1311) [spring-boot-2.4.2.jar:2.4.2]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300) [spring-boot-2.4.2.jar:2.4.2]
at com.example.test.TestApplication.main(TestApplication.java:10) [classes/:na]
Caused by: org.springframework.data.mapping.MappingException: The property 'null' is not mapped to a Graph property!
at org.springframework.data.neo4j.core.mapping.DefaultNeo4jPersistentProperty.getPropertyName(DefaultNeo4jPersistentProperty.java:247) ~[spring-data-neo4j-6.0.3.jar:6.0.3]
at org.springframework.data.neo4j.core.mapping.DefaultNeo4jPersistentEntity.computeIdDescription(DefaultNeo4jPersistentEntity.java:350) ~[spring-data-neo4j-6.0.3.jar:6.0.3]
at org.springframework.data.neo4j.core.mapping.DefaultNeo4jPersistentEntity.verify(DefaultNeo4jPersistentEntity.java:203) ~[spring-data-neo4j-6.0.3.jar:6.0.3]
at org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:388) ~[spring-data-commons-2.4.3.jar:2.4.3]
at org.springframework.data.neo4j.core.mapping.Neo4jMappingContext.addPersistentEntity(Neo4jMappingContext.java:258) ~[spring-data-neo4j-6.0.3.jar:6.0.3]
at org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:334) ~[spring-data-commons-2.4.3.jar:2.4.3]
at java.lang.Iterable.forEach(Iterable.java:75) ~[na:1.8.0_252]
at org.springframework.data.mapping.context.AbstractMappingContext.initialize(AbstractMappingContext.java:463) ~[spring-data-commons-2.4.3.jar:2.4.3]
at org.springframework.data.mapping.context.AbstractMappingContext.afterPropertiesSet(AbstractMappingContext.java:455) ~[spring-data-commons-2.4.3.jar:2.4.3]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1847) ~[spring-beans-5.3.3.jar:5.3.3]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1784) ~[spring-beans-5.3.3.jar:5.3.3]
... 17 common frames omitted
For future reference, @star4j, please include this sort information when opening an issue as it helps us to process things more efficiently.
Comment From: wilkinsona
The change in behaviour is due to https://github.com/spring-projects/spring-boot/pull/24239.
@meistermeier Friend
is now included in the initial entity set that's passed into Spring Data Neo4j's Neo4jMappingContext
. It's then failing when processing the entity. Can you please take a look?
Comment From: meistermeier
Will do. :+1:
Comment From: meistermeier
First of you are correct in tracking this down to the recent change we introduced in Spring Boot.
On the other side this was more or less just an alignment to the other stores and their auto configuration behaviour esp. to keep up with the scenarios if the mapping contexts are getting set explicitly into the strict mode. In those cases a registration of additional entities cannot be done later at runtime.
Having said this, digging a little bit deeper into e.g. SD Mongo's definition of the Document
annotation, I can see that the generic persistent type (annotation) gets inherited / declared. The change we introduced will now discover also Document
annotated entities because they are also Persistent
annotated.
Discovering Persistent
annotated entities is something that "every" (TBH I haven't checked all but for example https://github.com/spring-projects/spring-boot/blob/0104ee677ec5d9072948e3b6aa7ec9300945b49f/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataConfiguration.java#L51) other store also does. This means that a SD Mongo setup will also fail if we would inherit / decorate our very own annotations with Persistent
.
(This now gets longer than I have expected...but glad you are still here)
My suggestion is that if an entity should not get discovered is either creating a Neo4jMappingContext
or MongoMappingContext
bean manually and providing the initial entity set (setInitialEntitySet
) there.
I would far less be in favour to go the defensive way and revert the changes because the stores are now aligned.
What I would suggest, and can discuss with the Spring Data team, is that we talk about if and how to give users a more configuration-based way to separate the domain classes.
Comment From: wilkinsona
Thanks, @meistermeier.
While things are now aligned in terms of the annotations used when scanning, the behaviour when processing the results is not. For example, if I modify the supplied sample and replace Neo4j with Cassandra, the verification of the Friend
entity performed in BasicCassandraPersistentEntity
succeeds. In other words, Neo4j appears to be more restrictive in terms of the entities that will pass verification so the widening of the entities that are found (#24239) is now causing startup failures.
I think we either need to revert #24239 or Neo4j's verification needs to align with the other stores.
Comment From: meistermeier
Tried it with SD Cassandra and with the mongo/neo4j example provided ^^: Either replacing Neo4j with Cassandra or turning the example the other way around and making friend a Spring Data Neo4j Node
(and removing the Document
) will not result in an exception at startup but will register Friend
also as an eligible entity for SD Cassandra/Mongo. Of course accessing a Cassandra table entity with the Mongo operations will fail during runtime with arbitrary mapping errors.
I would suggest to "fix" the problem that we (you?) remove the Persistent
annotation from the initialEntityClasses
(we need to stick with the Node
and the newly introduced RelationshipProperties
). Additionally I had a chat with Mark about the overall usage of Persistent
in the other modules and we will discuss a long-term solution that probably have an impact on all store modules configuration.
Comment From: wilkinsona
I would suggest to "fix" the problem that we (you?) remove the Persistent annotation from the initialEntityClasses
That makes sense to me. We can take care of that.
Additionally I had a chat with Mark about the overall usage of Persistent in the other modules and we will discuss a long-term solution that probably have an impact on all store modules configuration.
That sounds good too. Boot includes @Persistent
when looking for Couchbase and Mongo entities. It's also included when looking for Cassandra entities but via code in CassandraEntityClassScanner
which is part of Spring Data.
@mp911de Please let us know how we can track the long-term solution so that we can keep Boot's code in sync.
Comment From: mp911de
We'll discuss that topic within our team. I'm not sure why @Persistent
-annotated entities were picked up in the first place. Once we've clarified that, we can proceed. In any case, scanning for @Persistent
entities is rather an obstacle in multi-store arrangements.
Comment From: mp911de
We discussed that topic with the Spring Data team and concluded that we should remove @Persistent
from the annotations that qualify for picking up a class as entity. Instead, we should use store-specific annotations. @Persistent
is an SPI to be used by Spring Data store modules. We will update the affected Spring Data modules.
Comment From: wilkinsona
Thanks, Mark. Is there an issue that we can subscribe to so that we can align Boot with Data when the time comes?
Until that time, we'll use this issue to remove @Persistent
from the Neo4j setup, i.e. we're going to partially revert #24239, keeping support for RelationshipProperties
.
Comment From: mp911de
We need to check which modules are affected and file tickets where the scanning needs to be fixed. I'll leave references here once we have created tickets.