Added support for read-only views of relationships (private Iterable<T> readOnlyField)

This commit is contained in:
David Montag
2010-08-24 13:53:37 +02:00
parent 9f5bfe3bd9
commit 3f119a28c1
4 changed files with 84 additions and 12 deletions

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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>());
}
}