Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Constraint causes exception with custom key converter #787

Closed
sdaschner opened this issue Apr 8, 2020 · 1 comment · Fixed by #788
Closed

Constraint causes exception with custom key converter #787

sdaschner opened this issue Apr 8, 2020 · 1 comment · Fixed by #788
Assignees
Labels

Comments

@sdaschner
Copy link

When using a custom key type with a custom serializer, loading and saving nodes via OGM works as expected, until a constraint is added.

Current Behavior

The following setup:

@NodeEntity
public class MyNode {

    @Id
    @Convert(MyKeyTypeStringConverter.class)
    public MyKeyType key;

    private MyNode() {}

    public MyNode(String key) {
        this.key = new MyKeyType(key);
    }

    // equals, hashCode, toString
}
public class MyKeyType implements Serializable {

    private final String key;

    public MyKeyType(String key) {
        this.key = key;
    }

    // getter, equals, hashCode, toString
}
public class MyKeyTypeStringConverter implements AttributeConverter<MyKeyType, String> {

    // maps string to `key.getKey()` and from `new MyKeyType(key)` ...

}

The following works as expected:

// some test
MyNode node = session.load(MyNode.class, new MyKeyType("1234"));
System.out.println("node = " + node);

node = new MyNode("2345");
session.save(node);
System.out.println("saved = " + node);

Now, if we add a key constraint (enterprise edition, haven't tested other constraints):

CREATE CONSTRAINT ON (n:MyNode) ASSERT (n.key) IS NODE KEY;

Then loading fails with the following exception:

org.neo4j.ogm.exception.CypherException: Cypher execution failed with code 'Neo.ClientError.Statement.TypeError': Property values can only be of primitive types or arrays thereof.

	at org.neo4j.ogm.drivers.bolt.response.BoltResponse.next(BoltResponse.java:51)
	at org.neo4j.ogm.response.Response.toList(Response.java:43)
	at org.neo4j.ogm.context.GraphRowModelMapper.map(GraphRowModelMapper.java:50)
	at org.neo4j.ogm.session.delegates.LoadOneDelegate.lambda$load$0(LoadOneDelegate.java:89)
	at org.neo4j.ogm.session.Neo4jSession.doInTransaction(Neo4jSession.java:590)
	at org.neo4j.ogm.session.Neo4jSession.doInTransaction(Neo4jSession.java:564)
	at org.neo4j.ogm.session.delegates.LoadOneDelegate.load(LoadOneDelegate.java:86)
	at org.neo4j.ogm.session.delegates.LoadOneDelegate.load(LoadOneDelegate.java:53)
	at org.neo4j.ogm.session.Neo4jSession.load(Neo4jSession.java:184)
	at com.sebastian_daschner.graph.GraphDBIT.testGetTestNode(GraphDBIT.java:44)
	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.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Caused by: org.neo4j.driver.exceptions.ClientException: Property values can only be of primitive types or arrays thereof
	at org.neo4j.driver.internal.util.Futures.blockingGet(Futures.java:143)
	at org.neo4j.driver.internal.InternalResult.blockingGet(InternalResult.java:128)
	at org.neo4j.driver.internal.InternalResult.hasNext(InternalResult.java:64)
	at org.neo4j.ogm.drivers.bolt.response.GraphModelResponse.fetchNext(GraphModelResponse.java:42)
	at org.neo4j.ogm.drivers.bolt.response.GraphModelResponse.fetchNext(GraphModelResponse.java:29)
	at org.neo4j.ogm.drivers.bolt.response.BoltResponse.next(BoltResponse.java:48)
	... 35 more
	Suppressed: org.neo4j.driver.internal.util.ErrorUtil$InternalExceptionCause
		at org.neo4j.driver.internal.util.ErrorUtil.newNeo4jError(ErrorUtil.java:79)
		at org.neo4j.driver.internal.async.inbound.InboundMessageDispatcher.handleFailureMessage(InboundMessageDispatcher.java:105)
		at org.neo4j.driver.internal.messaging.v1.MessageReaderV1.unpackFailureMessage(MessageReaderV1.java:83)
		at org.neo4j.driver.internal.messaging.v1.MessageReaderV1.read(MessageReaderV1.java:59)
		at org.neo4j.driver.internal.async.inbound.InboundMessageHandler.channelRead0(InboundMessageHandler.java:83)
		at org.neo4j.driver.internal.async.inbound.InboundMessageHandler.channelRead0(InboundMessageHandler.java:35)
		at org.neo4j.driver.internal.shaded.io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99)
		at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
		at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
		at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355)
		at org.neo4j.driver.internal.shaded.io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:321)
		at org.neo4j.driver.internal.shaded.io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:295)
		at org.neo4j.driver.internal.async.inbound.MessageDecoder.channelRead(MessageDecoder.java:47)
		at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
		at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
		at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355)
		at org.neo4j.driver.internal.shaded.io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:321)
		at org.neo4j.driver.internal.shaded.io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:295)
		at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
		at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
		at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355)
		at org.neo4j.driver.internal.shaded.io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
		at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
		at org.neo4j.driver.internal.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
		at org.neo4j.driver.internal.shaded.io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
		at org.neo4j.driver.internal.shaded.io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
		at org.neo4j.driver.internal.shaded.io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714)
		at org.neo4j.driver.internal.shaded.io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650)
		at org.neo4j.driver.internal.shaded.io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576)
		at org.neo4j.driver.internal.shaded.io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
		at org.neo4j.driver.internal.shaded.io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
		at org.neo4j.driver.internal.shaded.io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
		at org.neo4j.driver.internal.shaded.io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
		at java.base/java.lang.Thread.run(Thread.java:844)

Context

Note that it does works as expected when using a custom key type for which Neo provides a converter, e.g. UuidStringConverter. So the issue seems to be with custom converters.

Your Environment

  • OGM Version used: 3.2.10
  • Java Version used: 9.0.4
  • Neo4J Version used: 3.5.17
  • Bolt Driver Version used (if applicable): 3.2.10
@meistermeier
Copy link
Collaborator

meistermeier commented Apr 9, 2020

Thanks for reporting this.
The underlying problem is that the converter does not get called for the conversion of the MyKeyType when the load is executed. In general it is possible to use a map-like construct like {key: '1234'} as a parameter but with the constraint applied it has to be a scalar Cypher type.

Without the constraint you should not be able to find anything with the load method above if you save and load in different Neo4j-OGM sessions or do a session.clear()between them, right?

It works for UUID because the internal mapping of OGM calls the jackson object mapper and it gets converted to a String behind the scenes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants
@meistermeier @sdaschner and others