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

Generic abstract RelationshipEntity not working #66

Closed
nicoruti opened this issue Oct 8, 2015 · 5 comments
Closed

Generic abstract RelationshipEntity not working #66

nicoruti opened this issue Oct 8, 2015 · 5 comments
Labels

Comments

@nicoruti
Copy link

nicoruti commented Oct 8, 2015

I started looking at Neo4j today and am now running some tests with OGM. The library is really awesome, thanks for your work! However, when playing around with model abstractions, I encountered the following setup which throws an exception:

@NodeEntity
public class A {
   @GraphId
   private Long id;
   @Relationship(type = "R", direction = Relationship.OUTGOING)
   public R r;
}

@NodeEntity
public class B {
   @GraphId
   private Long id;
   @Relationship(type = "R", direction = Relationship.INCOMING)
   public R r;
}

// Generic base class for relationships
public class BaseR<S, T> {
   @GraphId
   private Long id;
   @StartNode
   private S fromNode;
   @EndNode
   private T toNode;

   protected BaseR(S fromNode, T toNode) {
      this.fromNode = fromNode;
      this.toNode = toNode;
   }
}

@RelationshipEntity
public class R extends BaseR<A, B> {
   public R(A fromNode, B toNode) {
      super(fromNode, toNode);
   }
}

The code I test with is

   @Test
   public void testUsingAbstractRelationShip() {      
      A a = new A();
      session.save(a);

      B b = new B();
      session.save(b);

      R r = new R(a, b);
      a.r = r;
      b.r = r;

      session.save(a); // --> throws exception below
   }

And here comes the exception:

java.lang.RuntimeException: @StartNode of a relationship entity may not be null
    at org.neo4j.ogm.mapper.EntityGraphMapper.getStartEntity(EntityGraphMapper.java:510)
    at org.neo4j.ogm.mapper.EntityGraphMapper.haveRelationEndsChanged(EntityGraphMapper.java:390)
    at org.neo4j.ogm.mapper.EntityGraphMapper.getRelationshipBuilder(EntityGraphMapper.java:363)
    at org.neo4j.ogm.mapper.EntityGraphMapper.link(EntityGraphMapper.java:326)
    at org.neo4j.ogm.mapper.EntityGraphMapper.mapEntityReferences(EntityGraphMapper.java:277)
    at org.neo4j.ogm.mapper.EntityGraphMapper.mapEntity(EntityGraphMapper.java:158)
    at org.neo4j.ogm.mapper.EntityGraphMapper.map(EntityGraphMapper.java:91)
    at org.neo4j.ogm.session.delegates.SaveDelegate.save(SaveDelegate.java:67)
    at org.neo4j.ogm.session.delegates.SaveDelegate.save(SaveDelegate.java:43)
    at org.neo4j.ogm.session.Neo4jSession.save(Neo4jSession.java:386)
    at .a.b.c.GenericTypesTest.testUsingAbstractRelationShip(GenericTypesTest.java:40)

It's interesting, as the base class without the generic types S and T does work as expected (although this breaks the reusability of the base relationship entity):

public class BaseR {
   @GraphId
   private Long id;
   @StartNode
   private A fromNode;
   @EndNode
   private B toNode;

   protected BaseR(A fromNode, B toNode) {
      this.fromNode = fromNode;
      this.toNode = toNode;
   }
}

@RelationshipEntity
public class R extends BaseR {
   public R(A fromNode, B toNode) {
      super(fromNode, toNode);
   }
}
@nicoruti
Copy link
Author

nicoruti commented Oct 8, 2015

As soon as published, the following workaround came to my mind: Use another base class (or interface) for the NodeEntities and code against them. This removes the need for generics. Here's a working example:

// Base Entity class
public class BaseE {
   @GraphId
   private Long id;
}

@NodeEntity
public class A extends BaseE {
   @Relationship(type = "R", direction = Relationship.OUTGOING)
   public R r;
}

@NodeEntity
public class B extends BaseE {
   @Relationship(type = "R", direction = Relationship.INCOMING)
   public R r;
}

public abstract class BaseR {
   @GraphId
   private Long id;
   @StartNode
   private BaseE fromNode;
   @EndNode
   private BaseE toNode;

   protected BaseR(BaseE fromNode, BaseE toNode) {
      this.fromNode = fromNode;
      this.toNode = toNode;
   }
}

@RelationshipEntity
public class R extends BaseR {
   public R(A fromNode, B toNode) {
      super(fromNode, toNode);
   }
}

@luanne luanne added the bug label Oct 15, 2015
@vince-bickers
Copy link

Fixed in 2.0.0-SNAPSHOT

@ghost
Copy link

ghost commented Jul 10, 2016

I'm using version 2.0.3, and I'm still getting this exception on generic relations.

Classes example

public class RelationEntity<O,T> {
    @GraphId
    public Long id;

    @StartNode
    public O orign;

    @EndNode
    public T target;

    @DateLong
    public Date createdAt;

}
@RelationshipEntity(type = "OWNS")
public class Owns<T> extends RelationEntity<User,T> {
    public Boolean isProfile;
}

java.lang.RuntimeException: @startnode of a relationship entity may not be null
at org.neo4j.ogm.context.EntityGraphMapper.getStartEntity(EntityGraphMapper.java:611)
at org.neo4j.ogm.context.EntityGraphMapper.haveRelationEndsChanged(EntityGraphMapper.java:476)
at org.neo4j.ogm.context.EntityGraphMapper.getRelationshipBuilder(EntityGraphMapper.java:444)
at org.neo4j.ogm.context.EntityGraphMapper.link(EntityGraphMapper.java:406)
at org.neo4j.ogm.context.EntityGraphMapper.mapEntityReferences(EntityGraphMapper.java:337)
at org.neo4j.ogm.context.EntityGraphMapper.mapEntity(EntityGraphMapper.java:207)
at org.neo4j.ogm.context.EntityGraphMapper.map(EntityGraphMapper.java:133)
at org.neo4j.ogm.session.delegates.SaveDelegate.save(SaveDelegate.java:69)
at org.neo4j.ogm.session.Neo4jSession.save(Neo4jSession.java:369)

@mangrish
Copy link
Contributor

mangrish commented Dec 8, 2016

This is still broken. Reopening.

@mangrish mangrish reopened this Dec 8, 2016
mangrish added a commit that referenced this issue Dec 8, 2016
…Generic superclasses in relationship entities.

- Refers to: #54, #66, #186
@frant-hartm
Copy link
Contributor

frant-hartm commented Jul 28, 2017

Fixed in master (for 3.0.0 release).

It still won't work for

class Owns<T> extends RelationEntity<User,T> 

use cases, but should work for

class Owns extends RelationEntity<User, User>

We use the types in query generation so this can't be (at the moment) completely generic.

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

No branches or pull requests

5 participants