added id and transient-field fieldFor in DelegatingFactory now iterates, start with EntityStateAccessors

This commit is contained in:
Michael Hunger
2010-09-15 00:10:11 +02:00
parent 82918a9aba
commit 53b367385b
7 changed files with 154 additions and 83 deletions

View File

@@ -41,27 +41,30 @@ public class ConvertingNodePropertyFieldAccessor extends NodePropertyFieldAccess
}
public static FieldAccessorFactory<NodeBacked> factory() {
return new FieldAccessorFactory<NodeBacked>() {
@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<NodeBacked> {
@Autowired
ConversionService conversionService;
@Override
public FieldAccessor<NodeBacked,?> 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<NodeBacked,?> 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());
}
}
}

View File

@@ -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<T> implements FieldAccessorFactory<T> {
private final GraphDatabaseContext graphDatabaseContext;
@@ -25,6 +22,8 @@ public class DelegatingFieldAccessorFactory<T> implements FieldAccessorFactory<T
}
final Collection<FieldAccessorFactory<?>> fieldAccessorFactories = Arrays.<FieldAccessorFactory<?>>asList(
IdFieldAccessor.factory(),
TransientFieldAccessor.factory(),
NodePropertyFieldAccessor.factory(),
ConvertingNodePropertyFieldAccessor.factory(),
SingleRelationshipFieldAccessor.factory(),
@@ -37,7 +36,7 @@ public class DelegatingFieldAccessorFactory<T> implements FieldAccessorFactory<T
);
public FieldAccessor forField(Field field) {
if (Modifier.isTransient(field.getModifiers())) return null;
if (field.getName().startsWith("ajc")) return null;
for (FieldAccessorFactory<?> fieldAccessorFactory : fieldAccessorFactories) {
if (fieldAccessorFactory.accept(field)) {
System.out.println("Factory " + fieldAccessorFactory + " used for field: " + field);
@@ -48,37 +47,6 @@ public class DelegatingFieldAccessorFactory<T> implements FieldAccessorFactory<T
}
private Class<? extends NodeBacked> targetFrom(Field field) {
return (Class<? extends NodeBacked>) field.getType();
}
private Class<? extends NodeBacked> 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<? extends RelationshipBacked> 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<T> implements FieldAccessorFactory<T
return false;
}
public List<FieldAccessor<T, ?>> listenersFor(Field field) {
List<FieldAccessor<T,?>> result=new ArrayList<FieldAccessor<T,?>>();
public List<FieldAccessListener<T, ?>> listenersFor(Field field) {
List<FieldAccessListener<T,?>> result=new ArrayList<FieldAccessListener<T,?>>();
for (FieldAccessorListenerFactory<?> fieldAccessorListenerFactory : fieldAccessorListenerFactories) {
if (fieldAccessorListenerFactory.accept(field)) {
final FieldAccessor<T, ?> listener = (FieldAccessor<T, ?>) fieldAccessorListenerFactory.forField(field);
final FieldAccessListener<T, ?> listener = (FieldAccessListener<T, ?>) fieldAccessorListenerFactory.forField(field);
result.add(listener);
}
}

View File

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

View File

@@ -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<NodeBacked, Object> {
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<NodeBacked> factory() {
return new FieldAccessorFactory<NodeBacked>() {
@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<NodeBacked,?> forField(final Field field) {
return new IdFieldAccessor(field);
}
};
}
}

View File

@@ -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<NodeBacked, Object> {
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<NodeBacked> factory() {
return new FieldAccessorFactory<NodeBacked>() {
@Override
public boolean accept(final Field f) {
return Modifier.isTransient(f.getModifiers());
}
@Override
public FieldAccessor<NodeBacked,?> forField(final Field field) {
return new TransientFieldAccessor(field);
}
};
}
}

View File

@@ -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<GraphEn
private void createAndAssignNode(NodeBacked entity) {
try {
entity.setUnderlyingNode(graphDatabaseContext.createNode());
Node node=graphDatabaseContext.createNode();
entity.setUnderlyingNode(node);
entity.underlyingState=new EntityStateAccessors<NodeBacked,Node>(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<GraphEn
// Introduced field
private Node NodeBacked.underlyingNode;
private EntityStateAccessors<NodeBacked,Node> NodeBacked.underlyingState;
private Map<Field,Object> NodeBacked.dirty;
public void NodeBacked.setUnderlyingNode(Node n) {
@@ -127,7 +130,7 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<GraphEn
public Iterable<? extends NodeBacked> NodeBacked.find(final Class<? extends NodeBacked> 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<? extends NodeBacked> NodeBacked.traverse(TraversalDescription traversalDescription) {
@@ -179,8 +182,6 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<GraphEn
return getUnderlyingNode().hashCode();
}
private Object getValueFromEntity(Field field, NodeBacked entity) {
try {
field.setAccessible(true);
@@ -386,17 +387,4 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<GraphEn
return graphEntityProperty!=null && graphEntityProperty.index();
}
public static class NodeBackedNodeIterableWrapper extends IterableWrapper<NodeBacked, Node> {
private final Class<? extends NodeBacked> targetType;
public NodeBackedNodeIterableWrapper(Traverser traverser, Class<? extends NodeBacked> targetType) {
super(traverser.nodes());
this.targetType = targetType;
}
@Override
protected NodeBacked underlyingObjectToObject(Node node) {
return Neo4jNodeBacking.aspectOf().graphDatabaseContext.createEntityFromState(node,targetType);
}
}
}

View File

@@ -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<NodeBacked, Node> {
private final Class<? extends NodeBacked> targetType;
private final GraphDatabaseContext graphDatabaseContext;
public NodeBackedNodeIterableWrapper(Traverser traverser, Class<? extends NodeBacked> targetType, final GraphDatabaseContext graphDatabaseContext) {
super(traverser.nodes());
this.targetType = targetType;
this.graphDatabaseContext = graphDatabaseContext;
}
@Override
protected NodeBacked underlyingObjectToObject(Node node) {
return graphDatabaseContext.createEntityFromState(node, targetType);
}
}