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 index 823ee84a4..ecc8eddb0 100644 --- a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/ConvertingNodePropertyFieldAccessor.java +++ b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/ConvertingNodePropertyFieldAccessor.java @@ -41,27 +41,30 @@ public class ConvertingNodePropertyFieldAccessor extends NodePropertyFieldAccess } public static FieldAccessorFactory factory() { - return new FieldAccessorFactory() { - @Autowired - ConversionService conversionService; + return new ConvertingNodePropertyFieldAccessorFactory(); + } - @Override - public boolean accept(final Field field) { - return isSerializableField(field) && isDeserializableField(field); - } + @Configurable + private static class ConvertingNodePropertyFieldAccessorFactory implements FieldAccessorFactory { + @Autowired + ConversionService conversionService; - @Override - public FieldAccessor forField(final Field field) { - return new ConvertingNodePropertyFieldAccessor(field,conversionService); - } + @Override + public boolean accept(final Field field) { + return isSerializableField(field) && isDeserializableField(field); + } - private boolean isSerializableField(final Field field) { - return !DelegatingFieldAccessorFactory.isRelationshipField(field) && conversionService.canConvert(field.getType(), String.class); - } + @Override + public FieldAccessor forField(final Field field) { + return new ConvertingNodePropertyFieldAccessor(field,conversionService); + } - private boolean isDeserializableField(final Field field) { - return !DelegatingFieldAccessorFactory.isRelationshipField(field) && conversionService.canConvert(String.class, field.getType()); - } - }; + private boolean isSerializableField(final Field field) { + return !DelegatingFieldAccessorFactory.isRelationshipField(field) && conversionService.canConvert(field.getType(), String.class); + } + + private boolean isDeserializableField(final Field field) { + return !DelegatingFieldAccessorFactory.isRelationshipField(field) && conversionService.canConvert(String.class, 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 1b7d7bcad..1dafbac76 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 @@ -1,17 +1,14 @@ package org.springframework.datastore.graph.neo4j.fieldaccess; +import org.springframework.datastore.graph.api.*; +import org.springframework.datastore.graph.neo4j.support.GraphDatabaseContext; + import java.lang.reflect.Field; -import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; -import org.neo4j.graphdb.Direction; -import org.neo4j.graphdb.DynamicRelationshipType; -import org.springframework.datastore.graph.api.*; -import org.springframework.datastore.graph.neo4j.support.GraphDatabaseContext; - public class DelegatingFieldAccessorFactory implements FieldAccessorFactory { private final GraphDatabaseContext graphDatabaseContext; @@ -25,6 +22,8 @@ public class DelegatingFieldAccessorFactory implements FieldAccessorFactory> fieldAccessorFactories = Arrays.>asList( + IdFieldAccessor.factory(), + TransientFieldAccessor.factory(), NodePropertyFieldAccessor.factory(), ConvertingNodePropertyFieldAccessor.factory(), SingleRelationshipFieldAccessor.factory(), @@ -37,7 +36,7 @@ public class DelegatingFieldAccessorFactory implements FieldAccessorFactory fieldAccessorFactory : fieldAccessorFactories) { if (fieldAccessorFactory.accept(field)) { System.out.println("Factory " + fieldAccessorFactory + " used for field: " + field); @@ -48,37 +47,6 @@ public class DelegatingFieldAccessorFactory implements FieldAccessorFactory targetFrom(Field field) { - return (Class) field.getType(); - } - - private Class targetFrom(GraphEntityRelationship relAnnotation) { - return relAnnotation.elementClass(); - } - - private Direction dirFrom(GraphEntityRelationship relAnnotation) { - return relAnnotation.direction().toNeo4jDir(); - } - - private DynamicRelationshipType typeFrom(Field field) { - return DynamicRelationshipType.withName(getNeo4jPropertyName(field)); - } - - private Class targetFrom(GraphEntityRelationshipEntity relEntityAnnotation) { - return relEntityAnnotation.elementClass(); - } - - private Direction dirFrom(GraphEntityRelationshipEntity relEntityAnnotation) { - return relEntityAnnotation.direction().toNeo4jDir(); - } - private DynamicRelationshipType typeFrom(GraphEntityRelationshipEntity relEntityAnnotation) { - return DynamicRelationshipType.withName(relEntityAnnotation.type()); - } - - private DynamicRelationshipType typeFrom(GraphEntityRelationship relAnnotation) { - return DynamicRelationshipType.withName(relAnnotation.type()); - } - public static boolean isRelationshipField(Field f) { return isSingleRelationshipField(f) || isOneToNRelationshipField(f) @@ -124,11 +92,11 @@ public class DelegatingFieldAccessorFactory implements FieldAccessorFactory> listenersFor(Field field) { - List> result=new ArrayList>(); + public List> listenersFor(Field field) { + List> result=new ArrayList>(); for (FieldAccessorListenerFactory fieldAccessorListenerFactory : fieldAccessorListenerFactories) { if (fieldAccessorListenerFactory.accept(field)) { - final FieldAccessor listener = (FieldAccessor) fieldAccessorListenerFactory.forField(field); + final FieldAccessListener listener = (FieldAccessListener) fieldAccessorListenerFactory.forField(field); result.add(listener); } } diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/EntityStateAccessors.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/EntityStateAccessors.java index 61f6e7103..b3fc0292c 100644 --- a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/EntityStateAccessors.java +++ b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/EntityStateAccessors.java @@ -1,11 +1,6 @@ package org.springframework.datastore.graph.neo4j.fieldaccess; -import org.neo4j.graphdb.Node; -import org.neo4j.graphdb.Relationship; -import org.springframework.datastore.graph.api.NodeBacked; -import org.springframework.datastore.graph.api.RelationshipBacked; import org.springframework.datastore.graph.neo4j.support.GraphDatabaseContext; -import org.springframework.persistence.support.EntityInstantiator; import org.springframework.util.ReflectionUtils; import java.lang.reflect.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 new file mode 100644 index 000000000..7249dac59 --- /dev/null +++ b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/IdFieldAccessor.java @@ -0,0 +1,48 @@ +package org.springframework.datastore.graph.neo4j.fieldaccess; + +import org.springframework.datastore.graph.api.NodeBacked; + +import java.lang.reflect.Field; + +/** + * @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 Object setValue(final NodeBacked nodeBacked, final Object newVal) { + return null; + } + + @Override + public Object getValue(final NodeBacked nodeBacked) { + return 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/TransientFieldAccessor.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/TransientFieldAccessor.java new file mode 100644 index 000000000..5d4d42016 --- /dev/null +++ b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/TransientFieldAccessor.java @@ -0,0 +1,42 @@ +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 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/spi/node/Neo4jNodeBacking.aj b/src/main/java/org/springframework/datastore/graph/neo4j/spi/node/Neo4jNodeBacking.aj index 8bb6d9573..fcca8b348 100644 --- a/src/main/java/org/springframework/datastore/graph/neo4j/spi/node/Neo4jNodeBacking.aj +++ b/src/main/java/org/springframework/datastore/graph/neo4j/spi/node/Neo4jNodeBacking.aj @@ -8,7 +8,6 @@ import org.aspectj.lang.reflect.FieldSignature; import org.neo4j.graphdb.*; import org.neo4j.graphdb.traversal.*; import org.neo4j.graphdb.traversal.Traverser; -import org.neo4j.helpers.collection.IterableWrapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.InvalidDataAccessResourceUsageException; import org.springframework.datastore.graph.api.GraphEntityProperty; @@ -17,10 +16,10 @@ import org.springframework.datastore.graph.api.RelationshipBacked; import org.springframework.datastore.graph.api.GraphEntity; import org.springframework.datastore.graph.neo4j.fieldaccess.DelegatingFieldAccessorFactory; +import org.springframework.datastore.graph.neo4j.fieldaccess.EntityStateAccessors; import org.springframework.datastore.graph.neo4j.fieldaccess.FieldAccessor; import org.springframework.datastore.graph.neo4j.support.GraphDatabaseContext; import org.springframework.persistence.support.AbstractTypeAnnotatingMixinFields; -import org.springframework.persistence.support.EntityInstantiator; import org.springframework.util.ObjectUtils; /** @@ -69,7 +68,9 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields(node,entity,entity.getClass(),graphDatabaseContext); log.info("User-defined constructor called on class " + entity.getClass() + "; created Node [" + entity.getUnderlyingNode() +"]; " + "Updating metamodel"); graphDatabaseContext.postEntityCreation(entity); @@ -80,6 +81,8 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields NodeBacked.underlyingState; + private Map NodeBacked.dirty; public void NodeBacked.setUnderlyingNode(Node n) { @@ -127,7 +130,7 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields NodeBacked.find(final Class targetType, TraversalDescription traversalDescription) { if (!hasUnderlyingNode()) throw new IllegalStateException("No node attached to " + this); final Traverser traverser = traversalDescription.traverse(this.getUnderlyingNode()); - return new Neo4jNodeBacking.NodeBackedNodeIterableWrapper(traverser, targetType); + return new NodeBackedNodeIterableWrapper(traverser, targetType, Neo4jNodeBacking.aspectOf().graphDatabaseContext); } /* public Iterable NodeBacked.traverse(TraversalDescription traversalDescription) { @@ -179,8 +182,6 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields { - private final Class targetType; - - public NodeBackedNodeIterableWrapper(Traverser traverser, Class targetType) { - super(traverser.nodes()); - this.targetType = targetType; - } - - @Override - protected NodeBacked underlyingObjectToObject(Node node) { - return Neo4jNodeBacking.aspectOf().graphDatabaseContext.createEntityFromState(node,targetType); - } - } } diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/spi/node/NodeBackedNodeIterableWrapper.java b/src/main/java/org/springframework/datastore/graph/neo4j/spi/node/NodeBackedNodeIterableWrapper.java new file mode 100644 index 000000000..9249d5710 --- /dev/null +++ b/src/main/java/org/springframework/datastore/graph/neo4j/spi/node/NodeBackedNodeIterableWrapper.java @@ -0,0 +1,27 @@ +package org.springframework.datastore.graph.neo4j.spi.node; + +import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.traversal.Traverser; +import org.neo4j.helpers.collection.IterableWrapper; +import org.springframework.datastore.graph.api.NodeBacked; +import org.springframework.datastore.graph.neo4j.support.GraphDatabaseContext; + +/** + * @author Michael Hunger + * @since 14.09.2010 + */ +public class NodeBackedNodeIterableWrapper extends IterableWrapper { + private final Class targetType; + private final GraphDatabaseContext graphDatabaseContext; + + public NodeBackedNodeIterableWrapper(Traverser traverser, Class targetType, final GraphDatabaseContext graphDatabaseContext) { + super(traverser.nodes()); + this.targetType = targetType; + this.graphDatabaseContext = graphDatabaseContext; + } + + @Override + protected NodeBacked underlyingObjectToObject(Node node) { + return graphDatabaseContext.createEntityFromState(node, targetType); + } +}