cancel
Showing results for 
Search instead for 
Did you mean: 

Neo4j-cypher-dsl java.util.MissingResourceException: Can't find resource for bundle java.util.PropertyResourceBundle, key assertions.node-required

tariqd
Node Link

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

1 ACCEPTED SOLUTION

tariqd
Node Link

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:

  1. Rename neo4j-cypher-dsl/messages.properties to neo4j-cypher-dsl/neo4j-cypher-dsl-messages.properties
  2. Update line 56 in org.neo4j.cypherdsl.core.Cypher as the following:
static final ResourceBundle messages = ResourceBundle.getBundle("neo4j-cypher-dsl-messages");

View solution in original post

5 REPLIES 5

tariqd
Node Link

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:

  1. Rename neo4j-cypher-dsl/messages.properties to neo4j-cypher-dsl/neo4j-cypher-dsl-messages.properties
  2. Update line 56 in org.neo4j.cypherdsl.core.Cypher as the following:
static final ResourceBundle messages = ResourceBundle.getBundle("neo4j-cypher-dsl-messages");

gerrit_meier
Neo4j
Neo4j

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.

tariqd
Node Link

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

Spring Boot 2.6.3 was released yesterday after I posted this issue, the fixed version is included there
3X_a_5_a567f90261b12dcf81903eaf98974f02fd378b2d.png
I've tested it and it is working properly

It was a native problem. Sorry, I did not catch this.

Nodes 2022
Nodes
NODES 2022, Neo4j Online Education Summit

On November 16 and 17 for 24 hours across all timezones, you’ll learn about best practices for beginners and experts alike.