restructured project, first implementation steps of mapping approach, in progress

This commit is contained in:
Michael Hunger
2011-10-02 10:20:10 +02:00
parent e08b1cebf1
commit 068951f3c5
179 changed files with 3529 additions and 1131 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
*.log
.DS_Store
target
.springBeans

View File

@@ -7,12 +7,14 @@
<name>Spring Data Neo4j Distribution</name>
<description><![CDATA[Within the Spring Data project the Spring Data Neo4j library provides integration with the Neo4j graph database, offering object graph mapping, a Neo4jTemplate and Spring-Data-Commons Repository implementations.
]]></description>
<version>1.2.0.BUILD-SNAPSHOT</version>
<version>2.0.0.BUILD-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>spring-data-neo4j-parent</module>
<module>spring-data-neo4j</module>
<module>spring-data-neo4j-rest</module>
<module>spring-data-neo4j-aspects</module>
<module>spring-data-neo4j-cross-store</module>
</modules>
<url>http://www.springsource.org/spring-data/neo4j</url>
<organization>
@@ -461,7 +463,7 @@
<dependency>
<groupId>org.springframework.build</groupId>
<artifactId>org.springframework.build.aws.ant</artifactId>
<version>3.0.5.RELEASE</version>
<version>3.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>net.java.dev.jets3t</groupId>

View File

@@ -0,0 +1,236 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j-parent</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
<relativePath>../spring-data-neo4j-parent/pom.xml</relativePath>
</parent>
<artifactId>spring-data-neo4j-aspects</artifactId>
<packaging>jar</packaging>
<name>Spring Data Neo4J Aspects</name>
<description><![CDATA[AspectJ based Object Graph(Neo4j) Mapping and Active Record like Mixins for POJO Domain Entities
]]></description>
<url>http://www.springsource.org/spring-data/neo4j</url>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
</dependency>
<!-- Spring Data -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j</artifactId>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-kernel</artifactId>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
</dependency>
<!-- JPA -->
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<version>1.0.0.Final</version>
</dependency>
<!-- For Tests -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>3.5.5-Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.0.0.GA</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.0.2.GA</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>neo4j-public-repository</id>
<name>Neo4J Public Repository</name>
<url>http://m2.neo4j.org</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-maven-snapshot</id>
<snapshots>
<enabled>true</enabled>
</snapshots>
<name>Springframework Maven SNAPSHOT Repository</name>
<url>http://maven.springframework.org/snapshot</url>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.2</version>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<outxml>true</outxml>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-data-neo4j-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.springsource.bundlor</groupId>
<artifactId>com.springsource.bundlor.maven</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,29 @@
package org.springframework.data.neo4j.config;
import org.springframework.context.annotation.Bean;
import org.springframework.data.neo4j.support.node.Neo4jNodeBacking;
import org.springframework.data.neo4j.support.node.NodeEntityStateFactory;
import org.springframework.data.neo4j.support.relationship.Neo4jRelationshipBacking;
/**
* @author mh
* @since 30.09.11
*/
public class Neo4jAspectConfiguration extends Neo4jConfiguration {
@Bean
public Neo4jRelationshipBacking neo4jRelationshipBacking() throws Exception {
Neo4jRelationshipBacking aspect = Neo4jRelationshipBacking.aspectOf();
aspect.setGraphDatabaseContext(graphDatabaseContext());
aspect.setRelationshipEntityStateFactory(relationshipEntityStateFactory());
return aspect;
}
@Bean
public Neo4jNodeBacking neo4jNodeBacking() throws Exception {
Neo4jNodeBacking aspect = Neo4jNodeBacking.aspectOf();
aspect.setGraphDatabaseContext(graphDatabaseContext());
NodeEntityStateFactory entityStateFactory = nodeEntityStateFactory();
aspect.setNodeEntityStateFactory(entityStateFactory);
return aspect;
}
}

View File

@@ -16,6 +16,8 @@
package org.springframework.data.neo4j.core;
import org.springframework.data.neo4j.support.ManagedEntity;
/**
* super interface denoting entities that are graph backed, the backing STATE can be a {@link org.neo4j.graphdb.Node}
* or a {@link org.neo4j.graphdb.Relationship}.
@@ -24,7 +26,7 @@ package org.springframework.data.neo4j.core;
* @author Michael Hunger
* @since 21.09.2010
*/
public interface GraphBacked<STATE> {
public interface GraphBacked<STATE> extends ManagedEntity<STATE> {
/**
* internal setter used for initializing the graph-db state on existing or newly created entities
*

View File

@@ -18,7 +18,8 @@ package org.springframework.data.neo4j.fieldaccess;
import org.springframework.data.neo4j.core.EntityState;
import org.springframework.data.neo4j.core.NodeBacked;
import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import javax.persistence.Id;
@@ -26,29 +27,39 @@ import javax.persistence.Id;
* @author Michael Hunger
* @since 12.09.2010
*/
public class JpaIdFieldAccessListenerFactory implements FieldAccessorListenerFactory<NodeBacked> {
public class JpaIdFieldAccessListenerFactory implements FieldAccessorListenerFactory {
private final GraphDatabaseContext graphDatabaseContext;
public JpaIdFieldAccessListenerFactory(GraphDatabaseContext graphDatabaseContext) {
this.graphDatabaseContext = graphDatabaseContext;
}
@Override
public boolean accept(final Neo4JPersistentProperty property) {
public boolean accept(final Neo4jPersistentProperty property) {
return property.isAnnotationPresent(Id.class);
}
@Override
public FieldAccessListener<NodeBacked, ?> forField(final Neo4JPersistentProperty property) {
return new JpaIdFieldListener(property);
public FieldAccessListener forField(final Neo4jPersistentProperty property) {
return new JpaIdFieldListener(property,graphDatabaseContext);
}
public static class JpaIdFieldListener implements FieldAccessListener<NodeBacked, Object> {
protected final Neo4JPersistentProperty property;
public static class JpaIdFieldListener implements FieldAccessListener {
protected final Neo4jPersistentProperty property;
private final GraphDatabaseContext graphDatabaseContext;
public JpaIdFieldListener(final Neo4JPersistentProperty property) {
public JpaIdFieldListener(final Neo4jPersistentProperty property, GraphDatabaseContext graphDatabaseContext) {
this.property = property;
this.graphDatabaseContext = graphDatabaseContext;
}
@Override
public void valueChanged(NodeBacked nodeBacked, Object oldVal, Object newVal) {
public void valueChanged(Object entity, Object oldVal, Object newVal) {
if (newVal != null) {
EntityState entityState =nodeBacked.getEntityState();
graphDatabaseContext.save(entity);
/* TODO EntityState entityState = entity.getEntityState();
entityState.persist();
*/
}
}
}

View File

@@ -62,13 +62,24 @@ import static org.springframework.data.neo4j.support.DoReturn.unwrap;
*
* Handles constructor invocation and partial entities as well.
*/
public aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMixinFields<NodeEntity, NodeBacked> {
public privileged aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMixinFields<NodeEntity, NodeBacked> {
protected final Log log = LogFactory.getLog(getClass());
declare parents : (@NodeEntity *) implements NodeBacked;
//declare @type: NodeBacked+: @Configurable;
private GraphDatabaseContext graphDatabaseContext;
private NodeEntityStateFactory entityStateFactory;
public void setGraphDatabaseContext(GraphDatabaseContext graphDatabaseContext) {
this.graphDatabaseContext = graphDatabaseContext;
}
public void setNodeEntityStateFactory(NodeEntityStateFactory entityStateFactory) {
this.entityStateFactory = entityStateFactory;
}
declare @field: @GraphProperty * (@Entity @NodeEntity(partial=true) *).*:@Transient;
declare @field: @RelatedTo * (@Entity @NodeEntity(partial=true) *).*:@Transient;
declare @field: @RelatedToVia * (@Entity @NodeEntity(partial=true) *).*:@Transient;
@@ -91,15 +102,6 @@ public aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMixinFields<No
!set(* NodeBacked.*);
private GraphDatabaseContext graphDatabaseContext;
private NodeEntityStateFactory entityStateFactory;
public void setGraphDatabaseContext(GraphDatabaseContext graphDatabaseContext) {
this.graphDatabaseContext = graphDatabaseContext;
}
public void setNodeEntityStateFactory(NodeEntityStateFactory entityStateFactory) {
this.entityStateFactory = entityStateFactory;
}
/**
* pointcut for constructors not taking a node to be handled by the aspect and the {@link org.springframework.data.neo4j.core.EntityState}
*/
@@ -128,7 +130,7 @@ public aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMixinFields<No
/**
* State accessors that encapsulate the underlying state and the behaviour related to it (field access, creation)
*/
private transient EntityState<NodeBacked,Node> NodeBacked.entityState;
private transient EntityState<Node> NodeBacked.entityState;
public <T extends NodeBacked> T NodeBacked.persist() {
return (T)this.entityState.persist();
@@ -145,7 +147,7 @@ public aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMixinFields<No
return this.entityState!=null ? this.entityState.getPersistentState() : null;
}
public EntityState<NodeBacked, Node> NodeBacked.getEntityState() {
public EntityState<Node> NodeBacked.getEntityState() {
return entityState;
}

View File

@@ -69,7 +69,7 @@ public aspect Neo4jRelationshipBacking {
/**
* field for {@link org.springframework.data.neo4j.core.EntityState} that takes care of all entity operations
*/
private EntityState<RelationshipBacked,Relationship> RelationshipBacked.entityState;
private EntityState<Relationship> RelationshipBacked.entityState;
public void RelationshipBacked.setPersistentState(Relationship r) {
if (this.entityState == null) {
@@ -92,7 +92,7 @@ public aspect Neo4jRelationshipBacking {
}
public EntityState<RelationshipBacked, Relationship> RelationshipBacked.getEntityState() {
public EntityState<Relationship> RelationshipBacked.getEntityState() {
return this.entityState;
}

View File

@@ -0,0 +1,38 @@
/**
* 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;
import org.springframework.data.neo4j.annotation.Indexed;
import org.springframework.data.neo4j.annotation.NodeEntity;
/**
* @author mh
* @since 27.04.11
*/
@NodeEntity
public class Attribute<T> {
@Indexed
T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}

View File

@@ -0,0 +1,30 @@
/**
* 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;
import org.neo4j.graphdb.Node;
import org.springframework.data.neo4j.annotation.NodeEntity;
@NodeEntity
public abstract class Car {
public Car() {
}
public Car(Node n) {
setPersistentState(n);
}
}

View File

@@ -0,0 +1,46 @@
/**
* 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;
import org.springframework.data.neo4j.annotation.NodeEntity;
/**
* @author mh
* @since 18.02.11
*/
@NodeEntity
public class Developer {
String name;
Person spouse;
public Developer(String name) {
this.name = name;
}
public String getName() {
return name;
}
public Person getSpouse() {
return spouse;
}
public void setSpouse(Person spouse) {
this.spouse = spouse;
}
}

View File

@@ -0,0 +1,107 @@
/**
* 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;
import java.util.Date;
import org.springframework.data.neo4j.annotation.EndNode;
import org.springframework.data.neo4j.annotation.Indexed;
import org.springframework.data.neo4j.annotation.RelationshipEntity;
import org.springframework.data.neo4j.annotation.StartNode;
import org.springframework.data.neo4j.fieldaccess.DynamicProperties;
@RelationshipEntity(useShortNames = false)
public class Friendship {
public Friendship() {
}
public Friendship(Person p1, Person p2) {
this.p1 = p1;
this.p2 = p2;
}
public Friendship(Person p1, Person p2, int years) {
this.p1 = p1;
this.p2 = p2;
this.years = years;
}
@StartNode
private Person p1;
@EndNode
private Person p2;
@Indexed
private int years;
private Date firstMeetingDate;
private DynamicProperties personalProperties;
private transient String latestLocation;
public void setPerson1(Person p) {
p1 = p;
}
public Person getPerson1() {
return p1;
}
public void setPerson2(Person p) {
p2 = p;
}
public Person getPerson2() {
return p2;
}
public void setYears(int years) {
this.years = years;
}
public int getYears() {
return years;
}
public void setFirstMeetingDate(Date firstMeetingDate) {
this.firstMeetingDate = firstMeetingDate;
}
public Date getFirstMeetingDate() {
return firstMeetingDate;
}
public void setLatestLocation(String latestLocation) {
this.latestLocation = latestLocation;
}
public String getLatestLocation() {
return latestLocation;
}
public void setPersonalProperties(DynamicProperties personalProperties) {
this.personalProperties = personalProperties;
}
public DynamicProperties getPersonalProperties() {
return personalProperties;
}
}

View File

@@ -0,0 +1,22 @@
/**
* 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;
import org.springframework.data.neo4j.repository.GraphRepository;
public interface FriendshipRepository extends GraphRepository<Friendship> {
}

View File

@@ -0,0 +1,164 @@
/**
* 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;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.DynamicRelationshipType;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.kernel.Traversal;
import org.neo4j.kernel.impl.traversal.TraversalDescriptionImpl;
import org.springframework.data.neo4j.annotation.*;
import org.springframework.data.neo4j.core.FieldTraversalDescriptionBuilder;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
import java.util.Collection;
@NodeEntity
public class Group {
public final static String OTHER_NAME_INDEX="other_name";
public static final String SEARCH_GROUPS_INDEX = "search-groups";
@RelatedTo(direction = Direction.OUTGOING)
private Collection<Person> persons;
@RelatedTo(type = "persons", elementClass = Person.class)
private Iterable<Person> readOnlyPersons;
@GraphTraversal(traversalBuilder = PeopleTraversalBuilder.class, elementClass = Person.class, params = "persons")
private Iterable<Person> people;
@GraphProperty
@Indexed
private String name;
@GraphProperty
@Indexed
private Boolean admin;
@GraphProperty
private String unindexedName;
private String unindexedName2;
@GraphProperty
@Indexed(indexName = SEARCH_GROUPS_INDEX, fulltext = true)
private String fullTextName;
@Indexed(fieldName = OTHER_NAME_INDEX)
private String otherName;
@Indexed(level=Indexed.Level.GLOBAL)
private String globalName;
@Indexed(level=Indexed.Level.CLASS)
private String classLevelName;
@Indexed(level=Indexed.Level.INSTANCE)
private String indexLevelName;
public String getFullTextName() {
return fullTextName;
}
public void setFullTextName(String fullTextName) {
this.fullTextName = fullTextName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setPersons(Collection<Person> persons) {
this.persons = persons;
}
public void addPerson(Person person) {
persons.add(person);
}
public Collection<Person> getPersons() {
return persons;
}
public Iterable<Person> getReadOnlyPersons() {
return readOnlyPersons;
}
public void setReadOnlyPersons(Iterable<Person> p) {
readOnlyPersons = p;
}
public Iterable<Person> getPeople() {
return people;
}
public void setOtherName(String otherName) {
this.otherName = otherName;
}
private static class PeopleTraversalBuilder implements FieldTraversalDescriptionBuilder {
@Override
public TraversalDescription build(Object start, Neo4jPersistentProperty property, String...params) {
return new TraversalDescriptionImpl()
.relationships(DynamicRelationshipType.withName(params[0]))
.filter(Traversal.returnAllButStartNode());
}
}
public String getUnindexedName() {
return unindexedName;
}
public void setUnindexedName(String unindexedName) {
this.unindexedName = unindexedName;
}
public String getUnindexedName2() {
return unindexedName2;
}
public void setUnindexedName2(String unindexedName2) {
this.unindexedName2 = unindexedName2;
}
public void setGlobalName(String globalName) {
this.globalName = globalName;
}
public void setClassLevelName(String classLevelName) {
this.classLevelName = classLevelName;
}
public void setIndexLevelName(String indexLevelName) {
this.indexLevelName = indexLevelName;
}
public Boolean isAdmin() {
return admin;
}
public void setAdmin(Boolean admin) {
this.admin = admin;
}
}

View File

@@ -0,0 +1,27 @@
/**
* 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;
import org.springframework.data.neo4j.repository.NamedIndexRepository;
import org.springframework.data.neo4j.repository.GraphRepository;
/**
* @author mh
* @since 29.03.11
*/
public interface GroupRepository extends GraphRepository<Group>, NamedIndexRepository<Group> {
}

View File

@@ -0,0 +1,28 @@
/**
* 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;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.data.neo4j.annotation.RelatedTo;
import java.util.Collection;
@NodeEntity
public class InvalidOneToNEntity {
@RelatedTo
private Collection<InvalidOneToNEntity> others;
}

View File

@@ -0,0 +1,26 @@
/**
* 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;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.data.neo4j.annotation.RelatedTo;
@NodeEntity
public class InvalidReadOnlyOneToNEntity {
@RelatedTo
private Iterable<InvalidReadOnlyOneToNEntity> others;
}

View File

@@ -0,0 +1,32 @@
/**
* 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;
import org.springframework.data.neo4j.annotation.NodeEntity;
/**
* @author mh
* @since 20.01.11
*/
@NodeEntity
public class Named {
public String name;
public String getName() {
return name;
}
}

View File

@@ -0,0 +1,244 @@
/**
* 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;
import java.util.Date;
import java.util.Map;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.Size;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
import org.springframework.data.neo4j.annotation.GraphId;
import org.springframework.data.neo4j.annotation.Indexed;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.neo4j.annotation.RelatedTo;
import org.springframework.data.neo4j.annotation.RelatedToVia;
import org.springframework.data.neo4j.fieldaccess.DynamicProperties;
@NodeEntity
public class Person {
public static final String NAME_INDEX = "name_index";
@GraphId
private Long graphId;
@Indexed(indexName = NAME_INDEX)
@Size(min = 3, max = 20)
private String name;
@Indexed
private String nickname;
@Max(100)
@Min(0)
@Indexed
private int age;
private Short height;
private transient String thought;
private Personality personality;
private Date birthdate;
private Person spouse;
private Car car;
private DynamicProperties personalProperties;
@RelatedTo
private Person mother;
@RelatedTo(type = "boss", direction = Direction.INCOMING)
private Person boss;
@RelatedToVia(type = "knows", elementClass = Friendship.class)
private Iterable<Friendship> friendships;
@Query(value = "start person=(%start) match (person)<-[:boss]-(boss) return boss")
private Person bossByQuery;
@Query(value = "start person=(%start) 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)
private Iterable<Person> otherTeamMembers;
@Query(value = "start person=(%start) match (person)<-[:persons]-(team)-[:persons]->(member) return member.name, member.age")
private Iterable<Map<String,Object>> otherTeamMemberData;
public Person(Node n) {
setPersistentState(n);
}
public String getBossName() {
return bossName;
}
public Iterable<Person> getOtherTeamMembers() {
return otherTeamMembers;
}
public Iterable<Map<String, Object>> getOtherTeamMemberData() {
return otherTeamMemberData;
}
public Person getBossByQuery() {
return bossByQuery;
}
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Short getHeight() {
return height;
}
public void setHeight(Short height) {
this.height = height;
}
public Person getSpouse() {
return spouse;
}
public void setSpouse(Person spouse) {
this.spouse = spouse;
}
public Person getMother() {
return mother;
}
public void setMother(Person mother) {
this.mother = mother;
}
public Person getBoss() {
return boss;
}
public void setBoss(Person boss) {
this.boss = boss;
}
@Override
public String toString() {
return name;
}
public Iterable<Friendship> getFriendships() {
return friendships;
}
public void setFriendships(Iterable<Friendship> f) {
friendships = f;
}
public Friendship knows(Person p) {
return (Friendship)relateTo(p, Friendship.class,"knows");
}
public void setPersonality(Personality personality) {
this.personality = personality;
}
public Personality getPersonality() {
return personality;
}
public void setThought(String thought) {
this.thought = thought;
}
public String getThought() {
return thought;
}
public Date getBirthdate() {
return birthdate;
}
public void setBirthdate(Date birthdate) {
this.birthdate = birthdate;
}
public long getId() {
return graphId;
}
public void setCar(Car car) {
this.car = car;
}
public Car getCar() {
return car;
}
public void setProperty(String key, Object value) {
personalProperties.setProperty(key, value);
}
public Object getProperty(String key) {
return personalProperties.getProperty(key);
}
public DynamicProperties getPersonalProperties() {
return personalProperties;
}
public void setPersonalProperties(DynamicProperties personalProperties) {
this.personalProperties = personalProperties;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public static Person persistedPerson(String name, int age) {
return new Person(name,age).persist();
}
}

View File

@@ -0,0 +1,31 @@
/**
* 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;
import org.neo4j.graphdb.Node;
import org.springframework.data.persistence.StateBackedCreator;
/**
* @author mh
* @since 25.03.11
*/
public class PersonCreator implements StateBackedCreator<Person,Node> {
@Override
public Person create(Node n, Class<Person> c) throws Exception {
return new Person(n);
}
}

View File

@@ -0,0 +1,54 @@
/**
* 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;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.neo4j.annotation.QueryType;
import org.springframework.data.neo4j.repository.GraphRepository;
import org.springframework.data.neo4j.repository.NamedIndexRepository;
import org.springframework.data.repository.query.Param;
import java.util.Map;
/**
* @author mh
* @since 29.03.11
*/
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(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 person=(%person) match (boss)-[:boss]->(person) return boss")
Person findBoss(@Param("person") Person person);
Group findTeam(@Param("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);
}

View File

@@ -0,0 +1,21 @@
/**
* 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;
public enum Personality {
EXTROVERT, INTROVERT
}

View File

@@ -0,0 +1,23 @@
/**
* 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;
import org.springframework.data.neo4j.annotation.*;
@NodeEntity
public class SubGroup extends Group {
}

View File

@@ -0,0 +1,22 @@
/**
* 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;
public class Toyota extends Car {
public Toyota() {
}
}

View File

@@ -0,0 +1,24 @@
/**
* 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;
import org.springframework.data.neo4j.annotation.NodeEntity;
public class Volvo extends Car {
public Volvo() {
}
}

View File

@@ -74,6 +74,12 @@ public class DynamicPropertiesTest
assertEquals("String two", nodeFor(p).getProperty("personalProperties-s"));
}
@Test
public void testSetNullValue() {
final Person james = Person.persistedPerson("James", 35);
james.setPersonalProperties(null);
assertEquals("empty properties after setting to null",true,james.getPersonalProperties().asMap().isEmpty());
}
Person createTestPerson() {
Person p = persistedPerson("James", 36);
p.setProperty("s", "String");

View File

@@ -123,7 +123,7 @@
<property name="mappingContext" ref="mappingContext"/>
</bean>
<bean id="mappingContext" class="org.springframework.data.neo4j.mapping.Neo4JMappingContext"/>
<bean id="mappingContext" class="org.springframework.data.neo4j.mapping.Neo4jMappingContext"/>
<bean id="relationshipEntityStateFactory" class="org.springframework.data.neo4j.support.relationship.RelationshipEntityStateFactory">

View File

@@ -118,7 +118,7 @@
<property name="mappingContext" ref="mappingContext"/>
</bean>
<bean id="mappingContext" class="org.springframework.data.neo4j.mapping.Neo4JMappingContext"/>
<bean id="mappingContext" class="org.springframework.data.neo4j.mapping.Neo4jMappingContext"/>
<bean id="relationshipEntityStateFactory" class="org.springframework.data.neo4j.support.relationship.RelationshipEntityStateFactory">
<property name="relationshipDelegatingFieldAccessorFactory">

View File

@@ -0,0 +1,231 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j-parent</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
<relativePath>../spring-data-neo4j-parent/pom.xml</relativePath>
</parent>
<artifactId>spring-data-neo4j-cross-store</artifactId>
<packaging>jar</packaging>
<name>Spring Data Neo4J Cross-Store Handling</name>
<description><![CDATA[Neo4j + JPA cross-store persistence ]]></description>
<url>http://www.springsource.org/spring-data/neo4j</url>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
</dependency>
<!-- Spring Data -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j-aspects</artifactId>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-kernel</artifactId>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
</dependency>
<!-- JPA -->
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<version>1.0.0.Final</version>
</dependency>
<!-- For Tests -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>3.5.5-Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.0.0.GA</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.0.2.GA</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>neo4j-public-repository</id>
<name>Neo4J Public Repository</name>
<url>http://m2.neo4j.org</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-maven-snapshot</id>
<snapshots>
<enabled>true</enabled>
</snapshots>
<name>Springframework Maven SNAPSHOT Repository</name>
<url>http://maven.springframework.org/snapshot</url>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.2</version>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<outxml>true</outxml>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.springsource.bundlor</groupId>
<artifactId>com.springsource.bundlor.maven</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,74 @@
package org.springframework.data.neo4j.config;
import org.neo4j.graphdb.Node;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.PartialNodeEntityInstantiator;
import org.springframework.data.neo4j.transaction.ChainedTransactionManager;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.jta.JtaTransactionManager;
import javax.persistence.EntityManagerFactory;
/**
* @author mh
* @since 30.09.11
*/
@Configuration
public class CrossStoreNeo4jConfiguration extends Neo4jAspectConfiguration {
private EntityManagerFactory entityManagerFactory;
public EntityManagerFactory getEntityManagerFactory() {
return entityManagerFactory;
}
@Qualifier("&entityManagerFactory")
@Autowired(required = false)
public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
}
public boolean isUsingCrossStorePersistence() {
return entityManagerFactory != null;
}
@Bean
protected EntityInstantiator<Node> graphEntityInstantiator() {
if (isUsingCrossStorePersistence()) {
return new PartialNodeEntityInstantiator(new NodeEntityInstantiator(mappingContext), entityManagerFactory);
} else {
return new NodeEntityInstantiator(mappingContext);
}
}
@Bean
public PlatformTransactionManager transactionManager() {
if (isUsingCrossStorePersistence()) {
JpaTransactionManager jpaTm = new JpaTransactionManager(getEntityManagerFactory());
JtaTransactionManager jtaTm = createJtaTransactionManager();
return new ChainedTransactionManager(jpaTm, jtaTm);
}
else {
return createJtaTransactionManager();
}
}
@Bean
public NodeEntityStateFactory nodeEntityStateFactory() throws Exception {
CrossStoreNodeEntityStateFactory entityStateFactory = new CrossStoreNodeEntityStateFactory();
entityStateFactory.setGraphDatabaseContext(graphDatabaseContext());
entityStateFactory.setEntityManagerFactory(entityManagerFactory);
entityStateFactory.setMappingContext(mappingContext());
entityStateFactory.setNodeDelegatingFieldAccessorFactory(nodeDelegatingFieldAccessorFactory());
return entityStateFactory;
}
}

View File

@@ -0,0 +1,55 @@
package org.springframework.data.neo4j.support.node;
import org.neo4j.graphdb.Node;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.data.neo4j.core.EntityState;
import org.springframework.data.neo4j.core.NodeBacked;
import org.springframework.data.neo4j.fieldaccess.DetachedEntityState;
import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity;
import javax.annotation.PostConstruct;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnitUtil;
/**
* @author mh
* @since 30.09.11
*/
public class CrossStoreNodeEntityStateFactory extends NodeEntityStateFactory {
private PartialNodeEntityState.PartialNodeDelegatingFieldAccessorFactory delegatingFieldAccessorFactory;
private EntityManagerFactory entityManagerFactory;
public EntityState<Node> getEntityState(final NodeBacked entity) {
final Class<?> entityType = entity.getClass();
final NodeEntity graphEntityAnnotation = entityType.getAnnotation(NodeEntity.class); // todo cache ??
final Neo4jPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(entityType);
if (graphEntityAnnotation.partial()) {
final PartialNodeEntityState<NodeBacked> partialNodeEntityState = new PartialNodeEntityState<NodeBacked>(null, entity, entityType, graphDatabaseContext, getPersistenceUnitUtils(), delegatingFieldAccessorFactory, (Neo4jPersistentEntity<NodeBacked>) persistentEntity);
return new DetachedEntityState<Node>(partialNodeEntityState, graphDatabaseContext) {
@Override
protected boolean isDetached() {
return super.isDetached() || partialNodeEntityState.getId(entity) == null;
}
};
} else {
NodeEntityState<NodeBacked> nodeEntityState = new NodeEntityState<NodeBacked>(null, entity, entityType, graphDatabaseContext, nodeDelegatingFieldAccessorFactory, (Neo4jPersistentEntity<NodeBacked>) persistentEntity);
// alternative was return new NestedTransactionEntityState<NodeBacked, Node>(nodeEntityState,graphDatabaseContext);
return new DetachedEntityState<Node>(nodeEntityState, graphDatabaseContext);
}
}
private PersistenceUnitUtil getPersistenceUnitUtils() {
if (entityManagerFactory == null) return null;
return entityManagerFactory.getPersistenceUnitUtil();
}
public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
}
@PostConstruct
private void setUp() {
this.delegatingFieldAccessorFactory = new PartialNodeEntityState.PartialNodeDelegatingFieldAccessorFactory(graphDatabaseContext);
}
}

View File

@@ -17,9 +17,8 @@
package org.springframework.data.neo4j.support.node;
import org.neo4j.graphdb.Node;
import org.springframework.data.neo4j.core.NodeBacked;
import org.springframework.data.neo4j.support.EntityInstantiator;
import org.springframework.orm.jpa.EntityManagerFactoryUtils;
import org.springframework.data.persistence.EntityInstantiator;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
@@ -30,7 +29,7 @@ import javax.persistence.EntityManagerFactory;
* @author Michael Hunger
* @since 02.10.2010
*/
public class PartialNodeEntityInstantiator implements EntityInstantiator<NodeBacked, Node> {
public class PartialNodeEntityInstantiator implements EntityInstantiator<Node> {
private final NodeEntityInstantiator delegate;
private EntityManagerFactory entityManagerFactory;
@@ -50,7 +49,7 @@ public class PartialNodeEntityInstantiator implements EntityInstantiator<NodeBac
* @param <T> generic type of the entity
* @return
*/
public <T extends NodeBacked> T createEntityFromState(Node n, Class<T> entityClass) {
public <T> T createEntityFromState(Node n, Class<T> entityClass) {
if (n.hasProperty(PartialNodeEntityState.FOREIGN_ID)) {
final Object foreignId = n.getProperty(PartialNodeEntityState.FOREIGN_ID);
final T result = entityManager().find(entityClass, foreignId);

View File

@@ -25,8 +25,8 @@ import org.springframework.data.neo4j.annotation.GraphProperty;
import org.springframework.data.neo4j.annotation.RelatedTo;
import org.springframework.data.neo4j.core.NodeBacked;
import org.springframework.data.neo4j.fieldaccess.*;
import org.springframework.data.neo4j.mapping.Neo4JPersistentEntity;
import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty;
import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import javax.persistence.PersistenceUnitUtil;
@@ -46,7 +46,7 @@ public class PartialNodeEntityState<ENTITY extends NodeBacked> extends DefaultEn
private final GraphDatabaseContext graphDatabaseContext;
private PersistenceUnitUtil persistenceUnitUtil;
public PartialNodeEntityState(final Node underlyingState, final ENTITY entity, final Class<? extends ENTITY> type, final GraphDatabaseContext graphDatabaseContext, PersistenceUnitUtil persistenceUnitUtil, final PartialNodeDelegatingFieldAccessorFactory delegatingFieldAccessorFactory, final Neo4JPersistentEntity<ENTITY> persistentEntity) {
public PartialNodeEntityState(final Node underlyingState, final ENTITY entity, final Class<? extends ENTITY> type, final GraphDatabaseContext graphDatabaseContext, PersistenceUnitUtil persistenceUnitUtil, final PartialNodeDelegatingFieldAccessorFactory delegatingFieldAccessorFactory, final Neo4jPersistentEntity<ENTITY> persistentEntity) {
super(underlyingState, entity, type, delegatingFieldAccessorFactory, persistentEntity);
this.graphDatabaseContext = graphDatabaseContext;
this.persistenceUnitUtil = persistenceUnitUtil;
@@ -126,11 +126,11 @@ public class PartialNodeEntityState<ENTITY extends NodeBacked> extends DefaultEn
newPropertyFieldAccessorFactory(),
newConvertingNodePropertyFieldAccessorFactory()) {
@Override
public boolean accept(Neo4JPersistentProperty property) {
public boolean accept(Neo4jPersistentProperty property) {
return property.isAnnotationPresent(GraphProperty.class) && super.accept(property);
}
},
new JpaIdFieldAccessListenerFactory());
new JpaIdFieldAccessListenerFactory(graphDatabaseContext));
}
@Override
@@ -144,7 +144,7 @@ public class PartialNodeEntityState<ENTITY extends NodeBacked> extends DefaultEn
newConvertingNodePropertyFieldAccessorFactory(),
new SingleRelationshipFieldAccessorFactory(getGraphDatabaseContext()) {
@Override
public boolean accept(Neo4JPersistentProperty property) {
public boolean accept(Neo4jPersistentProperty property) {
return property.isAnnotationPresent(RelatedTo.class) && super.accept(property);
}
},
@@ -157,8 +157,8 @@ public class PartialNodeEntityState<ENTITY extends NodeBacked> extends DefaultEn
private ConvertingNodePropertyFieldAccessorFactory newConvertingNodePropertyFieldAccessorFactory() {
return new ConvertingNodePropertyFieldAccessorFactory(getGraphDatabaseContext().getConversionService()) {
@Override
public boolean accept(Neo4JPersistentProperty f) {
return f.isAnnotationPresent(GraphProperty.class) && super.accept(f);
public boolean accept(Neo4jPersistentProperty property) {
return property.isAnnotationPresent(GraphProperty.class) && super.accept(property);
}
};
}
@@ -166,7 +166,7 @@ public class PartialNodeEntityState<ENTITY extends NodeBacked> extends DefaultEn
private PropertyFieldAccessorFactory newPropertyFieldAccessorFactory() {
return new PropertyFieldAccessorFactory(getGraphDatabaseContext().getConversionService()) {
@Override
public boolean accept(Neo4JPersistentProperty f) {
public boolean accept(Neo4jPersistentProperty f) {
return f.isAnnotationPresent(GraphProperty.class) && super.accept(f);
}
};

View File

@@ -149,7 +149,7 @@
<state />
</provider>
<provider selected="true" editor-type-id="text-editor">
<state line="2" column="0" selection-start="56" selection-end="850" vertical-scroll-proportion="0.08547009">
<state line="10" column="47" selection-start="850" selection-end="850" vertical-scroll-proportion="0.42735043">
<folding />
</state>
</provider>
@@ -608,7 +608,7 @@
<state />
</provider>
<provider selected="true" editor-type-id="text-editor">
<state line="2" column="0" selection-start="56" selection-end="850" vertical-scroll-proportion="0.08547009">
<state line="10" column="47" selection-start="850" selection-end="850" vertical-scroll-proportion="0.42735043">
<folding />
</state>
</provider>

View File

@@ -123,7 +123,7 @@
<log4j.version>1.2.15</log4j.version>
<org.mockito.version>1.8.4</org.mockito.version>
<org.slf4j.version>1.6.1</org.slf4j.version>
<org.springframework.version>3.0.5.RELEASE</org.springframework.version>
<org.springframework.version>3.0.6.RELEASE</org.springframework.version>
<data.commons.version>1.2.0.BUILD-SNAPSHOT</data.commons.version>
<neo4j.version>1.4.1</neo4j.version>
<aspectj.version>1.6.12.M1</aspectj.version>
@@ -284,6 +284,11 @@
<artifactId>spring-data-neo4j</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j-aspects</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Logging -->
<dependency>

View File

@@ -31,7 +31,7 @@
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j</artifactId>
<artifactId>spring-data-neo4j-aspects</artifactId>
<version>${project.version}</version>
<scope>test</scope>
<type>test-jar</type>

View File

@@ -9,7 +9,7 @@
</parent>
<artifactId>spring-data-neo4j</artifactId>
<packaging>jar</packaging>
<name>Spring Data Neo4J Core</name>
<name>Spring Data Neo4j</name>
<description><![CDATA[Spring Data Neo4j core support for Neo4j graph database, offering object graph mapping, a Neo4jTemplate and Spring-Data-Commons Repository implementations.
]]></description>
<url>http://www.springsource.org/spring-data/neo4j</url>
@@ -210,42 +210,6 @@
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.2</version>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<outxml>true</outxml>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>

View File

@@ -22,7 +22,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.data.neo4j.core.FieldTraversalDescriptionBuilder;
import org.springframework.data.neo4j.core.NodeBacked;
/**
* Field that provides access to an iterator which is created by applying the traversal that is built by the supplied
@@ -41,12 +41,13 @@ public @interface GraphTraversal {
/**
* @return Builder for the {@link org.neo4j.graphdb.traversal.TraversalDescription} to be applied
*/
Class<? extends FieldTraversalDescriptionBuilder> traversalBuilder() default FieldTraversalDescriptionBuilder.class;
// FQN is a fix for javac compiler bug
Class<? extends org.springframework.data.neo4j.core.FieldTraversalDescriptionBuilder> traversalBuilder() default org.springframework.data.neo4j.core.FieldTraversalDescriptionBuilder.class;
/**
* @return target graph entity to be iterated over.
*/
Class<? extends NodeBacked> elementClass() default NodeBacked.class;
Class<?> elementClass() default Object.class;
/**
* @return parameters that are passed to the @see FieldTraversalDescriptionBuilder#build

View File

@@ -38,7 +38,8 @@ public @interface Indexed {
String fieldName() default "";
Level level() default Level.CLASS;
// FQN is a fix for javac compiler bug http://bugs.sun.com/view_bug.do?bug_id=6512707
org.springframework.data.neo4j.annotation.Indexed.Level level() default org.springframework.data.neo4j.annotation.Indexed.Level.CLASS;
static class Name {
public static String getDefault(Field field) {

View File

@@ -50,5 +50,6 @@ public @interface Query {
*/
String[] params() default {};
QueryType type() default QueryType.Cypher;
// FQN is a fix for javac compiler bug
org.springframework.data.neo4j.annotation.QueryType type() default org.springframework.data.neo4j.annotation.QueryType.Cypher;
}

View File

@@ -18,7 +18,7 @@ package org.springframework.data.neo4j.annotation;
import org.neo4j.graphdb.Direction;
import org.springframework.data.annotation.Reference;
import org.springframework.data.neo4j.core.NodeBacked;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -55,10 +55,11 @@ public @interface RelatedTo {
/**
* @return direction for the relationship, by default outgoing
*/
Direction direction() default Direction.OUTGOING;
// FQN is a fix for javac compiler bug http://bugs.sun.com/view_bug.do?bug_id=6512707
org.neo4j.graphdb.Direction direction() default org.neo4j.graphdb.Direction.OUTGOING;
/**
* @return target class, required for collection based fields (no generic inferring)
*/
Class<? extends NodeBacked> elementClass() default NodeBacked.class;
Class<?> elementClass() default Object.class;
}

View File

@@ -23,7 +23,7 @@ import java.lang.annotation.Target;
import org.neo4j.graphdb.Direction;
import org.springframework.data.annotation.Reference;
import org.springframework.data.neo4j.core.RelationshipBacked;
/**
* Annotation for {@link org.springframework.data.neo4j.annotation.NodeEntity} fields that relate to other entities via
@@ -49,10 +49,11 @@ public @interface RelatedToVia {
/**
* @return direction for the relationship, by default outgoing
*/
Direction direction() default Direction.OUTGOING;
// FQN is a fix for javac compiler bug http://bugs.sun.com/view_bug.do?bug_id=6512707
org.neo4j.graphdb.Direction direction() default org.neo4j.graphdb.Direction.OUTGOING;
/**
* @return target relationship entity class
*/
Class<? extends RelationshipBacked> elementClass() default RelationshipBacked.class;
Class<?> elementClass() default Object.class;
}

View File

@@ -0,0 +1,33 @@
/**
* 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.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Field annotation for the type of a relationship entity. The field type must be a String or RelationshipType.
*
* @author Michael Hunger
* @since 27.08.2010
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface RelationshipType {
}

View File

@@ -16,7 +16,6 @@
package org.springframework.data.neo4j.config;
import javax.persistence.EntityManagerFactory;
import javax.validation.Validator;
import org.neo4j.graphdb.GraphDatabaseService;
@@ -26,32 +25,27 @@ import org.neo4j.kernel.AbstractGraphDatabase;
import org.neo4j.kernel.impl.transaction.SpringTransactionManager;
import org.neo4j.kernel.impl.transaction.UserTransactionImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.ConversionService;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.neo4j.core.NodeBacked;
import org.springframework.data.neo4j.core.RelationshipBacked;
import org.springframework.data.neo4j.fieldaccess.DelegatingFieldAccessorFactory;
import org.springframework.data.neo4j.fieldaccess.Neo4jConversionServiceFactoryBean;
import org.springframework.data.neo4j.fieldaccess.NodeDelegatingFieldAccessorFactory;
import org.springframework.data.neo4j.fieldaccess.RelationshipDelegatingFieldAccessorFactory;
import org.springframework.data.neo4j.mapping.Neo4JMappingContext;
import org.springframework.data.neo4j.mapping.Neo4jMappingContext;
import org.springframework.data.neo4j.mapping.Neo4jNodeConverterImpl;
import org.springframework.data.neo4j.repository.DirectGraphRepositoryFactory;
import org.springframework.data.neo4j.support.EntityInstantiator;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import org.springframework.data.neo4j.support.node.Neo4jNodeBacking;
import org.springframework.data.neo4j.support.node.NodeEntityInstantiator;
import org.springframework.data.neo4j.support.node.NodeEntityStateFactory;
import org.springframework.data.neo4j.support.node.PartialNodeEntityInstantiator;
import org.springframework.data.neo4j.support.relationship.Neo4jRelationshipBacking;
import org.springframework.data.neo4j.support.relationship.RelationshipEntityInstantiator;
import org.springframework.data.neo4j.support.relationship.RelationshipEntityStateFactory;
import org.springframework.data.neo4j.support.typerepresentation.TypeRepresentationStrategyFactory;
import org.springframework.data.neo4j.template.Neo4jExceptionTranslator;
import org.springframework.data.neo4j.transaction.ChainedTransactionManager;
import org.springframework.data.persistence.EntityInstantiator;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.jta.JtaTransactionManager;
import org.springframework.transaction.jta.UserTransactionAdapter;
@@ -63,7 +57,7 @@ import org.springframework.transaction.jta.UserTransactionAdapter;
* @author Thomas Risberg
*/
@Configuration
public class Neo4jConfiguration {
public abstract class Neo4jConfiguration {
private GraphDatabaseService graphDatabaseService;
@Autowired(required = false)
@@ -79,26 +73,10 @@ public class Neo4jConfiguration {
this.graphDatabaseService = graphDatabaseService;
}
private EntityManagerFactory entityManagerFactory;
public EntityManagerFactory getEntityManagerFactory() {
return entityManagerFactory;
}
@Qualifier("&entityManagerFactory")
@Autowired(required = false)
public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
}
public boolean isUsingCrossStorePersistence() {
return entityManagerFactory != null;
}
@Bean
@Bean
public GraphDatabaseContext graphDatabaseContext() throws Exception {
EntityInstantiator<RelationshipBacked, Relationship> relationshipEntityInstantiator = graphRelationshipInstantiator();
EntityInstantiator<NodeBacked, Node> graphEntityInstantiator = graphEntityInstantiator();
EntityInstantiator<Relationship> relationshipEntityInstantiator = graphRelationshipInstantiator();
EntityInstantiator<Node> graphEntityInstantiator = graphEntityInstantiator();
TypeRepresentationStrategyFactory typeRepresentationStrategyFactory =
new TypeRepresentationStrategyFactory(graphDatabaseService, graphEntityInstantiator, relationshipEntityInstantiator);
@@ -106,6 +84,8 @@ public class Neo4jConfiguration {
GraphDatabaseContext gdc = new GraphDatabaseContext();
gdc.setGraphDatabaseService(getGraphDatabaseService());
gdc.setConversionService(conversionService());
gdc.setMappingContext(mappingContext());
gdc.setConverter(neo4jConverter());
gdc.setNodeTypeRepresentationStrategy(typeRepresentationStrategyFactory.getNodeTypeRepresentationStrategy());
gdc.setRelationshipTypeRepresentationStrategy(typeRepresentationStrategyFactory.getRelationshipTypeRepresentationStrategy());
if (validator!=null) {
@@ -114,6 +94,11 @@ public class Neo4jConfiguration {
return gdc;
}
@Bean
public Neo4jNodeConverterImpl neo4jConverter() throws Exception {
return new Neo4jNodeConverterImpl(nodeEntityStateFactory());
}
@Bean
protected ConversionService conversionService() throws Exception {
return new Neo4jConversionServiceFactoryBean().getObject();
@@ -121,30 +106,18 @@ public class Neo4jConfiguration {
@Bean
protected RelationshipEntityInstantiator graphRelationshipInstantiator() {
return new RelationshipEntityInstantiator();
return new RelationshipEntityInstantiator(mappingContext());
}
@Bean
protected EntityInstantiator<NodeBacked, Node> graphEntityInstantiator() {
if (isUsingCrossStorePersistence()) {
return new PartialNodeEntityInstantiator(new NodeEntityInstantiator(), entityManagerFactory);
} else {
return new NodeEntityInstantiator();
}
protected EntityInstantiator<Node> graphEntityInstantiator() {
return new NodeEntityInstantiator(mappingContext());
}
@Bean
public DirectGraphRepositoryFactory directGraphRepositoryFactory() throws Exception {
return new DirectGraphRepositoryFactory(graphDatabaseContext());
}
@Bean
public Neo4jRelationshipBacking neo4jRelationshipBacking() throws Exception {
Neo4jRelationshipBacking aspect = Neo4jRelationshipBacking.aspectOf();
aspect.setGraphDatabaseContext(graphDatabaseContext());
aspect.setRelationshipEntityStateFactory(relationshipEntityStateFactory());
return aspect;
}
@Bean
public RelationshipEntityStateFactory relationshipEntityStateFactory() throws Exception {
@@ -156,17 +129,8 @@ public class Neo4jConfiguration {
}
@Bean
public Neo4jNodeBacking neo4jNodeBacking() throws Exception {
Neo4jNodeBacking aspect = Neo4jNodeBacking.aspectOf();
aspect.setGraphDatabaseContext(graphDatabaseContext());
NodeEntityStateFactory entityStateFactory = nodeEntityStateFactory();
aspect.setNodeEntityStateFactory(entityStateFactory);
return aspect;
}
@Bean
public Neo4JMappingContext mappingContext() {
return new Neo4JMappingContext();
public Neo4jMappingContext mappingContext() {
return new Neo4jMappingContext();
}
@Bean
@@ -174,35 +138,27 @@ public class Neo4jConfiguration {
NodeEntityStateFactory entityStateFactory = new NodeEntityStateFactory();
entityStateFactory.setGraphDatabaseContext(graphDatabaseContext());
entityStateFactory.setEntityManagerFactory(entityManagerFactory);
entityStateFactory.setMappingContext(mappingContext());
entityStateFactory.setNodeDelegatingFieldAccessorFactory(nodeDelegatingFieldAccessorFactory());
return entityStateFactory;
}
@Bean
public DelegatingFieldAccessorFactory<NodeBacked> nodeDelegatingFieldAccessorFactory() throws Exception {
public DelegatingFieldAccessorFactory nodeDelegatingFieldAccessorFactory() throws Exception {
return new NodeDelegatingFieldAccessorFactory(graphDatabaseContext());
}
@Bean
public DelegatingFieldAccessorFactory<RelationshipBacked> relationshipDelegatingFieldAccessorFactory() throws Exception {
public DelegatingFieldAccessorFactory relationshipDelegatingFieldAccessorFactory() throws Exception {
return new RelationshipDelegatingFieldAccessorFactory(graphDatabaseContext());
}
@Bean
public PlatformTransactionManager transactionManager() {
if (isUsingCrossStorePersistence()) {
JpaTransactionManager jpaTm = new JpaTransactionManager(getEntityManagerFactory());
JtaTransactionManager jtaTm = createJtaTransactionManager();
return new ChainedTransactionManager(jpaTm, jtaTm);
}
else {
return createJtaTransactionManager();
}
return createJtaTransactionManager();
}
private JtaTransactionManager createJtaTransactionManager() {
protected JtaTransactionManager createJtaTransactionManager() {
JtaTransactionManager jtaTm = new JtaTransactionManager();
final GraphDatabaseService gds = getGraphDatabaseService();
if (gds instanceof AbstractGraphDatabase) {

View File

@@ -17,22 +17,22 @@
package org.springframework.data.neo4j.core;
import org.neo4j.graphdb.Path;
import org.springframework.data.neo4j.core.RelationshipBacked;
/**
* @author mh
* @since 08.04.11
*/
public interface EntityPath<S extends NodeBacked,E extends NodeBacked> extends Path {
<T extends NodeBacked> T startEntity(Class<T>... types);
public interface EntityPath<S,E> extends Path {
<T> T startEntity(Class<T>... types);
<T extends NodeBacked> T endEntity(Class<T>... types);
<T> T endEntity(Class<T>... types);
<T extends RelationshipBacked> T lastRelationshipEntity(Class<T>... types);
<T> T lastRelationshipEntity(Class<T>... types);
<T extends NodeBacked> Iterable<T> nodeEntities();
<T> Iterable<T> nodeEntities();
<T extends RelationshipBacked> Iterable<T> relationshipEntities(Class<T>... relationships);
<T> Iterable<T> relationshipEntities(Class<T>... relationships);
<T extends GraphBacked> Iterable<T> allPathEntities(Class<T>... relationships);
<T> Iterable<T> allPathEntities(Class<T>... relationships);
}

View File

@@ -19,8 +19,8 @@ package org.springframework.data.neo4j.core;
import java.lang.reflect.Field;
import org.springframework.data.neo4j.fieldaccess.FieldAccessor;
import org.springframework.data.neo4j.mapping.Neo4JPersistentEntity;
import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty;
import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
/**
* Interface for classes encapsulating and delegating read and write field access of an GraphBacked entity to a number of field accessors.
@@ -28,8 +28,8 @@ import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty;
* @author Michael Hunger
* @since 15.09.2010
*/
public interface EntityState<ENTITY extends GraphBacked<STATE>,STATE> {
ENTITY getEntity();
public interface EntityState<STATE> {
Object getEntity();
void setPersistentState(STATE state);
@@ -58,7 +58,7 @@ public interface EntityState<ENTITY extends GraphBacked<STATE>,STATE> {
* @return sets the value in the entity and/or the state
*/
Object setValue(Field field, Object newVal);
Object setValue(Neo4JPersistentProperty property, Object newVal);
Object setValue(Neo4jPersistentProperty property, Object newVal);
/**
* callback for creating and initializing an initial state
@@ -70,7 +70,7 @@ public interface EntityState<ENTITY extends GraphBacked<STATE>,STATE> {
boolean hasPersistentState();
STATE getPersistentState();
ENTITY persist();
Object persist();
Neo4JPersistentEntity<ENTITY> getPersistentEntity();
Neo4jPersistentEntity<Object> getPersistentEntity();
}

View File

@@ -17,7 +17,7 @@
package org.springframework.data.neo4j.core;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
/**
* Interface for classes that build traversal descriptions. Those classes can be referred to by
@@ -35,5 +35,5 @@ public interface FieldTraversalDescriptionBuilder {
* @param property
* @return the TraversalDescription to apply on fieldaccess, the start node is the current entity node
*/
TraversalDescription build(NodeBacked start, Neo4JPersistentProperty property, String...params);
TraversalDescription build(Object start, Neo4jPersistentProperty property, String...params);
}

View File

@@ -18,6 +18,6 @@ package org.springframework.data.neo4j.core;
import org.neo4j.graphdb.Node;
public interface NodeTypeRepresentationStrategy extends TypeRepresentationStrategy<Node, NodeBacked> {
public interface NodeTypeRepresentationStrategy extends TypeRepresentationStrategy<Node> {
}

View File

@@ -18,6 +18,6 @@ package org.springframework.data.neo4j.core;
import org.neo4j.graphdb.Relationship;
public interface RelationshipTypeRepresentationStrategy extends TypeRepresentationStrategy<Relationship, RelationshipBacked> {
public interface RelationshipTypeRepresentationStrategy extends TypeRepresentationStrategy<Relationship> {
}

View File

@@ -32,33 +32,33 @@ import org.neo4j.helpers.collection.ClosableIterable;
* @author Michael Hunger
* @since 13.09.2010
*/
public interface TypeRepresentationStrategy<S extends PropertyContainer, T extends GraphBacked<S>> {
public interface TypeRepresentationStrategy<S extends PropertyContainer> {
/**
* Callback for setting up and/or storing type information after creation.
*
* @param state Backing state of entity being created
* @param type Type of entity being created
*/
void postEntityCreation(S state, Class<? extends T> type);
void postEntityCreation(S state, Class<?> type);
/**
*
* @param clazz Type whose instances should be iterated over
* @return lazy Iterable over all instances of the given type
*/
<U extends T> ClosableIterable<U> findAll(final Class<U> clazz);
<U> ClosableIterable<U> findAll(final Class<U> clazz);
/**
* @param entityClass
* @return number of instances of this class contained in the graph
*/
long count(final Class<? extends T> entityClass);
long count(final Class<?> entityClass);
/**
* @param state
* @return java type that of the node entity of this node
*/
<U extends T> Class<U> getJavaType(S state);
<U> Class<U> getJavaType(S state);
/**
* Callback for cleaning up type information before removal. If state does not have any
@@ -77,7 +77,7 @@ public interface TypeRepresentationStrategy<S extends PropertyContainer, T exten
* @throws IllegalStateException If the strategy is unable to infer any type from the state
* @return Entity instance
*/
<U extends T> U createEntity(S state) throws IllegalStateException;
<U> U createEntity(S state) throws IllegalStateException;
/**
* Instantiate the entity given its state. The type of the desired entity is also specified.
@@ -90,7 +90,7 @@ public interface TypeRepresentationStrategy<S extends PropertyContainer, T exten
* @throws IllegalArgumentException If the specified type does not match the inferred type
* @return Entity instance
*/
<U extends T> U createEntity(S state, Class<U> type) throws IllegalStateException, IllegalArgumentException;
<U> U createEntity(S state, Class<U> type) throws IllegalStateException, IllegalArgumentException;
/**
* Instantiate the entity of the given type, with the given state as backing state. No checking
@@ -100,5 +100,5 @@ public interface TypeRepresentationStrategy<S extends PropertyContainer, T exten
* @param type Type of entity to be instantiated
* @return Entity instance.
*/
<U extends T> U projectEntity(S state, Class<U> type);
<U> U projectEntity(S state, Class<U> type);
}

View File

@@ -18,9 +18,10 @@ package org.springframework.data.neo4j.fieldaccess;
import org.neo4j.graphdb.*;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.neo4j.core.GraphBacked;
import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import org.springframework.util.Assert;
import java.util.HashSet;
import java.util.Set;
@@ -29,14 +30,14 @@ import java.util.Set;
* @author Michael Hunger
* @since 11.09.2010
*/
public abstract class AbstractNodeRelationshipFieldAccessor<ENTITY extends GraphBacked,STATE extends PropertyContainer,TARGET extends GraphBacked,TSTATE extends PropertyContainer> implements FieldAccessor<ENTITY> {
public abstract class AbstractNodeRelationshipFieldAccessor<STATE extends PropertyContainer,TSTATE extends PropertyContainer> implements FieldAccessor {
protected final RelationshipType type;
protected final Neo4JPersistentProperty property;
protected final Neo4jPersistentProperty property;
protected final Direction direction;
protected final Class<? extends TARGET> relatedType;
protected final Class<?> relatedType;
protected final GraphDatabaseContext graphDatabaseContext;
public AbstractNodeRelationshipFieldAccessor(Class<? extends TARGET> clazz, GraphDatabaseContext graphDatabaseContext, Direction direction, RelationshipType type, Neo4JPersistentProperty property) {
public AbstractNodeRelationshipFieldAccessor(Class<?> clazz, GraphDatabaseContext graphDatabaseContext, Direction direction, RelationshipType type, Neo4jPersistentProperty property) {
this.relatedType = clazz;
this.graphDatabaseContext = graphDatabaseContext;
this.direction = direction;
@@ -45,11 +46,11 @@ public abstract class AbstractNodeRelationshipFieldAccessor<ENTITY extends Graph
}
@Override
public boolean isWriteable(ENTITY entity) {
public boolean isWriteable(Object entity) {
return true;
}
protected STATE checkUnderlyingNode(ENTITY entity) {
protected STATE checkUnderlyingNode(Object entity) {
if (entity==null) throw new IllegalStateException("Entity is null");
STATE node = getState(entity);
if (node != null) return node;
@@ -68,7 +69,7 @@ public abstract class AbstractNodeRelationshipFieldAccessor<ENTITY extends Graph
createSingleRelationship(node,targetNode);
}
}
// adding cascade
protected Set<STATE> checkTargetIsSetOfNodebacked(Object newVal) {
if (!(newVal instanceof Set)) {
throw new IllegalArgumentException("New value must be a Set, was: " + newVal.getClass());
@@ -78,20 +79,30 @@ public abstract class AbstractNodeRelationshipFieldAccessor<ENTITY extends Graph
if (!relatedType.isInstance(value)) {
throw new IllegalArgumentException("New value elements must be "+relatedType);
}
nodes.add(getState((ENTITY)value));
// nodes.add(getState(value));
nodes.add(getOrCreateState(value));
}
return nodes;
}
protected ManagedFieldAccessorSet<ENTITY,TARGET> createManagedSet(ENTITY entity, Set<TARGET> result) {
return new ManagedFieldAccessorSet<ENTITY,TARGET>(entity, result, property);
protected STATE getOrCreateState(Object value) {
final STATE state = getState(value);
if (state != null) return state;
final Object saved = graphDatabaseContext.save(value);
final STATE newState = getState(saved);
Assert.notNull(newState);
return newState;
}
protected Set<TARGET> createEntitySetFromRelationshipEndNodes(ENTITY entity) {
protected <T> ManagedFieldAccessorSet<T> createManagedSet(Object entity, Set<T> result) {
return new ManagedFieldAccessorSet<T>(entity, result, property,graphDatabaseContext,this);
}
protected Set<Object> createEntitySetFromRelationshipEndNodes(Object entity) {
final Iterable<TSTATE> nodes = getStatesFromEntity(entity);
final Set<TARGET> result = new HashSet<TARGET>();
final Set<Object> result = new HashSet<Object>();
for (final TSTATE otherNode : nodes) {
TARGET target=graphDatabaseContext.createEntityFromState(otherNode, relatedType);
Object target=graphDatabaseContext.createEntityFromState(otherNode, relatedType);
result.add(target);
}
return result;
@@ -119,7 +130,8 @@ public abstract class AbstractNodeRelationshipFieldAccessor<ENTITY extends Graph
protected abstract Relationship obtainSingleRelationship(STATE start, TSTATE end);
protected abstract Iterable<TSTATE> getStatesFromEntity(ENTITY entity);
protected abstract Iterable<TSTATE> getStatesFromEntity(Object entity);
protected abstract STATE getState(ENTITY entity);
protected abstract STATE
getState(Object entity);
}

View File

@@ -16,62 +16,62 @@
package org.springframework.data.neo4j.fieldaccess;
import org.neo4j.graphdb.PropertyContainer;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.neo4j.core.GraphBacked;
import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty;
import scala.annotation.target.field;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
/**
* @author Michael Hunger
* @since 12.09.2010
*/
@Configurable
public class ConvertingNodePropertyFieldAccessorFactory implements FieldAccessorFactory<GraphBacked<PropertyContainer>> {
public class ConvertingNodePropertyFieldAccessorFactory implements FieldAccessorFactory {
ConversionService conversionService;
public ConvertingNodePropertyFieldAccessorFactory(ConversionService conversionService) {
this.conversionService = conversionService;
}
private final GraphDatabaseContext graphDatabaseContext;
private ConversionService conversionService;
public ConvertingNodePropertyFieldAccessorFactory(GraphDatabaseContext graphDatabaseContext) {
this.graphDatabaseContext = graphDatabaseContext;
this.conversionService = graphDatabaseContext.getConversionService();
}
@Override
public boolean accept(final Neo4JPersistentProperty field) {
return field.isSerializableField(conversionService) && field.isDeserializableField(conversionService);
public boolean accept(final Neo4jPersistentProperty property) {
return property.isSerializableField(conversionService) && property.isDeserializableField(conversionService);
}
@Override
public FieldAccessor<GraphBacked<PropertyContainer>> forField(final Neo4JPersistentProperty property) {
return new ConvertingNodePropertyFieldAccessor(conversionService,property);
public FieldAccessor forField(final Neo4jPersistentProperty property) {
return new ConvertingNodePropertyFieldAccessor(property,graphDatabaseContext);
}
public static class ConvertingNodePropertyFieldAccessor extends PropertyFieldAccessorFactory.PropertyFieldAccessor {
private final ConversionService conversionService;
public ConvertingNodePropertyFieldAccessor(ConversionService conversionService, Neo4JPersistentProperty property) {
super(conversionService, property);
this.conversionService = conversionService;
public ConvertingNodePropertyFieldAccessor(Neo4jPersistentProperty property, GraphDatabaseContext graphDatabaseContext) {
super(graphDatabaseContext, property);
}
@Override
public Object setValue(final GraphBacked<PropertyContainer> graphBacked, final Object newVal) {
super.setValue(graphBacked, serializePropertyValue(newVal));
public Object setValue(final Object entity, final Object newVal) {
super.setValue(entity, serializePropertyValue(newVal));
return newVal;
}
@Override
public Object doGetValue(final GraphBacked<PropertyContainer> graphBacked) {
return deserializePropertyValue(super.doGetValue(graphBacked));
public Object doGetValue(final Object entity) {
return deserializePropertyValue(super.doGetValue(entity));
}
private Object serializePropertyValue(final Object newVal) {
return conversionService.convert(newVal, String.class);
return graphDatabaseContext.getConversionService().convert(newVal, String.class);
}
private Object deserializePropertyValue(final Object value) {
return conversionService.convert(value, fieldType);
return graphDatabaseContext.getConversionService().convert(value, fieldType);
}
}

View File

@@ -19,9 +19,9 @@ package org.springframework.data.neo4j.fieldaccess;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.data.neo4j.core.EntityState;
import org.springframework.data.neo4j.core.GraphBacked;
import org.springframework.data.neo4j.mapping.Neo4JPersistentEntity;
import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty;
import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
import java.lang.reflect.Field;
import java.util.HashMap;
@@ -32,17 +32,17 @@ import java.util.Map;
* @author Michael Hunger
* @since 12.09.2010
*/
public abstract class DefaultEntityState<ENTITY extends GraphBacked<STATE>, STATE> implements EntityState<ENTITY,STATE> {
protected final ENTITY entity;
protected final Class<? extends ENTITY> type;
private final Map<Neo4JPersistentProperty, FieldAccessor<ENTITY>> fieldAccessors = new HashMap<Neo4JPersistentProperty, FieldAccessor<ENTITY>>();
private final Map<Neo4JPersistentProperty,List<FieldAccessListener<ENTITY,?>>> fieldAccessorListeners = new HashMap<Neo4JPersistentProperty, List<FieldAccessListener<ENTITY, ?>>>();
public abstract class DefaultEntityState<STATE> implements EntityState<STATE> {
protected final Object entity;
protected final Class<? extends Object> type;
private final Map<Neo4jPersistentProperty, FieldAccessor> fieldAccessors = new HashMap<Neo4jPersistentProperty, FieldAccessor>();
private final Map<Neo4jPersistentProperty,List<FieldAccessListener>> fieldAccessorListeners = new HashMap<Neo4jPersistentProperty, List<FieldAccessListener>>();
private STATE state;
protected final static Log log= LogFactory.getLog(DefaultEntityState.class);
private final FieldAccessorFactoryProviders<ENTITY> fieldAccessorFactoryProviders;
private final Neo4JPersistentEntity<ENTITY> persistentEntity;
private final FieldAccessorFactoryProviders<Object> fieldAccessorFactoryProviders;
private final Neo4jPersistentEntity<Object> persistentEntity;
public DefaultEntityState(final STATE underlyingState, final ENTITY entity, final Class<? extends ENTITY> type, final DelegatingFieldAccessorFactory delegatingFieldAccessorFactory, Neo4JPersistentEntity<ENTITY> persistentEntity) {
public DefaultEntityState(final STATE underlyingState, final Object entity, final Class<? extends Object> type, final DelegatingFieldAccessorFactory delegatingFieldAccessorFactory, Neo4jPersistentEntity<Object> persistentEntity) {
this.state = underlyingState;
this.entity = entity;
this.type = type;
@@ -60,7 +60,7 @@ public abstract class DefaultEntityState<ENTITY extends GraphBacked<STATE>, STAT
public abstract void createAndAssignState();
@Override
public ENTITY getEntity() {
public Object getEntity() {
return entity;
}
@@ -79,20 +79,20 @@ public abstract class DefaultEntityState<ENTITY extends GraphBacked<STATE>, STAT
return state;
}
public Neo4JPersistentEntity<ENTITY> getPersistentEntity() {
public Neo4jPersistentEntity<Object> getPersistentEntity() {
return persistentEntity;
}
@Override
public boolean isWritable(Field field) {
final FieldAccessor<ENTITY> accessor = accessorFor(property(field));
final FieldAccessor accessor = accessorFor(property(field));
if (accessor == null) return true;
return accessor.isWriteable(entity);
}
@Override
public Object getValue(final Field field) {
final FieldAccessor<ENTITY> accessor = accessorFor(property(field));
final FieldAccessor accessor = accessorFor(property(field));
if (accessor == null) return null;
else return accessor.getValue(entity);
}
@@ -102,8 +102,8 @@ public abstract class DefaultEntityState<ENTITY extends GraphBacked<STATE>, STAT
}
@Override
public Object setValue(final Neo4JPersistentProperty property, final Object newVal) {
final FieldAccessor<ENTITY> accessor = accessorFor(property);
public Object setValue(final Neo4jPersistentProperty property, final Object newVal) {
final FieldAccessor accessor = accessorFor(property);
final Object result=accessor!=null ? accessor.setValue(entity, newVal) : newVal;
notifyListeners(property, result);
return result;
@@ -112,34 +112,29 @@ public abstract class DefaultEntityState<ENTITY extends GraphBacked<STATE>, STAT
@Override
public Object getDefaultImplementation(Field field) {
final FieldAccessor<ENTITY> accessor = accessorFor(property(field));
final FieldAccessor accessor = accessorFor(property(field));
if (accessor == null) return null;
else return accessor.getDefaultImplementation();
}
protected Neo4JPersistentProperty property(Field field) {
protected Neo4jPersistentProperty property(Field field) {
return persistentEntity.getPersistentProperty(field.getName());
}
protected FieldAccessor<ENTITY> accessorFor(final Neo4JPersistentProperty property) {
protected FieldAccessor accessorFor(final Neo4jPersistentProperty property) {
return fieldAccessors.get(property);
}
private void notifyListeners(final Neo4JPersistentProperty field, final Object result) {
private void notifyListeners(final Neo4jPersistentProperty field, final Object result) {
if (!fieldAccessorListeners.containsKey(field) || fieldAccessorListeners.get(field) == null) return;
for (final FieldAccessListener<ENTITY, ?> listener : fieldAccessorListeners.get(field)) {
for (final FieldAccessListener listener : fieldAccessorListeners.get(field)) {
listener.valueChanged(entity, null, result); // todo oldValue
}
}
protected Object getIdFromEntity() {
final Neo4JPersistentProperty idProperty = fieldAccessorFactoryProviders.getIdProperty();
final Neo4jPersistentProperty idProperty = fieldAccessorFactoryProviders.getIdProperty();
if (idProperty==null) return null;
try {
return idProperty.getValue(entity);
} catch (IllegalAccessException e) {
log.warn("Error accessing id field "+idProperty);
return null;
}
return idProperty.getValue(entity);
}
}

View File

@@ -21,24 +21,23 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.data.mapping.Association;
import org.springframework.data.mapping.AssociationHandler;
import org.springframework.data.mapping.PropertyHandler;
import org.springframework.data.neo4j.mapping.Neo4JPersistentEntity;
import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty;
import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import org.springframework.data.util.TypeInformation;
import java.lang.reflect.Field;
import java.util.*;
public abstract class DelegatingFieldAccessorFactory<T> implements FieldAccessorFactory<T> {
public abstract class DelegatingFieldAccessorFactory implements FieldAccessorFactory {
private final static Log log = LogFactory.getLog(DelegatingFieldAccessorFactory.class);
protected final GraphDatabaseContext graphDatabaseContext;
protected abstract Collection<FieldAccessorListenerFactory<?>> createListenerFactories();
protected abstract Collection<FieldAccessorListenerFactory> createListenerFactories();
protected abstract Collection<? extends FieldAccessorFactory<?>> createAccessorFactories();
protected abstract Collection<? extends FieldAccessorFactory> createAccessorFactories();
public DelegatingFieldAccessorFactory(final GraphDatabaseContext graphDatabaseContext) {
this.graphDatabaseContext = graphDatabaseContext;
@@ -52,45 +51,45 @@ public abstract class DelegatingFieldAccessorFactory<T> implements FieldAccessor
}
@Override
public boolean accept(final Neo4JPersistentProperty f) {
public boolean accept(final Neo4jPersistentProperty f) {
return true;
}
final Collection<FieldAccessorFactory<?>> fieldAccessorFactories = new ArrayList<FieldAccessorFactory<?>>();
final Collection<FieldAccessorListenerFactory<?>> fieldAccessorListenerFactories = new ArrayList<FieldAccessorListenerFactory<?>>();
final Collection<FieldAccessorFactory> fieldAccessorFactories = new ArrayList<FieldAccessorFactory>();
final Collection<FieldAccessorListenerFactory> fieldAccessorListenerFactories = new ArrayList<FieldAccessorListenerFactory>();
public FieldAccessor forField(final Neo4JPersistentProperty property) {
final FieldAccessorFactory<?> factory = factoryForField(property);
public FieldAccessor forField(final Neo4jPersistentProperty property) {
final FieldAccessorFactory factory = factoryForField(property);
return factory != null ? factory.forField(property) : null;
}
private <E> FieldAccessorFactory<E> factoryForField(final Neo4JPersistentProperty property) {
private <E> FieldAccessorFactory factoryForField(final Neo4jPersistentProperty property) {
if (property.isSyntheticField()) return null;
for (final FieldAccessorFactory<?> fieldAccessorFactory : fieldAccessorFactories) {
for (final FieldAccessorFactory fieldAccessorFactory : fieldAccessorFactories) {
if (fieldAccessorFactory.accept(property)) {
if (log.isInfoEnabled()) log.info("Factory " + fieldAccessorFactory + " used for field: " + property);
return (FieldAccessorFactory<E>) fieldAccessorFactory;
return (FieldAccessorFactory) fieldAccessorFactory;
}
}
if (log.isWarnEnabled()) log.warn("No FieldAccessor configured for field: " + property);
return null;
}
public List<FieldAccessListener<T, ?>> listenersFor(final Neo4JPersistentProperty property) {
final List<FieldAccessListener<T, ?>> result = new ArrayList<FieldAccessListener<T, ?>>();
final List<FieldAccessorListenerFactory<T>> fieldAccessListenerFactories = getFieldAccessListenerFactories(property);
for (final FieldAccessorListenerFactory<T> fieldAccessorListenerFactory : fieldAccessListenerFactories) {
final FieldAccessListener<T, ?> listener = fieldAccessorListenerFactory.forField(property);
public List<FieldAccessListener> listenersFor(final Neo4jPersistentProperty property) {
final List<FieldAccessListener> result = new ArrayList<FieldAccessListener>();
final List<FieldAccessorListenerFactory> fieldAccessListenerFactories = getFieldAccessListenerFactories(property);
for (final FieldAccessorListenerFactory fieldAccessorListenerFactory : fieldAccessListenerFactories) {
final FieldAccessListener listener = fieldAccessorListenerFactory.forField(property);
result.add(listener);
}
return result;
}
private <E> List<FieldAccessorListenerFactory<E>> getFieldAccessListenerFactories(final Neo4JPersistentProperty property) {
final List<FieldAccessorListenerFactory<E>> result = new ArrayList<FieldAccessorListenerFactory<E>>();
for (final FieldAccessorListenerFactory<?> fieldAccessorListenerFactory : fieldAccessorListenerFactories) {
private <E> List<FieldAccessorListenerFactory> getFieldAccessListenerFactories(final Neo4jPersistentProperty property) {
final List<FieldAccessorListenerFactory> result = new ArrayList<FieldAccessorListenerFactory>();
for (final FieldAccessorListenerFactory fieldAccessorListenerFactory : fieldAccessorListenerFactories) {
if (fieldAccessorListenerFactory.accept(property)) {
result.add((FieldAccessorListenerFactory<E>) fieldAccessorListenerFactory);
result.add((FieldAccessorListenerFactory) fieldAccessorListenerFactory);
}
}
return result;
@@ -101,25 +100,25 @@ public abstract class DelegatingFieldAccessorFactory<T> implements FieldAccessor
private final Map<TypeInformation<?>, FieldAccessorFactoryProviders> accessorFactoryProviderCache = new HashMap<TypeInformation<?>, FieldAccessorFactoryProviders>();
public <T> FieldAccessorFactoryProviders<T> accessorFactoriesFor(final Neo4JPersistentEntity<?> type) {
public <T> FieldAccessorFactoryProviders<T> accessorFactoriesFor(final Neo4jPersistentEntity<?> type) {
synchronized (this) {
final TypeInformation<?> typeInformation = type.getTypeInformation();
final FieldAccessorFactoryProviders<T> fieldAccessorFactoryProviders = accessorFactoryProviderCache.get(typeInformation);
if (fieldAccessorFactoryProviders != null) return fieldAccessorFactoryProviders;
final FieldAccessorFactoryProviders<T> newFieldAccessorFactories = new FieldAccessorFactoryProviders<T>(typeInformation);
type.doWithProperties(new PropertyHandler<Neo4JPersistentProperty>() {
final FieldAccessorFactoryProviders<T> newFieldAccessorFactories = new FieldAccessorFactoryProviders<T>(typeInformation,graphDatabaseContext);
type.doWithProperties(new PropertyHandler<Neo4jPersistentProperty>() {
@Override
public void doWithPersistentProperty(Neo4JPersistentProperty property) {
final FieldAccessorFactory<?> factory = factoryForField(property);
public void doWithPersistentProperty(Neo4jPersistentProperty property) {
final FieldAccessorFactory factory = factoryForField(property);
final List<FieldAccessorListenerFactory> listenerFactories = (List<FieldAccessorListenerFactory>) getFieldAccessListenerFactories(property);
newFieldAccessorFactories.add(property, factory, listenerFactories);
}
});
type.doWithAssociations(new AssociationHandler<Neo4JPersistentProperty>() {
type.doWithAssociations(new AssociationHandler<Neo4jPersistentProperty>() {
@Override
public void doWithAssociation(Association<Neo4JPersistentProperty> association) {
final Neo4JPersistentProperty property = association.getInverse();
final FieldAccessorFactory<?> factory = factoryForField(property);
public void doWithAssociation(Association<Neo4jPersistentProperty> association) {
final Neo4jPersistentProperty property = association.getInverse();
final FieldAccessorFactory factory = factoryForField(property);
final List<FieldAccessorListenerFactory> listenerFactories = (List<FieldAccessorListenerFactory>) getFieldAccessListenerFactories(property);
newFieldAccessorFactories.add(property, factory, listenerFactories);
}

View File

@@ -20,10 +20,10 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.neo4j.graphdb.Transaction;
import org.springframework.data.neo4j.core.EntityState;
import org.springframework.data.neo4j.core.GraphBacked;
import org.springframework.data.neo4j.core.NodeBacked;
import org.springframework.data.neo4j.mapping.Neo4JPersistentEntity;
import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty;
import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import org.springframework.util.ObjectUtils;
@@ -39,14 +39,14 @@ import static org.springframework.data.neo4j.support.DoReturn.unwrap;
* @author Michael Hunger
* @since 15.09.2010
*/
public class DetachedEntityState<ENTITY extends GraphBacked<STATE>, STATE> implements EntityState<ENTITY,STATE> {
public class DetachedEntityState<STATE> implements EntityState<STATE> {
private final Map<Field, ExistingValue> dirty = new HashMap<Field, ExistingValue>();
protected final EntityState<ENTITY,STATE> delegate;
protected final EntityState<STATE> delegate;
private final static Log log = LogFactory.getLog(DetachedEntityState.class);
private GraphDatabaseContext graphDatabaseContext;
private Neo4JPersistentEntity<ENTITY> persistentEntity;
private Neo4jPersistentEntity<Object> persistentEntity;
public DetachedEntityState(final EntityState<ENTITY, STATE> delegate, GraphDatabaseContext graphDatabaseContext) {
public DetachedEntityState(final EntityState<STATE> delegate, GraphDatabaseContext graphDatabaseContext) {
this.delegate = delegate;
this.persistentEntity = delegate.getPersistentEntity();
this.graphDatabaseContext = graphDatabaseContext;
@@ -58,7 +58,7 @@ public class DetachedEntityState<ENTITY extends GraphBacked<STATE>, STATE> imple
}
@Override
public ENTITY getEntity() {
public Object getEntity() {
return delegate.getEntity();
}
@@ -73,14 +73,14 @@ public class DetachedEntityState<ENTITY extends GraphBacked<STATE>, STATE> imple
}
@Override
public Neo4JPersistentEntity<ENTITY> getPersistentEntity() {
public Neo4jPersistentEntity<Object> getPersistentEntity() {
return persistentEntity;
}
@Override
public Object getValue(final Field field) {
if (isDetached()) {
if (getEntity().getPersistentState()==null || isDirty(field)) {
if (graphDatabaseContext.getPersistentState(getEntity())==null || isDirty(field)) {
if (log.isDebugEnabled()) log.debug("Outside of transaction, GET value from field " + field);
Object entityValue = getValueFromEntity(field);
if (entityValue != null) {
@@ -89,7 +89,7 @@ public class DetachedEntityState<ENTITY extends GraphBacked<STATE>, STATE> imple
Object defaultValue = getDefaultImplementation(field);
if (defaultValue != null) {
final ENTITY entity = getEntity();
final Object entity = getEntity();
try {
field.setAccessible(true);
field.set(entity, defaultValue);
@@ -137,12 +137,12 @@ public class DetachedEntityState<ENTITY extends GraphBacked<STATE>, STATE> imple
return setValue(property(field),newVal);
}
private Neo4JPersistentProperty property(Field field) {
private Neo4jPersistentProperty property(Field field) {
return persistentEntity.getPersistentProperty(field.getName());
}
@Override
public Object setValue(final Neo4JPersistentProperty property, final Object newVal) {
public Object setValue(final Neo4jPersistentProperty property, final Object newVal) {
if (isDetached()) {
final Field field = property.getField();
if (!isDirty(field) && isWritable(field)) {
@@ -186,7 +186,7 @@ public class DetachedEntityState<ENTITY extends GraphBacked<STATE>, STATE> imple
* always runs inside of a transaction
*/
private void flushDirty() {
final ENTITY entity = getEntity();
final Object entity = getEntity();
if (!hasPersistentState()) {
// createAndAssignState();
throw new IllegalStateException("Flushing detached entity without a persistent state, this had to be created first.");
@@ -199,15 +199,16 @@ public class DetachedEntityState<ENTITY extends GraphBacked<STATE>, STATE> imple
final Field field = entry.getKey();
Object valueFromEntity = getValueFromEntity(field);
cascadePersist(valueFromEntity);
if (log.isDebugEnabled()) log.debug("Flushing dirty Entity new node " + entity.getPersistentState() + " field " + field+ " with value "+ valueFromEntity);
if (log.isDebugEnabled()) log.debug("Flushing dirty Entity new node " + entity + " field " + field+ " with value "+ valueFromEntity);
checkConcurrentModification(entity, entry, field);
delegate.setValue(field, valueFromEntity);
}
}
}
private void cascadePersist(Object valueFromEntity) {
if (valueFromEntity instanceof NodeBacked) {
/* TODO if (valueFromEntity instanceof NodeBacked) {
((NodeBacked) valueFromEntity).persist();
}
if (valueFromEntity instanceof Collection) {
@@ -217,6 +218,7 @@ public class DetachedEntityState<ENTITY extends GraphBacked<STATE>, STATE> imple
}
}
}
*/
}
@Override
@@ -226,7 +228,7 @@ public class DetachedEntityState<ENTITY extends GraphBacked<STATE>, STATE> imple
private Object getValueFromEntity(final Field field) {
final ENTITY entity = getEntity();
final Object entity = getEntity();
try {
field.setAccessible(true);
return field.get(entity);
@@ -235,12 +237,12 @@ public class DetachedEntityState<ENTITY extends GraphBacked<STATE>, STATE> imple
}
}
private void checkConcurrentModification(final ENTITY entity, final Map.Entry<Field, ExistingValue> entry, final Field field) {
private void checkConcurrentModification(final Object entity, final Map.Entry<Field, ExistingValue> entry, final Field field) {
final ExistingValue previousValue = entry.getValue();
if (previousValue.mustCheckConcurrentModification()) {
final Object nodeValue = unwrap(delegate.getValue(field));
if (!ObjectUtils.nullSafeEquals(nodeValue, previousValue.value)) {
throw new ConcurrentModificationException("Node " + entity.getPersistentState() + " field " + field + " changed in between previous " + previousValue + " current " + nodeValue); // todo or just overwrite
throw new ConcurrentModificationException("Node " + entity + " field " + field + " changed in between previous " + previousValue + " current " + nodeValue); // todo or just overwrite
}
}
}
@@ -272,11 +274,11 @@ public class DetachedEntityState<ENTITY extends GraphBacked<STATE>, STATE> imple
// todo always create an transaction for persist, atomic operation when no outside tx exists
@Override
public ENTITY persist() {
public Object persist() {
if (!isDetached()) return getEntity();
Transaction tx = graphDatabaseContext.beginTx();
try {
ENTITY result = delegate.persist();
Object result = delegate.persist();
flushDirty();
tx.success();

View File

@@ -38,12 +38,12 @@ import org.springframework.data.neo4j.fieldaccess.DynamicPropertiesFieldAccessor
* Person p = new Person();
* p.persist();
* p.personalProperties.setProperty(&quot;ZIP&quot;, 8000);
* p.personalProperties.setProperty(&quot;City&quot;, &quot;Z<EFBFBD>rich&quot;);
* p.personalProperties.setProperty(&quot;City&quot;, &quot;Zürich&quot;);
* </pre>
* results in a node with the properties:
* <pre>
* "personalProperties-ZIP" => 8000
* "personalProperties-City" => "Z<EFBFBD>rich"
* "personalProperties-City" => "Zürich"
* </pre>
*/
public interface DynamicProperties {

View File

@@ -15,68 +15,70 @@
*/
package org.springframework.data.neo4j.fieldaccess;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;
import org.neo4j.graphdb.PropertyContainer;
import org.neo4j.helpers.collection.IteratorUtil;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.neo4j.core.GraphBacked;
import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
import org.springframework.data.neo4j.support.DoReturn;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
/**
* This accessor factory creates {@link DynamicPropertiesFieldAccessor}s for @NodeEntity properties of type
* {@link DynamicProperties}.
*/
public class DynamicPropertiesFieldAccessorFactory implements FieldAccessorFactory<GraphBacked<PropertyContainer>> {
public class DynamicPropertiesFieldAccessorFactory implements FieldAccessorFactory {
private final ConversionService conversionService;
private final GraphDatabaseContext graphDatabaseContext;
public DynamicPropertiesFieldAccessorFactory(final ConversionService conversionService) {
this.conversionService = conversionService;
public DynamicPropertiesFieldAccessorFactory(final GraphDatabaseContext graphDatabaseContext) {
this.graphDatabaseContext = graphDatabaseContext;
}
@Override
public boolean accept(Neo4JPersistentProperty f) {
public boolean accept(Neo4jPersistentProperty f) {
return DynamicProperties.class.isAssignableFrom(f.getType());
}
@Override
public FieldAccessor<GraphBacked<PropertyContainer>> forField(Neo4JPersistentProperty field) {
return new DynamicPropertiesFieldAccessor(conversionService,
public FieldAccessor forField(Neo4jPersistentProperty field) {
return new DynamicPropertiesFieldAccessor(graphDatabaseContext,
field.getNeo4jPropertyName(), field);
}
public static class DynamicPropertiesFieldAccessor implements FieldAccessor<GraphBacked<PropertyContainer>> {
private final ConversionService conversionService;
public static class DynamicPropertiesFieldAccessor implements FieldAccessor {
private final String propertyNamePrefix;
private final Neo4JPersistentProperty field;
private final Neo4jPersistentProperty field;
private final GraphDatabaseContext graphDatabaseContext;
public DynamicPropertiesFieldAccessor(ConversionService conversionService, String propertyName, Neo4JPersistentProperty field) {
this.conversionService = conversionService;
public DynamicPropertiesFieldAccessor(GraphDatabaseContext graphDatabaseContext, String propertyName, Neo4jPersistentProperty field) {
this.graphDatabaseContext = graphDatabaseContext;
this.propertyNamePrefix = propertyName;
this.field = field;
}
@Override
public Object setValue(final GraphBacked<PropertyContainer> entity, final Object newVal) {
final PropertyContainer propertyContainer = entity.getPersistentState();
public Object setValue(final Object entity, final Object newVal) {
final PropertyContainer propertyContainer = graphDatabaseContext.getPersistentState(entity);
PrefixedDynamicProperties dynamicProperties;
if (newVal instanceof ManagedPrefixedDynamicProperties) {
// newVal is already a managed container
dynamicProperties = (ManagedPrefixedDynamicProperties<?>) newVal;
dynamicProperties = (ManagedPrefixedDynamicProperties) newVal;
}
else {
// newVal is not a managed prefixed container and therefore contains
// pure key/values that must be converted to a prefixed form
dynamicProperties = new PrefixedDynamicProperties(propertyNamePrefix);
DynamicProperties newPropertiesVal = (DynamicProperties)newVal;
for(String key : newPropertiesVal.getPropertyKeys()) {
dynamicProperties.setProperty(key, newPropertiesVal.getProperty(key));
}
}
if (newVal != null) {
DynamicProperties newPropertiesVal = (DynamicProperties) newVal;
for (String key : newPropertiesVal.getPropertyKeys()) {
dynamicProperties.setProperty(key, newPropertiesVal.getProperty(key));
}
}
}
Set<String> dynamicProps = dynamicProperties.getPrefixedPropertyKeys();
@@ -105,10 +107,9 @@ public class DynamicPropertiesFieldAccessorFactory implements FieldAccessorFacto
}
@Override
public Object getValue(final GraphBacked<PropertyContainer> entity) {
PropertyContainer element = entity.getPersistentState();
ManagedPrefixedDynamicProperties<?> props = ManagedPrefixedDynamicProperties.create(propertyNamePrefix,
field, entity);
public Object getValue(final Object entity) {
PropertyContainer element = graphDatabaseContext.getPersistentState(entity);
ManagedPrefixedDynamicProperties props = ManagedPrefixedDynamicProperties.create(propertyNamePrefix, field, entity,graphDatabaseContext,this);
for (String key : element.getPropertyKeys()) {
props.setPropertyIfPrefixed(key, element.getProperty(key));
}
@@ -116,7 +117,7 @@ public class DynamicPropertiesFieldAccessorFactory implements FieldAccessorFacto
}
@Override
public boolean isWriteable(final GraphBacked<PropertyContainer> entity) {
public boolean isWriteable(final Object entity) {
return true;
}

View File

@@ -18,10 +18,8 @@ package org.springframework.data.neo4j.fieldaccess;
/**
* interface for listeners for field modifications, used for instance for indexing or tracing
* @param <ENTITY>
* @param <TARGET>
*/
public interface FieldAccessListener<ENTITY, TARGET> {
public interface FieldAccessListener {
/**
* callback method after modifying field write operation
@@ -29,6 +27,6 @@ public interface FieldAccessListener<ENTITY, TARGET> {
* @param oldVal
* @param newVal
*/
void valueChanged(ENTITY entity, Object oldVal, Object newVal);
void valueChanged(Object entity, Object oldVal, Object newVal);
}

View File

@@ -18,12 +18,9 @@ package org.springframework.data.neo4j.fieldaccess;
/**
* interface for field accessors, encapsulates reading and writing from fields and write support information about the field.
* It is used by the {@link org.springframework.data.neo4j.core.EntityState} which is delegated to by the
* {@link org.springframework.data.neo4j.support.node.Neo4jNodeBacking} {@link org.springframework.data.neo4j.support.relationship.Neo4jRelationshipBacking}
* aspects.
* @param <ENTITY>
* It is used by the {@link org.springframework.data.neo4j.core.EntityState}.
*/
public interface FieldAccessor<ENTITY> {
public interface FieldAccessor {
/**
* Returns a default implementation for a field or {@code null} if none is provided.
@@ -41,18 +38,18 @@ public interface FieldAccessor<ENTITY> {
* @return the written value or a DoReturn wrapper with the written value or null.
* DoReturn indicates that the aspect should not proceed to the original field access but instead return immediately.
*/
Object setValue(ENTITY entity, Object newVal);
Object setValue(Object entity, Object newVal);
/**
* @param entity
* @return the value or a DoReturn wrapper with the value for the field.
* DoReturn indicates that the aspect should not proceed to the original field access but instead return immediately.
*/
Object getValue(ENTITY entity);
Object getValue(Object entity);
/**
* @param entity
* @return false for read only or computed fields, true otherwise
*/
boolean isWriteable(ENTITY entity);
boolean isWriteable(Object entity);
}

View File

@@ -16,9 +16,7 @@
package org.springframework.data.neo4j.fieldaccess;
import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty;
import java.lang.reflect.Field;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
/**
* Factory interface for a single field / field accessor. Provides means to check if a certain field is eligible for this
@@ -27,18 +25,18 @@ import java.lang.reflect.Field;
* @author Michael Hunger
* @since 12.09.2010
*/
public interface FieldAccessorFactory<E> {
public interface FieldAccessorFactory {
/**
*
* @param f field to check
* @return true if this factory is responsible for creating a accessor for this field
*/
boolean accept(Neo4JPersistentProperty f);
boolean accept(Neo4jPersistentProperty f);
/**
*
* @param f the field to create an accessor for
* @return a field accessor for the field or null if none can be created
*/
FieldAccessor<E> forField(Neo4JPersistentProperty f);
FieldAccessor forField(Neo4jPersistentProperty f);
}

View File

@@ -16,10 +16,11 @@
package org.springframework.data.neo4j.fieldaccess;
import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import org.springframework.data.util.TypeInformation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -32,31 +33,31 @@ import java.util.Map;
public class FieldAccessorFactoryProviders<T> {
static class FieldAccessorFactoryProvider<E> {
private final Neo4JPersistentProperty property;
private final FieldAccessorFactory<E> fieldAccessorFactory;
private final List<FieldAccessorListenerFactory<E>> fieldAccessorListenerFactories;
private final Neo4jPersistentProperty property;
private final FieldAccessorFactory fieldAccessorFactory;
private final List<FieldAccessorListenerFactory> fieldAccessorListenerFactories;
FieldAccessorFactoryProvider(final Neo4JPersistentProperty property, final FieldAccessorFactory fieldAccessorFactory, final List fieldAccessorListenerFactories) {
FieldAccessorFactoryProvider(final Neo4jPersistentProperty property, final FieldAccessorFactory fieldAccessorFactory, final List fieldAccessorListenerFactories) {
this.property = property;
this.fieldAccessorFactory = fieldAccessorFactory;
this.fieldAccessorListenerFactories = fieldAccessorListenerFactories;
}
public FieldAccessor<E> accessor() {
public FieldAccessor accessor() {
if (fieldAccessorFactory == null) return null;
return fieldAccessorFactory.forField(property);
}
public List<FieldAccessListener<E, ?>> listeners() {
public List<FieldAccessListener> listeners() {
if (fieldAccessorListenerFactories == null) return null;
final List<FieldAccessListener<E, ?>> listeners = new ArrayList<FieldAccessListener<E, ?>>(fieldAccessorListenerFactories.size());
for (final FieldAccessorListenerFactory<E> fieldAccessorListenerFactory : fieldAccessorListenerFactories) {
final List<FieldAccessListener> listeners = new ArrayList<FieldAccessListener>(fieldAccessorListenerFactories.size());
for (final FieldAccessorListenerFactory fieldAccessorListenerFactory : fieldAccessorListenerFactories) {
listeners.add(fieldAccessorListenerFactory.forField(property));
}
return listeners;
}
public Neo4JPersistentProperty getProperty() {
public Neo4jPersistentProperty getProperty() {
return property;
}
}
@@ -64,37 +65,37 @@ public class FieldAccessorFactoryProviders<T> {
private final TypeInformation<?> type;
private final List<FieldAccessorFactoryProvider<T>> fieldAccessorFactoryProviders = new ArrayList<FieldAccessorFactoryProvider<T>>();
private final IdFieldAccessorFactory idFieldAccessorFactory;
private Neo4JPersistentProperty idProperty;
private Neo4jPersistentProperty idProperty;
FieldAccessorFactoryProviders(TypeInformation<?> type) {
FieldAccessorFactoryProviders(TypeInformation<?> type, GraphDatabaseContext graphDatabaseContext) {
this.type = type;
idFieldAccessorFactory = new IdFieldAccessorFactory();
idFieldAccessorFactory= new IdFieldAccessorFactory(graphDatabaseContext);
}
public Map<Neo4JPersistentProperty, FieldAccessor<T>> getFieldAccessors() {
final Map<Neo4JPersistentProperty, FieldAccessor<T>> result = new HashMap<Neo4JPersistentProperty, FieldAccessor<T>>(fieldAccessorFactoryProviders.size(),1);
public Map<Neo4jPersistentProperty, FieldAccessor> getFieldAccessors() {
final Map<Neo4jPersistentProperty, FieldAccessor> result = new HashMap<Neo4jPersistentProperty, FieldAccessor>(fieldAccessorFactoryProviders.size(),1);
for (final FieldAccessorFactoryProvider<T> fieldAccessorFactoryProvider : fieldAccessorFactoryProviders) {
final FieldAccessor<T> accessor = fieldAccessorFactoryProvider.accessor();
final FieldAccessor accessor = fieldAccessorFactoryProvider.accessor();
result.put(fieldAccessorFactoryProvider.getProperty(), accessor);
}
return result;
}
public Map<Neo4JPersistentProperty, List<FieldAccessListener<T,?>>> getFieldAccessListeners() {
final Map<Neo4JPersistentProperty, List<FieldAccessListener<T,?>>> result = new HashMap<Neo4JPersistentProperty, List<FieldAccessListener<T,?>>>(fieldAccessorFactoryProviders.size(),1);
public Map<Neo4jPersistentProperty, List<FieldAccessListener>> getFieldAccessListeners() {
final Map<Neo4jPersistentProperty, List<FieldAccessListener>> result = new HashMap<Neo4jPersistentProperty, List<FieldAccessListener>>(fieldAccessorFactoryProviders.size(),1);
for (final FieldAccessorFactoryProvider<T> fieldAccessorFactoryProvider : fieldAccessorFactoryProviders) {
final List<FieldAccessListener<T,?>> listeners = (List<FieldAccessListener<T,?>>) fieldAccessorFactoryProvider.listeners();
final List<FieldAccessListener> listeners = (List<FieldAccessListener>) fieldAccessorFactoryProvider.listeners();
result.put(fieldAccessorFactoryProvider.getProperty(), listeners);
}
return result;
}
public void add(Neo4JPersistentProperty property, FieldAccessorFactory<?> fieldAccessorFactory, List<FieldAccessorListenerFactory> listenerFactories) {
public void add(Neo4jPersistentProperty property, FieldAccessorFactory fieldAccessorFactory, List<FieldAccessorListenerFactory> listenerFactories) {
fieldAccessorFactoryProviders.add(new FieldAccessorFactoryProvider(property, fieldAccessorFactory, listenerFactories));
if (property.isIdProperty()) this.idProperty = property;
}
public Neo4JPersistentProperty getIdProperty() {
public Neo4jPersistentProperty getIdProperty() {
return idProperty;
}
}

Some files were not shown because too many files have changed in this diff Show More