Merge branch 'master' into rest

This commit is contained in:
Andres Taylor
2011-03-29 06:48:06 +02:00
30 changed files with 289 additions and 269 deletions

View File

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

View File

@@ -97,10 +97,10 @@
<property name="conversionService">
<bean class="org.springframework.data.graph.neo4j.fieldaccess.Neo4jConversionServiceFactoryBean"/>
</property>
<property name="nodeTypeStrategy" ref="nodeTypeStrategy"/>
<property name="typeRepresentationStrategy" ref="typeRepresentationStrategy"/>
</bean>
<bean id="nodeTypeStrategy" class="org.springframework.data.graph.neo4j.support.NodeTypeStrategyFactoryBean">
<bean id="typeRepresentationStrategy" class="org.springframework.data.graph.neo4j.support.NodeTypeStrategyFactoryBean">
<constructor-arg ref="graphDatabaseService"/>
<constructor-arg ref="graphEntityInstantiator"/>
</bean>

View File

@@ -27,6 +27,7 @@ package org.springframework.data.graph.core;
public interface GraphBacked<STATE> {
/**
* 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<STATE> {
* @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();
}

View File

@@ -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 &#64;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<Node> {
// 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 extends NodeBacked> T persist();
/**
* <p>
* Creates a relationship to the target node, returning a relationship entity representing the created
* relationship.
* </p>
* <p/>
* <p>
* Example:
* <pre>
* public class Person {
* ...
* public Friendship knows(Person p) {
* return (Friendship) relateTo(p, Friendship.class, "knows");
* }
* ...
* }
* </pre>
* </p>
*
* @param target other entity
* @param relationshipClass relationship entity class
* @param relationshipType type of relationship to be created
* @return relationship entity of specified relationshipClass
*/
<R extends RelationshipBacked, N extends NodeBacked> R relateTo(N target, Class<R> 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 extends NodeBacked> T projectTo(Class<T> 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
*/
<T extends NodeBacked> Iterable<T> findAllByTraversal(final Class<T> 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 extends RelationshipBacked> R getRelationshipTo(NodeBacked target, Class<R> 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<NodeBacked, Node> getEntityState();
// will possibly be used for object graphs
boolean refersTo(GraphBacked target);
}

View File

@@ -23,5 +23,19 @@ import org.neo4j.graphdb.Relationship;
* aspect, encapsulates a neo4j relationship as backing state
*/
public interface RelationshipBacked extends GraphBacked<Relationship>{
/**
* @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 extends RelationshipBacked> R projectTo(Class<R> targetType);
}

View File

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

View File

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

View File

@@ -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<NodeBacked,Node> getEntityState(final NodeBacked entity) {
final NodeEntity graphEntityAnnotation = entity.getClass().getAnnotation(NodeEntity.class); // todo cache ??
if (graphEntityAnnotation.partial()) {
PartialNodeEntityState<NodeBacked> partialNodeEntityState = new PartialNodeEntityState<NodeBacked>(null, entity, entity.getClass(), graphDatabaseContext, finderFactory);
final PartialNodeEntityState<NodeBacked> partialNodeEntityState = new PartialNodeEntityState<NodeBacked>(null, entity, entity.getClass(), graphDatabaseContext, finderFactory, getPersistenceUnitUtils());
return new DetachedEntityState<NodeBacked, Node>(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;
}
}

View File

@@ -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<ENTITY extends NodeBacked> 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<? extends ENTITY> type, final GraphDatabaseContext graphDatabaseContext, final FinderFactory finderFactory) {
public PartialNodeEntityState(final Node underlyingState, final ENTITY entity, final Class<? extends ENTITY> 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<ENTITY extends NodeBacked> 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<ENTITY extends NodeBacked> 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<Node> indexHits = getForeignIdIndex().get(FOREIGN_ID, foreignId);
@@ -162,21 +164,7 @@ public class PartialNodeEntityState<ENTITY extends NodeBacked> 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;
}
}

View File

@@ -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 <T> GraphBacked target of this finder, enables the finder methods to return this concrete type

View File

@@ -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 <S, T extends GraphBacked> T createEntityFromState(final S state, final Class<T> 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<? extends NodeBacked>)type));
return (T) graphEntityInstantiator.createEntityFromState((Node) state, typeRepresentationStrategy.confirmType((Node)state, (Class<? extends NodeBacked>)type));
else
return (T) relationshipEntityInstantiator.createEntityFromState((Relationship) state, (Class<? extends RelationshipBacked>) 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 <T>
* @return
@@ -230,7 +230,7 @@ public class GraphDatabaseContext {
*/
public <T extends GraphBacked> Iterable<T> findAll(final Class<T> clazz) {
if (!checkIsNodeBacked(clazz)) throw new UnsupportedOperationException("No support for relationships");
return (Iterable<T>) nodeTypeStrategy.findAll((Class<NodeBacked>)clazz);
return (Iterable<T>) typeRepresentationStrategy.findAll((Class<NodeBacked>)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<? extends GraphBacked> entityClass) {
if (!checkIsNodeBacked(entityClass)) throw new UnsupportedOperationException("No support for relationships");
return nodeTypeStrategy.count((Class<NodeBacked>)entityClass);
return typeRepresentationStrategy.count((Class<NodeBacked>)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 <T>
* @return entity type of the node
* @throws IllegalStateException for nodes that are not instance backing nodes of a known type
*/
public <T extends NodeBacked> Class<T> getJavaType(final Node node) {
return nodeTypeStrategy.getJavaType(node);
return typeRepresentationStrategy.getJavaType(node);
}
/**
@@ -327,7 +327,7 @@ public class GraphDatabaseContext {
}
public <T extends NodeBacked> T createEntityFromStoredType(Node node) {
return (T)graphEntityInstantiator.createEntityFromState(node,nodeTypeStrategy.<NodeBacked>getJavaType(node));
return (T)graphEntityInstantiator.createEntityFromState(node, typeRepresentationStrategy.<NodeBacked>getJavaType(node));
}
}

View File

@@ -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<String,Class<?>> cache=new HashMap<String, Class<?>>();
public IndexingNodeTypeStrategy(GraphDatabaseService graphDb, EntityInstantiator<NodeBacked, Node> graphEntityInstantiator) {
public IndexingTypeRepresentationStrategy(GraphDatabaseService graphDb, EntityInstantiator<NodeBacked, Node> graphEntityInstantiator) {
this.graphDb = graphDb;
this.graphEntityInstantiator = graphEntityInstantiator;
}

View File

@@ -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<NodeTypeStrategy> {
public class NodeTypeStrategyFactoryBean implements FactoryBean<TypeRepresentationStrategy> {
private GraphDatabaseService graphDatabaseService;
private EntityInstantiator<NodeBacked, Node> graphEntityInstantiator;
private Strategy strategy;
@@ -26,12 +26,12 @@ public class NodeTypeStrategyFactoryBean implements FactoryBean<NodeTypeStrategy
}
private boolean isAlreadyIndexed() {
return graphDatabaseService.index().existsForNodes(IndexingNodeTypeStrategy.NODE_INDEX_NAME);
return graphDatabaseService.index().existsForNodes(IndexingTypeRepresentationStrategy.NODE_INDEX_NAME);
}
private boolean isAlreadySubRef() {
for (Relationship rel : graphDatabaseService.getReferenceNode().getRelationships()) {
if (rel.getType().name().startsWith(SubReferenceNodeTypeStrategy.SUBREF_PREFIX)) {
if (rel.getType().name().startsWith(SubReferenceTypeRepresentationStrategy.SUBREF_PREFIX)) {
return true;
}
}
@@ -39,7 +39,7 @@ public class NodeTypeStrategyFactoryBean implements FactoryBean<NodeTypeStrategy
}
@Override
public NodeTypeStrategy getObject() throws Exception {
public TypeRepresentationStrategy getObject() throws Exception {
return strategy.getObject(graphDatabaseService, graphEntityInstantiator);
}
@@ -56,38 +56,38 @@ public class NodeTypeStrategyFactoryBean implements FactoryBean<NodeTypeStrategy
private enum Strategy {
SubRef {
@Override
NodeTypeStrategy getObject(GraphDatabaseService graphDatabaseService, EntityInstantiator<NodeBacked, Node> graphEntityInstantiator) {
return new SubReferenceNodeTypeStrategy(graphDatabaseService, graphEntityInstantiator);
TypeRepresentationStrategy getObject(GraphDatabaseService graphDatabaseService, EntityInstantiator<NodeBacked, Node> graphEntityInstantiator) {
return new SubReferenceTypeRepresentationStrategy(graphDatabaseService, graphEntityInstantiator);
}
@Override
Class<? extends NodeTypeStrategy> getObjectType() {
return SubReferenceNodeTypeStrategy.class;
Class<? extends TypeRepresentationStrategy> getObjectType() {
return SubReferenceTypeRepresentationStrategy.class;
}
},
Indexed {
@Override
NodeTypeStrategy getObject(GraphDatabaseService graphDatabaseService, EntityInstantiator<NodeBacked, Node> graphEntityInstantiator) {
return new IndexingNodeTypeStrategy(graphDatabaseService, graphEntityInstantiator);
TypeRepresentationStrategy getObject(GraphDatabaseService graphDatabaseService, EntityInstantiator<NodeBacked, Node> graphEntityInstantiator) {
return new IndexingTypeRepresentationStrategy(graphDatabaseService, graphEntityInstantiator);
}
@Override
Class<? extends NodeTypeStrategy> getObjectType() {
return IndexingNodeTypeStrategy.class;
Class<? extends TypeRepresentationStrategy> getObjectType() {
return IndexingTypeRepresentationStrategy.class;
}
},
Noop {
@Override
NodeTypeStrategy getObject(GraphDatabaseService graphDatabaseService, EntityInstantiator<NodeBacked, Node> graphEntityInstantiator) {
return new NoopNodeTypeStrategy();
TypeRepresentationStrategy getObject(GraphDatabaseService graphDatabaseService, EntityInstantiator<NodeBacked, Node> graphEntityInstantiator) {
return new NoopTypeRepresentationStrategy();
}
@Override
Class<? extends NodeTypeStrategy> getObjectType() {
return NoopNodeTypeStrategy.class;
Class<? extends TypeRepresentationStrategy> getObjectType() {
return NoopTypeRepresentationStrategy.class;
}
};
abstract NodeTypeStrategy getObject(GraphDatabaseService graphDatabaseService, EntityInstantiator<NodeBacked, Node> graphEntityInstantiator);
abstract Class<? extends NodeTypeStrategy> getObjectType();
abstract TypeRepresentationStrategy getObject(GraphDatabaseService graphDatabaseService, EntityInstantiator<NodeBacked, Node> graphEntityInstantiator);
abstract Class<? extends TypeRepresentationStrategy> getObjectType();
}
}

View File

@@ -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 <T extends NodeBacked> Iterable<T> findAll(Class<T> clazz) {
throw new UnsupportedOperationException("findAll not supported by NoopNodeTypeStrategy.");
throw new UnsupportedOperationException("findAll not supported by NoopTypeRepresentationStrategy.");
}
@Override
public long count(Class<? extends NodeBacked> entityClass) {
throw new UnsupportedOperationException("count not supported by NoopNodeTypeStrategy.");
throw new UnsupportedOperationException("count not supported by NoopTypeRepresentationStrategy.");
}
@Override
public <T extends NodeBacked> Class<T> getJavaType(Node node) {
throw new UnsupportedOperationException("getJavaType not supported NoopNodeTypeStrategy.");
throw new UnsupportedOperationException("getJavaType not supported NoopTypeRepresentationStrategy.");
}
@Override

View File

@@ -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<NodeBacked, Node> entityInstantiator;
public SubReferenceNodeTypeStrategy(GraphDatabaseService graphDatabaseService, EntityInstantiator<NodeBacked, Node> entityInstantiator) {
public SubReferenceTypeRepresentationStrategy(GraphDatabaseService graphDatabaseService, EntityInstantiator<NodeBacked, Node> entityInstantiator) {
this.graphDatabaseService = graphDatabaseService;
this.entityInstantiator = entityInstantiator;
}

View File

@@ -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<No
}
}
/**
* State accessors that encapsulate the underlying state and the behaviour related to it (field access, creation)
*/
private transient EntityState<NodeBacked,Node> NodeBacked.entityState;
public <T extends NodeBacked> 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,Node> 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<No
return this.entityState!=null ? this.entityState.getPersistentState() : null;
}
public EntityState NodeBacked.getEntityState() {
public EntityState<NodeBacked, Node> 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<No
return (T)Neo4jNodeBacking.aspectOf().graphDatabaseContext.projectTo( this, targetType);
}
/**
* 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
*/
public Relationship NodeBacked.relateTo(NodeBacked target, String type) {
if (target==null) throw new IllegalArgumentException("Target entity is null");
if (type==null) throw new IllegalArgumentException("Relationshiptype is null");
@@ -171,41 +162,17 @@ public aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMixinFields<No
return null;
}
/**
* @return node id or null if there is no underlying state
*/
public Long NodeBacked.getNodeId() {
if (!hasUnderlyingNode()) return null;
if (!hasPersistentState()) return null;
return getPersistentState().getId();
}
/**
* handles traversal from the current node with the given traversal description, the entities returned must be instances of the
* provided target type
* @param targetType node entity java types of the traversal results
* @param traversalDescription
* @return lazy Iterable over the traversal results, converted to the expected node entity instances
*/
public <T extends NodeBacked> Iterable<T> NodeBacked.findAllByTraversal(final Class<T> 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<T>(traverser, targetType, Neo4jNodeBacking.aspectOf().graphDatabaseContext);
}
// public Iterable<? extends NodeBacked> NodeBacked.traverse(TraversalDescription traversalDescription) {
// final Class<? extends NodeBacked> 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 extends RelationshipBacked, N extends NodeBacked> R NodeBacked.relateTo(N target, Class<R> 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<No
return (R)Neo4jNodeBacking.aspectOf().graphDatabaseContext.createEntityFromState(rel, relationshipClass);
}
/**
* 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
*/
public void NodeBacked.remove() {
Neo4jNodeBacking.aspectOf().graphDatabaseContext.removeNodeEntity(this);
}
/**
* removes the relationship to the target node entity with the given relationship type
* @param target node entity
* @param relationshipType
*/
public void NodeBacked.removeRelationshipTo(NodeBacked target, String relationshipType) {
if (target==null) throw new IllegalArgumentException("Target entity is null");
if (relationshipType==null) throw new IllegalArgumentException("Relationshiptype is null");
@@ -243,13 +201,6 @@ public aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMixinFields<No
}
}
/**
* introduced method for accessing and Relationship Entity instance for the given start node and relationship type.
* @param target start node
* @param relationshipClass class of the relationship entity
* @param type type of the graph relationship
* @return and instance of the requested relationshipClass if the relationship was found, null otherwise
*/
public <R extends RelationshipBacked> R NodeBacked.getRelationshipTo( NodeBacked target, Class<R> 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<No
*/
public final boolean NodeBacked.equals(Object obj) {
if (obj == this) return true;
if (!hasUnderlyingNode()) return false;
if (!hasPersistentState()) return false;
if (obj instanceof NodeBacked) {
return this.getPersistentState().equals(((NodeBacked) obj).getPersistentState());
}
@@ -282,7 +233,7 @@ public aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMixinFields<No
* @return result of the hashCode of the underlying node (if any, otherwise identityHashCode)
*/
public final int NodeBacked.hashCode() {
if (!hasUnderlyingNode()) return System.identityHashCode(this);
if (!hasPersistentState()) return System.identityHashCode(this);
return getPersistentState().hashCode();
}

View File

@@ -73,10 +73,6 @@ public aspect Neo4jRelationshipBacking {
*/
private EntityState<RelationshipBacked,Relationship> 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();
}

View File

@@ -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> 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> Person.findPersonEntries(int firstResult,
// int maxResults) {
// throw new UnsupportedOperationException();
// }
}

View File

@@ -36,7 +36,7 @@ public class AttachEntityTest {
}
private boolean hasUnderlyingNode(NodeBacked nodeBacked) {
return nodeBacked.hasUnderlyingNode();
return nodeBacked.hasPersistentState();
}
private Node nodeFor(NodeBacked nodeBacked) {

View File

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

View File

@@ -161,7 +161,7 @@ public class ModificationOutsideOfTransactionTest
private boolean hasUnderlyingNode( Person person )
{
return person.hasUnderlyingNode();
return person.hasPersistentState();
}
private Node nodeFor( Person person )

View File

@@ -25,7 +25,7 @@ public class NoopNodeTypeStrategyTest {
@Autowired
private GraphDatabaseContext graphDatabaseContext;
@Autowired
private NoopNodeTypeStrategy nodeTypeStrategy;
private NoopTypeRepresentationStrategy nodeTypeStrategy;
private Thing thing;

View File

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

View File

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

View File

@@ -100,10 +100,10 @@
<property name="conversionService">
<bean class="org.springframework.data.graph.neo4j.fieldaccess.Neo4jConversionServiceFactoryBean"/>
</property>
<property name="nodeTypeStrategy" ref="nodeTypeStrategy"/>
<property name="typeRepresentationStrategy" ref="typeRepresentationStrategy"/>
</bean>
<bean id="nodeTypeStrategy" class="org.springframework.data.graph.neo4j.support.NodeTypeStrategyFactoryBean">
<bean id="typeRepresentationStrategy" class="org.springframework.data.graph.neo4j.support.NodeTypeStrategyFactoryBean">
<constructor-arg ref="graphDatabaseService"/>
<constructor-arg ref="graphEntityInstantiator"/>
</bean>
@@ -120,6 +120,7 @@
</property>
<property name="graphDatabaseContext" ref="graphDatabaseContext"/>
<property name="finderFactory" ref="finderFactory"/>
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="relationshipEntityStateFactory" class="org.springframework.data.graph.neo4j.fieldaccess.RelationshipEntityStateFactory">

View File

@@ -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">
<bean id="nodeTypeStrategy" class="org.springframework.data.graph.neo4j.support.IndexingNodeTypeStrategy">
<bean id="typeRepresentationStrategy" class="org.springframework.data.graph.neo4j.support.IndexingTypeRepresentationStrategy">
<constructor-arg ref="graphDatabaseService" />
<constructor-arg ref="graphEntityInstantiator" />
</bean>

View File

@@ -91,7 +91,7 @@
<property name="conversionService">
<bean class="org.springframework.data.graph.neo4j.fieldaccess.Neo4jConversionServiceFactoryBean"/>
</property>
<property name="nodeTypeStrategy" ref="nodeTypeStrategy"/>
<property name="typeRepresentationStrategy" ref="typeRepresentationStrategy"/>
<property name="validator">
<bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
</property>
@@ -100,7 +100,7 @@
<bean id="graphEntityInstantiator"
class="org.springframework.data.graph.neo4j.support.node.Neo4jConstructorGraphEntityInstantiator"/>
<bean id="nodeTypeStrategy" class="org.springframework.data.graph.neo4j.support.NodeTypeStrategyFactoryBean">
<bean id="typeRepresentationStrategy" class="org.springframework.data.graph.neo4j.support.NodeTypeStrategyFactoryBean">
<constructor-arg ref="graphDatabaseService" />
<constructor-arg ref="graphEntityInstantiator" />
</bean>

View File

@@ -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">
<bean id="nodeTypeStrategy" class="org.springframework.data.graph.neo4j.support.NoopNodeTypeStrategy" />
<bean id="typeRepresentationStrategy" class="org.springframework.data.graph.neo4j.support.NoopTypeRepresentationStrategy" />
</beans>

View File

@@ -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">
<bean id="nodeTypeStrategy" class="org.springframework.data.graph.neo4j.support.SubReferenceNodeTypeStrategy">
<bean id="typeRepresentationStrategy" class="org.springframework.data.graph.neo4j.support.SubReferenceTypeRepresentationStrategy">
<constructor-arg ref="graphDatabaseService"/>
<constructor-arg ref="graphEntityInstantiator" />
</bean>

View File

@@ -26,7 +26,7 @@
// simplest example
@NodeEntity
public class Movie {
String title;
String title;
}
]]></programlisting>
</section>
@@ -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.
</para>
<para>
<code>@RelatedTo</code> also ensures that there is only one relationship of the given type between two
given entities.
</para>
<note>
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.
</note>
<programlisting language="java"><![CDATA[
@NodeEntity
public class Movie {
private Actor topActor;
private Actor topActor;
}
@NodeEntity
public class Person {
@RelatedTo(type = "topActor", direction = Direction.INCOMING)
private Movie wasTopActorIn;
@RelatedTo(type = "topActor", direction = Direction.INCOMING)
private Movie wasTopActorIn;
}
@NodeEntity
public class Actor {
@RelatedTo(type = "ACTS_IN", elementClass = Movie.class)
private Set<Movie> movies;
@RelatedTo(type = "ACTS_IN", elementClass = Movie.class)
private Set<Movie> movies;
}
]]></programlisting>
</section>
@@ -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;
}
]]></programlisting>
</section>
@@ -100,13 +110,13 @@ public class Role {
<programlisting language="java"><![CDATA[
@NodeEntity
public class Actor {
@RelatedToVia(type = "ACTS_IN", elementClass = Role.class)
private Iterable<Role> roles;
@RelatedToVia(type = "ACTS_IN", elementClass = Role.class)
private Iterable<Role> 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;
}
}
]]></programlisting>
@@ -153,21 +163,19 @@ public class Actor {
<programlisting language="java"><![CDATA[
@NodeEntity
public class Group {
@GraphTraversal(traversalBuilder = PeopleTraversalBuilder.class,
elementClass = Person.class, params = "persons")
private Iterable<Person> people;
@GraphTraversal(traversalBuilder = PeopleTraversalBuilder.class,
elementClass = Person.class, params = "persons")
private Iterable<Person> 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());
}
}
}
]]></programlisting>
</para>
</section>