restructured project, first implementation steps of mapping approach, in progress
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
*.log
|
||||
.DS_Store
|
||||
target
|
||||
.springBeans
|
||||
|
||||
6
pom.xml
6
pom.xml
@@ -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>
|
||||
|
||||
236
spring-data-neo4j-aspects/pom.xml
Normal file
236
spring-data-neo4j-aspects/pom.xml
Normal 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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
*
|
||||
@@ -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();
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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> {
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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> {
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 {
|
||||
}
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
@@ -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">
|
||||
@@ -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">
|
||||
231
spring-data-neo4j-cross-store/pom.xml
Normal file
231
spring-data-neo4j-cross-store/pom.xml
Normal 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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -38,12 +38,12 @@ import org.springframework.data.neo4j.fieldaccess.DynamicPropertiesFieldAccessor
|
||||
* Person p = new Person();
|
||||
* p.persist();
|
||||
* p.personalProperties.setProperty("ZIP", 8000);
|
||||
* p.personalProperties.setProperty("City", "Z<EFBFBD>rich");
|
||||
* p.personalProperties.setProperty("City", "Zürich");
|
||||
* </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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user