diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/config/DataGraphBeanDefinitionParser.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/config/DataGraphBeanDefinitionParser.java
index 76be46e32..135d44090 100644
--- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/config/DataGraphBeanDefinitionParser.java
+++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/config/DataGraphBeanDefinitionParser.java
@@ -25,6 +25,7 @@ import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
+import org.springframework.util.ClassUtils;
import org.w3c.dom.Element;
import static org.springframework.util.StringUtils.hasText;
@@ -32,22 +33,40 @@ import static org.springframework.util.StringUtils.hasText;
public class DataGraphBeanDefinitionParser extends AbstractBeanDefinitionParser {
private static final String GRAPH_DATABASE_SERVICE = "graphDatabaseService";
+ public static final String ASPECTJ_CONFIG = "org.springframework.data.neo4j.config.Neo4jAspectConfiguration";
+ public static final String CROSS_STORE_CONFIG = "org.springframework.data.neo4j.config.CrossStoreNeo4jConfiguration";
@Override
protected AbstractBeanDefinition parseInternal(Element element, ParserContext context) {
- BeanDefinitionBuilder configBuilder = createConfigurationBeanDefinition();
+ BeanDefinitionBuilder configBuilder = createConfigurationBeanDefinition(element);
setupGraphDatabase(element, context, configBuilder);
setupEntityManagerFactory(element, configBuilder);
setupConfigurationClassPostProcessor(context);
return getSourcedBeanDefinition(configBuilder, element, context);
}
- private BeanDefinitionBuilder createConfigurationBeanDefinition() {
- BeanDefinitionBuilder configBuilder = BeanDefinitionBuilder.rootBeanDefinition(Neo4jConfiguration.class);
+
+ private BeanDefinitionBuilder createConfigurationBeanDefinition(Element element) {
+ BeanDefinitionBuilder configBuilder = createConfigBuilderByMode(element);
configBuilder.setAutowireMode(Autowire.BY_TYPE.value());
return configBuilder;
}
+ // todo cross-store
+ private BeanDefinitionBuilder createConfigBuilderByMode(Element element) {
+ if (isModeCrossStore(element)) return BeanDefinitionBuilder.rootBeanDefinition(CROSS_STORE_CONFIG);
+ if (isModeAspectJ()) return BeanDefinitionBuilder.rootBeanDefinition(ASPECTJ_CONFIG);
+ return BeanDefinitionBuilder.rootBeanDefinition(Neo4jConfiguration.class);
+ }
+
+ private boolean isModeCrossStore(Element element) {
+ return isModeAspectJ() && isEntityManagerFactoryConfigured(element);
+ }
+
+ private boolean isModeAspectJ() {
+ return ClassUtils.isPresent(ASPECTJ_CONFIG, getClass().getClassLoader());
+ }
+
private void setupConfigurationClassPostProcessor(final ParserContext parserContext) {
BeanDefinitionRegistry beanDefinitionRegistry = parserContext.getRegistry();
@@ -72,12 +91,17 @@ public class DataGraphBeanDefinitionParser extends AbstractBeanDefinitionParser
}
private void setupEntityManagerFactory(Element element, BeanDefinitionBuilder configBuilder) {
- String entityManagerFactory = element.getAttribute("entityManagerFactory");
- if (hasText(entityManagerFactory)) {
+ if (isEntityManagerFactoryConfigured(element)) {
+ String entityManagerFactory = element.getAttribute("entityManagerFactory");
configBuilder.addPropertyReference("entityManagerFactory", entityManagerFactory);
}
}
+ private boolean isEntityManagerFactoryConfigured(Element element) {
+ String entityManagerFactory = element.getAttribute("entityManagerFactory");
+ return hasText(entityManagerFactory);
+ }
+
private String handleStoreDir(Element element, ParserContext context, BeanDefinitionBuilder configBuilder) {
String storeDir = element.getAttribute("storeDirectory");
if (!hasText(storeDir)) return null;
diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/config/Neo4jConfiguration.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/config/Neo4jConfiguration.java
index ca8340574..242765d19 100644
--- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/config/Neo4jConfiguration.java
+++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/config/Neo4jConfiguration.java
@@ -16,9 +16,6 @@
package org.springframework.data.neo4j.config;
-import javax.annotation.PostConstruct;
-import javax.validation.Validator;
-
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
@@ -30,8 +27,6 @@ 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.fieldaccess.DelegatingFieldAccessorFactory;
import org.springframework.data.neo4j.fieldaccess.Neo4jConversionServiceFactoryBean;
import org.springframework.data.neo4j.fieldaccess.NodeDelegatingFieldAccessorFactory;
@@ -40,6 +35,7 @@ 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.EntityStateHandler;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import org.springframework.data.neo4j.support.node.NodeEntityInstantiator;
import org.springframework.data.neo4j.support.node.NodeEntityStateFactory;
@@ -51,6 +47,9 @@ import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.jta.JtaTransactionManager;
import org.springframework.transaction.jta.UserTransactionAdapter;
+import javax.annotation.PostConstruct;
+import javax.validation.Validator;
+
/**
* Abstract base class for code based configuration of Spring managed Neo4j infrastructure.
*
Subclasses are required to provide an implementation of graphDbService ....
@@ -87,6 +86,7 @@ public abstract class Neo4jConfiguration {
gdc.setConversionService(conversionService());
gdc.setMappingContext(mappingContext());
gdc.setConverter(neo4jConverter());
+ gdc.setEntityStateHandler(entityStateHandler());
gdc.setNodeTypeRepresentationStrategy(typeRepresentationStrategyFactory.getNodeTypeRepresentationStrategy());
gdc.setRelationshipTypeRepresentationStrategy(typeRepresentationStrategyFactory.getRelationshipTypeRepresentationStrategy());
if (validator!=null) {
@@ -95,6 +95,11 @@ public abstract class Neo4jConfiguration {
return gdc;
}
+ @Bean
+ public EntityStateHandler entityStateHandler() {
+ return new EntityStateHandler(mappingContext(),graphDatabaseService);
+ }
+
@Bean
public Neo4jNodeConverterImpl neo4jConverter() throws Exception {
return new Neo4jNodeConverterImpl();
@@ -106,13 +111,13 @@ public abstract class Neo4jConfiguration {
}
@Bean
- protected RelationshipEntityInstantiator graphRelationshipInstantiator() {
- return new RelationshipEntityInstantiator(mappingContext());
+ protected RelationshipEntityInstantiator graphRelationshipInstantiator() throws Exception {
+ return new RelationshipEntityInstantiator(entityStateHandler());
}
@Bean
- protected EntityInstantiator graphEntityInstantiator() {
- return new NodeEntityInstantiator(mappingContext());
+ protected EntityInstantiator graphEntityInstantiator() throws Exception {
+ return new NodeEntityInstantiator(entityStateHandler());
}
@Bean
diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/GraphBackedEntityIterableWrapper.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/GraphBackedEntityIterableWrapper.java
new file mode 100644
index 000000000..cee856e77
--- /dev/null
+++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/GraphBackedEntityIterableWrapper.java
@@ -0,0 +1,45 @@
+/**
+ * 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.fieldaccess;
+
+import org.neo4j.graphdb.PropertyContainer;
+import org.neo4j.helpers.collection.IterableWrapper;
+import org.springframework.data.neo4j.support.GraphDatabaseContext;
+
+/**
+ * Simple wrapper to create an Iterable over @NodeEntities or @RelationshipEntities from an iterable over Nodes or Relationships.
+ * Creates NodeEntities on the fly while iterating the Iterator from original iterable.
+ */
+public class GraphBackedEntityIterableWrapper extends IterableWrapper {
+ private final Class targetType;
+ private final GraphDatabaseContext graphDatabaseContext;
+
+ public GraphBackedEntityIterableWrapper(Iterable iterable, Class targetType, final GraphDatabaseContext graphDatabaseContext) {
+ super(iterable);
+ this.targetType = targetType;
+ this.graphDatabaseContext = graphDatabaseContext;
+ }
+
+ @Override
+ protected ENTITY underlyingObjectToObject(STATE s) {
+ return graphDatabaseContext.createEntityFromState(s, targetType);
+ }
+
+ public static GraphBackedEntityIterableWrapper create(
+ Iterable iterable, Class targetType, final GraphDatabaseContext graphDatabaseContext) {
+ return new GraphBackedEntityIterableWrapper(iterable, targetType, graphDatabaseContext);
+ }
+}
\ No newline at end of file
diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedFieldAccessorSet.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedFieldAccessorSet.java
index 52ce0041f..8ccabc766 100644
--- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedFieldAccessorSet.java
+++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedFieldAccessorSet.java
@@ -16,10 +16,11 @@
package org.springframework.data.neo4j.fieldaccess;
-import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity;
+import org.springframework.data.neo4j.core.EntityState;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
import org.springframework.data.neo4j.support.DoReturn;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
+import org.springframework.data.neo4j.support.ManagedEntity;
import java.util.AbstractSet;
import java.util.Collection;
@@ -68,15 +69,20 @@ public class ManagedFieldAccessorSet extends AbstractSet {
}
private void update() {
- final Neo4jPersistentEntity> persistentEntity = property.getOwner();
- if (persistentEntity.isNodeEntity()) {
- updateValue();
- }
- if (persistentEntity.isRelationshipEntity()) {
+ if (ctx.isManaged(entity)) {
+ updateValueWithState(((ManagedEntity)entity).getEntityState());
+ } else {
updateValue();
}
}
+ private Object updateValueWithState(EntityState entityState) {
+ final Object newValue = entityState.setValue(property, delegate);
+ if (newValue instanceof DoReturn) return DoReturn.unwrap(newValue);
+ property.setValue(entity, newValue);
+ return newValue;
+ }
+
private Object updateValue() {
final Object newValue = fieldAccessor.setValue(entity,delegate);
if (newValue instanceof DoReturn) return DoReturn.unwrap(newValue);
diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedPrefixedDynamicProperties.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedPrefixedDynamicProperties.java
index 7eae2fb26..eba9695a3 100644
--- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedPrefixedDynamicProperties.java
+++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedPrefixedDynamicProperties.java
@@ -15,18 +15,13 @@
*/
package org.springframework.data.neo4j.fieldaccess;
-import java.lang.reflect.Field;
-import java.util.Map;
-
-import org.neo4j.graphdb.Node;
import org.springframework.data.neo4j.core.EntityState;
-
-
-
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
import org.springframework.data.neo4j.support.DoReturn;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
-import scala.annotation.target.field;
+import org.springframework.data.neo4j.support.ManagedEntity;
+
+import java.util.Map;
/**
* Updates the entity containing such a ManagedPrefixedDynamicProperties when some property is added, changed or
@@ -82,10 +77,6 @@ public class ManagedPrefixedDynamicProperties extends PrefixedDynamicProperties
return d;
}
- private void update() {
- updateValue();
- }
-
private Object updateValue() {
final Object newValue = fieldAccessor.setValue(entity, this);
if (newValue instanceof DoReturn)
@@ -93,4 +84,19 @@ public class ManagedPrefixedDynamicProperties extends PrefixedDynamicProperties
property.setValue(entity, newValue);
return newValue;
}
+
+ private void update() {
+ if (graphDatabaseContext.isManaged(entity)) {
+ updateValueWithState(((ManagedEntity)entity).getEntityState());
+ } else {
+ updateValue();
+ }
+ }
+
+ private Object updateValueWithState(EntityState entityState) {
+ final Object newValue = entityState.setValue(property, this);
+ if (newValue instanceof DoReturn) return DoReturn.unwrap(newValue);
+ property.setValue(entity, newValue);
+ return newValue;
+ }
}
diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/NodeToNodesRelationshipFieldAccessor.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/NodeToNodesRelationshipFieldAccessor.java
index 82f9ab8b6..d1503e7bc 100644
--- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/NodeToNodesRelationshipFieldAccessor.java
+++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/NodeToNodesRelationshipFieldAccessor.java
@@ -20,11 +20,8 @@ import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;
-
-
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;
@@ -59,7 +56,7 @@ public abstract class NodeToNodesRelationshipFieldAccessor extends AbstractNodeR
@Override
protected Node getState(final Object entity) {
- return property.getOwner().getPersistentState(entity, graphDatabaseContext);
+ return graphDatabaseContext.getPersistentState(entity);
}
}
diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessorFactory.java
index fe55d3613..c5b6b32b5 100644
--- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessorFactory.java
+++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessorFactory.java
@@ -16,17 +16,15 @@
package org.springframework.data.neo4j.fieldaccess;
-import org.neo4j.graphdb.*;
+import org.neo4j.graphdb.Direction;
+import org.neo4j.graphdb.Node;
+import org.neo4j.graphdb.Relationship;
+import org.neo4j.graphdb.RelationshipType;
import org.springframework.dao.InvalidDataAccessApiUsageException;
-
-
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
import org.springframework.data.neo4j.mapping.RelationshipInfo;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
-import java.util.HashSet;
-import java.util.Set;
-
import static org.springframework.data.neo4j.support.DoReturn.doReturn;
public class OneToNRelationshipEntityFieldAccessorFactory implements FieldAccessorFactory {
@@ -68,22 +66,16 @@ public class OneToNRelationshipEntityFieldAccessorFactory implements FieldAccess
@Override
public Object getValue(final Object entity) {
checkUnderlyingNode(entity);
- final Set> result = createEntitySetFromRelationships(entity);
- return doReturn(new ManagedFieldAccessorSet(entity, result, property,graphDatabaseContext, this));
- }
+ return doReturn(iterableFrom(entity));
+ }
- private Set> createEntitySetFromRelationships(final Object entity) {
- final Set