traversals for other target types than just nodes
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user