Merge branch 'master' of github.com:SpringSource/spring-data-neo4j

This commit is contained in:
Andreas Kollegger
2011-10-04 11:02:41 -07:00
75 changed files with 358 additions and 190 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
*.hprof*
ajcore*
.project
.classpath

View File

@@ -62,8 +62,14 @@ public interface NodeBacked extends GraphBacked<Node,NodeBacked> {
* @param target other entity
* @param relationshipClass relationship entity class
* @param relationshipType type of relationship to be created
* @param allowDuplicates duplication relationships of the same type are allowed between two entities
* @return relationship entity of specified relationshipClass
*/
<R extends RelationshipBacked, N extends NodeBacked> R relateTo(N target, Class<R> relationshipClass, String relationshipType,boolean allowDuplicates);
/**
* delegates to relateTo with allowDuplicates set to false
*/
<R extends RelationshipBacked, N extends NodeBacked> R relateTo(N target, Class<R> relationshipClass, String relationshipType);
@@ -151,7 +157,12 @@ public interface NodeBacked extends GraphBacked<Node,NodeBacked> {
*
* @param target entity
* @param type neo4j relationship type for the underlying relationship
* @param allowDuplicates duplication relationships of the same type are allowed between two entities
* @return the newly created relationship to the target node
*/
Relationship relateTo(NodeBacked target, String type, boolean allowDuplicates);
/**
* delegates to relateTo with allowDuplicates set to false
*/
Relationship relateTo(NodeBacked target, String type);
}

View File

@@ -162,11 +162,16 @@ public privileged aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMix
}
public Relationship NodeBacked.relateTo(NodeBacked target, String type) {
return this.relateTo(target,type,false);
}
public Relationship NodeBacked.relateTo(NodeBacked target, String type, boolean allowDuplicates) {
if (target==null) throw new IllegalArgumentException("Target entity is null");
if (type==null) throw new IllegalArgumentException("Relationshiptype is null");
Relationship relationship=getRelationshipTo(target,type);
if (relationship!=null) return relationship;
if (!allowDuplicates) {
Relationship relationship=getRelationshipTo(target,type);
if (relationship!=null) return relationship;
}
return this.getPersistentState().createRelationshipTo(target.getPersistentState(), DynamicRelationshipType.withName(type));
}
@@ -229,11 +234,14 @@ public privileged aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMix
}
public <R extends RelationshipBacked, N extends NodeBacked> R NodeBacked.relateTo(N target, Class<R> relationshipClass, String relationshipType) {
return this.relateTo(target,relationshipClass,relationshipType,false);
}
public <R extends RelationshipBacked, N extends NodeBacked> R NodeBacked.relateTo(N target, Class<R> relationshipClass, String relationshipType, boolean allowDuplicates) {
if (target==null) throw new IllegalArgumentException("Target entity is null");
if (relationshipClass==null) throw new IllegalArgumentException("Relationship class is null");
if (relationshipType==null) throw new IllegalArgumentException("Relationshiptype is null");
Relationship rel = this.relateTo(target,relationshipType);
Relationship rel = this.relateTo(target,relationshipType,allowDuplicates);
GraphDatabaseContext gdc = Neo4jNodeBacking.aspectOf().graphDatabaseContext;
gdc.postEntityCreation(rel, relationshipClass);

View File

@@ -18,13 +18,13 @@ package org.springframework.data.neo4j.aspects;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.DynamicRelationshipType;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.kernel.Traversal;
import org.neo4j.kernel.impl.traversal.TraversalDescriptionImpl;
import org.springframework.data.neo4j.aspects.Person;
import org.springframework.data.neo4j.annotation.*;
import org.springframework.data.neo4j.core.FieldTraversalDescriptionBuilder;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
import java.util.Collection;
@@ -44,6 +44,12 @@ public class Group {
@GraphTraversal(traversalBuilder = PeopleTraversalBuilder.class, elementClass = Person.class, params = "persons")
private Iterable<Person> people;
@GraphTraversal(traversalBuilder = PeopleTraversalBuilder.class, params = "persons")
private Iterable<Node> peopleNodes;
@GraphTraversal(traversalBuilder = PeopleTraversalBuilder.class, params = "persons")
private Iterable<Relationship> peopleRelationships;
@GraphProperty
@Indexed
private String name;
@@ -162,4 +168,12 @@ public class Group {
public void setAdmin(Boolean admin) {
this.admin = admin;
}
public Iterable<Node> getPeopleNodes() {
return peopleNodes;
}
public Iterable<Relationship> getPeopleRelationships() {
return peopleRelationships;
}
}

View File

@@ -76,16 +76,16 @@ public class Person {
@RelatedToVia(type = "knows", elementClass = Friendship.class)
private Iterable<Friendship> friendships;
@Query(value = "start person=(%start) match (person)<-[:boss]-(boss) return boss")
@Query(value = "start person=node({self}) match (person)<-[:boss]-(boss) return boss")
private Person bossByQuery;
@Query(value = "start person=(%start) match (person)<-[:boss]-(boss) return boss.%property",params = {"property","name"})
@Query(value = "start person=node({self}) match (person)<-[:boss]-(boss) return boss.name")
private String bossName;
@Query(value = "start person=(%start) match (person)<-[:persons]-(team)-[:persons]->(member) return member",elementClass = Person.class)
@Query(value = "start person=node({self}) match (person)<-[:persons]-(team)-[:persons]->(member) return member",elementClass = Person.class)
private Iterable<Person> otherTeamMembers;
@Query(value = "start person=(%start) match (person)<-[:persons]-(team)-[:persons]->(member) return member.name, member.age")
@Query(value = "start person=node({self}) match (person)<-[:persons]-(team)-[:persons]->(member) return member.name, member.age")
private Iterable<Map<String,Object>> otherTeamMemberData;
public Person(Node n) {

View File

@@ -19,8 +19,6 @@ package org.springframework.data.neo4j.aspects;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.neo4j.aspects.Group;
import org.springframework.data.neo4j.aspects.Person;
import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.neo4j.annotation.QueryType;
import org.springframework.data.neo4j.repository.GraphRepository;
@@ -35,22 +33,22 @@ import java.util.Map;
*/
public interface PersonRepository extends GraphRepository<Person>, NamedIndexRepository<Person> {
@Query("start team=(%team) match (team)-[:persons]->(member) return member")
Iterable<Person> findAllTeamMembers(@Param("team") Group team);
@Query("start team=node({p_team}) match (team)-[:persons]->(member) return member")
Iterable<Person> findAllTeamMembers(@Param("p_team") Group team);
@Query(value = "g.v(team).out('persons')", type = QueryType.Gremlin)
Iterable<Person> findAllTeamMembersGremlin(@Param("team") Group team);
@Query("start team=(%team) match (team)-[:persons]->(member) return member.name,member.age")
Iterable<Map<String,Object>> findAllTeamMemberData(@Param("team") Group team);
@Query("start team=node({p_team}) match (team)-[:persons]->(member) return member.name,member.age")
Iterable<Map<String,Object>> findAllTeamMemberData(@Param("p_team") Group team);
@Query("start person=(%person) match (boss)-[:boss]->(person) return boss")
Person findBoss(@Param("person") Person person);
@Query("start person=node({p_person}) match (person)<-[:boss]-(boss) return boss")
Person findBoss(@Param("p_person") Person person);
Group findTeam(@Param("person") Person person);
Group findTeam(@Param("p_person") Person person);
@Query("start team=(%team) match (team)-[:persons]->(member) return member")
Page<Person> findAllTeamMembersPaged(@Param("team") Group team, Pageable page);
@Query("start team=(%team) match (team)-[:persons]->(member) return member")
Iterable<Person> findAllTeamMembersSorted(@Param("team") Group team, Sort sort);
@Query("start team=node({p_team}) match (team)-[:persons]->(member) return member")
Page<Person> findAllTeamMembersPaged(@Param("p_team") Group team, Pageable page);
@Query("start team=node({p_team}) match (team)-[:persons]->(member) return member")
Iterable<Person> findAllTeamMembersSorted(@Param("p_team") Group team, Sort sort);
}

View File

@@ -21,7 +21,6 @@ import org.apache.commons.logging.LogFactory;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.neo4j.helpers.collection.ClosableIterable;
import org.neo4j.helpers.collection.IteratorUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;

View File

@@ -25,7 +25,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.neo4j.aspects.*;
import org.springframework.data.neo4j.aspects.Group;
import org.springframework.data.neo4j.aspects.Person;
import org.springframework.data.neo4j.aspects.PersonRepository;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import org.springframework.data.neo4j.support.node.Neo4jHelper;
import org.springframework.test.context.CleanContextCacheTestExecutionListener;
@@ -37,6 +39,7 @@ import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashSet;
import java.util.Map;
import static java.util.Arrays.asList;
@@ -45,6 +48,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.internal.matchers.IsCollectionContaining.hasItem;
import static org.junit.internal.matchers.IsCollectionContaining.hasItems;
import static org.neo4j.helpers.collection.IteratorUtil.addToCollection;
import static org.neo4j.helpers.collection.IteratorUtil.asCollection;
@RunWith(SpringJUnit4ClassRunner.class)
@@ -61,17 +65,16 @@ public class GraphRepositoryTest {
private PersonRepository personRepository;
private TestTeam testTeam;
@BeforeTransaction
public void cleanDb() {
Neo4jHelper.cleanDb(graphDatabaseContext);
}
@Before
public void setUp() throws Exception {
testTeam = new TestTeam();
testTeam.createSDGTeam();
}
@BeforeTransaction
public void cleanDb() {
Neo4jHelper.cleanDb(graphDatabaseContext);
}
@Test
@Transactional
public void testFindIterableOfPersonWithQueryAnnotation() {
@@ -117,7 +120,7 @@ public class GraphRepositoryTest {
@Transactional
public void testFindPagedNull() {
Page<Person> teamMemberPage1 = personRepository.findAllTeamMembersPaged(testTeam.sdg,null);
assertEquals(asList(testTeam.michael, testTeam.emil,testTeam.david), asCollection(teamMemberPage1));
assertEquals(new HashSet(asList(testTeam.david, testTeam.emil, testTeam.michael)), addToCollection(teamMemberPage1, new HashSet()));
assertThat(teamMemberPage1.isFirstPage(), is(true));
assertThat(teamMemberPage1.isLastPage(), is(false));
}

View File

@@ -26,6 +26,7 @@ import org.neo4j.helpers.collection.IteratorUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import static org.junit.Assert.assertTrue;
import static org.springframework.data.neo4j.aspects.Person.persistedPerson;
import org.springframework.data.neo4j.aspects.*;
@@ -146,7 +147,7 @@ public class NodeEntityRelationshipTest {
group.setPersons(persons);
Collection<Person> personsFromGet = group.getPersons();
assertEquals(persons, personsFromGet);
Assert.assertTrue(Set.class.isAssignableFrom(personsFromGet.getClass()));
assertTrue(Set.class.isAssignableFrom(personsFromGet.getClass()));
}
@Test
@@ -160,7 +161,7 @@ public class NodeEntityRelationshipTest {
group.getPersons().add(david);
Collection<Person> personsFromGet = group.getPersons();
assertEquals(new HashSet<Person>(Arrays.asList(david,michael)), personsFromGet);
Assert.assertTrue(Set.class.isAssignableFrom(personsFromGet.getClass()));
assertTrue(Set.class.isAssignableFrom(personsFromGet.getClass()));
}
@Test
@@ -244,6 +245,26 @@ public class NodeEntityRelationshipTest {
assertEquals(persons, IteratorUtil.addToCollection(group.getReadOnlyPersons().iterator(), new HashSet<Person>()));
}
@Test
@Transactional
public void multipleRelationshipsOfSameTypeBetweenTwoEntities() {
Person michael = persistedPerson("Michael", 35);
Person david = persistedPerson("David", 25);
Friendship friendship1 = michael.relateTo(david, Friendship.class, "knows", true);
friendship1.setYears(1);
Friendship friendship2 = michael.relateTo(david, Friendship.class, "knows",true);
friendship2.setYears(2);
assertTrue("two different relationships", friendship1 != friendship2);
assertTrue("two different relationships", friendship1.getPersistentState() != friendship2.getPersistentState());
assertEquals(1, friendship1.getYears());
assertEquals(2,friendship2.getYears());
final Collection<Relationship> friends = IteratorUtil.asCollection(michael.getPersistentState().getRelationships(Direction.OUTGOING, DynamicRelationshipType.withName("knows")));
assertEquals(2,friends.size());
assertTrue(friends.contains(friendship1.getPersistentState()));
assertTrue(friends.contains(friendship2.getPersistentState()));
}
@Test(expected = InvalidDataAccessApiUsageException.class)
@Transactional
public void testOneToManyReadOnlyShouldThrowExceptionOnSet() {

View File

@@ -46,7 +46,12 @@ public class TestTeam {
sdg.addPerson(michael);
sdg.addPerson(emil);
sdg.addPerson(david);
// todo those should be attached and automatically written through to the db
david.persist();
emil.persist();
michael.persist();
sdg.persist();
}
public Map<String, Object> simpleRowFor(final Person person, String prefix) {

View File

@@ -22,22 +22,20 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.DynamicRelationshipType;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.traversal.Evaluators;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.helpers.collection.IteratorUtil;
import org.neo4j.kernel.Traversal;
import org.neo4j.kernel.impl.traversal.TraversalDescriptionImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.neo4j.aspects.Group;
import org.springframework.data.neo4j.aspects.Person;
import org.springframework.data.neo4j.core.EntityPath;
import static org.springframework.data.neo4j.aspects.Person.persistedPerson;
import org.springframework.data.neo4j.repository.DirectGraphRepositoryFactory;
import org.springframework.data.neo4j.repository.GraphRepository;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import org.springframework.data.neo4j.support.node.Neo4jHelper;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -48,6 +46,7 @@ import java.util.Collections;
import java.util.HashSet;
import static org.junit.Assert.assertEquals;
import static org.springframework.data.neo4j.aspects.Person.persistedPerson;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:org/springframework/data/neo4j/aspects/support/Neo4jGraphPersistenceTest-context.xml"})
@@ -100,18 +99,29 @@ public class TraversalTest {
@Test
@Transactional
@Rollback(false)
public void testTraverseFieldFromGroupToPeople() {
Person p = persistedPerson("Michael", 35);
Group group = new Group().persist();
group.setName("dev");
group.addPerson(p);
Iterable<Person> people = group.getPeople();
final HashSet<Person> found = new HashSet<Person>();
for (Person person : people) {
found.add(person);
}
assertEquals(Collections.singleton(p),found);
assertEquals(Collections.singletonList(p),IteratorUtil.asCollection(group.getPeople()));
}
@Test
@Transactional
public void testTraverseFieldFromGroupToPeopleNodes() {
Person p = persistedPerson("Michael", 35);
Group group = new Group().persist();
group.addPerson(p);
assertEquals(Collections.singletonList(p.getPersistentState()), IteratorUtil.asCollection(group.getPeopleNodes()));
}
@Test
@Transactional
public void testTraverseFieldFromGroupToPeopleRelationships() {
Person p = persistedPerson("Michael", 35);
Group group = new Group().persist();
group.addPerson(p);
Relationship personRelationship = group.getPersistentState().getSingleRelationship(DynamicRelationshipType.withName("persons"),Direction.OUTGOING);
assertEquals(Collections.singletonList(personRelationship), IteratorUtil.asCollection(group.getPeopleRelationships()));
}
@Test

View File

@@ -94,14 +94,14 @@ public class GremlinQueryEngineTest {
/*
@Test
public void testQueryListOfTypeNode() throws Exception {
final String queryString = "start person=(name_index,name,\"%name\") match (person) <-[:boss]- (boss) return boss";
final String queryString = "start person=(name_index,name,\"{name}\") match (person) <-[:boss]- (boss) return boss";
final Collection<Node> result = IteratorUtil.asCollection(queryEngine.query(queryString, michaelsName()).to(Node.class));
assertEquals(asList(nodeFor(testTeam.emil)),result);
}
@Test
public void testQueryListOfTypePerson() throws Exception {
final String queryString = "start person=(name_index,name,\"%name\") match (person) <-[:boss]- (boss) return boss";
final String queryString = "start person=(name_index,name,\"{name}\") match (person) <-[:boss]- (boss) return boss";
final Collection<Person> result = IteratorUtil.asCollection(queryEngine.query(queryString, michaelsName()).to(Person.class, new EntityResultConverter(graphDatabaseContext)));
assertEquals(asList(testTeam.emil),result);
@@ -110,7 +110,7 @@ public class GremlinQueryEngineTest {
@Test
public void testQuerySingleOfTypePerson() throws Exception {
final String queryString = "start person=(name_index,name,\"%name\") match (person) <-[:boss]- (boss) return boss";
final String queryString = "start person=(name_index,name,\"{name}\") match (person) <-[:boss]- (boss) return boss";
final Person result = queryEngine.query(queryString, michaelsName()).to(Person.class, new EntityResultConverter<Map<String,Object>,Person>(graphDatabaseContext)).single();
assertEquals(testTeam.emil,result);
@@ -132,14 +132,14 @@ public class GremlinQueryEngineTest {
@Test
public void testQueryForObjectAsString() throws Exception {
final String queryString = "start person=(name_index,name,\"%name\") match (person) <-[:persons]- (team) return team.name";
final String queryString = "start person=(name_index,name,\"{name}\") match (person) <-[:persons]- (team) return team.name";
final String result = queryEngine.query(queryString, michaelsName()).to(String.class).single();
assertEquals(testTeam.sdg.getName(),result);
}
@Test
public void testQueryForObjectAsEnum() throws Exception {
final String queryString = "start person=(name_index,name,\"%name\") return person.personality";
final String queryString = "start person=(name_index,name,\"{name}\") return person.personality";
final Personality result = queryEngine.query(queryString, michaelsName()).to(Personality.class).single();
assertEquals(michael.getPersonality(),result);

View File

@@ -87,17 +87,16 @@ public class QueryEngineTest {
}
@Test
@Transactional
public void testQueryList() throws Exception {
final String queryString = "start person=(%michael,%david) return person.name, person.age";
final Collection<Map<String,Object>> result = IteratorUtil.asCollection(queryEngine.query(queryString, MapUtil.map("michael",idFor(michael), "david",idFor(testTeam.david))));
final String queryString = "start person=node({people}) return person.name, person.age";
final Collection<Map<String,Object>> result = IteratorUtil.asCollection(queryEngine.query(queryString, MapUtil.map("people",asList(idFor(michael),idFor(testTeam.david)))));
assertEquals(asList(testTeam.simpleRowFor(michael,"person"),testTeam.simpleRowFor(testTeam.david,"person")),result);
}
@Test
public void testQueryListOfTypeNode() throws Exception {
final String queryString = "start person=(name_index,name,\"%name\") match (person) <-[:boss]- (boss) return boss";
final String queryString = "start person=node:name_index(name={name}) match (person) <-[:boss]- (boss) return boss";
final QueryResult<Map<String,Object>> queryResult = queryEngine.query(queryString, michaelsName());
final Collection<Node> result = IteratorUtil.asCollection(queryResult.to(Node.class));
@@ -105,7 +104,7 @@ public class QueryEngineTest {
}
@Test
public void testQueryListOfTypePerson() throws Exception {
final String queryString = "start person=(name_index,name,\"%name\") match (person) <-[:boss]- (boss) return boss";
final String queryString = "start person=node:name_index(name={name}) match (person) <-[:boss]- (boss) return boss";
final Collection<Person> result = IteratorUtil.asCollection(queryEngine.query(queryString, michaelsName()).to(Person.class, new EntityResultConverter(graphDatabaseContext)));
assertEquals(asList(testTeam.emil),result);
@@ -117,7 +116,7 @@ public class QueryEngineTest {
@Test
public void testQuerySingleOfTypePerson() throws Exception {
final String queryString = "start person=(name_index,name,\"%name\") match (person) <-[:boss]- (boss) return boss";
final String queryString = "start person=node:name_index(name={name}) match (person) <-[:boss]- (boss) return boss";
final Person result = queryEngine.query(queryString, michaelsName()).to(Person.class, new EntityResultConverter<Map<String,Object>,Person>(graphDatabaseContext)).single();
assertEquals(testTeam.emil,result);
@@ -125,7 +124,7 @@ public class QueryEngineTest {
@Test
public void testQueryListWithCustomConverter() throws Exception {
final String queryString = String.format("start person=(name_index,name,\"%s\") match (person) <-[:boss]- (boss) return boss", michael.getName());
final String queryString = "start person=node:name_index(name={name}) match (person) <-[:boss]- (boss) return boss";
final Collection<String> result = IteratorUtil.asCollection(queryEngine.query(queryString, michaelsName()).to(String.class, new ResultConverter<Map<String, Object>, String>() {
@Override
public String convert(Map<String, Object> row, Class<String> target) {
@@ -145,14 +144,14 @@ public class QueryEngineTest {
@Test
public void testQueryForObjectAsString() throws Exception {
final String queryString = "start person=(name_index,name,\"%name\") match (person) <-[:persons]- (team) return team.name";
final String queryString = "start person=node:name_index(name={name}) match (person) <-[:persons]- (team) return team.name";
final String result = queryEngine.query(queryString, michaelsName()).to(String.class).single();
assertEquals(testTeam.sdg.getName(),result);
}
@Test
public void testQueryForObjectAsEnum() throws Exception {
final String queryString = "start person=(name_index,name,\"%name\") return person.personality";
final String queryString = "start person=node:name_index(name={name}) return person.personality";
final Personality result = queryEngine.query(queryString, michaelsName()).to(Personality.class).single();
assertEquals(michael.getPersonality(),result);

View File

@@ -172,7 +172,7 @@
<property name="namedQueries">
<bean class="org.springframework.data.repository.core.support.PropertiesBasedNamedQueries">
<constructor-arg>
<props><prop key="Person.findTeam">start p=(%person) match (p)&lt;-[:persons]-(group) return group</prop></props>
<props><prop key="Person.findTeam">start p=node({p_person}) match (p)&lt;-[:persons]-(group) return group</prop></props>
</constructor-arg>
</bean>
</property>

View File

@@ -11,6 +11,6 @@
<context:annotation-config/>
<neo4j:config graphDatabaseService="graphDatabaseService"/>
<neo4j:repositories base-package="org.springframework.data.neo4j.aspects"/>
<bean id="graphDatabaseService" class="org.neo4j.test.ImpermanentGraphDatabase"/>
<bean id="graphDatabaseService" class="org.neo4j.test.ImpermanentGraphDatabase" destroy-method="shutdown"/>
</beans>

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.neo4j.config;
package org.springframework.data.neo4j.cross_store.config;
import org.neo4j.graphdb.Node;
import org.springframework.beans.factory.annotation.Autowired;
@@ -21,11 +21,11 @@ import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.aspects.config.Neo4jAspectConfiguration;
import org.springframework.data.neo4j.cross_store.support.node.CrossStoreNodeEntityInstantiator;
import org.springframework.data.neo4j.cross_store.support.node.CrossStoreNodeEntityStateFactory;
import org.springframework.data.neo4j.support.EntityInstantiator;
import org.springframework.data.neo4j.support.node.CrossStoreNodeEntityStateFactory;
import org.springframework.data.neo4j.support.node.NodeEntityInstantiator;
import org.springframework.data.neo4j.support.node.NodeEntityStateFactory;
import org.springframework.data.neo4j.support.node.CrossStoreNodeEntityInstantiator;
import org.springframework.data.neo4j.transaction.ChainedTransactionManager;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

View File

@@ -14,11 +14,12 @@
* limitations under the License.
*/
package org.springframework.data.neo4j.support.node;
package org.springframework.data.neo4j.cross_store.support.node;
import org.neo4j.graphdb.Node;
import org.springframework.data.neo4j.aspects.core.NodeBacked;
import org.springframework.data.neo4j.support.EntityInstantiator;
import org.springframework.data.neo4j.support.node.NodeEntityInstantiator;
import org.springframework.orm.jpa.EntityManagerFactoryUtils;
import javax.persistence.EntityManager;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.neo4j.support.node;
package org.springframework.data.neo4j.cross_store.support.node;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.NotInTransactionException;

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.neo4j.support.node;
package org.springframework.data.neo4j.cross_store.support.node;
import org.neo4j.graphdb.Node;
import org.springframework.data.neo4j.annotation.NodeEntity;
@@ -21,6 +21,8 @@ import org.springframework.data.neo4j.aspects.core.NodeBacked;
import org.springframework.data.neo4j.core.EntityState;
import org.springframework.data.neo4j.fieldaccess.DetachedEntityState;
import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity;
import org.springframework.data.neo4j.support.node.NodeEntityState;
import org.springframework.data.neo4j.support.node.NodeEntityStateFactory;
import javax.annotation.PostConstruct;
import javax.persistence.EntityManagerFactory;

View File

@@ -96,7 +96,7 @@
<property name="entityStateHandler" ref="entityStateHandler"/>
<property name="mappingContext" ref="mappingContext"/>
</bean>
<bean id="graphEntityInstantiator" class="org.springframework.data.neo4j.support.node.CrossStoreNodeEntityInstantiator">
<bean id="graphEntityInstantiator" class="org.springframework.data.neo4j.cross_store.support.node.CrossStoreNodeEntityInstantiator">
<constructor-arg ref="nodeEntityInstantiator"/>
<constructor-arg ref="entityManagerFactory"/>
</bean>
@@ -121,7 +121,7 @@
<bean id="nodeTypeRepresentationStrategy" factory-bean="typeRepresentationStrategyFactory" factory-method="getNodeTypeRepresentationStrategy" />
<bean id="relationshipTypeRepresentationStrategy" factory-bean="typeRepresentationStrategyFactory" factory-method="getRelationshipTypeRepresentationStrategy"/>
<bean id="nodeEntityStateFactory" class="org.springframework.data.neo4j.support.node.CrossStoreNodeEntityStateFactory">
<bean id="nodeEntityStateFactory" class="org.springframework.data.neo4j.cross_store.support.node.CrossStoreNodeEntityStateFactory">
<property name="nodeDelegatingFieldAccessorFactory">
<bean class="org.springframework.data.neo4j.fieldaccess.NodeDelegatingFieldAccessorFactory">
<constructor-arg ref="graphDatabaseContext"/>

View File

@@ -0,0 +1,42 @@
Bundle-SymbolicName: org.springframework.data.neo4j
Bundle-Name: Spring Data Neo4J
Bundle-Vendor: SpringSource
Bundle-ManifestVersion: 2
Import-Package:
sun.reflect;version="0";resolution:=optional
Import-Template:
org.springframework.beans.*;version="[3.0.0, 4.0.0)",
org.springframework.context.*;version="[3.0.0, 4.0.0)",
org.springframework.core.*;version="[3.0.0, 4.0.0)",
org.springframework.dao.*;version="[3.0.0, 4.0.0)",
org.springframework.jdbc.*;version="[3.0.0, 4.0.0)",
org.springframework.stereotype.*;version="[3.0.0, 4.0.0)",
org.springframework.orm.*;version="[3.0.0, 4.0.0)",
org.springframework.transaction.*;version="[3.0.0, 4.0.0)",
org.springframework.util.*;version="[3.0.0, 4.0.0)",
org.springframework.data.*;version="[1.0.0, 2.0.0)",
org.springframework.persistence.*;version="[1.0.0, 2.0.0)",
org.springframework.data.neo4j.*;version="0",
org.neo4j.*;version="0",
org.neo4j.cypher.*;version="0";resolution:=optional,
org.w3c.dom.*;version="0",
org.aspectj.*;version="[1.6.5, 2.0.0)",
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
org.apache.commons.configuration.*;version="0",
org.objectweb.jotm.*;version="0",
org.apache.lucene.*;version="0",
javax.validation.*;version="0";resolution:=optional,
javax.annotation.*;version="0";resolution:=optional,
javax.naming.*;version="0";resolution:=optional,
javax.script.*;version="0";resolution:=optional,
javax.persistence.*;version="[1.0.0, 3.0.0)";resolution:=optional,
javax.persistence.spi.*;version="[1.0.0, 3.0.0)";resolution:=optional,
javax.transaction.*;version="[1.0.1, 2.0.0)";resolution:=optional,
com.tinkerpop.blueprints.*;version="[0.8,1.0)";resolution:=optional,
com.tinkerpop.gremlin.*;version="[1.1,2.0)";resolution:=optional,
com.tinkerpop.pipes.util.*;version="[0.8,1.0)";resolution:=optional
Import-Package:
net.sf.cglib.proxy;version="[2.2.0,3.0.0)",
net.sf.cglib.core;version="[2.2.0,3.0.0)",
net.sf.cglib.reflect;version="[2.2.0,3.0.0)"
DynamicImport-Package: *

View File

@@ -16,6 +16,7 @@ import java.util.Set;
public class Person {
@Indexed
String id;
@Indexed(fulltext = true, indexName = "people")
String name;
private Date birthday;
private String birthplace;

View File

@@ -0,0 +1,50 @@
package org.neo4j.cineasts.movieimport;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import java.util.Collections;
import java.util.Map;
/**
* @author mh
* @since 04.10.11
*/
public class MovieImporter {
private final MovieDbImportService importer;
public static void main(String[] args) {
final FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext("src/main/webapp/WEB-INF/applicationContext.xml");
try {
final MovieDbImportService importer = ctx.getBean(MovieDbImportService.class);
final MovieImporter movieImporter = new MovieImporter(importer);
movieImporter.runImport(getMovieIdsToImport(args));
} finally {
ctx.close();
}
}
public MovieImporter(MovieDbImportService importer) {
this.importer = importer;
}
private void runImport(Map<Integer, Integer> movieIdsToImport) {
final long start = System.currentTimeMillis();
final Map<Integer, String> result = importer.importMovies(movieIdsToImport);
final long time = System.currentTimeMillis() - start;
for (Map.Entry<Integer, String> movie : result.entrySet()) {
System.out.println(movie.getKey() + "\t" + movie.getValue());
}
System.out.println("Imported movies took "+ time+" ms.");
}
private static Map<Integer, Integer> getMovieIdsToImport(String[] args) {
if (args.length == 0) {
throw new IllegalArgumentException("Usage: MovieImporter 1 10000\nWorking Directory should be the cineasts directory with the json files in data/json.");
}
if (args.length == 1) {
return Collections.singletonMap(Integer.valueOf(args[0]), Integer.valueOf(args[0]));
}
return Collections.singletonMap(Integer.valueOf(args[0]), Integer.valueOf(args[1]));
}
}

View File

@@ -45,9 +45,10 @@ public class RestCypherQueryEngine implements QueryEngine<Map<String,Object>> {
@Override
public QueryResult<Map<String, Object>> query(String statement, Map<String, Object> params) {
final String parametrizedStatement = QueryResultBuilder.replaceParams(statement, params);
final RequestResult requestResult = restRequest.get("ext/CypherPlugin/graphdb/execute_query", JsonHelper.createJsonFrom(MapUtil.map("query", parametrizedStatement)));
return new RestQueryResult(restRequest.toMap(requestResult),restGraphDatabase,resultConverter);
final RequestResult requestResult = restRequest.get("ext/CypherPlugin/graphdb/execute_query", JsonHelper.createJsonFrom(MapUtil.map("query", statement, "params", params)));
final Map<?, ?> resultMap = restRequest.toMap(requestResult);
if (RestResultException.isExceptionResult(resultMap)) throw new RestResultException(resultMap);
return new RestQueryResult(resultMap,restGraphDatabase,resultConverter);
}
static class RestQueryResult implements QueryResult<Map<String,Object>> {

View File

@@ -116,6 +116,12 @@ public class LocalTestServer {
startupListener.await();
}
@Override
public void stop() {
getJetty().setStopAtShutdown(false);
super.stop();
}
};
neoServer = new NeoServerWithEmbeddedWebServer(bootstrapper
, addressResolver, new StartupHealthCheck(), new PropertyFileConfigurator(new File(url.getPath())), jettyWebServer, serverModules) {

View File

@@ -30,11 +30,12 @@ public class RestTestHelper
protected RestGraphDatabase graphDb;
private static final String HOSTNAME = "localhost";
private static final int PORT = 7473;
private static LocalTestServer neoServer = new LocalTestServer(HOSTNAME,PORT).withPropertiesFile("test-db.properties");
private static LocalTestServer neoServer;
private static final String SERVER_ROOT_URI = "http://" + HOSTNAME + ":" + PORT + "/db/data/";
public void startServer() throws Exception {
BasicConfigurator.configure();
neoServer = new LocalTestServer(HOSTNAME,PORT).withPropertiesFile("test-db.properties");
neoServer.start();
}
@@ -48,5 +49,6 @@ public class RestTestHelper
public static void shutdownServer() {
neoServer.stop();
neoServer = null;
}
}

View File

@@ -36,7 +36,7 @@ import java.lang.annotation.Target;
@Target({ElementType.FIELD,ElementType.METHOD})
public @interface Query {
/**
* @return Query to be executed %start will be replaced by the node-id of the current entity other placeholders (%name) by the given named params
* @return Query to be executed {self} will be provided by the node-id of the current entity other parameters (e.g. {name}) by the given named params
*/
String value() default "";

View File

@@ -33,8 +33,8 @@ import static org.springframework.util.StringUtils.hasText;
public class DataGraphBeanDefinitionParser extends AbstractBeanDefinitionParser {
private static final String GRAPH_DATABASE_SERVICE = "graphDatabaseService";
public static final String ASPECTJ_CONFIG = "org.springframework.data.neo4j.config.Neo4jAspectConfiguration";
public static final String CROSS_STORE_CONFIG = "org.springframework.data.neo4j.config.CrossStoreNeo4jConfiguration";
public static final String ASPECTJ_CONFIG = "org.springframework.data.neo4j.aspects.config.Neo4jAspectConfiguration";
public static final String CROSS_STORE_CONFIG = "org.springframework.data.neo4j.cross_store.config.CrossStoreNeo4jConfiguration";
@Override
protected AbstractBeanDefinition parseInternal(Element element, ParserContext context) {

View File

@@ -21,7 +21,6 @@ import org.neo4j.helpers.collection.ClosableIterable;
import org.neo4j.helpers.collection.IteratorWrapper;
import java.util.Iterator;
import java.util.Map;
/**
* @author mh
@@ -33,6 +32,7 @@ public class QueryResultBuilder<T> implements QueryResult<T> {
private final boolean isClosableIterable;
private boolean isClosed;
@SuppressWarnings("unchecked")
public QueryResultBuilder(Iterable<T> result) {
this(result, new DefaultConverter());
}
@@ -43,14 +43,7 @@ public class QueryResultBuilder<T> implements QueryResult<T> {
this.defaultConverter = defaultConverter;
}
public static String replaceParams(String statement, Map<String, Object> params) {
if (params==null || params.isEmpty()) return statement;
for (Map.Entry<String, Object> param : params.entrySet()) {
statement = statement.replaceAll("%"+param.getKey()+"\\b",""+param.getValue());
}
return statement;
}
@SuppressWarnings("unchecked")
@Override
public <R> ConvertedResult<R> to(Class<R> type) {
return this.to(type, defaultConverter);

View File

@@ -143,13 +143,10 @@ public class DetachedEntityState<STATE> implements EntityState<STATE> {
if (isDetached()) {
final Field field = property.getField();
if (!isDirty(field) && isWritable(field)) {
Object existingValue;
if (hasPersistentState()) {
addDirty(field, unwrap(delegate.getValue(field)), true);
}
else {
// existingValue = getValueFromEntity(field);
// if (existingValue == null) existingValue = getDefaultValue(field.getType());
addDirty(field, newVal, false);
}
}
@@ -170,6 +167,7 @@ public class DetachedEntityState<STATE> implements EntityState<STATE> {
return null;
}
@SuppressWarnings("deprecation")
@Override
public void createAndAssignState() {
if (graphDatabaseContext.transactionIsRunning()) {

View File

@@ -86,6 +86,7 @@ public class Neo4jConversionServiceFactoryBean implements FactoryBean<Conversion
public static class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {
@SuppressWarnings("unchecked")
public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
return new StringToEnum(targetType);
}
@@ -97,6 +98,7 @@ public class Neo4jConversionServiceFactoryBean implements FactoryBean<Conversion
public StringToEnum(Class<T> enumType) {
this.enumType = enumType;
}
@SuppressWarnings("RedundantCast")
public T convert(String source) {
if (source == null) return null;
final String trimmed=source.trim();

View File

@@ -45,7 +45,7 @@ public class OneToNRelationshipFieldAccessorFactory extends NodeRelationshipFiel
@Override
public FieldAccessor forField(final Neo4jPersistentProperty property) {
final RelationshipInfo relationshipInfo = property.getRelationshipInfo();
final Class<?> targetType = (Class<?>) relationshipInfo.getTargetType().getType();
final Class<?> targetType = relationshipInfo.getTargetType().getType();
return new OneToNRelationshipFieldAccessor(relationshipInfo.getRelationshipType(), relationshipInfo.getDirection(), targetType, graphDatabaseContext,property);
}

View File

@@ -99,7 +99,7 @@ public class QueryFieldAccessorFactory implements FieldAccessorFactory {
private Map<String, Object> createPlaceholderParams(Object entity) {
Map<String,Object> params=new HashMap<String, Object>();
final Node startNode = graphDatabaseContext.<Node>getPersistentState(entity);
params.put("start", startNode.getId());
params.put("self", startNode.getId());
if (annotationParams.length==0) return params;
for (int i = 0; i < annotationParams.length; i+=2) {
params.put(annotationParams[i],annotationParams[i+1]);

View File

@@ -69,6 +69,7 @@ class Neo4jPersistentPropertyImpl extends AbstractPersistentProperty<Neo4jPersis
return annotation!=null ? new IndexInfo(annotation) : null;
}
@SuppressWarnings("unchecked")
public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
return (T) annotations.get(annotationType);
}

View File

@@ -68,6 +68,7 @@ public class Neo4jPersistentEntityImpl<T> extends BasicPersistentEntity<T, Neo4j
return hasAnnotation(RelationshipEntity.class);
}
@SuppressWarnings("unchecked")
private <T extends Annotation> T getAnnotation(Class<T> annotationType) {
return (T) annotations.get(annotationType);
}

View File

@@ -38,6 +38,7 @@ public class GraphMetamodelEntityInformation<S extends PropertyContainer, T> ext
private final RelationshipEntity relationshipEntity;
private final NodeEntity nodeEntity;
@SuppressWarnings("unchecked")
public GraphMetamodelEntityInformation(Class domainClass, GraphDatabaseContext graphDatabaseContext) {
super(domainClass);
this.graphDatabaseContext = graphDatabaseContext;

View File

@@ -43,6 +43,7 @@ public class RelationshipGraphRepository<T> extends AbstractGraphRepository<Rela
return entity;
}
@SuppressWarnings("unchecked")
@Override
public Iterable<T> save(Iterable<? extends T> entities) {
return (Iterable<T>) entities;

View File

@@ -67,7 +67,8 @@ public abstract class SpringPluginInitializer implements PluginLifecycle {
ProvidedClassPathXmlApplicationContext appCtx = SpringPluginInitializer.this.ctx;
for ( final Pair<String, Class> exposedBean : exposedBeans ) {
// Class<?> concreteType = ctx.getType( exposedBean );
result.add( new SpringBeanInjectable( appCtx, exposedBean.first(), exposedBean.other() ) );
@SuppressWarnings("unchecked") final SpringBeanInjectable injectable = new SpringBeanInjectable(appCtx, exposedBean.first(), exposedBean.other());
result.add(injectable);
}
return result;
}
@@ -86,7 +87,7 @@ public abstract class SpringPluginInitializer implements PluginLifecycle {
*
* @param <T> optional type of the bean
*/
private static class SpringBeanInjectable<T extends Object> implements Injectable<T> {
private static class SpringBeanInjectable<T> implements Injectable<T> {
private final String exposedBean;
protected ApplicationContext ctx;
private final Class<T> clazz;
@@ -97,6 +98,7 @@ public abstract class SpringPluginInitializer implements PluginLifecycle {
this.clazz = clazz;
}
@SuppressWarnings("unchecked")
public T getValue() {
return (T)ctx.getBean( exposedBean );

View File

@@ -34,6 +34,7 @@ public class EntityStateHandler {
this.service = service;
}
@SuppressWarnings("unchecked")
public <S extends PropertyContainer> void setPersistentState(Object entity, S state) {
if (entity instanceof PropertyContainer) {
return;

View File

@@ -37,6 +37,7 @@ public class EntityResultConverter<T,R> extends DefaultConverter<T,R> {
conversionService = this.ctx.getConversionService();
}
@SuppressWarnings("unchecked")
@Override
protected Object doConvert(Object value, Class<?> sourceType, Class targetType) {
if (ctx.isNodeEntity(targetType)) {

View File

@@ -27,6 +27,7 @@ import org.springframework.data.neo4j.conversion.QueryResult;
import org.springframework.data.neo4j.conversion.QueryResultBuilder;
import org.springframework.data.neo4j.conversion.ResultConverter;
import java.util.Collections;
import java.util.Map;
public class CypherQueryEngine implements QueryEngine<Map<String,Object>> {
@@ -48,19 +49,18 @@ public class CypherQueryEngine implements QueryEngine<Map<String,Object>> {
@Override
public QueryResult<Map<String, Object>> query(String statement, Map<String, Object> params) {
try {
String parametrizedQuery = QueryResultBuilder.replaceParams(statement,params);
ExecutionResult result = parseAndExecuteQuery(parametrizedQuery);
ExecutionResult result = parseAndExecuteQuery(statement,params);
return new QueryResultBuilder<Map<String,Object>>(result,resultConverter);
} catch (Exception e) {
throw new InvalidDataAccessResourceUsageException("Error executing statement " + statement, e);
}
}
private ExecutionResult parseAndExecuteQuery(String statement) {
private ExecutionResult parseAndExecuteQuery(String statement, Map<String, Object> params) {
try {
CypherParser parser = new CypherParser();
Query query = parser.parse(statement);
return executionEngine.execute(query);
return executionEngine.execute(query,params==null ? Collections.<String,Object>emptyMap() : params);
} catch(Exception e) {
throw new InvalidDataAccessResourceUsageException("Error executing statement " + statement, e);
}

View File

@@ -31,11 +31,10 @@ import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
@SuppressWarnings("ALL")
public class GremlinExecutor {
public static final int REFRESH_ENGINE_COUNT = 10000;
private final String g = "g";
private static final String GRAPH_VARIABLE = "g";
private volatile ScriptEngine engine;
private ScriptEngine createScriptEngine() {
@@ -49,6 +48,7 @@ public class GremlinExecutor {
this.graphDatabaseService = graphDatabaseService;
}
@SuppressWarnings("unchecked")
public Iterable<Object> query(String statement, Map<String,Object> params) {
try {
final Bindings bindings = createBindings(params);
@@ -62,7 +62,7 @@ public class GremlinExecutor {
private Bindings createBindings(Map<String, Object> params) {
final Bindings bindings = new SimpleBindings();
bindings.put(g, new Neo4jGraph(graphDatabaseService));
bindings.put(GRAPH_VARIABLE, new Neo4jGraph(graphDatabaseService));
if (params==null) return bindings;
for (Map.Entry<String, Object> entry : params.entrySet()) {
bindings.put(entry.getKey(),entry.getValue());
@@ -73,12 +73,13 @@ public class GremlinExecutor {
private ScriptEngine engine() {
if (engine == null || executionCount.incrementAndGet() > REFRESH_ENGINE_COUNT) {
executionCount.set(0);
this.engine = new ScriptEngineManager().getEngineByName("gremlin");
this.engine = createScriptEngine();
}
return this.engine;
}
@SuppressWarnings("unchecked")
public static Iterable getRepresentation(final Object result) {
if (result instanceof Iterable) {
if (result instanceof Table) {

View File

@@ -16,7 +16,9 @@
package org.springframework.data.neo4j.support.typerepresentation;
import org.neo4j.graphdb.*;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.index.Index;
import org.neo4j.graphdb.index.IndexHits;
import org.neo4j.helpers.Predicate;
@@ -24,14 +26,9 @@ import org.neo4j.helpers.collection.ClosableIterable;
import org.neo4j.helpers.collection.FilteringIterable;
import org.neo4j.helpers.collection.IterableWrapper;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.data.neo4j.core.NodeTypeRepresentationStrategy;
import org.springframework.data.neo4j.support.EntityInstantiator;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
public class IndexingNodeTypeRepresentationStrategy implements NodeTypeRepresentationStrategy {
public static final String INDEX_NAME = "__types__";
@@ -89,6 +86,7 @@ public class IndexingNodeTypeRepresentationStrategy implements NodeTypeRepresent
return count;
}
@SuppressWarnings("unchecked")
@Override
public Class<?> getJavaType(Node node) {
if (node == null) throw new IllegalArgumentException("Node is null");

View File

@@ -57,10 +57,10 @@ public class IndexingRelationshipTypeRepresentationStrategy implements Relations
}
private void addToTypesIndex(Relationship node, Class<?> entityClass) {
Class<?> klass = entityClass;
while (klass.getAnnotation(RelationshipEntity.class) != null) {
getRelTypesIndex().add(node, INDEX_KEY, klass.getName());
klass = klass.getSuperclass();
Class<?> type = entityClass;
while (type.getAnnotation(RelationshipEntity.class) != null) {
getRelTypesIndex().add(node, INDEX_KEY, type.getName());
type = type.getSuperclass();
}
}

View File

@@ -136,6 +136,7 @@ public class SubReferenceNodeTypeRepresentationStrategy implements NodeTypeRepre
return clazz;
}
@SuppressWarnings("unchecked")
private <T> Class<T> resolveType(Node node, String typeName) {
final Class<?> type = typeCache.getClassForName(typeName);
if (type == null) {
@@ -180,7 +181,7 @@ public class SubReferenceNodeTypeRepresentationStrategy implements NodeTypeRepre
@Override
protected T underlyingObjectToObject(final Relationship rel) {
final Node node = rel.getStartNode();
T entity = (T) entityInstantiator.createEntityFromState(node, getJavaType(node));
@SuppressWarnings("unchecked") T entity = (T) entityInstantiator.createEntityFromState(node, getJavaType(node));
if (log.isDebugEnabled()) log.debug("Converting node: " + node + " to entity: " + entity);
return entity;
}

View File

@@ -53,7 +53,6 @@ public class Neo4jTemplate implements Neo4jOperations {
/**
* @param graphDatabase the neo4j graph database
* @param transactionManager if passed in, will be used to create implicit transactions whenever needed
* @return a Neo4jTemplate instance
*/
public Neo4jTemplate(final GraphDatabase graphDatabase, PlatformTransactionManager transactionManager) {
notNull(graphDatabase, "graphDatabase");
@@ -61,10 +60,6 @@ public class Neo4jTemplate implements Neo4jOperations {
this.graphDatabase = graphDatabase;
}
/**
* @param graphDatabase the neo4j graph database
* @return a Neo4jTemplate instance
*/
public Neo4jTemplate(final GraphDatabase graphDatabase) {
notNull(graphDatabase, "graphDatabase");
transactionManager = null;
@@ -178,11 +173,13 @@ public class Neo4jTemplate implements Neo4jOperations {
});
}
@SuppressWarnings("unchecked")
public QueryResult<Map<String, Object>> query(String statement, Map<String, Object> params) {
notNull(statement, "statement");
return queryEngineFor(QueryType.Cypher).query(statement, params);
}
@SuppressWarnings("unchecked")
@Override
public QueryResult<Object> execute(String statement, Map<String, Object> params) {
notNull(statement, "statement");

View File

@@ -22,7 +22,7 @@ import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.kernel.EmbeddedGraphDatabase;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.neo4j.PersonRepository;
import org.springframework.data.neo4j.model.PersonRepository;
import org.springframework.data.neo4j.repository.DirectGraphRepositoryFactory;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import org.springframework.transaction.PlatformTransactionManager;

View File

@@ -17,7 +17,7 @@ package org.springframework.data.neo4j.mapping;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.neo4j.Person;
import org.springframework.data.neo4j.model.Person;
import static org.junit.Assert.assertEquals;

View File

@@ -24,8 +24,8 @@ import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.index.Index;
import org.neo4j.test.ImpermanentGraphDatabase;
import org.springframework.data.neo4j.Person;
import org.springframework.data.neo4j.Personality;
import org.springframework.data.neo4j.model.Person;
import org.springframework.data.neo4j.model.Personality;
import org.springframework.data.neo4j.fieldaccess.Neo4jConversionServiceFactoryBean;
import org.springframework.data.neo4j.fieldaccess.NodeDelegatingFieldAccessorFactory;
import org.springframework.data.neo4j.support.EntityStateHandler;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.neo4j;
package org.springframework.data.neo4j.model;
import org.springframework.data.neo4j.annotation.Indexed;
import org.springframework.data.neo4j.annotation.NodeEntity;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.neo4j;
package org.springframework.data.neo4j.model;
import org.neo4j.graphdb.Node;
import org.springframework.data.neo4j.annotation.GraphId;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.neo4j;
package org.springframework.data.neo4j.model;
import org.springframework.data.neo4j.annotation.NodeEntity;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.neo4j;
package org.springframework.data.neo4j.model;
import org.springframework.data.neo4j.annotation.*;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.neo4j;
package org.springframework.data.neo4j.model;
import org.springframework.data.neo4j.repository.GraphRepository;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.neo4j;
package org.springframework.data.neo4j.model;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.DynamicRelationshipType;
@@ -116,6 +116,7 @@ public class Group {
}
private static class PeopleTraversalBuilder implements FieldTraversalDescriptionBuilder {
@SuppressWarnings("deprecation")
@Override
public TraversalDescription build(Object start, Neo4jPersistentProperty property, String...params) {
return new TraversalDescriptionImpl()

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.neo4j;
package org.springframework.data.neo4j.model;
import org.springframework.data.neo4j.repository.GraphRepository;
import org.springframework.data.neo4j.repository.NamedIndexRepository;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.neo4j;
package org.springframework.data.neo4j.model;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.data.neo4j.annotation.RelatedTo;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.neo4j;
package org.springframework.data.neo4j.model;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.data.neo4j.annotation.RelatedTo;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.neo4j;
package org.springframework.data.neo4j.model;
import org.springframework.data.neo4j.annotation.NodeEntity;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.neo4j;
package org.springframework.data.neo4j.model;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
@@ -70,16 +70,16 @@ public class Person {
@RelatedToVia(type = "knows", elementClass = Friendship.class)
private Iterable<Friendship> friendships;
@Query(value = "start person=(%start) match (person)<-[:boss]-(boss) return boss")
@Query(value = "start person=node({self}) match (person)<-[:boss]-(boss) return boss")
private Person bossByQuery;
@Query(value = "start person=(%start) match (person)<-[:boss]-(boss) return boss.%property",params = {"property","name"})
@Query(value = "start person=node({self}) match (person)<-[:boss]-(boss) return boss.%property",params = {"property","name"})
private String bossName;
@Query(value = "start person=(%start) match (person)<-[:persons]-(team)-[:persons]->(member) return member",elementClass = Person.class)
@Query(value = "start person=node({self}) match (person)<-[:persons]-(team)-[:persons]->(member) return member",elementClass = Person.class)
private Iterable<Person> otherTeamMembers;
@Query(value = "start person=(%start) match (person)<-[:persons]-(team)-[:persons]->(member) return member.name, member.age")
@Query(value = "start person=node({self}) match (person)<-[:persons]-(team)-[:persons]->(member) return member.name, member.age")
private Iterable<Map<String,Object>> otherTeamMemberData;
public Person(Node n) {

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.neo4j;
package org.springframework.data.neo4j.model;
import org.neo4j.graphdb.Node;
import org.springframework.data.persistence.StateBackedCreator;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.neo4j;
package org.springframework.data.neo4j.model;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
@@ -33,22 +33,22 @@ import java.util.Map;
*/
public interface PersonRepository extends GraphRepository<Person>, NamedIndexRepository<Person> {
@Query("start team=(%team) match (team)-[:persons]->(member) return member")
Iterable<Person> findAllTeamMembers(@Param("team") Group team);
@Query("start team=node({p_team}) match (team)-[:persons]->(member) return member")
Iterable<Person> findAllTeamMembers(@Param("p_team") Group team);
@Query(value = "g.v(team).out('persons')", type = QueryType.Gremlin)
Iterable<Person> findAllTeamMembersGremlin(@Param("team") Group team);
@Query("start team=(%team) match (team)-[:persons]->(member) return member.name,member.age")
Iterable<Map<String,Object>> findAllTeamMemberData(@Param("team") Group team);
@Query("start team=node({p_team}) match (team)-[:persons]->(member) return member.name,member.age")
Iterable<Map<String,Object>> findAllTeamMemberData(@Param("p_team") Group team);
@Query("start person=(%person) match (boss)-[:boss]->(person) return boss")
Person findBoss(@Param("person") Person person);
@Query("start person=node({p_person}) match (boss)-[:boss]->(person) return boss")
Person findBoss(@Param("p_person") Person person);
Group findTeam(@Param("person") Person person);
Group findTeam(@Param("p_person") Person person);
@Query("start team=(%team) match (team)-[:persons]->(member) return member")
Page<Person> findAllTeamMembersPaged(@Param("team") Group team, Pageable page);
@Query("start team=(%team) match (team)-[:persons]->(member) return member")
Iterable<Person> findAllTeamMembersSorted(@Param("team") Group team, Sort sort);
@Query("start team=node({p_team}) match (team)-[:persons]->(member) return member")
Page<Person> findAllTeamMembersPaged(@Param("p_team") Group team, Pageable page);
@Query("start team=node({p_team}) match (team)-[:persons]->(member) return member")
Iterable<Person> findAllTeamMembersSorted(@Param("p_team") Group team, Sort sort);
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.neo4j;
package org.springframework.data.neo4j.model;
public enum Personality {
EXTROVERT, INTROVERT

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.neo4j;
package org.springframework.data.neo4j.model;
import org.springframework.data.neo4j.annotation.NodeEntity;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.neo4j;
package org.springframework.data.neo4j.model;
public class Toyota extends Car {
public Toyota() {

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.data.neo4j;
package org.springframework.data.neo4j.model;
public class Volvo extends Car {
public Volvo() {

View File

@@ -14,19 +14,16 @@
* limitations under the License.
*/
package org.springframework.data.neo4j.aspects.support;
package org.springframework.data.neo4j.support;
import org.hamcrest.core.Is;
import org.hamcrest.core.IsInstanceOf;
import org.hamcrest.core.IsNot;
import org.hamcrest.core.IsNull;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.neo4j.core.GraphDatabase;
import org.springframework.data.neo4j.support.DelegatingGraphDatabase;
import org.springframework.data.neo4j.support.GraphDatabaseFactory;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.hamcrest.core.IsNot.not;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertThat;
/**
* @author mh
@@ -39,8 +36,8 @@ public class GraphDatabaseFactoryTest {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("GraphDatabaseFactory-context.xml");
try {
GraphDatabase graphDatabase = ctx.getBean("graphDatabase", GraphDatabase.class);
assertThat(graphDatabase, is(not(nullValue())));
assertThat(graphDatabase, is(instanceOf(DelegatingGraphDatabase.class)));
Assert.assertThat(graphDatabase, Is.is(IsNot.not(IsNull.nullValue())));
Assert.assertThat(graphDatabase, Is.is(IsInstanceOf.instanceOf(DelegatingGraphDatabase.class)));
} finally {
ctx.close();
}
@@ -52,8 +49,8 @@ public class GraphDatabaseFactoryTest {
try {
factory.setStoreLocation("target/test-db");
GraphDatabase graphDatabase = factory.getObject();
assertThat(graphDatabase, is(not(nullValue())));
assertThat(graphDatabase,is(instanceOf(DelegatingGraphDatabase.class)));
Assert.assertThat(graphDatabase, Is.is(IsNot.not(IsNull.nullValue())));
Assert.assertThat(graphDatabase, Is.is(IsInstanceOf.instanceOf(DelegatingGraphDatabase.class)));
} finally {
factory.shutdown();
}

View File

@@ -18,10 +18,7 @@ package org.springframework.data.neo4j.template;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.TermQuery;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.*;
import org.neo4j.graphdb.*;
import org.neo4j.graphdb.index.Index;
import org.neo4j.graphdb.traversal.TraversalDescription;
@@ -51,12 +48,12 @@ public class Neo4jTemplateApiTest {
private static final DynamicRelationshipType KNOWS = DynamicRelationshipType.withName("knows");
private static final DynamicRelationshipType HAS = DynamicRelationshipType.withName("has");
protected Neo4jTemplate template;
protected static GraphDatabase graphDatabase;
protected GraphDatabase graphDatabase;
protected Node referenceNode;
protected Relationship relationship1;
protected Node node1;
protected static PlatformTransactionManager transactionManager;
protected static GraphDatabaseService graphDatabaseService;
protected PlatformTransactionManager transactionManager;
protected GraphDatabaseService graphDatabaseService;
@@ -85,7 +82,7 @@ public class Neo4jTemplateApiTest {
private void createData() {
new TransactionTemplate(Neo4jTemplateApiTest.transactionManager).execute(new TransactionCallbackWithoutResult() {
new TransactionTemplate(transactionManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
referenceNode.setProperty("name", "node0");
@@ -98,8 +95,8 @@ public class Neo4jTemplateApiTest {
});
}
@AfterClass
public static void tearDown() throws Exception {
@After
public void tearDown() throws Exception {
if (graphDatabaseService!=null) {
graphDatabaseService.shutdown();
}
@@ -137,7 +134,7 @@ public class Neo4jTemplateApiTest {
@Test
public void shouldRollbackViaStatus() throws Exception {
new TransactionTemplate(Neo4jTemplateApiTest.transactionManager).execute(new TransactionCallbackWithoutResult() {
new TransactionTemplate(transactionManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(final TransactionStatus status) {
template.exec(new GraphCallback.WithoutResult() {
@@ -174,7 +171,7 @@ public class Neo4jTemplateApiTest {
}
@Test(expected = DataAccessException.class)
public void shouldConvertNotFoundExceptionToDataAccessException() {
Neo4jTemplate template = new Neo4jTemplate(graphDatabase, Neo4jTemplateApiTest.transactionManager);
Neo4jTemplate template = new Neo4jTemplate(graphDatabase, transactionManager);
template.exec(new GraphCallback.WithoutResult() {
@Override
public void doWithGraphWithoutResult(GraphDatabase graph) throws Exception {
@@ -267,6 +264,7 @@ public class Neo4jTemplateApiTest {
assertSingleResult("rel1",template.lookup("relationship", "name", "rel1").to(String.class, new PropertyContainerNameConverter()));
}
@SuppressWarnings("deprecation")
@Test
public void testTraverse() throws Exception {
final TraversalDescription description = Traversal.description().relationships(KNOWS).prune(Traversal.pruneAfterDepth(1)).filter(Traversal.returnAllButStartNode());
@@ -275,7 +273,7 @@ public class Neo4jTemplateApiTest {
@Test
public void shouldFindNextNodeViaCypher() throws Exception {
assertSingleResult(node1, template.query("start n=(0) match n-->m return m", null).to(Node.class));
assertSingleResult(node1, template.query("start n=node(0) match n-->m return m", null).to(Node.class));
}
@Test

View File

@@ -51,7 +51,7 @@ public class NeoTraversalTest extends NeoApiTest {
});
final Set<String> resultSet = new HashSet<String>();
final TraversalDescription description = Traversal.description().relationships(HAS).filter(returnAllButStartNode()).prune(Traversal.pruneAfterDepth(2));
@SuppressWarnings("deprecation") final TraversalDescription description = Traversal.description().relationships(HAS).filter(returnAllButStartNode()).prune(Traversal.pruneAfterDepth(2));
final QueryResult<Path> queryResult = template.traverse(template.getReferenceNode(), description);
queryResult.handle(new Handler<Path>() {
@Override

View File

@@ -16,9 +16,9 @@
package org.springframework.test.context;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.support.AbstractTestExecutionListener;
import java.applet.AppletContext;
import java.lang.reflect.Field;
import java.util.Map;
@@ -31,7 +31,7 @@ public class CleanContextCacheTestExecutionListener extends AbstractTestExecutio
ContextCache cache = (ContextCache) cacheField.get(testContext);
Field cacheMapField = ContextCache.class.getDeclaredField("contextKeyToContextMap");
cacheMapField.setAccessible(true);
Map<String, AppletContext> cacheMap = (Map<String, AppletContext>) cacheMapField.get(cache);
@SuppressWarnings("unchecked") Map<String, ApplicationContext> cacheMap = (Map<String, ApplicationContext>) cacheMapField.get(cache);
String[] keys = new String[cacheMap.size()];
cacheMap.keySet().toArray(keys);
for (String key : keys) {

View File

@@ -1 +1 @@
Person.findTeam=start p=(%person) match (p)<-[:persons]-(group) return group
Person.findTeam=start p=node({p_person}) match (p)<-[:persons]-(group) return group

View File

@@ -114,19 +114,19 @@
</listitem>
</varlistentry>
<varlistentry>
<term>Executes the given query, replacing <code>%start</code> with the node-id and returning the results converted to the target type.</term>
<term>Executes the given query, providing the <code>{self}</code> variable with the node-id and returning the results converted to the target type.</term>
<listitem>
<para><code>&lt;T&gt; Iterable&lt;T&gt; NodeBacked.findAllByQuery(final String query, final Class&lt;T&gt; targetType)</code></para>
</listitem>
</varlistentry>
<varlistentry>
<term>Executes the given query, replacing <code>%start</code> with the node-id and returning the original result, but with nodes and relationships replaced by their appropriate entities.</term>
<term>Executes the given query, providing <code>{self}</code> variable with the node-id and returning the original result, but with nodes and relationships replaced by their appropriate entities.</term>
<listitem>
<para><code>Iterable&lt;Map&lt;String,Object&gt;&gt; NodeBacked.findAllByQuery(final String query)</code></para>
</listitem>
</varlistentry>
<varlistentry>
<term>Executes the given query, replacing <code>%start</code> with the node-id and returns a single result converted to the target type.</term>
<term>Executes the given query, providing <code>{self}</code> variable with the node-id and returns a single result converted to the target type.</term>
<listitem>
<para><code>&lt;T&gt; T NodeBacked.findByQuery(final String query, final Class&lt;T&gt; targetType)</code></para>
</listitem>

View File

@@ -76,8 +76,8 @@ public class Movie {
<para>
The <code>@Query</code> annotation leverages the delegation infrastructure used by the
Spring Data Neo4j aspects. It provides dynamic fields which, when accessed, return the values
selected by the provided query language expression. The provided query must contain a placeholder named <code>%start</code>
for the id of the current entity. For instance <code>start n=(%start) match n-[:FRIEND]->friend return friend</code>.
selected by the provided query language expression. The provided query must contain a placeholder named <code>{self}</code>
for the id of the current entity. For instance <code>start n=({self}) match n-[:FRIEND]->friend return friend</code>.
Graph queries can return variable number of entities. That's why annotation can be put onto fields
with a single value, an Iterable of a concrete type or an Iterable of <code>Map&lt;String,Object&gt;</code>.
Additional parameters are taken from the params attribute of the <code>@Query</code> annotation.
@@ -87,7 +87,7 @@ public class Movie {
<title>@Graph on a node entity field</title>
<programlisting language="java"><![CDATA[@NodeEntity
public class Group {
@Query(value = "start n=(%start) match (n)-[:%relType]->(friend) return friend",
@Query(value = "start n=({self}) match (n)-[:%relType]->(friend) return friend",
params = {"relType", "FRIEND"})
private Iterable<Person> friends;
}

View File

@@ -149,9 +149,9 @@
<title>Named Queries</title>
<para>Spring Data Neo4j also supports the notion of named queries which are externalized in property-config-files
(<code>META-INF/neo4j-named-queries.properties</code>). Those files have the format:
<code>Entity.finderName=query</code> (e.g. <code>Person.findBoss=start p=(%person) match (p)&lt;-[:BOSS]-(boss) return boss</code>).
<code>Entity.finderName=query</code> (e.g. <code>Person.findBoss=start p=({p_person}) match (p)&lt;-[:BOSS]-(boss) return boss</code>).
Otherwise named queries support the same parameters as annotated queries. For using the named parameters you have to either
annotate the parameters of the method with the <code>@Param("person")</code> annotation or enable debug symbols.
annotate the parameters of the method with the <code>@Param("p_person")</code> annotation or enable debug symbols.
</para>
</section>
<section>

View File

@@ -31,7 +31,7 @@ neo.createRelationship(mark,thomas, WORKS_WITH, map("project","spring-data"));
neo.index("devs",thomas, "name","Thomas");
// Cypher
assert "Mark".equals(neo.query("start p=(%person) match p<-[:WORKS_WITH]-other return other.name",
assert "Mark".equals(neo.query("start p=({p_person}) match p<-[:WORKS_WITH]-other return other.name",
map("person",thomas)).to(String.class).single());
// Gremlin