Added support for read-only views of relationships (private Iterable<T> readOnlyField)
This commit is contained in:
@@ -217,6 +217,10 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<Graph.E
|
||||
return new OneToNRelationshipInfo(DynamicRelationshipType.withName(relAnnotation.type()),
|
||||
relAnnotation.direction().toNeo4jDir(), relAnnotation.elementClass(), graphEntityInstantiator);
|
||||
}
|
||||
if (isReadOnlyOneToNRelationshipField(field)) {
|
||||
return new ReadOnlyOneToNRelationshipInfo(DynamicRelationshipType.withName(relAnnotation.type()),
|
||||
relAnnotation.direction().toNeo4jDir(), relAnnotation.elementClass(), graphEntityInstantiator);
|
||||
}
|
||||
if (isOneToNRelationshipEntityField(field)) {
|
||||
Graph.Entity.RelationshipEntity relEntityAnnotation = field.getAnnotation(Graph.Entity.RelationshipEntity.class);
|
||||
return new OneToNRelationshipEntityInfo(DynamicRelationshipType.withName(relEntityAnnotation.type()),
|
||||
@@ -225,19 +229,28 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<Graph.E
|
||||
throw new IllegalArgumentException("Not a Neo4j relationship field: " + field);
|
||||
}
|
||||
|
||||
private boolean isOneToNRelationshipEntityField(Field f) {
|
||||
if (!Iterable.class.isAssignableFrom(f.getType())) return false;
|
||||
return f.isAnnotationPresent(Graph.Entity.RelationshipEntity.class);
|
||||
}
|
||||
|
||||
private static boolean isSingleRelationshipField(Field f) {
|
||||
return NodeBacked.class.isAssignableFrom(f.getType());
|
||||
}
|
||||
|
||||
private static boolean isOneToNRelationshipField(Field f) {
|
||||
if (!Collection.class.isAssignableFrom(f.getType())) return false;
|
||||
Graph.Entity.Relationship relationship = f.getAnnotation(Graph.Entity.Relationship.class);
|
||||
return relationship != null && NodeBacked.class.isAssignableFrom(relationship.elementClass()) && !relationship.elementClass().equals(NodeBacked.class);
|
||||
Graph.Entity.Relationship relAnnotation = f.getAnnotation(Graph.Entity.Relationship.class);
|
||||
return relAnnotation != null && NodeBacked.class.isAssignableFrom(relAnnotation.elementClass()) && !relAnnotation.elementClass().equals(NodeBacked.class);
|
||||
}
|
||||
|
||||
private boolean isReadOnlyOneToNRelationshipField(Field f) {
|
||||
Graph.Entity.Relationship relAnnotation = f.getAnnotation(Graph.Entity.Relationship.class);
|
||||
return Iterable.class.equals(f.getType())
|
||||
&& relAnnotation != null
|
||||
&& !NodeBacked.class.equals(relAnnotation.elementClass());
|
||||
}
|
||||
|
||||
private boolean isOneToNRelationshipEntityField(Field f) {
|
||||
Graph.Entity.RelationshipEntity relEntityAnnotation = f.getAnnotation(Graph.Entity.RelationshipEntity.class);
|
||||
return Iterable.class.isAssignableFrom(f.getType())
|
||||
&& relEntityAnnotation != null
|
||||
&& !RelationshipBacked.class.equals(relEntityAnnotation.elementClass());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,7 +307,7 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<Graph.E
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class OneToNRelationshipInfo implements RelationshipInfo {
|
||||
|
||||
private final RelationshipType type;
|
||||
@@ -362,6 +375,39 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<Graph.E
|
||||
|
||||
}
|
||||
|
||||
public static class ReadOnlyOneToNRelationshipInfo implements RelationshipInfo {
|
||||
|
||||
private final RelationshipType type;
|
||||
private final Direction direction;
|
||||
private final Class<? extends NodeBacked> relatedType;
|
||||
private final EntityInstantiator<NodeBacked, Node> graphEntityInstantiator;
|
||||
|
||||
public ReadOnlyOneToNRelationshipInfo(RelationshipType type, Direction direction, Class<? extends NodeBacked> elementClass, EntityInstantiator<NodeBacked, Node> graphEntityInstantiator) {
|
||||
this.type = type;
|
||||
this.direction = direction;
|
||||
this.relatedType = elementClass;
|
||||
this.graphEntityInstantiator = graphEntityInstantiator;
|
||||
}
|
||||
|
||||
public Object apply(final NodeBacked entity, final Object newVal) {
|
||||
throw new InvalidDataAccessApiUsageException("Cannot set read-only relationship entity field.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readObject(NodeBacked entity) {
|
||||
Node entityNode = entity.getUnderlyingNode();
|
||||
if (entityNode == null) {
|
||||
throw new IllegalStateException("Entity must have a backing Node");
|
||||
}
|
||||
Set<NodeBacked> result = new HashSet<NodeBacked>();
|
||||
for (Relationship rel : entityNode.getRelationships(type, direction)) {
|
||||
result.add(graphEntityInstantiator.createEntityFromState(rel.getOtherNode(entityNode), relatedType));
|
||||
}
|
||||
return new ManagedSet<NodeBacked>(entity, result, this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class OneToNRelationshipEntityInfo implements RelationshipInfo {
|
||||
|
||||
private final RelationshipType type;
|
||||
|
||||
@@ -4,12 +4,16 @@ import org.springframework.persistence.graph.Direction;
|
||||
import org.springframework.persistence.graph.Graph;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
@Graph.Entity
|
||||
public class Group {
|
||||
|
||||
@Graph.Entity.Relationship(type = "persons", direction = Direction.OUTGOING, elementClass = Person.class)
|
||||
private Collection<Person> persons;
|
||||
|
||||
@Graph.Entity.Relationship(type = "persons", elementClass = Person.class)
|
||||
private Iterable<Person> readOnlyPersons;
|
||||
|
||||
public void setPersons(Collection<Person> persons) {
|
||||
this.persons = persons;
|
||||
@@ -23,4 +27,12 @@ public class Group {
|
||||
return persons;
|
||||
}
|
||||
|
||||
public Iterable<Person> getReadOnlyPersons() {
|
||||
return readOnlyPersons;
|
||||
}
|
||||
|
||||
public void setReadOnlyPersons(Iterable<Person> p) {
|
||||
readOnlyPersons = p;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package org.springframework.persistence.test;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.neo4j.graphdb.DynamicRelationshipType;
|
||||
import org.neo4j.graphdb.Relationship;
|
||||
import org.springframework.persistence.graph.Direction;
|
||||
@@ -32,13 +30,11 @@ public class Person {
|
||||
// @Property(serialize=SerializationPolicy.STRING, index=true, queryable=true, removeOnReset=true)
|
||||
// Date birthday;
|
||||
|
||||
|
||||
public Person(String name, int age) {
|
||||
this.name = name;
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -342,4 +342,22 @@ public class Neo4jGraphPersistenceTest {
|
||||
Person p = new Person("Michael", 35);
|
||||
p.setFriendships(new HashSet<Friendship>());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Transactional
|
||||
public void testOneToManyReadOnly() {
|
||||
Person michael = new Person("Michael", 35);
|
||||
Person david = new Person("David", 25);
|
||||
Group group = new Group();
|
||||
Set<Person> persons = new HashSet<Person>(Arrays.asList(michael, david));
|
||||
group.setPersons(persons);
|
||||
Assert.assertEquals(persons, IteratorUtil.addToCollection(group.getReadOnlyPersons().iterator(), new HashSet<Person>()));
|
||||
}
|
||||
|
||||
@Test(expected = InvalidDataAccessApiUsageException.class)
|
||||
@Transactional
|
||||
public void testOneToManyReadOnlyShouldThrowExceptionOnSet() {
|
||||
Group group = new Group();
|
||||
group.setReadOnlyPersons(new HashSet<Person>());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user