Sir4ur0n
Sir4ur0n

Reputation: 1833

JSON to @RelationshipEntity (via Spring Boot)

I'm learning Neo4j and using it through spring-data-neo4j, but I'm struggling to make it work for my needs.

Basically I want to represent this:

A -[{...relationshipKey}]-> B

i.e. A contains a map of Bs, and each key of the map is represented by the property relationshipKey. I do this because AFAIU it's not possible for Neo4J to store a map.

So I'm using @RelationshipEntity like this:

@Data
@NodeEntity
class A {
  @Relationship(type = "CONTAINS_B")
  Set<ContainsB> containsB;
}

@RelationshipEntity(type = "CONTAINS_B")
@Data
class ContainsB {
  @GraphId Long id;
  @StartNode A a;
  @EndNode B b;
  @Property RelationshipKey relationshipKey; // an enum
}

@Data
@NodeEntity
class B {
  // Whatever
}

And I'm trying to save a new graph using a spring-boot controller to which I pass a JSON.

Controller:

@PostMapping(value = BASE_PATH + "/create")
A createA(@RequestBody @NonNull A a) {
  return ARepository.save(a);
}

JSON:

{
    "containsB": [{
        "relationshipKey": "key1",
        "b": {"someB": "properties"}
    },{
        "relationshipKey": "key2",
        "b": {"someB": "different properties"}
    }]
}

Yet when I invoke the controller, I get this exception:

org.neo4j.ogm.exception.MappingException: Relationship entity A(...) cannot have a missing start or end node

When I debug the controller invocation, a.getContainsB().iterator().next().getA() is null but a.getContainsB().iterator().next().getB() is instantiated and has the correct properties.

If I do this before the repository saving, then it seems to works fine, and A and B are correctly related:

a.getContainsB().iterator().next().setA(new A())

Is there a way to pass a JSON that will be correctly interpreted by Neo4J?

Upvotes: 0

Views: 191

Answers (1)

Vince
Vince

Reputation: 2181

Reason for the error

Your JSON is defining an instance of A with two relationships "ContainsB", which are represented by a @RelationshipEntity in the domain model. However, the definition of "ContainsB" in the JSON does not itself contain a reference to its enclosing A, so when each ContainsB is created it has no reference A.

Solutions

There are a couple of things you could try.

The obvious one is to create instances of "ContainsB" instead:

{
  "relationshipKey": "key1",
  "a": { ... },
  "b": { ... }
}

Another option is to use a JSON generator that allows you to create object references and refer to them internally in your definition. The JSOG format will allow you to do this, and is compatible with Jackson. See https://github.com/jsog/jsog for more details.

Upvotes: 1

Related Questions