Is it possible to add @NodeEntity
(or even @RelationshipEntity
) annotation from SpringData Neo4j
on an interface or abstact class or their fields? If not, how do you manage these situations?
Asked
Active
Viewed 1,658 times
2

tigerjack
- 1,158
- 3
- 21
- 39
2 Answers
4
Definitely you can do that on Abstract classes
, and I think it's a good practice in some common cases. Let me give you an example that I'm using in my graph model:
@NodeEntity
public abstract class BasicNodeEntity implements Serializable {
@GraphId
private Long nodeId;
public Long getNodeId() {
return nodeId;
}
@Override
public abstract boolean equals(Object o);
@Override
public abstract int hashCode();
}
public abstract class IdentifiableEntity extends BasicNodeEntity {
@Indexed(unique = true)
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof IdentifiableEntity)) return false;
IdentifiableEntity entity = (IdentifiableEntity) o;
if (id != null ? !id.equals(entity.id) : entity.id != null) return false;
return true;
}
@Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
}
}
Example of entity idenifiable.
public class User extends IdentifiableEntity {
private String firstName;
// ...
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
OTOH, as far as I know, if you annotate an interface with @NodeEntity
, those classes who implement the interface DON'T inherite the annotation. To be sure I've made a test to check it and definately spring-data-neo4j
throws an Exception because don't recognize the inherited class neither an NodeEntity
nor a RelationshipEntity
.
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'neo4jMappingContext' defined in class org.springframework.data.neo4j.config.Neo4jConfiguration: Invocation of init method failed; nested exception is org.springframework.data.neo4j.mapping.InvalidEntityTypeException: Type class com.xxx.yyy.rest.user.domain.User is neither a @NodeEntity nor a @RelationshipEntity
Hope it helps

troig
- 7,072
- 4
- 37
- 63
-
Thanks for your help, again :) Indeed, I started to use a lot this kind annotations on a class. As a side note: I've seen the usage of a `String id` on a lot of project: why is this? Is it related to `hash()` or even `equals()`? – tigerjack May 12 '15 at 08:44
-
1Your welcome! The string Id is the unique identifier of each entity. You cannot use @GraphId as identifiers because they don't persist ([see this post](http://stackoverflow.com/questions/9051442/node-identifiers-in-neo4j)). In my case, I use UUID as Id's `UUID.randomUUID().toString()`, and I generate them before save each entity in a BeforeSaveEvent . There is an [example](http://stackoverflow.com/questions/30106772/sdn-beforesaveeventt-capture-events-before-save-entities-t) in my SO question. Hope it helps – troig May 12 '15 at 08:55
-
Coming back to the original question, is it also good to use the @NodeEntity annotation on interfaces? I mean, what if I have a `@NodeEntity interface ComparableObject` and other entities that implement this interface? What if these entities are also annotated as `@NodeEntity`? – tigerjack May 12 '15 at 10:26
-
See my edit @tigerjack89! It seems to be that you cannot use it on interfaces. – troig May 15 '15 at 10:51
-
Thanks again for your help. Well, I'm not too sure about it because I'm having a lot of problems with Spring Data Neo4j lately (and I can't update it to the latest version fwiw), but maybe a working solution could be to annotate with @NodeEntity the class that implements the interface? – tigerjack May 15 '15 at 12:48
-
yes, definately you can annotate each class (although this implements an interface), but you cannot avoid having to annotate each one. To have an abstract class with the annotation and the @GraphId property, like the example of my answer, is a good solution for me. Hope it helps, good luck! – troig May 15 '15 at 13:00
-
Yep, but I can't extend more than one abstract class :) – tigerjack May 15 '15 at 13:18
-
1To add another interesting point, while annotations on interfaces are not inherited (and I think it is the right way to proceed tbh), you can easily annotate an interface as an entity and use it in whatever part of your code, provided that the actual class is also the same type of entity. However, you MUST annotate both interfaces and classes implementing them as @NodeEntity or @RelationshipEntity, otherwise the spring framework will come with an exception saying `MyClass [or MyInterface] is neither a @NodeEntity nor a @RelationshipEntity`. – tigerjack May 18 '15 at 14:19
0
@NodeEntity or @RelationshipEntity needs to be defined on POJO or concrete classes. Think it same as @Entity in Hibernate. But do you see any valid use case for annotating Interfaces or Abstract Classes?

Sumit
- 1,400
- 7
- 9
-
There are many use cases that come in minds at this moment. For example, `@NodeEntity abstract class User`; in this way, you know that each class extending this class, such as `UserPerson` or `UserOrganization`, is always a Node in the graph. Also, it is useful if you have common annotated fields, such as the simple `@GraphId Long id` or the more complex case `@RelatedTo(...) private Set
messages`. What is the standard way to manage these cases? – tigerjack Apr 25 '15 at 07:38 -
1I haven't tried yet but as per documentation @NodeEntity is inherited in case it is defined on Interface or Abstract classes. - http://docs.spring.io/spring-data/neo4j/docs/current/reference/html/#reference_programming-model_annotations – Sumit Apr 25 '15 at 23:11
-
Thanks for the reference, looks great. You can update your answer to reflect your new discoveries. I'll wait some days to see if there are better clarifications and/or examples from other users, but otherwise it surely will be the accepted answer. – tigerjack Apr 26 '15 at 07:03