traversals for other target types than just nodes

This commit is contained in:
Michael Hunger
2011-09-23 02:35:04 +02:00
parent 05996a3480
commit 9565ef18bb
4 changed files with 49 additions and 57 deletions

View File

@@ -93,7 +93,7 @@ public interface NodeBacked extends GraphBacked<Node> {
* @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);
<T> Iterable<T> findAllByTraversal(final Class<T> targetType, TraversalDescription traversalDescription);
/**
* Perform a traversal from this entity's underlying node with the given traversal description. The found paths

View File

@@ -16,13 +16,15 @@
package org.springframework.data.neo4j.fieldaccess;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Path;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.neo4j.annotation.GraphTraversal;
import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.neo4j.core.FieldTraversalDescriptionBuilder;
import org.springframework.data.neo4j.core.NodeBacked;
import org.springframework.data.neo4j.repository.DirectGraphRepositoryFactory;
import org.springframework.data.neo4j.core.RelationshipBacked;
import org.springframework.data.neo4j.support.GenericTypeExtractor;
import java.lang.reflect.Constructor;
@@ -52,7 +54,7 @@ public class TraversalFieldAccessorFactory implements FieldAccessorFactory<NodeB
public static class TraversalFieldAccessor implements FieldAccessor<NodeBacked> {
protected final Field field;
private final FieldTraversalDescriptionBuilder fieldTraversalDescriptionBuilder;
private Class<? extends NodeBacked> target;
private Class<?> target;
protected String[] params;
public TraversalFieldAccessor(final Field field) {
@@ -63,15 +65,23 @@ public class TraversalFieldAccessorFactory implements FieldAccessorFactory<NodeB
this.fieldTraversalDescriptionBuilder = createTraversalDescription(graphEntityTraversal);
}
private Class<? extends NodeBacked> resolveTarget(GraphTraversal graphTraversal, Field field) {
if (!graphTraversal.elementClass().equals(Object.class)) return graphTraversal.elementClass();
private Class<?> resolveTarget(GraphTraversal graphTraversal, Field field) {
if (!graphTraversal.elementClass().equals(NodeBacked.class)) return graphTraversal.elementClass();
final Class<?> result = GenericTypeExtractor.resolveFieldType(field);
if (!NodeBacked.class.isAssignableFrom(result)) throw new IllegalArgumentException("The target result type of the traversal is no node entity: "+field);
return (Class<? extends NodeBacked>) result;
Class<?>[] allowedTypes={NodeBacked.class,RelationshipBacked.class,Node.class,Relationship.class, Path.class};
if (!checkTypes(result,allowedTypes)) throw new IllegalArgumentException("The target result type "+result+" of the traversal is no subclass of the allowed types: "+field+" "+allowedTypes);
return result;
}
private boolean checkTypes(Class<?> target, Class<?>...allowedTypes) {
for (Class<?> type : allowedTypes) {
if (type.isAssignableFrom(target)) return true;
}
return false;
}
@Override
@Override
public boolean isWriteable(NodeBacked nodeBacked) {
return false;
}
@@ -84,7 +94,7 @@ public class TraversalFieldAccessorFactory implements FieldAccessorFactory<NodeB
@Override
public Object getValue(final NodeBacked nodeBacked) {
final TraversalDescription traversalDescription = fieldTraversalDescriptionBuilder.build(nodeBacked,field,params);
return doReturn(nodeBacked.findAllByTraversal((Class<? extends NodeBacked>) target, traversalDescription));
return doReturn(nodeBacked.findAllByTraversal(target, traversalDescription));
}

View File

@@ -21,6 +21,8 @@ import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.FieldSignature;
import org.neo4j.graphdb.DynamicRelationshipType;
import org.neo4j.graphdb.Path;
import org.neo4j.helpers.collection.IterableWrapper;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.traversal.TraversalDescription;
@@ -180,10 +182,35 @@ public aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMixinFields<No
return getPersistentState().getId();
}
public <T extends NodeBacked> Iterable<T> NodeBacked.findAllByTraversal(final Class<T> targetType, TraversalDescription traversalDescription) {
public <T> Iterable<T> NodeBacked.findAllByTraversal(final Class<T> targetType, TraversalDescription traversalDescription) {
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);
if (Node.class.isAssignableFrom(targetType)) return (Iterable<T>) traverser.nodes();
if (Relationship.class.isAssignableFrom(targetType)) return (Iterable<T>) traverser.relationships();
if (Path.class.isAssignableFrom(targetType)) return (Iterable<T>) traverser;
return (Iterable<T>)Neo4jNodeBacking.aspectOf().convertToGraphEntity(traverser,targetType);
}
private Iterable<?> convertToGraphEntity(Traverser traverser, final Class<?> targetType) {
final GraphDatabaseContext ctx = Neo4jNodeBacking.aspectOf().graphDatabaseContext;
if (NodeBacked.class.isAssignableFrom(targetType)) {
return new IterableWrapper<Object,Node>(traverser.nodes()) {
@Override
protected Object underlyingObjectToObject(Node node) {
return ctx.createEntityFromState(node,(Class<? extends NodeBacked>)targetType);
}
};
}
if (RelationshipBacked.class.isAssignableFrom(targetType)) {
return new IterableWrapper<Object,Relationship>(traverser.relationships()) {
@Override
protected Object underlyingObjectToObject(Relationship relationship) {
return ctx.createEntityFromState(relationship,(Class<? extends RelationshipBacked>)targetType);
}
};
}
throw new IllegalStateException("Can't determine valid type for traversal target "+targetType);
}
public <T> Iterable<T> NodeBacked.findAllByQuery(final String query, final Class<T> targetType, Map<String,Object> params) {

View File

@@ -1,45 +0,0 @@
/**
* Copyright 2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.neo4j.support.node;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.traversal.Traverser;
import org.neo4j.helpers.collection.IterableWrapper;
import org.springframework.data.neo4j.core.NodeBacked;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
/**
* Simple wrapper to create an Iterable from a traverser, tied to a NodeBacked entity. Creates NodeEntities on the fly
* while iterating the Iterator from the traverersal result.
* @author Michael Hunger
* @since 14.09.2010
*/
public class NodeBackedNodeIterableWrapper<T extends NodeBacked> extends IterableWrapper<T, Node> {
private final Class<T> targetType;
private final GraphDatabaseContext graphDatabaseContext;
public NodeBackedNodeIterableWrapper(Traverser traverser, Class<T> targetType, final GraphDatabaseContext graphDatabaseContext) {
super(traverser.nodes());
this.targetType = targetType;
this.graphDatabaseContext = graphDatabaseContext;
}
@Override
protected T underlyingObjectToObject(Node node) {
return graphDatabaseContext.createEntityFromState(node, targetType);
}
}