diff --git a/src/main/java/org/springframework/persistence/graph/neo4j/ConstructorBypassingGraphEntityInstantiator.java b/src/main/java/org/springframework/persistence/graph/neo4j/ConstructorBypassingGraphRelationshipInstantiator.java similarity index 74% rename from src/main/java/org/springframework/persistence/graph/neo4j/ConstructorBypassingGraphEntityInstantiator.java rename to src/main/java/org/springframework/persistence/graph/neo4j/ConstructorBypassingGraphRelationshipInstantiator.java index eddaab36f..e3390ff41 100644 --- a/src/main/java/org/springframework/persistence/graph/neo4j/ConstructorBypassingGraphEntityInstantiator.java +++ b/src/main/java/org/springframework/persistence/graph/neo4j/ConstructorBypassingGraphRelationshipInstantiator.java @@ -2,12 +2,12 @@ package org.springframework.persistence.graph.neo4j; import java.lang.reflect.Constructor; -import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.Relationship; import org.springframework.persistence.support.EntityInstantiator; import sun.reflect.ReflectionFactory; -public class ConstructorBypassingGraphEntityInstantiator implements EntityInstantiator { +public class ConstructorBypassingGraphRelationshipInstantiator implements EntityInstantiator { protected static T createWithoutConstructorInvocation(Class clazz) { return createWithoutConstructorInvocation(clazz, Object.class); @@ -29,9 +29,9 @@ public class ConstructorBypassingGraphEntityInstantiator implements EntityInstan } @Override - public T createEntityFromState(Node n, Class c) { + public T createEntityFromState(Relationship r, Class c) { T t = createWithoutConstructorInvocation(c); - t.setUnderlyingNode(n); + t.setUnderlyingRelationship(r); return t; } diff --git a/src/main/java/org/springframework/persistence/graph/neo4j/Neo4jNodeBacking.aj b/src/main/java/org/springframework/persistence/graph/neo4j/Neo4jNodeBacking.aj index b0f1b525b..39558ae6f 100644 --- a/src/main/java/org/springframework/persistence/graph/neo4j/Neo4jNodeBacking.aj +++ b/src/main/java/org/springframework/persistence/graph/neo4j/Neo4jNodeBacking.aj @@ -45,13 +45,16 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields relationshipEntityInstantiator; @Autowired - public void init(GraphDatabaseService gds, EntityInstantiator gei) { + public void init(GraphDatabaseService gds, EntityInstantiator gei, EntityInstantiator rei) { this.graphDatabaseService = gds; this.graphEntityInstantiator = gei; + this.relationshipEntityInstantiator = rei; this.graphDatabaseUtil = new GraphDatabaseUtil(gds); - this.relationshipInfoFactory = new RelationshipInfoFactory(graphEntityInstantiator); + this.relationshipInfoFactory = new RelationshipInfoFactory(graphEntityInstantiator, relationshipEntityInstantiator); } @@ -192,9 +195,11 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields graphEntityInstantiator; + private final EntityInstantiator relationshipEntityInstantiator; - public RelationshipInfoFactory(EntityInstantiator graphEntityInstantiator) { + public RelationshipInfoFactory(EntityInstantiator graphEntityInstantiator, EntityInstantiator relationshipEntityInstantiator) { this.graphEntityInstantiator = graphEntityInstantiator; + this.relationshipEntityInstantiator = relationshipEntityInstantiator; } public RelationshipInfo forField(Field field) { @@ -215,7 +220,7 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields { - private final NodeBacked entity; - final Set delegate; - private final RelationshipInfo relationshipInfo; - - private ManagedSet(NodeBacked entity, Object newVal, RelationshipInfo relationshipInfo) { - this.entity = entity; - this.relationshipInfo = relationshipInfo; - delegate = (Set) newVal; - } - - @Override - public Iterator iterator() { - return delegate.iterator(); - } - - @Override - public int size() { - return delegate.size(); - } - - @Override - public boolean add(NodeBacked e) { - boolean res=delegate.add(e); - if (res) { - relationshipInfo.apply(entity, delegate); - } - return res; - } - } - private final RelationshipType type; private final Direction direction; private final Class relatedType; @@ -370,7 +344,7 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields(entity, newVal,this); // TODO managedSet that for each mutating method calls this apply (todo use AspectJ to handle that?) } @Override @@ -381,10 +355,9 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields result = new HashSet(); for (Relationship rel : entityNode.getRelationships(type, direction)) { - NodeBacked newEntity = graphEntityInstantiator.createEntityFromState(rel.getOtherNode(entityNode), relatedType); - result.add(newEntity); + result.add(graphEntityInstantiator.createEntityFromState(rel.getOtherNode(entityNode), relatedType)); } - return new ManagedSet(entity, result,this); + return new ManagedSet(entity, result, this); } } @@ -394,12 +367,13 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields elementClass; + private final EntityInstantiator relationshipEntityInstantiator; - public OneToNRelationshipEntityInfo(RelationshipType type, Direction direction, Class elementClass) { + public OneToNRelationshipEntityInfo(RelationshipType type, Direction direction, Class elementClass, EntityInstantiator relationshipEntityInstantiator) { this.type = type; this.direction = direction; this.elementClass = elementClass; - + this.relationshipEntityInstantiator = relationshipEntityInstantiator; } @Override @@ -409,9 +383,53 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields result = new HashSet(); + for (Relationship rel : entity.getUnderlyingNode().getRelationships(type, direction)) { + result.add(relationshipEntityInstantiator.createEntityFromState(rel, elementClass)); + } + return new ManagedSet(entity, result, this); } } + private static final class ManagedSet extends AbstractSet { + private final NodeBacked entity; + final Set delegate; + private final RelationshipInfo relationshipInfo; + + private ManagedSet(NodeBacked entity, Object newVal, RelationshipInfo relationshipInfo) { + this.entity = entity; + this.relationshipInfo = relationshipInfo; + delegate = (Set) newVal; + } + + @Override + public Iterator iterator() { + return delegate.iterator(); + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean add(T e) { + boolean res = delegate.add(e); + if (res) { + relationshipInfo.apply(entity, delegate); + } + return res; + } + + @Override + public boolean remove(Object o) { + boolean res = delegate.remove(o); + if (res) { + relationshipInfo.apply(entity, delegate); + } + return res; + } + + } + } diff --git a/src/test/java/org/springframework/persistence/test/graph/Neo4jGraphPersistenceTest.java b/src/test/java/org/springframework/persistence/test/graph/Neo4jGraphPersistenceTest.java index bd291b9a9..914fd0d94 100644 --- a/src/test/java/org/springframework/persistence/test/graph/Neo4jGraphPersistenceTest.java +++ b/src/test/java/org/springframework/persistence/test/graph/Neo4jGraphPersistenceTest.java @@ -5,7 +5,6 @@ import junit.framework.Assert; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.neo4j.graphdb.Direction; @@ -32,6 +31,7 @@ import org.springframework.transaction.annotation.Transactional; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -236,6 +236,17 @@ public class Neo4jGraphPersistenceTest { Assert.assertTrue(Set.class.isAssignableFrom(personsFromGet.getClass())); } + @Test + @Transactional + public void testRemoveFromOneToManyRelationship() { + Person michael = new Person("Michael", 35); + Person david = new Person("David", 25); + Group group = new Group(); + group.setPersons(new HashSet(Arrays.asList(michael, david))); + group.getPersons().remove(david); + Assert.assertEquals(Collections.singleton(michael), group.getPersons()); + } + @Test @Transactional public void testFinderFindAll() { @@ -315,7 +326,6 @@ public class Neo4jGraphPersistenceTest { } @Test - @Ignore @Transactional public void testRelationshipGetEntities() { Person p = new Person("Michael", 35); diff --git a/src/test/resources/org/springframework/persistence/test/graph/Neo4jGraphPersistenceTest-context.xml b/src/test/resources/org/springframework/persistence/test/graph/Neo4jGraphPersistenceTest-context.xml index 59cbfd34d..559adff73 100644 --- a/src/test/resources/org/springframework/persistence/test/graph/Neo4jGraphPersistenceTest-context.xml +++ b/src/test/resources/org/springframework/persistence/test/graph/Neo4jGraphPersistenceTest-context.xml @@ -89,6 +89,8 @@ + +