Spring Data, FloatValue to Float Uncoercible error

In the AdditionalTypes class from Spring Data, there's a converter for Float:

On line 77/78

hlp.add(ConverterBuilder.reading(Value.class, Float.class, AdditionalTypes::asFloat).andWriting(AdditionalTypes::value));
		hlp.add(ConverterBuilder.reading(Value.class, float.class, AdditionalTypes::asFloat).andWriting(AdditionalTypes::value));

Then later on, as this method is called in line 312:

static Float asFloat(Value value) {
		return Float.parseFloat(value.asString());
	}

It does an asString on the ValueAdapter, which in turn throws an exception:

@Override
    public String asString()
    {
        throw new Uncoercible( type().name(), "Java String" );
    }

This is using the following:

    implementation 'org.springframework.boot:spring-boot-starter-data-neo4j'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.boot:spring-boot-starter-actuator'
	implementation 'org.hibernate:hibernate-spatial:5.4.22.Final'	
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testImplementation 'org.springframework.batch:spring-batch-test'
	testImplementation('org.hamcrest:hamcrest:2.2')
	testCompile (group: 'org.neo4j.test', name: 'neo4j-harness', version: '4.0.11'){
		exclude group: 'org.slf4j', module: 'slf4j-nop'
	}
	testImplementation 'org.testcontainers:neo4j'
	testCompile 'org.neo4j.procedure:apoc:4.0.0.18'

I believe instead of the AsString this method could've called toString and it would've been fine?

Note that I'm stuck on org.neo4j.test 4.0.x as it's the only version that allows installing the apoc plugin.

Can you please share the full stack trace?

Can you also please share the output of the Gradle equivalent of mvn dependency:tree? (I believe it's gradle -q dependencies).

Finally, can you elaborate on the issue with APOC? There 4.1.x and 4.2.x for APOC as well, so I don't see why they would not work with latest Neo4j versions (4.2.x).
Is there a reason you use testcontainers AND test-harness? It's usually one or the other.

Thanks!

Thanks for your swift reply.
To elobrate, 4.1.x and 4.2.x doesn't work with APOC 4.1.x or 4.2.x, I'm not the first one to notice this: cypher - Configuration of embedded Neo4j to run APOC procedures - Stack Overflow

Test containers are a relic, from trying things out. Removed them for now. And ran again.

Dependencies added as attachment, stack trace below.

Error mapping Record<{n: {__internalNeo4jId__: 1797, __paths__: [path[(1797)<-[2131:CONNECTED]-(251)], path[(1797)<-[2131:CONNECTED]-(251), (251)<-[295:ASSET_RELATIONSHIP]-(344)], path[(1797)<-[2131:CONNECTED]-(251), (251)<-[295:ASSET_RELATIONSHIP]-(344) - **path goes on**
org.springframework.data.neo4j.core.mapping.DefaultNeo4jEntityConverter.read(DefaultNeo4jEntityConverter.java:112)
	at org.springframework.data.neo4j.core.mapping.DefaultNeo4jEntityConverter.read(DefaultNeo4jEntityConverter.java:67)
	at org.springframework.data.neo4j.core.mapping.Schema.lambda$getRequiredMappingFunctionFor$0(Schema.java:96)
	at org.springframework.data.neo4j.core.PreparedQuery$AggregatingMappingFunction.apply(PreparedQuery.java:218)
	at org.springframework.data.neo4j.core.PreparedQuery$AggregatingMappingFunction.apply(PreparedQuery.java:154)
	at org.springframework.data.neo4j.core.DelegatingMappingFunctionWithNullCheck.apply(DelegatingMappingFunctionWithNullCheck.java:45)
	at org.springframework.data.neo4j.core.DelegatingMappingFunctionWithNullCheck.apply(DelegatingMappingFunctionWithNullCheck.java:35)
	at org.springframework.data.neo4j.core.DefaultNeo4jClient$DefaultRecordFetchSpec.one(DefaultNeo4jClient.java:285)
	at org.springframework.data.neo4j.core.Neo4jTemplate$DefaultExecutableQuery.getSingleResult(Neo4jTemplate.java:584)
	at org.springframework.data.neo4j.repository.query.Neo4jQueryExecution$DefaultQueryExecution.execute(Neo4jQueryExecution.java:53)
	at org.springframework.data.neo4j.repository.query.AbstractNeo4jQuery.execute(AbstractNeo4jQuery.java:85)
	at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:137)
	at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:121)
	at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:152)
	at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:131)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
	at com.sun.proxy.$Proxy227.findOneById(Unknown Source)
	at com.alliander.gpsapineo4jbatch.integration.Neo4jBatchTest.checkNeo4jObjects(Neo4jBatchTest.java:148)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:564)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:210)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:206)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:131)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
	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:96)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75)
	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 java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:564)
	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 com.sun.proxy.$Proxy5.stop(Unknown Source)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:133)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:564)
	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:1130)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
	at java.base/java.lang.Thread.run(Thread.java:832)
Caused by: org.springframework.dao.TypeMismatchDataAccessException: Could not convert 4.430600166320801 into java.lang.Float; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [org.neo4j.driver.internal.value.FloatValue] to type [java.lang.Float] for value '4.430600166320801'; nested exception is org.neo4j.driver.exceptions.value.Uncoercible: Cannot coerce FLOAT to Java String
	at org.springframework.data.neo4j.core.mapping.DefaultNeo4jConversionService.readValueImpl(DefaultNeo4jConversionService.java:97)
	at org.springframework.data.neo4j.core.mapping.DefaultNeo4jConversionService.readValue(DefaultNeo4jConversionService.java:74)
	at org.springframework.data.neo4j.core.mapping.DefaultNeo4jEntityConverter.lambda$populateFrom$3(DefaultNeo4jEntityConverter.java:365)
	at org.springframework.data.mapping.model.BasicPersistentEntity.doWithProperties(BasicPersistentEntity.java:360)
	at org.springframework.data.neo4j.core.mapping.DefaultNeo4jEntityConverter.lambda$map$2(DefaultNeo4jEntityConverter.java:270)
	at org.springframework.data.neo4j.core.mapping.DefaultNeo4jEntityConverter.map(DefaultNeo4jEntityConverter.java:289)
	at org.springframework.data.neo4j.core.mapping.DefaultNeo4jEntityConverter.map(DefaultNeo4jEntityConverter.java:239)
	at org.springframework.data.neo4j.core.mapping.DefaultNeo4jEntityConverter.read(DefaultNeo4jEntityConverter.java:110)
	... 118 more
Caused by: org.springframework.core.convert.ConversionFailedException: Failed to convert from type [org.neo4j.driver.internal.value.FloatValue] to type [java.lang.Float] for value '4.430600166320801'; nested exception is org.neo4j.driver.exceptions.value.Uncoercible: Cannot coerce FLOAT to Java String
	at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:47)
	at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:192)
	at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:175)
	at org.springframework.data.neo4j.core.mapping.DefaultNeo4jConversionService.lambda$readValue$0(DefaultNeo4jConversionService.java:71)
	at org.springframework.data.neo4j.core.mapping.DefaultNeo4jConversionService.readValueImpl(DefaultNeo4jConversionService.java:94)
	... 125 more
Caused by: org.neo4j.driver.exceptions.value.Uncoercible: Cannot coerce FLOAT to Java String
	at org.neo4j.driver.internal.value.ValueAdapter.asString(ValueAdapter.java:91)
	at org.springframework.data.neo4j.core.convert.AdditionalTypes.asFloat(AdditionalTypes.java:313)
	at org.springframework.data.convert.DefaultConverterBuilder$ConfigurableGenericConverter.convert(DefaultConverterBuilder.java:151)
	at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:41)
	... 129 more

dependencies.txt (168.9 KB)

Can you upgrade to Spring Data Neo4j 6.0.5 and see if the error still occurs? There has been a few improvements with regards to path mapping.

Hi Florent,
Just upgraded to 6.0.5 by going to Spring Data 2.4.3, this gives the same behaviour.
Cheers,
Boyen

Can you edit your initial post to include the entities, the repositories and the test at play here? Thanks a lot!

Hello.

Neo4j the database doesn't support java.lang.float or java.lang.Float. What is called Float in Neo4j matches the Double range.
We (SDN 6) stores Java Floats as String.

See Chapter conversions here: Spring Data Neo4j
Therefor, the converter is correct.

For things that are Neo4j double inside the database (doesn't matter if returned from APOC or actual properties), map them as Double inside your domain model.
OR converter them to valid ISO Float strings.

Cheers.

1 Like

@michael_simons1 thanks for the answer, that clears it up.
I would've expected to get an error if a type is not store-able. Now it's a silent failure that shows up when you try to read the value in a full round trip, values should always be round-trippable.

Also the error is quite cryptic in that you do have a FloatValue Neo4j object: org.neo4j.driver.internal.value.FloatValue

I have a hard time explaining to my peers why a FloatValue can not be converted to a Float at least.

We'll opt for the Double.

Hi. Thanks for your feedback. Sure, your 100% right. If you have stored the value from SDN 6, than of course you can read it back.