diff --git a/spring-data-neo4j-rest/src/test/resources/log4j.properties b/spring-data-neo4j-rest/src/test/resources/log4j.properties index e69fbde1b..9b295b169 100644 --- a/spring-data-neo4j-rest/src/test/resources/log4j.properties +++ b/spring-data-neo4j-rest/src/test/resources/log4j.properties @@ -18,7 +18,7 @@ log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n log4j.category.org.springframework=WARN -#log4j.category.org.springframework.data.graph.neo4j.support.SubReferenceNodeTypeStrategy=DEBUG +#log4j.category.org.springframework.data.graph.neo4j.support.SubReferenceTypeRepresentationStrategy=DEBUG #log4j.category.org.springframework.data.graph.neo4j.fieldaccess=DEBUG #log4j.category.org.springframework.data=TRACE #log4j.category.org.springframework.data.support=TRACE diff --git a/spring-data-neo4j-roo/src/test/resources/org/springframework/data/graph/neo4j/jpa/Neo4jEntityManagerTest-context.xml b/spring-data-neo4j-roo/src/test/resources/org/springframework/data/graph/neo4j/jpa/Neo4jEntityManagerTest-context.xml index dddb3438c..f37b31c94 100644 --- a/spring-data-neo4j-roo/src/test/resources/org/springframework/data/graph/neo4j/jpa/Neo4jEntityManagerTest-context.xml +++ b/spring-data-neo4j-roo/src/test/resources/org/springframework/data/graph/neo4j/jpa/Neo4jEntityManagerTest-context.xml @@ -97,10 +97,10 @@ - + - + diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/GraphBacked.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/GraphBacked.java index 3f01693b6..3133bd07e 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/GraphBacked.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/GraphBacked.java @@ -27,6 +27,7 @@ package org.springframework.data.graph.core; public interface GraphBacked { /** * internal setter used for initializing the graph-db state on existing or newly created entities + * * @param state (Node or Relationship) */ void setPersistentState(STATE state); @@ -35,4 +36,13 @@ public interface GraphBacked { * @return the underlying graph-db state or null if the current entity is not related to the graph-store (possible with unsaved or partial entities) */ STATE getPersistentState(); + + boolean hasPersistentState(); + + /** + * removes the entity using @{link GraphDatabaseContext.removeNodeEntity} + * the entity and relationship are still accessible after removal but before transaction commit + * but all modifications will throw an exception + */ + void remove(); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/NodeBacked.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/NodeBacked.java index e80c9dba2..1d76a6ad4 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/NodeBacked.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/NodeBacked.java @@ -17,14 +17,126 @@ package org.springframework.data.graph.core; import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.Relationship; +import org.neo4j.graphdb.traversal.TraversalDescription; +import org.springframework.data.graph.neo4j.fieldaccess.EntityState; /** * Interface introduced to objects annotated with @NodeEntity by the {@link org.springframework.data.graph.neo4j.support.node.Neo4jNodeBacking} aspect. * annotation, to hold underlying Neo4j Node state. + * * @author Rod Johnson */ public interface NodeBacked extends GraphBacked { - // Relationship relateTo(NodeBacked nb, RelationshipType type); + /** + * Attach the entity inside a running transaction. Creating or changing an entity outside of a transaction + * detaches it. It must be subsequently attached in order to be persisted. + * + * @return the attached entity + */ + T persist(); + + /** + *

+ * Creates a relationship to the target node, returning a relationship entity representing the created + * relationship. + *

+ *

+ *

+ * Example: + *

+     * public class Person {
+     *     ...
+     *     public Friendship knows(Person p) {
+     *         return (Friendship) relateTo(p, Friendship.class, "knows");
+     *     }
+     *     ...
+     * }
+     * 
+ *

+ * + * @param target other entity + * @param relationshipClass relationship entity class + * @param relationshipType type of relationship to be created + * @return relationship entity of specified relationshipClass + */ + R relateTo(N target, Class relationshipClass, String relationshipType); + + + /** + * Reify this entity as another node backed type. The same underlying node will be used for the new entity. + * + * @param targetType type to project to + * @return new instance of specified type, sharing the same underlying node with this entity + */ + T projectTo(Class targetType); + + + /** + * Get the ID of the entity. + * + * @return underlying node ID, or null if there is no underlying node + */ + Long getNodeId(); + + + /** + * Perform a traversal from this entity's underlying node with the given traversal description. The found nodes + * are used as underlying nodes for new entities of the specified type. + * provided target type + * + * @param targetType node entity type for new entities + * @param traversalDescription traversal description used + * @return Lazy {@link java.lang.Iterable} over the traversal results, converted to the expected node + * entity instances + */ + Iterable findAllByTraversal(final Class targetType, TraversalDescription traversalDescription); + + + /** + * Removes the all relationships of the given type between this entity's underlying node and the target + * entity's underlying node. Note that this is handled automatically by + * {@link org.springframework.data.graph.annotation.RelatedTo} fields, + * single-relationship non-annotated fields, and + * {@link org.springframework.data.graph.annotation.RelatedToVia} fields. + * + * @param target other node entity + * @param relationshipType type to be removed + */ + void removeRelationshipTo(NodeBacked target, String relationshipType); + + /** + * Finds the relationship of the specified type, from this entity's underlying node to the target entity's + * underlying node. If a relationship is found, it is used as state for a relationship entity that is returned. + * + * @param target end node of relationship + * @param relationshipClass class of the relationship entity + * @param type type of the sought relationship + * @return Instance of the requested relationshipClass if the relationship was found, null otherwise + */ + R getRelationshipTo(NodeBacked target, Class relationshipClass, String type); + + + + + + Relationship getRelationshipTo(NodeBacked target, String type); + + /** + * Creates a relationship to the target node entity with the given relationship type. + * + * @param target entity + * @param type neo4j relationship type for the underlying relationship + * @return the newly created relationship to the target node + */ + Relationship relateTo(NodeBacked target, String type); + + // get internal state object + EntityState getEntityState(); + + + // will possibly be used for object graphs + boolean refersTo(GraphBacked target); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/RelationshipBacked.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/RelationshipBacked.java index e9fb753e5..4ef36158f 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/RelationshipBacked.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/RelationshipBacked.java @@ -23,5 +23,19 @@ import org.neo4j.graphdb.Relationship; * aspect, encapsulates a neo4j relationship as backing state */ public interface RelationshipBacked extends GraphBacked{ - + + /** + * @return relationship id if there is an underlying relationship + */ + Long getRelationshipId(); + + + /** + * Reify this relationship entity as another relationship backed type. The same underlying relationship will be + * used for the new entity. + * + * @param targetType type to project to + * @return new instance of specified type, sharing the same underlying relationship with this entity + */ + R projectTo(Class targetType); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/NodeTypeStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/TypeRepresentationStrategy.java similarity index 96% rename from spring-data-neo4j/src/main/java/org/springframework/data/graph/core/NodeTypeStrategy.java rename to spring-data-neo4j/src/main/java/org/springframework/data/graph/core/TypeRepresentationStrategy.java index 1b8485f6a..af3be4df0 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/NodeTypeStrategy.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/TypeRepresentationStrategy.java @@ -17,7 +17,6 @@ package org.springframework.data.graph.core; import org.neo4j.graphdb.Node; -import org.springframework.data.graph.core.NodeBacked; /** * Strategy to handle representation of java types in the graph. Possible implementation are type/class nodes @@ -30,7 +29,7 @@ import org.springframework.data.graph.core.NodeBacked; * @author Michael Hunger * @since 13.09.2010 */ -public interface NodeTypeStrategy { +public interface TypeRepresentationStrategy { /** * callback on entity creation for setting up type representation * @param entity diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java index 7cccb26b0..bba485461 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java @@ -95,7 +95,7 @@ public class Neo4jConfiguration { gdc.setGraphEntityInstantiator(graphEntityInstantiator); gdc.setConversionService(conversionService()); NodeTypeStrategyFactoryBean nodeTypeStrategyFactoryBean = new NodeTypeStrategyFactoryBean(graphDatabaseService, graphEntityInstantiator); - gdc.setNodeTypeStrategy(nodeTypeStrategyFactoryBean.getObject()); + gdc.setTypeRepresentationStrategy(nodeTypeStrategyFactoryBean.getObject()); if (validator!=null) { gdc.setValidator(validator); } @@ -144,6 +144,7 @@ public class Neo4jConfiguration { NodeEntityStateFactory entityStateFactory = new NodeEntityStateFactory(); entityStateFactory.setGraphDatabaseContext(graphDatabaseContext); entityStateFactory.setFinderFactory(finderFactory); + entityStateFactory.setEntityManagerFactory(entityManagerFactory); entityStateFactory.setNodeDelegatingFieldAccessorFactory( new NodeDelegatingFieldAccessorFactory(graphDatabaseContext, finderFactory)); aspect.setNodeEntityStateFactory(entityStateFactory); diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/NodeEntityStateFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/NodeEntityStateFactory.java index f36fdfe77..b9d574693 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/NodeEntityStateFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/NodeEntityStateFactory.java @@ -22,9 +22,8 @@ import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.neo4j.finder.FinderFactory; import org.springframework.data.graph.neo4j.support.GraphDatabaseContext; -import java.lang.reflect.Field; - -import static org.springframework.data.graph.neo4j.fieldaccess.PartialNodeEntityState.getId; +import javax.persistence.EntityManagerFactory; +import javax.persistence.PersistenceUnitUtil; public class NodeEntityStateFactory { @@ -32,16 +31,18 @@ public class NodeEntityStateFactory { private FinderFactory finderFactory; + private EntityManagerFactory entityManagerFactory; + private NodeDelegatingFieldAccessorFactory nodeDelegatingFieldAccessorFactory; public EntityState getEntityState(final NodeBacked entity) { final NodeEntity graphEntityAnnotation = entity.getClass().getAnnotation(NodeEntity.class); // todo cache ?? if (graphEntityAnnotation.partial()) { - PartialNodeEntityState partialNodeEntityState = new PartialNodeEntityState(null, entity, entity.getClass(), graphDatabaseContext, finderFactory); + final PartialNodeEntityState partialNodeEntityState = new PartialNodeEntityState(null, entity, entity.getClass(), graphDatabaseContext, finderFactory, getPersistenceUnitUtils()); return new DetachedEntityState(partialNodeEntityState, graphDatabaseContext) { @Override protected boolean isDetached() { - return super.isDetached() || getId(entity, entity.getClass()) == null; + return super.isDetached() || partialNodeEntityState.getId(entity) == null; } }; } else { @@ -51,7 +52,12 @@ public class NodeEntityStateFactory { } } - public void setNodeDelegatingFieldAccessorFactory( + private PersistenceUnitUtil getPersistenceUnitUtils() { + if (entityManagerFactory == null) return null; + return entityManagerFactory.getPersistenceUnitUtil(); + } + + public void setNodeDelegatingFieldAccessorFactory( NodeDelegatingFieldAccessorFactory nodeDelegatingFieldAccessorFactory) { this.nodeDelegatingFieldAccessorFactory = nodeDelegatingFieldAccessorFactory; } @@ -64,4 +70,7 @@ public class NodeEntityStateFactory { this.finderFactory = finderFactory; } + public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) { + this.entityManagerFactory = entityManagerFactory; + } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/PartialNodeEntityState.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/PartialNodeEntityState.java index 2e566b262..3a7c30d6a 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/PartialNodeEntityState.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/PartialNodeEntityState.java @@ -28,7 +28,7 @@ import org.springframework.data.graph.neo4j.finder.FinderFactory; import org.springframework.data.graph.neo4j.support.GraphDatabaseContext; import org.springframework.data.persistence.StateProvider; -import javax.persistence.Id; +import javax.persistence.PersistenceUnitUtil; import java.lang.reflect.Field; import java.util.Arrays; import java.util.Collection; @@ -43,8 +43,9 @@ public class PartialNodeEntityState extends DefaultEn public static final String FOREIGN_ID_INDEX = "foreign_id"; private final GraphDatabaseContext graphDatabaseContext; + private PersistenceUnitUtil persistenceUnitUtil; - public PartialNodeEntityState(final Node underlyingState, final ENTITY entity, final Class type, final GraphDatabaseContext graphDatabaseContext, final FinderFactory finderFactory) { + public PartialNodeEntityState(final Node underlyingState, final ENTITY entity, final Class type, final GraphDatabaseContext graphDatabaseContext, final FinderFactory finderFactory, PersistenceUnitUtil persistenceUnitUtil) { super(underlyingState, entity, type, new DelegatingFieldAccessorFactory(graphDatabaseContext, finderFactory) { @Override @@ -101,6 +102,7 @@ public class PartialNodeEntityState extends DefaultEn } }); this.graphDatabaseContext = graphDatabaseContext; + this.persistenceUnitUtil = persistenceUnitUtil; } // TODO handle non persisted Entity like running outside of an transaction @@ -108,7 +110,7 @@ public class PartialNodeEntityState extends DefaultEn public void createAndAssignState() { if (entity.getPersistentState() != null) return; try { - final Object id = getId(entity,type); + final Object id = getId(entity); if (id == null) return; final String foreignId = createForeignId(id); IndexHits indexHits = getForeignIdIndex().get(FOREIGN_ID, foreignId); @@ -162,21 +164,7 @@ public class PartialNodeEntityState extends DefaultEn return type.getName() + ":" + id; } - public static Object getId(final Object entity, Class type) { - Class clazz = type; - while (clazz != null) { - for (Field field : clazz.getDeclaredFields()) { - if (field.isAnnotationPresent(Id.class)) { - try { - field.setAccessible(true); - return field.get(entity); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - } - clazz = clazz.getSuperclass(); - } - return null; + public Object getId(final Object entity) { + return persistenceUnitUtil!=null ? persistenceUnitUtil.getIdentifier(entity) : null; } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/finder/AbstractFinder.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/finder/AbstractFinder.java index c8d44c896..e7377dad3 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/finder/AbstractFinder.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/finder/AbstractFinder.java @@ -12,7 +12,7 @@ import org.springframework.data.graph.neo4j.support.GraphDatabaseContext; import java.util.Collections; /** - * Repository like finder for Node and Relationship-Entities. Provides finder methods for direct access, access via {@link org.springframework.data.graph.core.NodeTypeStrategy} + * Repository like finder for Node and Relationship-Entities. Provides finder methods for direct access, access via {@link org.springframework.data.graph.core.TypeRepresentationStrategy} * and indexing. * * @param GraphBacked target of this finder, enables the finder methods to return this concrete type diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/GraphDatabaseContext.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/GraphDatabaseContext.java index ac24b6925..751f80e09 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/GraphDatabaseContext.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/GraphDatabaseContext.java @@ -27,7 +27,7 @@ import org.springframework.core.convert.ConversionService; import org.springframework.data.annotation.Indexed; import org.springframework.data.graph.core.GraphBacked; import org.springframework.data.graph.core.NodeBacked; -import org.springframework.data.graph.core.NodeTypeStrategy; +import org.springframework.data.graph.core.TypeRepresentationStrategy; import org.springframework.data.graph.core.RelationshipBacked; import org.springframework.data.persistence.EntityInstantiator; @@ -39,7 +39,7 @@ import java.util.Map; /** * Mediator class for the graph related services like the {@link GraphDatabaseService}, the used - * {@link NodeTypeStrategy}, entity instantiators for nodes and relationships as well as a spring conversion service. + * {@link org.springframework.data.graph.core.TypeRepresentationStrategy}, entity instantiators for nodes and relationships as well as a spring conversion service. * * It delegates the appropriate methods to those services. The services are not intended to be accessible from outside. * @@ -59,7 +59,7 @@ public class GraphDatabaseContext { private ConversionService conversionService; - private NodeTypeStrategy nodeTypeStrategy; + private TypeRepresentationStrategy typeRepresentationStrategy; private Validator validator; @@ -99,12 +99,12 @@ public class GraphDatabaseContext { this.conversionService = conversionService; } - public NodeTypeStrategy getNodeTypeStrategy() { - return nodeTypeStrategy; + public TypeRepresentationStrategy getTypeRepresentationStrategy() { + return typeRepresentationStrategy; } - public void setNodeTypeStrategy(NodeTypeStrategy nodeTypeStrategy) { - this.nodeTypeStrategy = nodeTypeStrategy; + public void setTypeRepresentationStrategy(TypeRepresentationStrategy typeRepresentationStrategy) { + this.typeRepresentationStrategy = typeRepresentationStrategy; } public Node createNode() { @@ -139,7 +139,7 @@ public class GraphDatabaseContext { public void removeNodeEntity(NodeBacked entity) { Node node = entity.getPersistentState(); if (node==null) return; - this.nodeTypeStrategy.preEntityRemoval(entity); + this.typeRepresentationStrategy.preEntityRemoval(entity); for (Relationship relationship : node.getRelationships()) { removeRelationship(relationship); } @@ -171,7 +171,7 @@ public class GraphDatabaseContext { public T createEntityFromState(final S state, final Class type) { if (state==null) throw new IllegalArgumentException("state has to be either a Node or Relationship, not null"); if (state instanceof Node) - return (T) graphEntityInstantiator.createEntityFromState((Node) state, nodeTypeStrategy.confirmType((Node)state, (Class)type)); + return (T) graphEntityInstantiator.createEntityFromState((Node) state, typeRepresentationStrategy.confirmType((Node)state, (Class)type)); else return (T) relationshipEntityInstantiator.createEntityFromState((Relationship) state, (Class) type); } @@ -214,15 +214,15 @@ public class GraphDatabaseContext { } /** - * delegates to the configured @{link NodeTypeStrategy} for after entity creation operations + * delegates to the configured @{link TypeRepresentationStrategy} for after entity creation operations * @param entity */ public void postEntityCreation(final NodeBacked entity) { - nodeTypeStrategy.postEntityCreation(entity); + typeRepresentationStrategy.postEntityCreation(entity); } /** - * delegates to the configured @{link NodeTypeStrategy} to iterate over all instances of this type + * delegates to the configured @{link TypeRepresentationStrategy} to iterate over all instances of this type * @param clazz type of entity * @param * @return @@ -230,7 +230,7 @@ public class GraphDatabaseContext { */ public Iterable findAll(final Class clazz) { if (!checkIsNodeBacked(clazz)) throw new UnsupportedOperationException("No support for relationships"); - return (Iterable) nodeTypeStrategy.findAll((Class)clazz); + return (Iterable) typeRepresentationStrategy.findAll((Class)clazz); } /** @@ -241,24 +241,24 @@ public class GraphDatabaseContext { } /** - * delegates to the configured @{link NodeTypeStrategy} for a count of all instances of this type + * delegates to the configured @{link TypeRepresentationStrategy} for a count of all instances of this type * @param entityClass * @return count of all instances */ public long count(final Class entityClass) { if (!checkIsNodeBacked(entityClass)) throw new UnsupportedOperationException("No support for relationships"); - return nodeTypeStrategy.count((Class)entityClass); + return typeRepresentationStrategy.count((Class)entityClass); } /** - * delegates to the configured @{link NodeTypeStrategy} to lookup the type information for the given node + * delegates to the configured @{link TypeRepresentationStrategy} to lookup the type information for the given node * @param node * @param * @return entity type of the node * @throws IllegalStateException for nodes that are not instance backing nodes of a known type */ public Class getJavaType(final Node node) { - return nodeTypeStrategy.getJavaType(node); + return typeRepresentationStrategy.getJavaType(node); } /** @@ -327,7 +327,7 @@ public class GraphDatabaseContext { } public T createEntityFromStoredType(Node node) { - return (T)graphEntityInstantiator.createEntityFromState(node,nodeTypeStrategy.getJavaType(node)); + return (T)graphEntityInstantiator.createEntityFromState(node, typeRepresentationStrategy.getJavaType(node)); } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingTypeRepresentationStrategy.java similarity index 93% rename from spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategy.java rename to spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingTypeRepresentationStrategy.java index f5470c0b0..ff29cf854 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategy.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingTypeRepresentationStrategy.java @@ -10,13 +10,13 @@ import org.neo4j.helpers.collection.FilteringIterable; import org.neo4j.helpers.collection.IterableWrapper; import org.springframework.data.graph.annotation.NodeEntity; import org.springframework.data.graph.core.NodeBacked; -import org.springframework.data.graph.core.NodeTypeStrategy; +import org.springframework.data.graph.core.TypeRepresentationStrategy; import org.springframework.data.persistence.EntityInstantiator; import java.util.HashMap; import java.util.Map; -public class IndexingNodeTypeStrategy implements NodeTypeStrategy { +public class IndexingTypeRepresentationStrategy implements TypeRepresentationStrategy { public static final String NODE_INDEX_NAME = "__types__"; public static final String TYPE_PROPERTY_NAME = "__type__"; @@ -25,7 +25,7 @@ public class IndexingNodeTypeStrategy implements NodeTypeStrategy { private GraphDatabaseService graphDb; private final Map> cache=new HashMap>(); - public IndexingNodeTypeStrategy(GraphDatabaseService graphDb, EntityInstantiator graphEntityInstantiator) { + public IndexingTypeRepresentationStrategy(GraphDatabaseService graphDb, EntityInstantiator graphEntityInstantiator) { this.graphDb = graphDb; this.graphEntityInstantiator = graphEntityInstantiator; } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java index e3d97b7b0..694abf51f 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java @@ -5,10 +5,10 @@ import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Relationship; import org.springframework.beans.factory.FactoryBean; import org.springframework.data.graph.core.NodeBacked; -import org.springframework.data.graph.core.NodeTypeStrategy; +import org.springframework.data.graph.core.TypeRepresentationStrategy; import org.springframework.data.persistence.EntityInstantiator; -public class NodeTypeStrategyFactoryBean implements FactoryBean { +public class NodeTypeStrategyFactoryBean implements FactoryBean { private GraphDatabaseService graphDatabaseService; private EntityInstantiator graphEntityInstantiator; private Strategy strategy; @@ -26,12 +26,12 @@ public class NodeTypeStrategyFactoryBean implements FactoryBean graphEntityInstantiator) { - return new SubReferenceNodeTypeStrategy(graphDatabaseService, graphEntityInstantiator); + TypeRepresentationStrategy getObject(GraphDatabaseService graphDatabaseService, EntityInstantiator graphEntityInstantiator) { + return new SubReferenceTypeRepresentationStrategy(graphDatabaseService, graphEntityInstantiator); } @Override - Class getObjectType() { - return SubReferenceNodeTypeStrategy.class; + Class getObjectType() { + return SubReferenceTypeRepresentationStrategy.class; } }, Indexed { @Override - NodeTypeStrategy getObject(GraphDatabaseService graphDatabaseService, EntityInstantiator graphEntityInstantiator) { - return new IndexingNodeTypeStrategy(graphDatabaseService, graphEntityInstantiator); + TypeRepresentationStrategy getObject(GraphDatabaseService graphDatabaseService, EntityInstantiator graphEntityInstantiator) { + return new IndexingTypeRepresentationStrategy(graphDatabaseService, graphEntityInstantiator); } @Override - Class getObjectType() { - return IndexingNodeTypeStrategy.class; + Class getObjectType() { + return IndexingTypeRepresentationStrategy.class; } }, Noop { @Override - NodeTypeStrategy getObject(GraphDatabaseService graphDatabaseService, EntityInstantiator graphEntityInstantiator) { - return new NoopNodeTypeStrategy(); + TypeRepresentationStrategy getObject(GraphDatabaseService graphDatabaseService, EntityInstantiator graphEntityInstantiator) { + return new NoopTypeRepresentationStrategy(); } @Override - Class getObjectType() { - return NoopNodeTypeStrategy.class; + Class getObjectType() { + return NoopTypeRepresentationStrategy.class; } }; - abstract NodeTypeStrategy getObject(GraphDatabaseService graphDatabaseService, EntityInstantiator graphEntityInstantiator); - abstract Class getObjectType(); + abstract TypeRepresentationStrategy getObject(GraphDatabaseService graphDatabaseService, EntityInstantiator graphEntityInstantiator); + abstract Class getObjectType(); } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NoopNodeTypeStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NoopTypeRepresentationStrategy.java similarity index 75% rename from spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NoopNodeTypeStrategy.java rename to spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NoopTypeRepresentationStrategy.java index 76c0822a7..387e0c71c 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NoopNodeTypeStrategy.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NoopTypeRepresentationStrategy.java @@ -2,26 +2,26 @@ package org.springframework.data.graph.neo4j.support; import org.neo4j.graphdb.Node; import org.springframework.data.graph.core.NodeBacked; -import org.springframework.data.graph.core.NodeTypeStrategy; +import org.springframework.data.graph.core.TypeRepresentationStrategy; -public class NoopNodeTypeStrategy implements NodeTypeStrategy { +public class NoopTypeRepresentationStrategy implements TypeRepresentationStrategy { @Override public void postEntityCreation(NodeBacked entity) { } @Override public Iterable findAll(Class clazz) { - throw new UnsupportedOperationException("findAll not supported by NoopNodeTypeStrategy."); + throw new UnsupportedOperationException("findAll not supported by NoopTypeRepresentationStrategy."); } @Override public long count(Class entityClass) { - throw new UnsupportedOperationException("count not supported by NoopNodeTypeStrategy."); + throw new UnsupportedOperationException("count not supported by NoopTypeRepresentationStrategy."); } @Override public Class getJavaType(Node node) { - throw new UnsupportedOperationException("getJavaType not supported NoopNodeTypeStrategy."); + throw new UnsupportedOperationException("getJavaType not supported NoopTypeRepresentationStrategy."); } @Override diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceTypeRepresentationStrategy.java similarity index 95% rename from spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategy.java rename to spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceTypeRepresentationStrategy.java index 9cfc3728b..8d7027474 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategy.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceTypeRepresentationStrategy.java @@ -24,13 +24,13 @@ import org.neo4j.helpers.collection.CombiningIterable; import org.neo4j.helpers.collection.IterableWrapper; import org.neo4j.kernel.impl.traversal.TraversalDescriptionImpl; import org.springframework.data.graph.core.NodeBacked; -import org.springframework.data.graph.core.NodeTypeStrategy; +import org.springframework.data.graph.core.TypeRepresentationStrategy; import org.springframework.data.persistence.EntityInstantiator; import java.util.*; /** - * A {@link NodeTypeStrategy} that uses a hierarchy of reference nodes to represent the java type of the entity in the + * A {@link org.springframework.data.graph.core.TypeRepresentationStrategy} that uses a hierarchy of reference nodes to represent the java type of the entity in the * graph database. Entity nodes are related to their concrete type via an INSTANCE_OF relationship, the type hierarchy is * related to supertypes via SUBCLASS_OF relationships. Each concrete subreference node keeps a count property with the number of * instances of this class in the graph. @@ -38,8 +38,8 @@ import java.util.*; * @author Michael Hunger * @since 13.09.2010 */ -public class SubReferenceNodeTypeStrategy implements NodeTypeStrategy { - private final static Log log = LogFactory.getLog(SubReferenceNodeTypeStrategy.class); +public class SubReferenceTypeRepresentationStrategy implements TypeRepresentationStrategy { + private final static Log log = LogFactory.getLog(SubReferenceTypeRepresentationStrategy.class); public final static RelationshipType INSTANCE_OF_RELATIONSHIP_TYPE = DynamicRelationshipType.withName("INSTANCE_OF"); public final static RelationshipType SUBCLASS_OF_RELATIONSHIP_TYPE = DynamicRelationshipType.withName("SUBCLASS_OF"); @@ -51,7 +51,7 @@ public class SubReferenceNodeTypeStrategy implements NodeTypeStrategy { private GraphDatabaseService graphDatabaseService; private EntityInstantiator entityInstantiator; - public SubReferenceNodeTypeStrategy(GraphDatabaseService graphDatabaseService, EntityInstantiator entityInstantiator) { + public SubReferenceTypeRepresentationStrategy(GraphDatabaseService graphDatabaseService, EntityInstantiator entityInstantiator) { this.graphDatabaseService = graphDatabaseService; this.entityInstantiator = entityInstantiator; } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/Neo4jNodeBacking.aj b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/Neo4jNodeBacking.aj index 153225113..3ebdfcf3b 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/Neo4jNodeBacking.aj +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/Neo4jNodeBacking.aj @@ -23,17 +23,18 @@ import org.aspectj.lang.reflect.FieldSignature; import org.neo4j.graphdb.*; import org.neo4j.graphdb.traversal.TraversalDescription; import org.neo4j.graphdb.traversal.Traverser; -import org.springframework.beans.factory.annotation.Configurable; import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.core.GraphBacked; import org.springframework.data.graph.core.RelationshipBacked; import org.springframework.data.graph.neo4j.fieldaccess.*; import org.springframework.data.graph.neo4j.support.GraphDatabaseContext; + +import java.lang.reflect.Field; import org.springframework.data.graph.annotation.*; import javax.persistence.Transient; import javax.persistence.Entity; +import org.springframework.beans.factory.annotation.Configurable; -import java.lang.reflect.Field; import static org.springframework.data.graph.neo4j.fieldaccess.DoReturn.unwrap; @@ -106,22 +107,18 @@ public aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMixinFields NodeBacked.entityState; + public T NodeBacked.persist() { return (T)this.entityState.persist(); } public boolean NodeBacked.refersTo(GraphBacked target) { return this.entityState.refersTo(target); } - /** - * State accessors that encapsulate the underlying state and the behaviour related to it (field access, creation) - */ - private transient EntityState NodeBacked.entityState; - /** - * sets the underlying state to the given node, creates an {@link org.springframework.data.graph.neo4j.fieldaccess.EntityState} instance on demand for delegating - * the behaviour, otherwise just updates the backing state - * @param n the node to be the backing state of the entity - */ public void NodeBacked.setPersistentState(Node n) { if (this.entityState == null) { this.entityState = Neo4jNodeBacking.aspectOf().entityStateFactory.getEntityState(this); @@ -133,11 +130,11 @@ public aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMixinFields NodeBacked.getEntityState() { return entityState; } - public boolean NodeBacked.hasUnderlyingNode() { + public boolean NodeBacked.hasPersistentState() { return this.entityState!=null && this.entityState.hasPersistentState(); } @@ -145,12 +142,6 @@ public aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMixinFields Iterable NodeBacked.findAllByTraversal(final Class targetType, TraversalDescription traversalDescription) { - if (!hasUnderlyingNode()) throw new IllegalStateException("No node attached to " + this); + if (!hasPersistentState()) throw new IllegalStateException("No node attached to " + this); final Traverser traverser = traversalDescription.traverse(this.getPersistentState()); return new NodeBackedNodeIterableWrapper(traverser, targetType, Neo4jNodeBacking.aspectOf().graphDatabaseContext); } - -// public Iterable NodeBacked.traverse(TraversalDescription traversalDescription) { -// final Class target = this.getClass(); -// return this.traverse(target,traversalDescription); -// } - - - /** - * Creates a relationship to the target node with the given relationship type. - * @param target node - * @param relationshipClass expected relationship class of the resulting relationship entity - * @param relationshipType - * @return relationship entity, instance of the provided relationshipClass - */ public R NodeBacked.relateTo(N target, Class relationshipClass, String relationshipType) { if (target==null) throw new IllegalArgumentException("Target entity is null"); if (relationshipClass==null) throw new IllegalArgumentException("Relationship class is null"); @@ -215,19 +182,10 @@ public aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMixinFields R NodeBacked.getRelationshipTo( NodeBacked target, Class relationshipClass, String type) { if (target ==null) throw new IllegalArgumentException("Target entity is null"); if (relationshipClass==null) throw new IllegalArgumentException("Relationship class is null"); @@ -271,7 +222,7 @@ public aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMixinFields RelationshipBacked.entityState; - /** - * creates a new {@link org.springframework.data.graph.neo4j.fieldaccess.EntityState} instance with the relationship parameter or updates an existing one - * @param r - */ public void RelationshipBacked.setPersistentState(Relationship r) { if (this.entityState == null) { this.entityState = Neo4jRelationshipBacking.aspectOf().entityStateFactory.getEntityState(this); @@ -88,15 +84,12 @@ public aspect Neo4jRelationshipBacking { return this.entityState!=null ? this.entityState.getPersistentState() : null; } - public boolean RelationshipBacked.hasUnderlyingRelationship() { + public boolean RelationshipBacked.hasPersistentState() { return this.entityState!=null && this.entityState.hasPersistentState(); } - /** - * @return relationship id if there is an underlying relationship - */ public Long RelationshipBacked.getRelationshipId() { - if (!hasUnderlyingRelationship()) return null; + if (!hasPersistentState()) return null; return getPersistentState().getId(); } @@ -107,7 +100,7 @@ public aspect Neo4jRelationshipBacking { */ public final boolean RelationshipBacked.equals(Object obj) { if (this==obj) return true; - if (!hasUnderlyingRelationship()) return false; + if (!hasPersistentState()) return false; if (obj instanceof RelationshipBacked) { return this.getPersistentState().equals(((RelationshipBacked) obj).getPersistentState()); } @@ -118,7 +111,7 @@ public aspect Neo4jRelationshipBacking { * @return hashCode of the underlying relationship */ public final int RelationshipBacked.hashCode() { - if (!hasUnderlyingRelationship()) return System.identityHashCode(this); + if (!hasPersistentState()) return System.identityHashCode(this); return getPersistentState().hashCode(); } diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/Person_Graph_Entity.aj b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/Person_Graph_Entity.aj deleted file mode 100644 index 45dba874a..000000000 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/Person_Graph_Entity.aj +++ /dev/null @@ -1,63 +0,0 @@ -package org.springframework.data.graph.neo4j; - -import org.neo4j.graphdb.Node; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Configurable; -import org.springframework.data.graph.neo4j.support.GraphDatabaseContext; - -/** - * EXAMPLE OF CODE THAT SHOULD BE GENERATED BY ROO BESIDES EACH GRAPHENTITY CLASS - * - * Note: Combines X_Roo_Entity with X_Roo_Finder, as - * we need only a single aspect for entities. - * @author rodjohnson - * - */ -privileged aspect Person_Graph_Entity { - - // TODO should be a better way of getting this? Could at least pull out gdsholder class - private static GraphDatabaseContext graphDatabaseContext() { - return new Person_Graph_Entity.GdsHolder().graphDatabaseContext; - } - - @Configurable - public static class GdsHolder { - @Autowired - public GraphDatabaseContext graphDatabaseContext; - } - - /** - * Add constructor that takes node. - * @param node - */ - public Person.new(Node node) { - setPersistentState(node); - } - -// public static long Person.countPeople() { -// return new SubReferenceNodeTypeStrategy(graphDatabaseContext()).count(Person.class); -// } -// -// public static Iterable Person.findAllPeople() { -// final SubReferenceNodeTypeStrategy strategy = new SubReferenceNodeTypeStrategy(graphDatabaseContext()); -// return strategy.findAll(Person.class); -// } -// -// public static Person Person.findPerson(Long id) { -// Node personNode = Person_Graph_Entity.graphDatabaseContext().getNodeById(id); -// return new Person(personNode); -// } - - - // Pluggable query executors/resolvers, discussed with PL -// public static Person.findFooBars(int a, int b) { -// return executeQuery("foobar", a, b); -// // First look for String, then for method -// // QueryInterceptionResolver -// } - -// public static List Person.findPersonEntries(int firstResult, -// int maxResults) { -// throw new UnsupportedOperationException(); -// } -} diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/AttachEntityTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/AttachEntityTest.java index 77717e6d6..a5aac202c 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/AttachEntityTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/AttachEntityTest.java @@ -36,7 +36,7 @@ public class AttachEntityTest { } private boolean hasUnderlyingNode(NodeBacked nodeBacked) { - return nodeBacked.hasUnderlyingNode(); + return nodeBacked.hasPersistentState(); } private Node nodeFor(NodeBacked nodeBacked) { diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java index 2076af873..018ad6413 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java @@ -1,7 +1,6 @@ package org.springframework.data.graph.neo4j.support; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.neo4j.graphdb.GraphDatabaseService; @@ -39,7 +38,7 @@ public class IndexingNodeTypeStrategyTest { @Autowired private GraphDatabaseService graphDatabaseService; @Autowired - private IndexingNodeTypeStrategy nodeTypeStrategy; + private IndexingTypeRepresentationStrategy nodeTypeStrategy; private Thing thing; private SubThing subThing; diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/ModificationOutsideOfTransactionTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/ModificationOutsideOfTransactionTest.java index 68036cd1d..9361722f1 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/ModificationOutsideOfTransactionTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/ModificationOutsideOfTransactionTest.java @@ -161,7 +161,7 @@ public class ModificationOutsideOfTransactionTest private boolean hasUnderlyingNode( Person person ) { - return person.hasUnderlyingNode(); + return person.hasPersistentState(); } private Node nodeFor( Person person ) diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/NoopNodeTypeStrategyTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/NoopNodeTypeStrategyTest.java index e5a7c83ae..08a46db89 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/NoopNodeTypeStrategyTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/NoopNodeTypeStrategyTest.java @@ -25,7 +25,7 @@ public class NoopNodeTypeStrategyTest { @Autowired private GraphDatabaseContext graphDatabaseContext; @Autowired - private NoopNodeTypeStrategy nodeTypeStrategy; + private NoopTypeRepresentationStrategy nodeTypeStrategy; private Thing thing; diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategyTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategyTest.java index ba1871523..f75bf0760 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategyTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategyTest.java @@ -14,7 +14,6 @@ import org.neo4j.helpers.collection.IteratorUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.graph.annotation.NodeEntity; import org.springframework.data.graph.core.NodeBacked; -import org.springframework.data.graph.core.NodeTypeStrategy; import org.springframework.data.graph.neo4j.Car; import org.springframework.data.graph.neo4j.Person; import static org.springframework.data.graph.neo4j.Person.persistedPerson; @@ -24,7 +23,6 @@ import org.springframework.data.graph.neo4j.finder.FinderFactory; import org.springframework.data.graph.neo4j.finder.NodeFinder; import org.springframework.data.graph.neo4j.support.node.Neo4jHelper; -import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.CleanContextCacheTestExecutionListener; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestExecutionListeners; @@ -55,7 +53,7 @@ public class SubReferenceNodeTypeStrategyTest { @Autowired private FinderFactory finderFactory; @Autowired - private SubReferenceNodeTypeStrategy nodeTypeStrategy; + private SubReferenceTypeRepresentationStrategy nodeTypeStrategy; private Node thingNode; private Thing thing; @@ -75,8 +73,8 @@ public class SubReferenceNodeTypeStrategyTest { public void testPostEntityCreation() throws Exception { Node typeNode = getInstanceofRelationship().getOtherNode(thingNode); Assert.assertNotNull("type node for thing exists", typeNode); - Assert.assertEquals("type node has property of type Thing.class", Thing.class.getName(), typeNode.getProperty(SubReferenceNodeTypeStrategy.SUBREF_CLASS_KEY)); - Assert.assertEquals("one thing has been created", 1, typeNode.getProperty(SubReferenceNodeTypeStrategy.SUBREFERENCE_NODE_COUNTER_KEY)); + Assert.assertEquals("type node has property of type Thing.class", Thing.class.getName(), typeNode.getProperty(SubReferenceTypeRepresentationStrategy.SUBREF_CLASS_KEY)); + Assert.assertEquals("one thing has been created", 1, typeNode.getProperty(SubReferenceTypeRepresentationStrategy.SUBREFERENCE_NODE_COUNTER_KEY)); } @Test(expected = IllegalArgumentException.class) public void gettingTypeFromNonTypeNodeShouldThrowAnDescriptiveException() throws Exception { @@ -115,13 +113,13 @@ public class SubReferenceNodeTypeStrategyTest { Node typeNode = getInstanceofRelationship().getOtherNode(thingNode); nodeTypeStrategy.preEntityRemoval(thing); Assert.assertNull("instanceof relationship was removed", getInstanceofRelationship()); - Assert.assertEquals("no things left after removal", 0, typeNode.getProperty(SubReferenceNodeTypeStrategy.SUBREFERENCE_NODE_COUNTER_KEY)); + Assert.assertEquals("no things left after removal", 0, typeNode.getProperty(SubReferenceTypeRepresentationStrategy.SUBREFERENCE_NODE_COUNTER_KEY)); } @Transactional private Relationship getInstanceofRelationship() { - return thingNode.getSingleRelationship(SubReferenceNodeTypeStrategy.INSTANCE_OF_RELATIONSHIP_TYPE, Direction.OUTGOING); + return thingNode.getSingleRelationship(SubReferenceTypeRepresentationStrategy.INSTANCE_OF_RELATIONSHIP_TYPE, Direction.OUTGOING); } @Test diff --git a/spring-data-neo4j/src/test/resources/log4j.properties b/spring-data-neo4j/src/test/resources/log4j.properties index e69fbde1b..c33528705 100644 --- a/spring-data-neo4j/src/test/resources/log4j.properties +++ b/spring-data-neo4j/src/test/resources/log4j.properties @@ -18,7 +18,7 @@ log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n log4j.category.org.springframework=WARN -#log4j.category.org.springframework.data.graph.neo4j.support.SubReferenceNodeTypeStrategy=DEBUG +#log4j.category.org.springframework.data.graph.neo4j.support.SubReferenceTypeRepresentationStrategyonStrategy=DEBUG #log4j.category.org.springframework.data.graph.neo4j.fieldaccess=DEBUG #log4j.category.org.springframework.data=TRACE #log4j.category.org.springframework.data.support=TRACE diff --git a/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/partial/Neo4jGraphRecommendationTest-context.xml b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/partial/Neo4jGraphRecommendationTest-context.xml index 2a444b96d..43b2288e9 100644 --- a/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/partial/Neo4jGraphRecommendationTest-context.xml +++ b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/partial/Neo4jGraphRecommendationTest-context.xml @@ -100,10 +100,10 @@ - +
- + @@ -120,6 +120,7 @@
+ diff --git a/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyOverride-context.xml b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyOverride-context.xml index 8c0941652..6b5470375 100644 --- a/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyOverride-context.xml +++ b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyOverride-context.xml @@ -14,7 +14,7 @@ http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> - + diff --git a/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/Neo4jGraphPersistenceTest-context.xml b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/Neo4jGraphPersistenceTest-context.xml index 4c20f924d..b8c13e80a 100644 --- a/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/Neo4jGraphPersistenceTest-context.xml +++ b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/Neo4jGraphPersistenceTest-context.xml @@ -91,7 +91,7 @@ - + @@ -100,7 +100,7 @@ - + diff --git a/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/NoopNodeTypeStrategyOverride-context.xml b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/NoopNodeTypeStrategyOverride-context.xml index b535caf13..052d9b45e 100644 --- a/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/NoopNodeTypeStrategyOverride-context.xml +++ b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/NoopNodeTypeStrategyOverride-context.xml @@ -14,5 +14,5 @@ http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> - + \ No newline at end of file diff --git a/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategyOverride-context.xml b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategyOverride-context.xml index e2d8e83f7..31fb50433 100644 --- a/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategyOverride-context.xml +++ b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategyOverride-context.xml @@ -14,7 +14,7 @@ http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> - + diff --git a/src/docbkx/reference/programming-model/annotations.xml b/src/docbkx/reference/programming-model/annotations.xml index a4ee07134..56fb59573 100644 --- a/src/docbkx/reference/programming-model/annotations.xml +++ b/src/docbkx/reference/programming-model/annotations.xml @@ -26,7 +26,7 @@ // simplest example @NodeEntity public class Movie { - String title; + String title; } ]]> @@ -47,20 +47,30 @@ public class Movie { null. For multi-relationships the field provides a managed collection (Set) that handles addition and removal of node entities and reflects those in the graph relationships. + + @RelatedTo also ensures that there is only one relationship of the given type between two + given entities. + + + By setting direction to BOTH, relationships are created in the outgoing direction, but when the 1:N field + is read, it will include relationships in both directions. + movies; + @RelatedTo(type = "ACTS_IN", elementClass = Movie.class) + private Set movies; } ]]> @@ -82,8 +92,8 @@ public class Actor { public class Role { String title; - @StartNode private Actor actor; - @EndNode private Movie movie; + @StartNode private Actor actor; + @EndNode private Movie movie; } ]]> @@ -100,13 +110,13 @@ public class Role { roles; + @RelatedToVia(type = "ACTS_IN", elementClass = Role.class) + private Iterable roles; - public Role playedIn(Movie movie, String title) { - Role role=relateTo(movie,Role.class,"ACTS_IN"); - role.setTitle(title); - return role; + public Role playedIn(Movie movie, String title) { + Role role=relateTo(movie,Role.class,"ACTS_IN"); + role.setTitle(title); + return role; } } ]]> @@ -153,21 +163,19 @@ public class Actor { people; + @GraphTraversal(traversalBuilder = PeopleTraversalBuilder.class, + elementClass = Person.class, params = "persons") + private Iterable people; - private static class PeopleTraversalBuilder implements FieldTraversalDescriptionBuilder { - @Override - public TraversalDescription build(NodeBacked start, Field field, String...params) { - return new TraversalDescriptionImpl() - .relationships(DynamicRelationshipType.withName(params[0])) - .filter(Traversal.returnAllButStartNode()); - - } - } + private static class PeopleTraversalBuilder implements FieldTraversalDescriptionBuilder { + @Override + public TraversalDescription build(NodeBacked start, Field field, String...params) { + return new TraversalDescriptionImpl() + .relationships(DynamicRelationshipType.withName(params[0])) + .filter(Traversal.returnAllButStartNode()); + } + } } - ]]>