diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/ConvertingNodePropertyFieldAccessor.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/ConvertingNodePropertyFieldAccessor.java deleted file mode 100644 index a2ac9b254..000000000 --- a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/ConvertingNodePropertyFieldAccessor.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.springframework.datastore.graph.neo4j.fieldaccess; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Configurable; -import org.springframework.core.convert.ConversionService; -import org.springframework.datastore.graph.api.NodeBacked; -import org.springframework.datastore.graph.api.RelationshipBacked; - -import java.lang.reflect.Field; - -/** - * @author Michael Hunger - * @since 12.09.2010 - */ -@Configurable -public class ConvertingNodePropertyFieldAccessor extends NodePropertyFieldAccessor { - - private final ConversionService conversionService; - - public ConvertingNodePropertyFieldAccessor(final Field field, final ConversionService conversionService) { - super(field); - this.conversionService = conversionService; - } - - @Override - public Object setValue(final NodeBacked nodeBacked, final Object newVal) { - super.setValue(nodeBacked, serializePropertyValue(newVal)); - return newVal; - } - - @Override - public Object doGetValue(final NodeBacked nodeBacked) { - return deserializePropertyValue(super.doGetValue(nodeBacked)); - } - - private Object serializePropertyValue(final Object newVal) { - return conversionService.convert(newVal, String.class); - } - - private Object deserializePropertyValue(final Object value) { - return conversionService.convert(value, field.getType()); - } - - public static FieldAccessorFactory factory() { - return new ConvertingNodePropertyFieldAccessorFactory(); - } - - @Configurable - private static class ConvertingNodePropertyFieldAccessorFactory implements FieldAccessorFactory { - @Autowired - ConversionService conversionService; - - @Override - public boolean accept(final Field field) { - return isSerializableField(field) && isDeserializableField(field); - } - - @Override - public FieldAccessor forField(final Field field) { - return new ConvertingNodePropertyFieldAccessor(field, conversionService); - } - - private boolean isSerializableField(final Field field) { - return isSimpleValueField(field) && conversionService.canConvert(field.getType(), String.class); - } - - private boolean isDeserializableField(final Field field) { - return isSimpleValueField(field) && conversionService.canConvert(String.class, field.getType()); - } - - private boolean isSimpleValueField(final Field field) { - final Class type = field.getType(); - if (Iterable.class.isAssignableFrom(type) || NodeBacked.class.isAssignableFrom(type) || RelationshipBacked.class.isAssignableFrom(type)) - return false; - return true; - } - } -} diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/ConvertingNodePropertyFieldAccessorFactory.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/ConvertingNodePropertyFieldAccessorFactory.java new file mode 100644 index 000000000..2272d023a --- /dev/null +++ b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/ConvertingNodePropertyFieldAccessorFactory.java @@ -0,0 +1,75 @@ +package org.springframework.datastore.graph.neo4j.fieldaccess; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Configurable; +import org.springframework.core.convert.ConversionService; +import org.springframework.datastore.graph.api.NodeBacked; +import org.springframework.datastore.graph.api.RelationshipBacked; + +import java.lang.reflect.Field; + +/** + * @author Michael Hunger + * @since 12.09.2010 + */ +@Configurable +public class ConvertingNodePropertyFieldAccessorFactory implements FieldAccessorFactory { + @Autowired + ConversionService conversionService; + + @Override + public boolean accept(final Field field) { + return isSerializableField(field) && isDeserializableField(field); + } + + @Override + public FieldAccessor forField(final Field field) { + return new ConvertingNodePropertyFieldAccessor(field, conversionService); + } + + private boolean isSerializableField(final Field field) { + return isSimpleValueField(field) && conversionService.canConvert(field.getType(), String.class); + } + + private boolean isDeserializableField(final Field field) { + return isSimpleValueField(field) && conversionService.canConvert(String.class, field.getType()); + } + + private boolean isSimpleValueField(final Field field) { + final Class type = field.getType(); + if (Iterable.class.isAssignableFrom(type) || NodeBacked.class.isAssignableFrom(type) || RelationshipBacked.class.isAssignableFrom(type)) + return false; + return true; + } + + @Configurable + public static class ConvertingNodePropertyFieldAccessor extends NodePropertyFieldAccessorFactory.NodePropertyFieldAccessor { + + private final ConversionService conversionService; + + public ConvertingNodePropertyFieldAccessor(final Field field, final ConversionService conversionService) { + super(field); + this.conversionService = conversionService; + } + + @Override + public Object setValue(final NodeBacked nodeBacked, final Object newVal) { + super.setValue(nodeBacked, serializePropertyValue(newVal)); + return newVal; + } + + @Override + public Object doGetValue(final NodeBacked nodeBacked) { + return deserializePropertyValue(super.doGetValue(nodeBacked)); + } + + private Object serializePropertyValue(final Object newVal) { + return conversionService.convert(newVal, String.class); + } + + private Object deserializePropertyValue(final Object value) { + return conversionService.convert(value, field.getType()); + } + + } +} diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/DelegatingFieldAccessorFactory.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/DelegatingFieldAccessorFactory.java index 39f4ab6a8..10020942e 100644 --- a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/DelegatingFieldAccessorFactory.java +++ b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/DelegatingFieldAccessorFactory.java @@ -26,18 +26,18 @@ public class DelegatingFieldAccessorFactory implements FieldAccessorFactory> fieldAccessorFactories = Arrays.>asList( - IdFieldAccessor.factory(), - TransientFieldAccessor.factory(), - NodePropertyFieldAccessor.factory(), - ConvertingNodePropertyFieldAccessor.factory(), - SingleRelationshipFieldAccessor.factory(), - OneToNRelationshipFieldAccessor.factory(), - ReadOnlyOneToNRelationshipFieldAccessor.factory(), - TraversalFieldAccessor.factory(), - OneToNRelationshipEntityFieldAccessor.factory() + new IdFieldAccessorFactory(), + new TransientFieldAccessorFactory(), + new NodePropertyFieldAccessorFactory(), + new ConvertingNodePropertyFieldAccessorFactory(), + new SingleRelationshipFieldAccessorFactory(), + new OneToNRelationshipFieldAccessorFactory(), + new ReadOnlyOneToNRelationshipFieldAccessorFactory(), + new TraversalFieldAccessorFactory(), + new OneToNRelationshipEntityFieldAccessorFactory() ); - final Collection> fieldAccessorListenerFactories = Arrays.>asList( - IndexingNodePropertyFieldAccessorListener.factory() + final Collection> fieldAccessorListenerFactories = Arrays.>asList( + IndexingNodePropertyFieldAccessorListenerFactory.IndexingNodePropertyFieldAccessorListener.factory() ); public FieldAccessor forField(Field field) { diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/IdFieldAccessor.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/IdFieldAccessor.java deleted file mode 100644 index 6c425233a..000000000 --- a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/IdFieldAccessor.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.springframework.datastore.graph.neo4j.fieldaccess; - -import org.springframework.datastore.graph.api.NodeBacked; - -import java.lang.reflect.Field; - -import static org.springframework.datastore.graph.neo4j.fieldaccess.DoReturn.doReturn; - -/** - * @author Michael Hunger - * @since 12.09.2010 - */ -public class IdFieldAccessor implements FieldAccessor { - protected final Field field; - - public IdFieldAccessor(final Field field) { - this.field = field; - } - - @Override - public boolean isWriteable(NodeBacked nodeBacked) { - return false; - } - - @Override - public Object setValue(final NodeBacked nodeBacked, final Object newVal) { - return doReturn(null); - } - - @Override - public Object getValue(final NodeBacked nodeBacked) { - return doReturn(nodeBacked.getUnderlyingNode().getId()); - } - - public static FieldAccessorFactory factory() { - return new FieldAccessorFactory() { - @Override - public boolean accept(final Field f) { - return isIdField(f); - } - - private boolean isIdField(Field field) { - if (!field.getName().equals("id")) return false; - final Class type = field.getType(); - return type.equals(Long.class) || type.equals(long.class); - } - - - @Override - public FieldAccessor forField(final Field field) { - return new IdFieldAccessor(field); - } - }; - } -} diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/IdFieldAccessorFactory.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/IdFieldAccessorFactory.java new file mode 100644 index 000000000..8feb2ec65 --- /dev/null +++ b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/IdFieldAccessorFactory.java @@ -0,0 +1,53 @@ +package org.springframework.datastore.graph.neo4j.fieldaccess; + +import org.springframework.datastore.graph.api.NodeBacked; + +import java.lang.reflect.Field; + +import static org.springframework.datastore.graph.neo4j.fieldaccess.DoReturn.doReturn; + +/** + * @author Michael Hunger + * @since 12.09.2010 + */ +public class IdFieldAccessorFactory implements FieldAccessorFactory { + @Override + public boolean accept(final Field f) { + return isIdField(f); + } + + private boolean isIdField(Field field) { + if (!field.getName().equals("id")) return false; + final Class type = field.getType(); + return type.equals(Long.class) || type.equals(long.class); + } + + @Override + public FieldAccessor forField(final Field field) { + return new IdFieldAccessor(field); + } + + public static class IdFieldAccessor implements FieldAccessor { + protected final Field field; + + public IdFieldAccessor(final Field field) { + this.field = field; + } + + @Override + public boolean isWriteable(NodeBacked nodeBacked) { + return false; + } + + @Override + public Object setValue(final NodeBacked nodeBacked, final Object newVal) { + return doReturn(null); + } + + @Override + public Object getValue(final NodeBacked nodeBacked) { + return doReturn(nodeBacked.getUnderlyingNode().getId()); + } + + } +} diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/IndexingNodePropertyFieldAccessorListener.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/IndexingNodePropertyFieldAccessorListener.java deleted file mode 100644 index f087ecad9..000000000 --- a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/IndexingNodePropertyFieldAccessorListener.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.springframework.datastore.graph.neo4j.fieldaccess; - -import org.neo4j.index.IndexService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Configurable; -import org.springframework.datastore.graph.api.NodeBacked; - -import java.lang.reflect.Field; - -/** - * @author Michael Hunger - * @since 12.09.2010 - */ -public class IndexingNodePropertyFieldAccessorListener implements FieldAccessListener { - protected final Field field; - private final IndexService indexService; - - public IndexingNodePropertyFieldAccessorListener(final Field field, final IndexService indexService) { - this.field = field; - this.indexService = indexService; - } - - @Override - public void valueChanged(final NodeBacked nodeBacked, final Object oldVal, final Object newVal) { - if (newVal==null) indexService.removeIndex(nodeBacked.getUnderlyingNode(),getPropertyName()); - else indexService.index(nodeBacked.getUnderlyingNode(), getPropertyName(),newVal); - } - - // todo - private String getPropertyName() { - return DelegatingFieldAccessorFactory.getNeo4jPropertyName(field); - } - - public static FieldAccessorListenerFactory factory() { - return new NodeBackedFieldAccessorListenerFactory(); - } - - @Configurable - private static class NodeBackedFieldAccessorListenerFactory implements FieldAccessorListenerFactory { - @Autowired - IndexService indexService; - - @Override - public boolean accept(final Field f) { - return NodePropertyFieldAccessor.factory().accept(f) || ConvertingNodePropertyFieldAccessor.factory().accept(f); - } - - @Override - public FieldAccessListener forField(final Field field) { - return new IndexingNodePropertyFieldAccessorListener(field,indexService); - } - } -} diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/IndexingNodePropertyFieldAccessorListenerFactory.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/IndexingNodePropertyFieldAccessorListenerFactory.java new file mode 100644 index 000000000..e7891175b --- /dev/null +++ b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/IndexingNodePropertyFieldAccessorListenerFactory.java @@ -0,0 +1,54 @@ +package org.springframework.datastore.graph.neo4j.fieldaccess; + +import org.neo4j.index.IndexService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Configurable; +import org.springframework.datastore.graph.api.NodeBacked; + +import java.lang.reflect.Field; + +@Configurable +class IndexingNodePropertyFieldAccessorListenerFactory implements FieldAccessorListenerFactory { + @Autowired + IndexService indexService; + + @Override + public boolean accept(final Field f) { + return new NodePropertyFieldAccessorFactory().accept(f) || new ConvertingNodePropertyFieldAccessorFactory().accept(f); + } + + @Override + public FieldAccessListener forField(final Field field) { + return new IndexingNodePropertyFieldAccessorListener(field,indexService); + } + + /** + * @author Michael Hunger + * @since 12.09.2010 + */ + public static class IndexingNodePropertyFieldAccessorListener implements FieldAccessListener { + protected final Field field; + private final IndexService indexService; + + public IndexingNodePropertyFieldAccessorListener(final Field field, final IndexService indexService) { + this.field = field; + this.indexService = indexService; + } + + @Override + public void valueChanged(final NodeBacked nodeBacked, final Object oldVal, final Object newVal) { + if (newVal==null) indexService.removeIndex(nodeBacked.getUnderlyingNode(),getPropertyName()); + else indexService.index(nodeBacked.getUnderlyingNode(), getPropertyName(),newVal); + } + + // todo + private String getPropertyName() { + return DelegatingFieldAccessorFactory.getNeo4jPropertyName(field); + } + + public static FieldAccessorListenerFactory factory() { + return new IndexingNodePropertyFieldAccessorListenerFactory(); + } + + } +} diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/NodePropertyFieldAccessor.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/NodePropertyFieldAccessor.java deleted file mode 100644 index 19c0797c7..000000000 --- a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/NodePropertyFieldAccessor.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.springframework.datastore.graph.neo4j.fieldaccess; - -import org.springframework.datastore.graph.api.NodeBacked; - -import java.lang.reflect.Field; - -import static org.springframework.datastore.graph.neo4j.fieldaccess.DoReturn.doReturn; - -/** - * @author Michael Hunger - * @since 12.09.2010 - */ -public class NodePropertyFieldAccessor implements FieldAccessor { - protected final Field field; - - public NodePropertyFieldAccessor(final Field field) { - this.field = field; - } - - @Override - public boolean isWriteable(NodeBacked nodeBacked) { - return true; - } - - @Override - public Object setValue(final NodeBacked nodeBacked, final Object newVal) { - nodeBacked.getUnderlyingNode().setProperty(getPropertyName(),newVal); - return newVal; - } - - @Override - public final Object getValue(final NodeBacked nodeBacked) { - return doReturn(doGetValue(nodeBacked)); - } - - protected Object doGetValue(NodeBacked nodeBacked) { - return nodeBacked.getUnderlyingNode().getProperty(getPropertyName()); - } - - private String getPropertyName() { - return DelegatingFieldAccessorFactory.getNeo4jPropertyName(field); - } - - public static FieldAccessorFactory factory() { - return new FieldAccessorFactory() { - @Override - public boolean accept(final Field f) { - return isNeo4jPropertyType(f.getType()); - } - - @Override - public FieldAccessor forField(final Field field) { - return new NodePropertyFieldAccessor(field); - } - - private boolean isNeo4jPropertyType(final Class fieldType) { - // todo: add array support - return fieldType.isPrimitive() - || (fieldType.isArray() && !fieldType.getComponentType().isArray() && isNeo4jPropertyType(fieldType.getComponentType())) - || fieldType.equals(String.class) - || fieldType.equals(Character.class) - || fieldType.equals(Boolean.class) - || (fieldType.getName().startsWith("java.lang") && Number.class.isAssignableFrom(fieldType)); - } - - }; - } -} diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/NodePropertyFieldAccessorFactory.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/NodePropertyFieldAccessorFactory.java new file mode 100644 index 000000000..95d8d2ca2 --- /dev/null +++ b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/NodePropertyFieldAccessorFactory.java @@ -0,0 +1,66 @@ +package org.springframework.datastore.graph.neo4j.fieldaccess; + +import org.springframework.datastore.graph.api.NodeBacked; + +import java.lang.reflect.Field; + +import static org.springframework.datastore.graph.neo4j.fieldaccess.DoReturn.doReturn; + +/** + * @author Michael Hunger + * @since 12.09.2010 + */ +public class NodePropertyFieldAccessorFactory implements FieldAccessorFactory { + @Override + public boolean accept(final Field f) { + return isNeo4jPropertyType(f.getType()); + } + + @Override + public FieldAccessor forField(final Field field) { + return new NodePropertyFieldAccessor(field); + } + + private boolean isNeo4jPropertyType(final Class fieldType) { + // todo: add array support + return fieldType.isPrimitive() + || (fieldType.isArray() && !fieldType.getComponentType().isArray() && isNeo4jPropertyType(fieldType.getComponentType())) + || fieldType.equals(String.class) + || fieldType.equals(Character.class) + || fieldType.equals(Boolean.class) + || (fieldType.getName().startsWith("java.lang") && Number.class.isAssignableFrom(fieldType)); + } + + public static class NodePropertyFieldAccessor implements FieldAccessor { + protected final Field field; + + public NodePropertyFieldAccessor(final Field field) { + this.field = field; + } + + @Override + public boolean isWriteable(NodeBacked nodeBacked) { + return true; + } + + @Override + public Object setValue(final NodeBacked nodeBacked, final Object newVal) { + nodeBacked.getUnderlyingNode().setProperty(getPropertyName(),newVal); + return newVal; + } + + @Override + public final Object getValue(final NodeBacked nodeBacked) { + return doReturn(doGetValue(nodeBacked)); + } + + protected Object doGetValue(NodeBacked nodeBacked) { + return nodeBacked.getUnderlyingNode().getProperty(getPropertyName()); + } + + private String getPropertyName() { + return DelegatingFieldAccessorFactory.getNeo4jPropertyName(field); + } + + } +} diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessor.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessor.java deleted file mode 100644 index 1cb8d979e..000000000 --- a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessor.java +++ /dev/null @@ -1,106 +0,0 @@ -package org.springframework.datastore.graph.neo4j.fieldaccess; - -import org.neo4j.graphdb.*; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Configurable; -import org.springframework.dao.InvalidDataAccessApiUsageException; -import org.springframework.datastore.graph.api.GraphEntityRelationshipEntity; -import org.springframework.datastore.graph.api.NodeBacked; -import org.springframework.datastore.graph.api.RelationshipBacked; -import org.springframework.datastore.graph.neo4j.support.GraphDatabaseContext; - -import java.lang.reflect.Field; -import java.util.HashSet; -import java.util.Set; - -import static org.springframework.datastore.graph.neo4j.fieldaccess.DoReturn.doReturn; - -public class OneToNRelationshipEntityFieldAccessor extends AbstractRelationshipFieldAccessor { - - public OneToNRelationshipEntityFieldAccessor(final RelationshipType type, final Direction direction, final Class elementClass, final GraphDatabaseContext graphDatabaseContext) { - super(elementClass, graphDatabaseContext, direction, type); - } - - @Override - public Object setValue(final NodeBacked entity, final Object newVal) { - throw new InvalidDataAccessApiUsageException("Cannot set read-only relationship entity field."); - } - - @Override - public boolean isWriteable(NodeBacked nodeBacked) { - return false; - } - - @Override - public Object getValue(final NodeBacked entity) { - checkUnderlyingNode(entity); - final Set result = createEntitySetFromRelationships(entity); - return doReturn(new ManagedFieldAccessorSet(entity, result, this)); - } - - private Set createEntitySetFromRelationships(final NodeBacked entity) { - final Set result = new HashSet(); - for (final Relationship rel : getStatesFromEntity(entity)) { - final RelationshipBacked relationshipEntity = (RelationshipBacked) graphDatabaseContext.createEntityFromState(rel, (Class) relatedType); - result.add(relationshipEntity); - } - return result; - } - - @Override - protected Iterable getStatesFromEntity(final NodeBacked entity) { - return entity.getUnderlyingNode().getRelationships(type, direction); - } - - @Override - protected Relationship obtainSingleRelationship(final Node start, final Relationship end) { - return null; - } - - @Override - protected Node getState(final NodeBacked nodeBacked) { - return nodeBacked.getUnderlyingNode(); - } - - public static FieldAccessorFactory factory() { - return new RelationshipEntityFieldAccessorFactory(); - } - - @Configurable - private static class RelationshipEntityFieldAccessorFactory implements FieldAccessorFactory { - @Autowired - private GraphDatabaseContext graphDatabaseContext; - - @Override - public boolean accept(final Field f) { - return Iterable.class.isAssignableFrom(f.getType()) && hasValidRelationshipAnnotation(f); - } - - @Override - public FieldAccessor forField(final Field field) { - final GraphEntityRelationshipEntity relEntityAnnotation = getRelationshipAnnotation(field); - return new OneToNRelationshipEntityFieldAccessor(typeFrom(relEntityAnnotation), dirFrom(relEntityAnnotation), targetFrom(relEntityAnnotation), graphDatabaseContext); - } - - private boolean hasValidRelationshipAnnotation(final Field f) { - final GraphEntityRelationshipEntity relEntityAnnotation = getRelationshipAnnotation(f); - return relEntityAnnotation != null && !RelationshipBacked.class.equals(relEntityAnnotation.elementClass()); - } - - private GraphEntityRelationshipEntity getRelationshipAnnotation(final Field field) { - return field.getAnnotation(GraphEntityRelationshipEntity.class); - } - - private Class targetFrom(final GraphEntityRelationshipEntity relEntityAnnotation) { - return relEntityAnnotation.elementClass(); - } - - private Direction dirFrom(final GraphEntityRelationshipEntity relEntityAnnotation) { - return relEntityAnnotation.direction().toNeo4jDir(); - } - - private DynamicRelationshipType typeFrom(final GraphEntityRelationshipEntity relEntityAnnotation) { - return DynamicRelationshipType.withName(relEntityAnnotation.type()); - } - } -} diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessorFactory.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessorFactory.java new file mode 100644 index 000000000..e5bff897b --- /dev/null +++ b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessorFactory.java @@ -0,0 +1,103 @@ +package org.springframework.datastore.graph.neo4j.fieldaccess; + +import org.neo4j.graphdb.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Configurable; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.datastore.graph.api.GraphEntityRelationshipEntity; +import org.springframework.datastore.graph.api.NodeBacked; +import org.springframework.datastore.graph.api.RelationshipBacked; +import org.springframework.datastore.graph.neo4j.support.GraphDatabaseContext; + +import java.lang.reflect.Field; +import java.util.HashSet; +import java.util.Set; + +import static org.springframework.datastore.graph.neo4j.fieldaccess.DoReturn.doReturn; + +@Configurable +public class OneToNRelationshipEntityFieldAccessorFactory implements FieldAccessorFactory { + @Autowired + private GraphDatabaseContext graphDatabaseContext; + + @Override + public boolean accept(final Field f) { + return Iterable.class.isAssignableFrom(f.getType()) && hasValidRelationshipAnnotation(f); + } + + @Override + public FieldAccessor forField(final Field field) { + final GraphEntityRelationshipEntity relEntityAnnotation = getRelationshipAnnotation(field); + return new OneToNRelationshipEntityFieldAccessor(typeFrom(relEntityAnnotation), dirFrom(relEntityAnnotation), targetFrom(relEntityAnnotation), graphDatabaseContext); + } + + private boolean hasValidRelationshipAnnotation(final Field f) { + final GraphEntityRelationshipEntity relEntityAnnotation = getRelationshipAnnotation(f); + return relEntityAnnotation != null && !RelationshipBacked.class.equals(relEntityAnnotation.elementClass()); + } + + private GraphEntityRelationshipEntity getRelationshipAnnotation(final Field field) { + return field.getAnnotation(GraphEntityRelationshipEntity.class); + } + + private Class targetFrom(final GraphEntityRelationshipEntity relEntityAnnotation) { + return relEntityAnnotation.elementClass(); + } + + private Direction dirFrom(final GraphEntityRelationshipEntity relEntityAnnotation) { + return relEntityAnnotation.direction().toNeo4jDir(); + } + + private DynamicRelationshipType typeFrom(final GraphEntityRelationshipEntity relEntityAnnotation) { + return DynamicRelationshipType.withName(relEntityAnnotation.type()); + } + + public static class OneToNRelationshipEntityFieldAccessor extends AbstractRelationshipFieldAccessor { + + public OneToNRelationshipEntityFieldAccessor(final RelationshipType type, final Direction direction, final Class elementClass, final GraphDatabaseContext graphDatabaseContext) { + super(elementClass, graphDatabaseContext, direction, type); + } + + @Override + public Object setValue(final NodeBacked entity, final Object newVal) { + throw new InvalidDataAccessApiUsageException("Cannot set read-only relationship entity field."); + } + + @Override + public boolean isWriteable(NodeBacked nodeBacked) { + return false; + } + + @Override + public Object getValue(final NodeBacked entity) { + checkUnderlyingNode(entity); + final Set result = createEntitySetFromRelationships(entity); + return doReturn(new ManagedFieldAccessorSet(entity, result, this)); + } + + private Set createEntitySetFromRelationships(final NodeBacked entity) { + final Set result = new HashSet(); + for (final Relationship rel : getStatesFromEntity(entity)) { + final RelationshipBacked relationshipEntity = (RelationshipBacked) graphDatabaseContext.createEntityFromState(rel, (Class) relatedType); + result.add(relationshipEntity); + } + return result; + } + + @Override + protected Iterable getStatesFromEntity(final NodeBacked entity) { + return entity.getUnderlyingNode().getRelationships(type, direction); + } + + @Override + protected Relationship obtainSingleRelationship(final Node start, final Relationship end) { + return null; + } + + @Override + protected Node getState(final NodeBacked nodeBacked) { + return nodeBacked.getUnderlyingNode(); + } + + } +} diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/OneToNRelationshipFieldAccessor.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/OneToNRelationshipFieldAccessor.java deleted file mode 100644 index 11b4c8ff1..000000000 --- a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/OneToNRelationshipFieldAccessor.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.springframework.datastore.graph.neo4j.fieldaccess; - -import org.neo4j.graphdb.Direction; -import org.neo4j.graphdb.Node; -import org.neo4j.graphdb.RelationshipType; -import org.springframework.datastore.graph.api.GraphEntityRelationship; -import org.springframework.datastore.graph.api.NodeBacked; -import org.springframework.datastore.graph.neo4j.support.GraphDatabaseContext; - -import java.lang.reflect.Field; -import java.util.Collection; -import java.util.Collections; -import java.util.Set; - -import static org.springframework.datastore.graph.neo4j.fieldaccess.DoReturn.doReturn; - -public class OneToNRelationshipFieldAccessor extends NodeToNodesRelationshipFieldAccessor { - - public OneToNRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class elementClass, final GraphDatabaseContext graphDatabaseContext) { - super(elementClass, graphDatabaseContext, direction, type); - } - - public Object setValue(final NodeBacked entity, final Object newVal) { - final Node node = checkUnderlyingNode(entity); - if (newVal == null) { - removeMissingRelationships(node, Collections.emptySet()); - return null; - } - final Set targetNodes = checkTargetIsSetOfNodebacked(newVal); - checkNoCircularReference(node, targetNodes); - removeMissingRelationships(node, targetNodes); - createAddedRelationships(node, targetNodes); - return createManagedSet(entity, (Set) newVal); - } - - @Override - public Object getValue(final NodeBacked entity) { - checkUnderlyingNode(entity); - final Set result = createEntitySetFromRelationshipEndNodes(entity); - return doReturn(createManagedSet(entity, result)); - } - - public static FieldAccessorFactory factory() { - return new RelationshipFieldAccessorFactory() { - @Override - public boolean accept(final Field f) { - return Collection.class.isAssignableFrom(f.getType()) && hasValidRelationshipAnnotation(f); - } - - @Override - public FieldAccessor forField(final Field field) { - final GraphEntityRelationship relAnnotation = getRelationshipAnnotation(field); - return new OneToNRelationshipFieldAccessor(typeFrom(relAnnotation), dirFrom(relAnnotation), targetFrom(relAnnotation), graphDatabaseContext); - } - - }; - } -} - - \ No newline at end of file diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/OneToNRelationshipFieldAccessorFactory.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/OneToNRelationshipFieldAccessorFactory.java new file mode 100644 index 000000000..a3f9cb531 --- /dev/null +++ b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/OneToNRelationshipFieldAccessorFactory.java @@ -0,0 +1,56 @@ +package org.springframework.datastore.graph.neo4j.fieldaccess; + +import org.neo4j.graphdb.Direction; +import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.RelationshipType; +import org.springframework.datastore.graph.api.GraphEntityRelationship; +import org.springframework.datastore.graph.api.NodeBacked; +import org.springframework.datastore.graph.neo4j.support.GraphDatabaseContext; + +import java.lang.reflect.Field; +import java.util.Collection; +import java.util.Collections; +import java.util.Set; + +import static org.springframework.datastore.graph.neo4j.fieldaccess.DoReturn.doReturn; + +public class OneToNRelationshipFieldAccessorFactory extends RelationshipFieldAccessorFactory { + @Override + public boolean accept(final Field f) { + return Collection.class.isAssignableFrom(f.getType()) && hasValidRelationshipAnnotation(f); + } + + @Override + public FieldAccessor forField(final Field field) { + final GraphEntityRelationship relAnnotation = getRelationshipAnnotation(field); + return new OneToNRelationshipFieldAccessor(typeFrom(relAnnotation), dirFrom(relAnnotation), targetFrom(relAnnotation), graphDatabaseContext); + } + + public static class OneToNRelationshipFieldAccessor extends NodeToNodesRelationshipFieldAccessor { + + public OneToNRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class elementClass, final GraphDatabaseContext graphDatabaseContext) { + super(elementClass, graphDatabaseContext, direction, type); + } + + public Object setValue(final NodeBacked entity, final Object newVal) { + final Node node = checkUnderlyingNode(entity); + if (newVal == null) { + removeMissingRelationships(node, Collections.emptySet()); + return null; + } + final Set targetNodes = checkTargetIsSetOfNodebacked(newVal); + checkNoCircularReference(node, targetNodes); + removeMissingRelationships(node, targetNodes); + createAddedRelationships(node, targetNodes); + return createManagedSet(entity, (Set) newVal); + } + + @Override + public Object getValue(final NodeBacked entity) { + checkUnderlyingNode(entity); + final Set result = createEntitySetFromRelationshipEndNodes(entity); + return doReturn(createManagedSet(entity, result)); + } + + } +} diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/ReadOnlyOneToNRelationshipFieldAccessor.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/ReadOnlyOneToNRelationshipFieldAccessor.java deleted file mode 100644 index 75103cd95..000000000 --- a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/ReadOnlyOneToNRelationshipFieldAccessor.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.springframework.datastore.graph.neo4j.fieldaccess; - -import java.lang.reflect.Field; - -import org.neo4j.graphdb.Direction; -import org.neo4j.graphdb.RelationshipType; -import org.springframework.dao.InvalidDataAccessApiUsageException; -import org.springframework.datastore.graph.api.GraphEntityRelationship; -import org.springframework.datastore.graph.api.NodeBacked; -import org.springframework.datastore.graph.neo4j.support.GraphDatabaseContext; - -public class ReadOnlyOneToNRelationshipFieldAccessor extends OneToNRelationshipFieldAccessor { - - public ReadOnlyOneToNRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class elementClass, final GraphDatabaseContext graphDatabaseContext) { - super(type,direction,elementClass, graphDatabaseContext); - } - - @Override - public boolean isWriteable(NodeBacked nodeBacked) { - return false; - } - - public Object setValue(final NodeBacked entity, final Object newVal) { - throw new InvalidDataAccessApiUsageException("Cannot set read-only relationship entity field."); - } - - public static FieldAccessorFactory factory() { - return new RelationshipFieldAccessorFactory() { - @Override - public boolean accept(final Field f) { - return Iterable.class.equals(f.getType()) && hasValidRelationshipAnnotation(f); - } - - @Override - public FieldAccessor forField(final Field field) { - final GraphEntityRelationship relAnnotation = getRelationshipAnnotation(field); - return new ReadOnlyOneToNRelationshipFieldAccessor(typeFrom(relAnnotation), dirFrom(relAnnotation), targetFrom(relAnnotation), graphDatabaseContext); - } - - }; - } - -} diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/ReadOnlyOneToNRelationshipFieldAccessorFactory.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/ReadOnlyOneToNRelationshipFieldAccessorFactory.java new file mode 100644 index 000000000..4b708524e --- /dev/null +++ b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/ReadOnlyOneToNRelationshipFieldAccessorFactory.java @@ -0,0 +1,40 @@ +package org.springframework.datastore.graph.neo4j.fieldaccess; + +import org.neo4j.graphdb.Direction; +import org.neo4j.graphdb.RelationshipType; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.datastore.graph.api.GraphEntityRelationship; +import org.springframework.datastore.graph.api.NodeBacked; +import org.springframework.datastore.graph.neo4j.support.GraphDatabaseContext; + +import java.lang.reflect.Field; + +public class ReadOnlyOneToNRelationshipFieldAccessorFactory extends RelationshipFieldAccessorFactory { + @Override + public boolean accept(final Field f) { + return Iterable.class.equals(f.getType()) && hasValidRelationshipAnnotation(f); + } + + @Override + public FieldAccessor forField(final Field field) { + final GraphEntityRelationship relAnnotation = getRelationshipAnnotation(field); + return new ReadOnlyOneToNRelationshipFieldAccessor(typeFrom(relAnnotation), dirFrom(relAnnotation), targetFrom(relAnnotation), graphDatabaseContext); + } + + public static class ReadOnlyOneToNRelationshipFieldAccessor extends OneToNRelationshipFieldAccessorFactory.OneToNRelationshipFieldAccessor { + + public ReadOnlyOneToNRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class elementClass, final GraphDatabaseContext graphDatabaseContext) { + super(type,direction,elementClass, graphDatabaseContext); + } + + @Override + public boolean isWriteable(NodeBacked nodeBacked) { + return false; + } + + public Object setValue(final NodeBacked entity, final Object newVal) { + throw new InvalidDataAccessApiUsageException("Cannot set read-only relationship entity field."); + } + + } +} diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/SingleRelationshipFieldAccessor.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/SingleRelationshipFieldAccessor.java deleted file mode 100644 index f4bff76ee..000000000 --- a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/SingleRelationshipFieldAccessor.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.springframework.datastore.graph.neo4j.fieldaccess; - -import org.neo4j.graphdb.Direction; -import org.neo4j.graphdb.Node; -import org.neo4j.graphdb.RelationshipType; -import org.springframework.datastore.graph.api.GraphEntityRelationship; -import org.springframework.datastore.graph.api.NodeBacked; -import org.springframework.datastore.graph.neo4j.support.GraphDatabaseContext; - -import java.lang.reflect.Field; -import java.util.Collections; -import java.util.Set; - -public class SingleRelationshipFieldAccessor extends NodeToNodesRelationshipFieldAccessor { - public SingleRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class clazz, final GraphDatabaseContext graphDatabaseContext) { - super(clazz, graphDatabaseContext, direction, type); - } - - @Override - public Object setValue(final NodeBacked entity, final Object newVal) { - final Node node=checkUnderlyingNode(entity); - if (newVal == null) { - removeMissingRelationships(node, Collections.emptySet()); - return null; - } - final Set target=checkTargetIsSetOfNodebacked(Collections.singleton(newVal)); - checkNoCircularReference(node,target); - removeMissingRelationships(node, target); - createAddedRelationships(node,target); - return newVal; - } - - @Override - public Object getValue(final NodeBacked entity) { - checkUnderlyingNode(entity); - final Set result = createEntitySetFromRelationshipEndNodes(entity); - return result.isEmpty() ? null : result.iterator().next(); - } - - public static FieldAccessorFactory factory() { - return new RelationshipFieldAccessorFactory() { - @Override - public boolean accept(final Field f) { - return NodeBacked.class.isAssignableFrom(f.getType()); - } - - @Override - public FieldAccessor forField(final Field field) { - final GraphEntityRelationship relAnnotation = getRelationshipAnnotation(field); - if (relAnnotation == null) - return new SingleRelationshipFieldAccessor(typeFrom(field), Direction.OUTGOING, targetFrom(field), graphDatabaseContext); - return new SingleRelationshipFieldAccessor(typeFrom(relAnnotation), dirFrom(relAnnotation), targetFrom(field), graphDatabaseContext); - } - }; - } - -} \ No newline at end of file diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/SingleRelationshipFieldAccessorFactory.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/SingleRelationshipFieldAccessorFactory.java new file mode 100644 index 000000000..3b75e9f96 --- /dev/null +++ b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/SingleRelationshipFieldAccessorFactory.java @@ -0,0 +1,55 @@ +package org.springframework.datastore.graph.neo4j.fieldaccess; + +import org.neo4j.graphdb.Direction; +import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.RelationshipType; +import org.springframework.datastore.graph.api.GraphEntityRelationship; +import org.springframework.datastore.graph.api.NodeBacked; +import org.springframework.datastore.graph.neo4j.support.GraphDatabaseContext; + +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.Set; + +public class SingleRelationshipFieldAccessorFactory extends RelationshipFieldAccessorFactory { + @Override + public boolean accept(final Field f) { + return NodeBacked.class.isAssignableFrom(f.getType()); + } + + @Override + public FieldAccessor forField(final Field field) { + final GraphEntityRelationship relAnnotation = getRelationshipAnnotation(field); + if (relAnnotation == null) + return new SingleRelationshipFieldAccessor(typeFrom(field), Direction.OUTGOING, targetFrom(field), graphDatabaseContext); + return new SingleRelationshipFieldAccessor(typeFrom(relAnnotation), dirFrom(relAnnotation), targetFrom(field), graphDatabaseContext); + } + + public static class SingleRelationshipFieldAccessor extends NodeToNodesRelationshipFieldAccessor { + public SingleRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class clazz, final GraphDatabaseContext graphDatabaseContext) { + super(clazz, graphDatabaseContext, direction, type); + } + + @Override + public Object setValue(final NodeBacked entity, final Object newVal) { + final Node node=checkUnderlyingNode(entity); + if (newVal == null) { + removeMissingRelationships(node, Collections.emptySet()); + return null; + } + final Set target=checkTargetIsSetOfNodebacked(Collections.singleton(newVal)); + checkNoCircularReference(node,target); + removeMissingRelationships(node, target); + createAddedRelationships(node,target); + return newVal; + } + + @Override + public Object getValue(final NodeBacked entity) { + checkUnderlyingNode(entity); + final Set result = createEntitySetFromRelationshipEndNodes(entity); + return result.isEmpty() ? null : result.iterator().next(); + } + + } +} diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/TransientFieldAccessor.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/TransientFieldAccessor.java deleted file mode 100644 index 59812d444..000000000 --- a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/TransientFieldAccessor.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.springframework.datastore.graph.neo4j.fieldaccess; - -import org.springframework.datastore.graph.api.NodeBacked; - -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; - -/** - * @author Michael Hunger - * @since 12.09.2010 - */ -public class TransientFieldAccessor implements FieldAccessor { - protected final Field field; - - public TransientFieldAccessor(final Field field) { - this.field = field; - } - - @Override - public Object setValue(final NodeBacked nodeBacked, final Object newVal) { - return newVal; - } - - @Override - public boolean isWriteable(NodeBacked nodeBacked) { - return true; - } - - @Override - public Object getValue(final NodeBacked nodeBacked) { - return null; - } - - public static FieldAccessorFactory factory() { - return new FieldAccessorFactory() { - @Override - public boolean accept(final Field f) { - return Modifier.isTransient(f.getModifiers()); - } - - @Override - public FieldAccessor forField(final Field field) { - return new TransientFieldAccessor(field); - } - }; - } -} diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/TransientFieldAccessorFactory.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/TransientFieldAccessorFactory.java new file mode 100644 index 000000000..486d0e40b --- /dev/null +++ b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/TransientFieldAccessorFactory.java @@ -0,0 +1,46 @@ +package org.springframework.datastore.graph.neo4j.fieldaccess; + +import org.springframework.datastore.graph.api.NodeBacked; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +public class TransientFieldAccessorFactory implements FieldAccessorFactory { + @Override + public boolean accept(final Field f) { + return Modifier.isTransient(f.getModifiers()); + } + + @Override + public FieldAccessor forField(final Field field) { + return new TransientFieldAccessor(field); + } + + /** + * @author Michael Hunger + * @since 12.09.2010 + */ + public static class TransientFieldAccessor implements FieldAccessor { + protected final Field field; + + public TransientFieldAccessor(final Field field) { + this.field = field; + } + + @Override + public Object setValue(final NodeBacked nodeBacked, final Object newVal) { + return newVal; + } + + @Override + public boolean isWriteable(NodeBacked nodeBacked) { + return true; + } + + @Override + public Object getValue(final NodeBacked nodeBacked) { + return null; + } + + } +} diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/TraversalFieldAccessor.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/TraversalFieldAccessor.java deleted file mode 100644 index 98dfa77b4..000000000 --- a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/TraversalFieldAccessor.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.springframework.datastore.graph.neo4j.fieldaccess; - -import org.neo4j.graphdb.traversal.TraversalDescription; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Configurable; -import org.springframework.dao.InvalidDataAccessApiUsageException; -import org.springframework.datastore.graph.api.FieldTraversalDescriptionBuilder; -import org.springframework.datastore.graph.api.GraphEntityTraversal; -import org.springframework.datastore.graph.api.NodeBacked; -import org.springframework.datastore.graph.neo4j.finder.Finder; -import org.springframework.datastore.graph.neo4j.finder.FinderFactory; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; - -import static org.springframework.datastore.graph.neo4j.fieldaccess.DoReturn.doReturn; - -/** - * @author Michael Hunger - * @since 12.09.2010 - */ -public class TraversalFieldAccessor implements FieldAccessor { - protected final Field field; - private final FinderFactory finderFactory; - private final FieldTraversalDescriptionBuilder fieldTraversalDescriptionBuilder; - private Class target; - - public TraversalFieldAccessor(final Field field, FinderFactory finderFactory) { - this.field = field; - this.finderFactory = finderFactory; - final GraphEntityTraversal graphEntityTraversal = field.getAnnotation(GraphEntityTraversal.class); - this.target = graphEntityTraversal.elementClass(); - this.fieldTraversalDescriptionBuilder = createTraversalDescription(graphEntityTraversal); - } - - @Override - public boolean isWriteable(NodeBacked nodeBacked) { - return false; - } - - @Override - public Object setValue(final NodeBacked nodeBacked, final Object newVal) { - throw new InvalidDataAccessApiUsageException("Cannot set readonly traversal description field " + field); - } - - @Override - public Object getValue(final NodeBacked nodeBacked) { - final Finder finder = finderFactory.getFinderForClass(target); - final TraversalDescription traversalDescription = fieldTraversalDescriptionBuilder.build(nodeBacked,field); - return doReturn(finder.findAllByTraversal(nodeBacked, traversalDescription)); - } - - - private FieldTraversalDescriptionBuilder createTraversalDescription(final GraphEntityTraversal graphEntityTraversal) { - try { - final Class traversalDescriptionClass = graphEntityTraversal.traversalBuilder(); - final Constructor constructor = traversalDescriptionClass.getDeclaredConstructor(); - constructor.setAccessible(true); - return constructor.newInstance(); - } catch (Exception e) { - throw new RuntimeException("Error creating TraversalDescription from " + field,e); - } - } - - public static FieldAccessorFactory factory() { - return new TraversalFieldAccessorFactory(); - } - - @Configurable - private static class TraversalFieldAccessorFactory implements FieldAccessorFactory { - @Autowired - private FinderFactory finderFactory; - - @Override - public boolean accept(final Field f) { - final GraphEntityTraversal graphEntityTraversal = f.getAnnotation(GraphEntityTraversal.class); - return graphEntityTraversal != null - && graphEntityTraversal.traversalBuilder() != TraversalDescription.class - && f.getType().equals(Iterable.class); - } - - - @Override - public FieldAccessor forField(final Field field) { - return new TraversalFieldAccessor(field, finderFactory); - } - } -} diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/TraversalFieldAccessorFactory.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/TraversalFieldAccessorFactory.java new file mode 100644 index 000000000..32d18ad52 --- /dev/null +++ b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/TraversalFieldAccessorFactory.java @@ -0,0 +1,85 @@ +package org.springframework.datastore.graph.neo4j.fieldaccess; + +import org.neo4j.graphdb.traversal.TraversalDescription; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Configurable; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.datastore.graph.api.FieldTraversalDescriptionBuilder; +import org.springframework.datastore.graph.api.GraphEntityTraversal; +import org.springframework.datastore.graph.api.NodeBacked; +import org.springframework.datastore.graph.neo4j.finder.Finder; +import org.springframework.datastore.graph.neo4j.finder.FinderFactory; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; + +import static org.springframework.datastore.graph.neo4j.fieldaccess.DoReturn.doReturn; + +@Configurable +public class TraversalFieldAccessorFactory implements FieldAccessorFactory { + @Autowired + private FinderFactory finderFactory; + + @Override + public boolean accept(final Field f) { + final GraphEntityTraversal graphEntityTraversal = f.getAnnotation(GraphEntityTraversal.class); + return graphEntityTraversal != null + && graphEntityTraversal.traversalBuilder() != TraversalDescription.class + && f.getType().equals(Iterable.class); + } + + + @Override + public FieldAccessor forField(final Field field) { + return new TraversalFieldAccessor(field, finderFactory); + } + + /** + * @author Michael Hunger + * @since 12.09.2010 + */ + public static class TraversalFieldAccessor implements FieldAccessor { + protected final Field field; + private final FinderFactory finderFactory; + private final FieldTraversalDescriptionBuilder fieldTraversalDescriptionBuilder; + private Class target; + + public TraversalFieldAccessor(final Field field, FinderFactory finderFactory) { + this.field = field; + this.finderFactory = finderFactory; + final GraphEntityTraversal graphEntityTraversal = field.getAnnotation(GraphEntityTraversal.class); + this.target = graphEntityTraversal.elementClass(); + this.fieldTraversalDescriptionBuilder = createTraversalDescription(graphEntityTraversal); + } + + @Override + public boolean isWriteable(NodeBacked nodeBacked) { + return false; + } + + @Override + public Object setValue(final NodeBacked nodeBacked, final Object newVal) { + throw new InvalidDataAccessApiUsageException("Cannot set readonly traversal description field " + field); + } + + @Override + public Object getValue(final NodeBacked nodeBacked) { + final Finder finder = finderFactory.getFinderForClass(target); + final TraversalDescription traversalDescription = fieldTraversalDescriptionBuilder.build(nodeBacked,field); + return doReturn(finder.findAllByTraversal(nodeBacked, traversalDescription)); + } + + + private FieldTraversalDescriptionBuilder createTraversalDescription(final GraphEntityTraversal graphEntityTraversal) { + try { + final Class traversalDescriptionClass = graphEntityTraversal.traversalBuilder(); + final Constructor constructor = traversalDescriptionClass.getDeclaredConstructor(); + constructor.setAccessible(true); + return constructor.newInstance(); + } catch (Exception e) { + throw new RuntimeException("Error creating TraversalDescription from " + field,e); + } + } + + } +}