Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.
01-20-2022 10:30 AM
Hello,
I'm using Spring Boot 2.6.2 (comes with spring-data-neo4j:6.2.0 and neo4j-cypher-dsl:2021.4.1), I'm having the following error
java.util.MissingResourceException: Can't find resource for bundle java.util.PropertyResourceBundle, key assertions.node-required
at java.base/java.util.ResourceBundle.getObject(ResourceBundle.java:564) ~[na:na]
at java.base/java.util.ResourceBundle.getString(ResourceBundle.java:521) ~[na:na]
at org.neo4j.cypherdsl.core.Functions.id(Functions.java:57) ~[neo4j-cypher-dsl-2021.4.1.jar:2021.4.1]
at org.neo4j.cypherdsl.core.AbstractNode.internalId(AbstractNode.java:96) ~[neo4j-cypher-dsl-2021.4.1.jar:2021.4.1]
at org.springframework.data.neo4j.core.mapping.CypherGenerator.prepareSaveOf(CypherGenerator.java:337) ~[spring-data-neo4j-6.2.0.jar:6.2.0]
at org.springframework.data.neo4j.core.Neo4jTemplate.lambda$saveImpl$2(Neo4jTemplate.java:394) ~[spring-data-neo4j-6.2.0.jar:6.2.0]
at org.springframework.data.neo4j.core.DefaultNeo4jClient$RunnableStatement.runWith(DefaultNeo4jClient.java:208) ~[spring-data-neo4j-6.2.0.jar:6.2.0]
at org.springframework.data.neo4j.core.DefaultNeo4jClient$DefaultRecordFetchSpec.one(DefaultNeo4jClient.java:453) ~[spring-data-neo4j-6.2.0.jar:6.2.0]
at org.springframework.data.neo4j.core.Neo4jTemplate.saveImpl(Neo4jTemplate.java:398) ~[spring-data-neo4j-6.2.0.jar:6.2.0]
at org.springframework.data.neo4j.core.Neo4jTemplate.save(Neo4jTemplate.java:343) ~[spring-data-neo4j-6.2.0.jar:6.2.0]
at org.springframework.data.neo4j.repository.support.SimpleNeo4jRepository.save(SimpleNeo4jRepository.java:119) ~[spring-data-neo4j-6.2.0.jar:6.2.0]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new$0(RepositoryMethodInvoker.java:289) ~[spring-data-commons-2.6.0.jar:2.6.0]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:137) ~[spring-data-commons-2.6.0.jar:2.6.0]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:121) ~[spring-data-commons-2.6.0.jar:2.6.0]
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:529) ~[spring-data-commons-2.6.0.jar:2.6.0]
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:285) ~[spring-data-commons-2.6.0.jar:2.6.0]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:638) ~[spring-data-commons-2.6.0.jar:2.6.0]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.14.jar:5.3.14]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:163) ~[spring-data-commons-2.6.0.jar:2.6.0]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:138) ~[spring-data-commons-2.6.0.jar:2.6.0]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.14.jar:5.3.14]
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80) ~[spring-data-commons-2.6.0.jar:2.6.0]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.14.jar:5.3.14]
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) ~[spring-tx-5.3.14.jar:5.3.14]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388) ~[spring-tx-5.3.14.jar:5.3.14]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-5.3.14.jar:5.3.14]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.14.jar:5.3.14]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137) ~[spring-tx-5.3.14.jar:5.3.14]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.14.jar:5.3.14]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-5.3.14.jar:5.3.14]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.14.jar:5.3.14]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.14.jar:5.3.14]
at com.sun.proxy.$Proxy198.save(Unknown Source) ~[na:na]
at com.acme.FooBarDao.save(FooBarDao.java:82) ~[classes/:na]
...
The FooBarDao.java:82 line is a simple call to the node repository as the following
fooBarNodeRepository.save(fooBarNode);
the FooBarNodeRepository is a simple node repository as the following:
public interface FooBarNodeRepository extends Neo4jRepository<FooBarNode, Long> {
Optional<FooBarNode> findByGid(String gid);
void deleteByGid(String gid);
@Query("MATCH (n:FooBar) WHERE n.gid = $gid RETURN id(n)")
Long getIdByGid(String gid);
}
The same code was working with no issue under Spring Boot 2.5.2
I've done some debugging, the exception is thrown from org.neo4j.cypherdsl.core.Functions line 57 as the below
Assertions.notNull(node, Cypher.messages.getString(MessageKeys.ASSERTIONS_NODE_REQUIRED));
node is not null, and for some reason Cypher.messages are not being loaded
Solved! Go to Solution.
01-20-2022 11:11 PM
The root issue has been found.
When enabling TRACE in the logging I found the folloing in the logs:
2022-01-21 10:29:20.484 TRACE 19636 --- [ restartedMain] .i.s.PathMatchingResourcePatternResolver : Resolved classpath location [messages.properties] to resources [URL [file:/E:/AcmeFoobar/target/classes/messages.properties], URL [jar:file:/C:/Users/tariqd/.m2/repository/org/neo4j/neo4j-cypher-dsl/2021.4.1/neo4j-cypher-dsl-2021.4.1.jar!/messages.properties]]
2022-01-21 10:29:20.484 TRACE 19636 --- [ restartedMain] utoConfiguration$ResourceBundleCondition : Condition MessageSourceAutoConfiguration.ResourceBundleCondition on org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration matched due to ResourceBundle found bundle URL [file:/E:/AcmeFoobar/target/classes/messages.properties]
So Spring Boot is injecting Cypher.messages with the project's messages.properties instead of neo4j-cypher-dsl one.
As a proof of concept, I inserted the content of neo4j-cypher-dsl-2021.4.1.jar!/messages.properties to the tail of the project's messages.properties and it worked.
The above can serve as a work-around for the time being, but since the messages.properties is the default in any Spring Boot application, then I'd suggest the following fix:
static final ResourceBundle messages = ResourceBundle.getBundle("neo4j-cypher-dsl-messages");
01-20-2022 11:11 PM
The root issue has been found.
When enabling TRACE in the logging I found the folloing in the logs:
2022-01-21 10:29:20.484 TRACE 19636 --- [ restartedMain] .i.s.PathMatchingResourcePatternResolver : Resolved classpath location [messages.properties] to resources [URL [file:/E:/AcmeFoobar/target/classes/messages.properties], URL [jar:file:/C:/Users/tariqd/.m2/repository/org/neo4j/neo4j-cypher-dsl/2021.4.1/neo4j-cypher-dsl-2021.4.1.jar!/messages.properties]]
2022-01-21 10:29:20.484 TRACE 19636 --- [ restartedMain] utoConfiguration$ResourceBundleCondition : Condition MessageSourceAutoConfiguration.ResourceBundleCondition on org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration matched due to ResourceBundle found bundle URL [file:/E:/AcmeFoobar/target/classes/messages.properties]
So Spring Boot is injecting Cypher.messages with the project's messages.properties instead of neo4j-cypher-dsl one.
As a proof of concept, I inserted the content of neo4j-cypher-dsl-2021.4.1.jar!/messages.properties to the tail of the project's messages.properties and it worked.
The above can serve as a work-around for the time being, but since the messages.properties is the default in any Spring Boot application, then I'd suggest the following fix:
static final ResourceBundle messages = ResourceBundle.getBundle("neo4j-cypher-dsl-messages");
01-20-2022 11:47 PM
Could you provide a reproducer? I do not see any reason why this should be needed. Tried to reproduce it with different scenarios but the resources are always available.
01-21-2022 07:07 AM
I've checked cypher-dsl GitHub and the guys there have already addressed this issue.
GH-252 - Use a namespace for the message bundle.
This improvement moves `messages.properties` to a package in the project's namespace.
This prevents conflicts if the library is used in a project where a `messages.properties` is used from the resources root.
it is tagged as 2022.0.0 2021.4.2
01-21-2022 07:33 AM
Spring Boot 2.6.3 was released yesterday after I posted this issue, the fixed version is included there
I've tested it and it is working properly
01-21-2022 08:44 AM
It was a native problem. Sorry, I did not catch this.
All the sessions of the conference are now available online