added support for load-store pattern, cascading copying of properties
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
* eclipse / STS setup with m2e, AspectJConfigurator and Weaving enabled etc. https://jira.springsource.org/browse/DATAGRAPH-104
|
||||
|
||||
* fetch-strategies / behaviour
|
||||
* cascading persist/save
|
||||
* cascading persist/save
|
||||
* @Indexed(level)
|
||||
*
|
||||
4
pom.xml
4
pom.xml
@@ -36,14 +36,14 @@
|
||||
</issueManagement>
|
||||
<mailingLists>
|
||||
<mailingList>
|
||||
<name>Spring Batch Forum</name>
|
||||
<name>Spring Data Forum</name>
|
||||
<post>http://forum.springsource.org/forumdisplay.php?f=80</post>
|
||||
<archive>http://forum.springsource.org/forumdisplay.php?f=80</archive>
|
||||
</mailingList>
|
||||
</mailingLists>
|
||||
<ciManagement>
|
||||
<system>Bamboo</system>
|
||||
<url>https://build.springsource.org/browse/SPRINGDATA</url>
|
||||
<url>https://build.springsource.org/browse/SPRINGDATA-DATAGRAPH</url>
|
||||
</ciManagement>
|
||||
|
||||
<developers>
|
||||
|
||||
@@ -16,22 +16,26 @@
|
||||
package org.springframework.data.neo4j.aspects.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.neo4j.aspects.support.node.Neo4jNodeBacking;
|
||||
import org.springframework.data.neo4j.aspects.support.relationship.Neo4jRelationshipBacking;
|
||||
import org.springframework.data.neo4j.config.Neo4jConfiguration;
|
||||
import org.springframework.data.neo4j.support.node.NodeEntityStateFactory;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 30.09.11
|
||||
*/
|
||||
@Configuration
|
||||
public class Neo4jAspectConfiguration extends Neo4jConfiguration
|
||||
{
|
||||
@Bean
|
||||
public Neo4jRelationshipBacking neo4jRelationshipBacking() throws Exception {
|
||||
Neo4jRelationshipBacking aspect = Neo4jRelationshipBacking.aspectOf();
|
||||
aspect.setGraphDatabaseContext(graphDatabaseContext());
|
||||
aspect.setRelationshipEntityStateFactory(relationshipEntityStateFactory());
|
||||
aspect.setRelationshipEntityStateFactory(relationshipEntityStateFactory());
|
||||
return aspect;
|
||||
}
|
||||
|
||||
@@ -43,4 +47,10 @@ aspect.setRelationshipEntityStateFactory(relationshipEntityStateFactory());
|
||||
aspect.setNodeEntityStateFactory(entityStateFactory);
|
||||
return aspect;
|
||||
}
|
||||
|
||||
@Override
|
||||
@PostConstruct
|
||||
public void wireEntityStateFactories() throws Exception {
|
||||
super.wireEntityStateFactories();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ public privileged aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMix
|
||||
log.error("entityStateFactory not set, not creating accessors for " + entity.getClass());
|
||||
} else {
|
||||
if (entity.entityState != null) return;
|
||||
entity.entityState = entityStateFactory.getEntityState(entity);
|
||||
entity.entityState = entityStateFactory.getEntityState(entity, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ public privileged aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMix
|
||||
|
||||
public void NodeBacked.setPersistentState(Node n) {
|
||||
if (this.entityState == null) {
|
||||
this.entityState = Neo4jNodeBacking.aspectOf().entityStateFactory.getEntityState(this);
|
||||
this.entityState = Neo4jNodeBacking.aspectOf().entityStateFactory.getEntityState(this, false);
|
||||
}
|
||||
this.entityState.setPersistentState(n);
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ public aspect Neo4jRelationshipBacking {
|
||||
|
||||
public void RelationshipBacked.setPersistentState(Relationship r) {
|
||||
if (this.entityState == null) {
|
||||
this.entityState = Neo4jRelationshipBacking.aspectOf().entityStateFactory.getEntityState(this);
|
||||
this.entityState = Neo4jRelationshipBacking.aspectOf().entityStateFactory.getEntityState(this, true);
|
||||
}
|
||||
this.entityState.setPersistentState(r);
|
||||
}
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
<bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
|
||||
</property>
|
||||
<property name="mappingContext" ref="mappingContext"/>
|
||||
<property name="nodeEntityConverter" ref="nodeEntityConverter"/>
|
||||
</bean>
|
||||
|
||||
|
||||
@@ -131,6 +132,39 @@
|
||||
<property name="nodeEntityStateFactory" ref="nodeEntityStateFactory"/>
|
||||
</bean-->
|
||||
|
||||
<bean id="nodeEntityConverter" class="org.springframework.data.neo4j.mapping.Neo4jEntityConverterImpl">
|
||||
<constructor-arg index="0" ref="mappingContext"/>
|
||||
<constructor-arg index="1" ref="conversionService"/>
|
||||
<constructor-arg index="2" ref="graphEntityInstantiator"/>
|
||||
<constructor-arg index="3" ref="entityStateHandler"/>
|
||||
<constructor-arg index="4" ref="nodeTypeMapper"/>
|
||||
<constructor-arg index="5" ref="nodeSourceStateTransmitter"/>
|
||||
<constructor-arg index="6" ref="entityFetchHandler"/>
|
||||
</bean>
|
||||
|
||||
<bean id="entityFetchHandler" class="org.springframework.data.neo4j.mapping.Neo4jEntityFetchHandler">
|
||||
<constructor-arg index="0" ref="entityStateHandler"/>
|
||||
<constructor-arg index="1" ref="conversionService"/>
|
||||
<constructor-arg index="2" ref="nodeSourceStateTransmitter"/>
|
||||
<constructor-arg index="3" ref="relationshipSourceStateTransmitter"/>
|
||||
</bean>
|
||||
|
||||
<bean id="nodeSourceStateTransmitter" class="org.springframework.data.neo4j.mapping.SourceStateTransmitter">
|
||||
<constructor-arg index="0" ref="nodeEntityStateFactory"/>
|
||||
</bean>
|
||||
|
||||
<bean id="relationshipSourceStateTransmitter" class="org.springframework.data.neo4j.mapping.SourceStateTransmitter">
|
||||
<constructor-arg index="0" ref="relationshipEntityStateFactory"/>
|
||||
</bean>
|
||||
|
||||
<bean id="nodeTypeMapper" class="org.springframework.data.convert.DefaultTypeMapper">
|
||||
<constructor-arg index="0">
|
||||
<bean class="org.springframework.data.neo4j.mapping.TRSTypeAliasAccessor">
|
||||
<constructor-arg index="0" ref="nodeTypeRepresentationStrategy"/>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="mappingContext" class="org.springframework.data.neo4j.mapping.Neo4jMappingContext"/>
|
||||
|
||||
<bean id="relationshipEntityStateFactory" class="org.springframework.data.neo4j.support.relationship.RelationshipEntityStateFactory">
|
||||
|
||||
@@ -78,13 +78,13 @@ public class CrossStoreNeo4jConfiguration extends Neo4jAspectConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public NodeEntityStateFactory nodeEntityStateFactory() throws Exception {
|
||||
public CrossStoreNodeEntityStateFactory nodeEntityStateFactory() throws Exception {
|
||||
return new CrossStoreNodeEntityStateFactory();
|
||||
}
|
||||
|
||||
CrossStoreNodeEntityStateFactory entityStateFactory = new CrossStoreNodeEntityStateFactory();
|
||||
entityStateFactory.setGraphDatabaseContext(graphDatabaseContext());
|
||||
entityStateFactory.setEntityManagerFactory(entityManagerFactory);
|
||||
entityStateFactory.setMappingContext(mappingContext());
|
||||
entityStateFactory.setNodeDelegatingFieldAccessorFactory(nodeDelegatingFieldAccessorFactory());
|
||||
return entityStateFactory;
|
||||
@Override
|
||||
public void wireEntityStateFactories() throws Exception {
|
||||
super.wireEntityStateFactories();
|
||||
nodeEntityStateFactory().setEntityManagerFactory(entityManagerFactory);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,12 +36,15 @@ public class CrossStoreNodeEntityStateFactory extends NodeEntityStateFactory {
|
||||
private CrossStoreNodeEntityState.CrossStoreNodeDelegatingFieldAccessorFactory delegatingFieldAccessorFactory;
|
||||
private EntityManagerFactory entityManagerFactory;
|
||||
|
||||
public EntityState<Node> getEntityState(final Object entity) {
|
||||
public EntityState<Node> getEntityState(final Object entity, boolean detachable) {
|
||||
final Class<?> entityType = entity.getClass();
|
||||
final NodeEntity graphEntityAnnotation = entityType.getAnnotation(NodeEntity.class); // todo cache ??
|
||||
final Neo4jPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(entityType);
|
||||
if (graphEntityAnnotation.partial()) {
|
||||
final CrossStoreNodeEntityState<NodeBacked> partialNodeEntityState = new CrossStoreNodeEntityState<NodeBacked>(null, (NodeBacked)entity, (Class<? extends NodeBacked>) entityType, graphDatabaseContext, getPersistenceUnitUtils(), delegatingFieldAccessorFactory, persistentEntity);
|
||||
if (isPartial(entityType)) {
|
||||
final Neo4jPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(entityType);
|
||||
@SuppressWarnings("unchecked") final CrossStoreNodeEntityState<NodeBacked> partialNodeEntityState =
|
||||
new CrossStoreNodeEntityState<NodeBacked>(null, (NodeBacked)entity, (Class<? extends NodeBacked>) entityType,
|
||||
graphDatabaseContext, getPersistenceUnitUtils(), delegatingFieldAccessorFactory,
|
||||
persistentEntity);
|
||||
if (!detachable) return partialNodeEntityState;
|
||||
return new DetachedEntityState<Node>(partialNodeEntityState, graphDatabaseContext) {
|
||||
@Override
|
||||
protected boolean isDetached() {
|
||||
@@ -49,12 +52,15 @@ public class CrossStoreNodeEntityStateFactory extends NodeEntityStateFactory {
|
||||
}
|
||||
};
|
||||
} else {
|
||||
NodeEntityState nodeEntityState = new NodeEntityState(null, entity, entityType, graphDatabaseContext, nodeDelegatingFieldAccessorFactory, (Neo4jPersistentEntity) persistentEntity);
|
||||
// alternative was return new NestedTransactionEntityState<NodeBacked, Node>(nodeEntityState,graphDatabaseContext);
|
||||
return new DetachedEntityState<Node>(nodeEntityState, graphDatabaseContext);
|
||||
return super.getEntityState(entity,detachable);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPartial(Class<?> entityType) {
|
||||
final NodeEntity graphEntityAnnotation = entityType.getAnnotation(NodeEntity.class); // todo cache ??
|
||||
return graphEntityAnnotation.partial();
|
||||
}
|
||||
|
||||
private PersistenceUnitUtil getPersistenceUnitUtils() {
|
||||
if (entityManagerFactory == null|| !entityManagerFactory.isOpen()) return null;
|
||||
return entityManagerFactory.getPersistenceUnitUtil();
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.sun.jersey.api.client.ClientResponse;
|
||||
import com.sun.jersey.api.client.WebResource;
|
||||
import org.codehaus.jackson.map.ObjectMapper;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.neo4j.rest.graphdb.RequestResult;
|
||||
import org.springframework.data.neo4j.aspects.Person;
|
||||
@@ -38,6 +39,7 @@ import static org.springframework.data.neo4j.aspects.Person.persistedPerson;
|
||||
* @author mh
|
||||
* @since 14.04.11
|
||||
*/
|
||||
@Ignore("TODO")
|
||||
public class ServerPluginTest extends RestTestBase {
|
||||
|
||||
private Person person;
|
||||
|
||||
@@ -10,6 +10,6 @@
|
||||
|
||||
<neo4j:config graphDatabaseService="graphDatabaseService"/>
|
||||
|
||||
<neo4j:repositories base-package="org.springframework.data.neo4j.aspects"/>
|
||||
<neo4j:repositories base-package="org.springframework.data.neo4j.rest"/>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
@@ -103,6 +104,7 @@
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -132,7 +134,7 @@
|
||||
<dependency>
|
||||
<groupId>org.neo4j</groupId>
|
||||
<artifactId>server-api</artifactId>
|
||||
<optional>true</optional>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.data.neo4j.annotation;
|
||||
|
||||
import org.springframework.data.annotation.Reference;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -30,5 +32,6 @@ import java.lang.annotation.Target;
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD,ElementType.METHOD})
|
||||
@Reference
|
||||
public @interface EndNode {
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.data.neo4j.annotation;
|
||||
|
||||
import org.springframework.data.annotation.Reference;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -30,5 +32,6 @@ import java.lang.annotation.Target;
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD,ElementType.METHOD})
|
||||
@Reference
|
||||
public @interface StartNode {
|
||||
}
|
||||
|
||||
@@ -28,13 +28,15 @@ 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.convert.DefaultTypeMapper;
|
||||
import org.springframework.data.convert.TypeMapper;
|
||||
import org.springframework.data.neo4j.core.GraphDatabase;
|
||||
import org.springframework.data.neo4j.core.TypeRepresentationStrategy;
|
||||
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.Neo4jNodeConverterImpl;
|
||||
import org.springframework.data.neo4j.mapping.*;
|
||||
import org.springframework.data.neo4j.repository.DirectGraphRepositoryFactory;
|
||||
import org.springframework.data.neo4j.support.DelegatingGraphDatabase;
|
||||
import org.springframework.data.neo4j.support.EntityInstantiator;
|
||||
@@ -53,6 +55,8 @@ import org.springframework.transaction.jta.UserTransactionAdapter;
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.validation.Validator;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
/**
|
||||
* Abstract base class for code based configuration of Spring managed Neo4j infrastructure.
|
||||
* <p>Subclasses are required to provide an implementation of graphDbService ....
|
||||
@@ -78,20 +82,15 @@ public abstract class Neo4jConfiguration {
|
||||
|
||||
@Bean
|
||||
public GraphDatabaseContext graphDatabaseContext() throws Exception {
|
||||
EntityInstantiator<Relationship> relationshipEntityInstantiator = graphRelationshipInstantiator();
|
||||
EntityInstantiator<Node> graphEntityInstantiator = graphEntityInstantiator();
|
||||
|
||||
TypeRepresentationStrategyFactory typeRepresentationStrategyFactory =
|
||||
new TypeRepresentationStrategyFactory(graphDatabaseService, graphEntityInstantiator, relationshipEntityInstantiator);
|
||||
|
||||
GraphDatabaseContext gdc = new GraphDatabaseContext();
|
||||
gdc.setGraphDatabaseService(getGraphDatabaseService());
|
||||
gdc.setConversionService(conversionService());
|
||||
gdc.setMappingContext(mappingContext());
|
||||
gdc.setConverter(neo4jConverter());
|
||||
gdc.setNodeEntityConverter(nodeEntityConverter());
|
||||
gdc.setEntityStateHandler(entityStateHandler());
|
||||
gdc.setNodeTypeRepresentationStrategy(typeRepresentationStrategyFactory.getNodeTypeRepresentationStrategy());
|
||||
gdc.setRelationshipTypeRepresentationStrategy(typeRepresentationStrategyFactory.getRelationshipTypeRepresentationStrategy());
|
||||
gdc.setNodeTypeRepresentationStrategy(nodeTypeRepresentationStrategy());
|
||||
gdc.setRelationshipTypeRepresentationStrategy(relationshipTypeRepresentationStrategy());
|
||||
if (validator!=null) {
|
||||
gdc.setValidator(validator);
|
||||
}
|
||||
@@ -99,13 +98,45 @@ public abstract class Neo4jConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public EntityStateHandler entityStateHandler() {
|
||||
return new EntityStateHandler(mappingContext(),graphDatabaseService);
|
||||
public TypeRepresentationStrategy<Relationship> relationshipTypeRepresentationStrategy() throws Exception {
|
||||
return typeRepresentationStrategyFactory().getRelationshipTypeRepresentationStrategy();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Neo4jNodeConverterImpl neo4jConverter() throws Exception {
|
||||
return new Neo4jNodeConverterImpl();
|
||||
public TypeRepresentationStrategy<Node> nodeTypeRepresentationStrategy() throws Exception {
|
||||
return typeRepresentationStrategyFactory().getNodeTypeRepresentationStrategy();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TypeRepresentationStrategyFactory typeRepresentationStrategyFactory() throws Exception {
|
||||
return new TypeRepresentationStrategyFactory(graphDatabaseService, graphEntityInstantiator(), graphRelationshipInstantiator());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public EntityStateHandler entityStateHandler() {
|
||||
return new EntityStateHandler(mappingContext(),graphDatabaseService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Neo4jEntityConverter<Object,Node> nodeEntityConverter() throws Exception {
|
||||
return new Neo4jEntityConverterImpl<Object, Node>(mappingContext(), conversionService(), graphEntityInstantiator() ,entityStateHandler(),typeMapper(), nodeStateTransmitter(), entityFetchHandler());
|
||||
}
|
||||
|
||||
private TypeMapper<Node> typeMapper() throws Exception {
|
||||
return new DefaultTypeMapper<Node>(new TRSTypeAliasAccessor<Node>(nodeTypeRepresentationStrategy()),asList(new ClassValueTypeInformationMapper()));
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public Neo4jEntityFetchHandler entityFetchHandler() throws Exception {
|
||||
final SourceStateTransmitter<Node> nodeSourceStateTransmitter = nodeStateTransmitter();
|
||||
final SourceStateTransmitter<Relationship> relationshipSourceStateTransmitter = new SourceStateTransmitter<Relationship>(relationshipEntityStateFactory());
|
||||
return new Neo4jEntityFetchHandler(entityStateHandler(), conversionService(), relationshipSourceStateTransmitter, nodeSourceStateTransmitter);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SourceStateTransmitter<Node> nodeStateTransmitter() throws Exception {
|
||||
return new SourceStateTransmitter<Node>(nodeEntityStateFactory());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -128,31 +159,34 @@ public abstract class Neo4jConfiguration {
|
||||
return new DirectGraphRepositoryFactory(graphDatabaseContext());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RelationshipEntityStateFactory relationshipEntityStateFactory() throws Exception {
|
||||
RelationshipEntityStateFactory entityStateFactory = new RelationshipEntityStateFactory();
|
||||
entityStateFactory.setGraphDatabaseContext(graphDatabaseContext());
|
||||
entityStateFactory.setMappingContext(mappingContext());
|
||||
entityStateFactory.setRelationshipDelegatingFieldAccessorFactory(relationshipDelegatingFieldAccessorFactory());
|
||||
return entityStateFactory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Neo4jMappingContext mappingContext() {
|
||||
return new Neo4jMappingContext();
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void setupContext() throws Exception {
|
||||
neo4jConverter().setNodeEntityStateFactory(nodeEntityStateFactory());
|
||||
@Bean
|
||||
public RelationshipEntityStateFactory relationshipEntityStateFactory() throws Exception {
|
||||
return new RelationshipEntityStateFactory();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public NodeEntityStateFactory nodeEntityStateFactory() throws Exception {
|
||||
NodeEntityStateFactory entityStateFactory = new NodeEntityStateFactory();
|
||||
entityStateFactory.setGraphDatabaseContext(graphDatabaseContext());
|
||||
entityStateFactory.setMappingContext(mappingContext());
|
||||
entityStateFactory.setNodeDelegatingFieldAccessorFactory(nodeDelegatingFieldAccessorFactory());
|
||||
return entityStateFactory;
|
||||
return new NodeEntityStateFactory();
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void wireEntityStateFactories() throws Exception {
|
||||
final NodeEntityStateFactory nodeEntityStateFactory = nodeEntityStateFactory();
|
||||
nodeEntityStateFactory.setGraphDatabaseContext(graphDatabaseContext());
|
||||
nodeEntityStateFactory.setMappingContext(mappingContext());
|
||||
nodeEntityStateFactory.setNodeDelegatingFieldAccessorFactory(nodeDelegatingFieldAccessorFactory());
|
||||
|
||||
final RelationshipEntityStateFactory relationshipEntityStateFactory = relationshipEntityStateFactory();
|
||||
relationshipEntityStateFactory.setGraphDatabaseContext(graphDatabaseContext());
|
||||
relationshipEntityStateFactory.setMappingContext(mappingContext());
|
||||
relationshipEntityStateFactory.setRelationshipDelegatingFieldAccessorFactory(relationshipDelegatingFieldAccessorFactory());
|
||||
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -31,16 +31,19 @@ public class ConvertingNodePropertyFieldAccessorFactory implements FieldAccessor
|
||||
|
||||
|
||||
private final GraphDatabaseContext graphDatabaseContext;
|
||||
private ConversionService conversionService;
|
||||
|
||||
public ConvertingNodePropertyFieldAccessorFactory(GraphDatabaseContext graphDatabaseContext) {
|
||||
this.graphDatabaseContext = graphDatabaseContext;
|
||||
this.conversionService = graphDatabaseContext.getConversionService();
|
||||
}
|
||||
|
||||
|
||||
private ConversionService getConversionService() {
|
||||
return graphDatabaseContext.getConversionService();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean accept(final Neo4jPersistentProperty property) {
|
||||
final ConversionService conversionService = getConversionService();
|
||||
return property.isSerializableField(conversionService) && property.isDeserializableField(conversionService);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ public class RelationshipDelegatingFieldAccessorFactory extends DelegatingFieldA
|
||||
protected Collection<? extends FieldAccessorFactory> createAccessorFactories() {
|
||||
return Arrays.<FieldAccessorFactory>asList(
|
||||
new TransientFieldAccessorFactory(),
|
||||
new IdFieldAccessorFactory(graphDatabaseContext),
|
||||
new RelationshipNodeFieldAccessorFactory(graphDatabaseContext),
|
||||
new PropertyFieldAccessorFactory(graphDatabaseContext),
|
||||
new ConvertingNodePropertyFieldAccessorFactory(graphDatabaseContext),
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 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.mapping;
|
||||
|
||||
import org.springframework.data.convert.TypeInformationMapper;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 09.10.11
|
||||
*/
|
||||
public class ClassValueTypeInformationMapper implements TypeInformationMapper {
|
||||
@Override
|
||||
public TypeInformation<?> resolveTypeFrom(Object alias) {
|
||||
if (!(alias instanceof Class)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ClassTypeInformation.from((Class<?>) alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object createAliasFor(TypeInformation<?> type) {
|
||||
return type.getType();
|
||||
}
|
||||
}
|
||||
@@ -221,4 +221,15 @@ class Neo4jPersistentPropertyImpl extends AbstractPersistentProperty<Neo4jPersis
|
||||
public Neo4jPersistentEntity<?> getOwner() {
|
||||
return (Neo4jPersistentEntity<?>)super.getOwner();
|
||||
}
|
||||
@Override
|
||||
public boolean isEntity() {
|
||||
return super.isEntity() && (isRelationshipEntity() || isNodeEntity());
|
||||
}
|
||||
|
||||
private boolean isRelationshipEntity() {
|
||||
return getType().isAnnotationPresent(RelationshipEntity.class);
|
||||
}
|
||||
private boolean isNodeEntity() {
|
||||
return getType().isAnnotationPresent(NodeEntity.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.mapping;
|
||||
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.PropertyContainer;
|
||||
import org.springframework.data.convert.EntityConverter;
|
||||
import org.springframework.data.convert.EntityReader;
|
||||
import org.springframework.data.convert.EntityWriter;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 27.09.11
|
||||
*/
|
||||
public interface Neo4jEntityConverter<T, S extends PropertyContainer> extends EntityConverter<Neo4jPersistentEntity<?>, Neo4jPersistentProperty, T, S>, EntityWriter<T,S>,
|
||||
EntityReader<T, S> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* 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.mapping;
|
||||
|
||||
import org.neo4j.graphdb.PropertyContainer;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.convert.TypeMapper;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.AssociationHandler;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.BeanWrapper;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.neo4j.support.EntityInstantiator;
|
||||
import org.springframework.data.neo4j.support.EntityStateHandler;
|
||||
import org.springframework.data.neo4j.support.ManagedEntity;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 07.10.11
|
||||
*/
|
||||
public class Neo4jEntityConverterImpl<T,S extends PropertyContainer> implements Neo4jEntityConverter<T,S> {
|
||||
private final Neo4jMappingContext mappingContext;
|
||||
private final ConversionService conversionService;
|
||||
private final EntityInstantiator<S> entityInstantiator;
|
||||
private final EntityStateHandler entityStateHandler;
|
||||
private final TypeMapper<S> typeMapper;
|
||||
private final SourceStateTransmitter<S> sourceStateTransmitter;
|
||||
private final Neo4jEntityFetchHandler entityFetchHandler;
|
||||
public Neo4jEntityConverterImpl(Neo4jMappingContext mappingContext, ConversionService conversionService, EntityInstantiator<S> entityInstantiator,
|
||||
EntityStateHandler entityStateHandler, TypeMapper<S> typeMapper,
|
||||
SourceStateTransmitter<S> sourceStateTransmitter, Neo4jEntityFetchHandler entityFetchHandler) {
|
||||
this.mappingContext = mappingContext;
|
||||
this.conversionService = conversionService;
|
||||
this.entityInstantiator = entityInstantiator;
|
||||
this.entityStateHandler = entityStateHandler;
|
||||
this.typeMapper = typeMapper;
|
||||
this.sourceStateTransmitter = sourceStateTransmitter;
|
||||
this.entityFetchHandler = entityFetchHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingContext<? extends Neo4jPersistentEntity<?>, Neo4jPersistentProperty> getMappingContext() {
|
||||
return mappingContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConversionService getConversionService() {
|
||||
return conversionService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R extends T> R read(Class<R> requestedType, S source) {
|
||||
// 1) source -> type alias
|
||||
// 2) type alias -> type
|
||||
// 3) check for subtype matching / enforcement
|
||||
final TypeInformation<R> requestedTypeInformation = ClassTypeInformation.from(requestedType);
|
||||
final TypeInformation<? extends R> targetType = typeMapper.readType(source, requestedTypeInformation);
|
||||
|
||||
// retrieve meta-information about the type
|
||||
@SuppressWarnings("unchecked") final Neo4jPersistentEntityImpl<R> persistentEntity = (Neo4jPersistentEntityImpl<R>) mappingContext.getPersistentEntity(targetType);
|
||||
|
||||
// 4) create object instance
|
||||
final R createdEntity = entityInstantiator.createEntityFromState(source, targetType.getType());
|
||||
|
||||
// 5) connect state
|
||||
entityStateHandler.setPersistentState(createdEntity,source);
|
||||
|
||||
if (!persistentEntity.isManaged()) {
|
||||
// 5a) depending on mode -> copy data
|
||||
final BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper = BeanWrapper.create(createdEntity, conversionService);
|
||||
sourceStateTransmitter.copyPropertiesFrom(wrapper, source, persistentEntity);
|
||||
// 6) handle cascading fetches
|
||||
cascadeFetch(persistentEntity, wrapper);
|
||||
}
|
||||
return createdEntity;
|
||||
}
|
||||
|
||||
private <R extends T> void cascadeFetch(Neo4jPersistentEntityImpl<R> persistentEntity, final BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper) {
|
||||
persistentEntity.doWithAssociations(new AssociationHandler<Neo4jPersistentProperty>() {
|
||||
@Override
|
||||
public void doWithAssociation(Association<Neo4jPersistentProperty> association) {
|
||||
final Neo4jPersistentProperty property = association.getInverse();
|
||||
if (property.isRelationship()) {
|
||||
final Object value = getProperty(wrapper, property);
|
||||
@SuppressWarnings("unchecked") final Neo4jPersistentEntityImpl<Object> persistentEntity =
|
||||
(Neo4jPersistentEntityImpl<Object>) mappingContext.getPersistentEntity(property.getTypeInformation().getActualType());
|
||||
final Object fetchedValue = entityFetchHandler.fetch(value, persistentEntity, property);
|
||||
// replace fetched one-time iterables and similiar managed values
|
||||
sourceStateTransmitter.setProperty(wrapper, property, fetchedValue);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private <R> Object getProperty(BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper, Neo4jPersistentProperty property) {
|
||||
try {
|
||||
return wrapper.getProperty(property);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new MappingException("Error retrieving property " + property.getName() + " from " + wrapper.getBean(), e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new MappingException("Error retrieving property " + property.getName() + " from " + wrapper.getBean(), e.getTargetException());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(T source, S sink) {
|
||||
final Class<?> sourceType = source.getClass();
|
||||
@SuppressWarnings("unchecked") final Neo4jPersistentEntityImpl<T> persistentEntity = (Neo4jPersistentEntityImpl<T>) mappingContext.getPersistentEntity(sourceType);
|
||||
if (persistentEntity.isManaged()) { // todo check if typerepreentationstragegy is called ??
|
||||
((ManagedEntity)source).persist();
|
||||
return;
|
||||
}
|
||||
|
||||
final BeanWrapper<Neo4jPersistentEntity<T>, T> wrapper = BeanWrapper.create(source, conversionService);
|
||||
if (sink == null) {
|
||||
sink = entityStateHandler.useOrCreateState(source,sink); // todo handling of changed state
|
||||
entityStateHandler.setPersistentState(source, sink);
|
||||
typeMapper.writeType(sourceType, sink);
|
||||
}
|
||||
sourceStateTransmitter.copyPropertiesTo(wrapper, sink, persistentEntity);
|
||||
}
|
||||
/*
|
||||
private Node useGetOrCreateNode(S node, Neo4jPersistentEntity<?> persistentEntity, BeanWrapper<Neo4jPersistentEntity<Object>, Object> wrapper) {
|
||||
if (node != null) return node;
|
||||
final Neo4jPersistentProperty idProperty = persistentEntity.getIdProperty();
|
||||
final Long id = getProperty(wrapper, idProperty, Long.class, true);
|
||||
if (id == null) {
|
||||
final Node newNode = getGraphDatabaseContext().createNode();
|
||||
setProperty(wrapper, idProperty, newNode.getId());
|
||||
return newNode;
|
||||
}
|
||||
try {
|
||||
return getGraphDatabaseContext().getNodeById(id);
|
||||
} catch (NotFoundException nfe) {
|
||||
throw new MappingException("Could not find node with id " + id);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* 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.mapping;
|
||||
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.PropertyContainer;
|
||||
import org.neo4j.graphdb.Relationship;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.mapping.model.BeanWrapper;
|
||||
import org.springframework.data.neo4j.annotation.Fetch;
|
||||
import org.springframework.data.neo4j.support.EntityStateHandler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 08.10.11
|
||||
*/
|
||||
public class Neo4jEntityFetchHandler {
|
||||
private final SourceStateTransmitter<Node> nodeStateTransmitter;
|
||||
private final SourceStateTransmitter<Relationship> relationshipStateTransmitter;
|
||||
private final EntityStateHandler entityStateHandler;
|
||||
private final ConversionService conversionService;
|
||||
|
||||
public Neo4jEntityFetchHandler(EntityStateHandler entityStateHandler, ConversionService conversionService, SourceStateTransmitter<Relationship> relationshipStateTransmitter, SourceStateTransmitter<Node> nodeStateTransmitter) {
|
||||
this.conversionService = conversionService;
|
||||
this.entityStateHandler = entityStateHandler;
|
||||
this.relationshipStateTransmitter = relationshipStateTransmitter;
|
||||
this.nodeStateTransmitter = nodeStateTransmitter;
|
||||
}
|
||||
|
||||
|
||||
// todo actually cascade !!
|
||||
public Object fetch(final Object value, Neo4jPersistentEntity<Object> persistentEntity, Neo4jPersistentProperty property) {
|
||||
if (value == null || !property.isAnnotationPresent(Fetch.class)) return value;
|
||||
if (property.getTypeInformation().isCollectionLike()) {
|
||||
List<Object> replacement = new ArrayList<Object>();
|
||||
for (Object inner : ((Iterable) value)) {
|
||||
final BeanWrapper<Neo4jPersistentEntity<Object>, Object> innerWrapper = BeanWrapper.create(inner, conversionService);
|
||||
final PropertyContainer state = entityStateHandler.getPersistentState(inner);
|
||||
fetchValue(innerWrapper, state, persistentEntity);
|
||||
replacement.add(inner);
|
||||
//sourceStateTransmitter.copyPropertiesFrom(innerWrapper, entityStateHandler.<S>getPersistentState(inner), persistentEntity);
|
||||
}
|
||||
return replacement;
|
||||
} else {
|
||||
final BeanWrapper<Neo4jPersistentEntity<Object>, Object> innerWrapper = BeanWrapper.create(value, conversionService);
|
||||
final PropertyContainer state = entityStateHandler.getPersistentState(value);
|
||||
fetchValue(innerWrapper, state, persistentEntity);
|
||||
// sourceStateTransmitter.copyPropertiesFrom(innerWrapper, entityStateHandler.<S>getPersistentState(value), persistentEntity);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
public void fetchValue(final BeanWrapper<Neo4jPersistentEntity<Object>, Object> wrapper, PropertyContainer source, Neo4jPersistentEntity<Object> persistentEntity) {
|
||||
if (persistentEntity.isNodeEntity()) {
|
||||
nodeStateTransmitter.copyPropertiesFrom(wrapper, (Node) source,persistentEntity);
|
||||
}
|
||||
if (persistentEntity.isRelationshipEntity()) {
|
||||
relationshipStateTransmitter.copyPropertiesFrom(wrapper, (Relationship) source, persistentEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,12 @@ package org.springframework.data.neo4j.mapping;
|
||||
import org.neo4j.graphdb.PropertyContainer;
|
||||
import org.springframework.data.mapping.context.AbstractMappingContext;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.neo4j.annotation.NodeEntity;
|
||||
import org.springframework.data.neo4j.annotation.RelationshipEntity;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import scala.annotation.target.field;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
@@ -34,7 +38,14 @@ import java.lang.reflect.Field;
|
||||
public class Neo4jMappingContext extends AbstractMappingContext<Neo4jPersistentEntityImpl<?>, Neo4jPersistentProperty> {
|
||||
|
||||
protected <T> Neo4jPersistentEntityImpl<?> createPersistentEntity(TypeInformation<T> typeInformation) {
|
||||
return new Neo4jPersistentEntityImpl<T>(typeInformation);
|
||||
final Class<T> type = typeInformation.getType();
|
||||
if (type.isAnnotationPresent(NodeEntity.class)) {
|
||||
return new Neo4jPersistentEntityImpl<T>(typeInformation);
|
||||
}
|
||||
if (type.isAnnotationPresent(RelationshipEntity.class)) {
|
||||
return new Neo4jPersistentEntityImpl<T>(typeInformation);
|
||||
}
|
||||
throw new MappingException("Type "+type+" is neither a @NodeEntity nor a @RelationshipEntity");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -55,5 +66,4 @@ public class Neo4jMappingContext extends AbstractMappingContext<Neo4jPersistentE
|
||||
final Neo4jPersistentEntityImpl<?> persistentEntity = getPersistentEntity(entity.getClass());
|
||||
persistentEntity.setPersistentState(entity, pc);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import org.springframework.data.convert.EntityWriter;
|
||||
* @author mh
|
||||
* @since 27.09.11
|
||||
*/
|
||||
public interface Neo4jNodeConverter extends EntityConverter<Neo4jPersistentEntity<?>, Neo4jPersistentProperty, Object, Node>, EntityWriter<Object,Node>,
|
||||
EntityReader<Object, Node> {
|
||||
public interface Neo4jNodeConverter<T> extends Neo4jEntityConverter<T,Node> {
|
||||
|
||||
}
|
||||
|
||||
@@ -1,186 +0,0 @@
|
||||
/**
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.neo4j.mapping;
|
||||
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.NotFoundException;
|
||||
import org.neo4j.graphdb.Transaction;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.AssociationHandler;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.BeanWrapper;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.neo4j.core.EntityState;
|
||||
import org.springframework.data.neo4j.support.DoReturn;
|
||||
import org.springframework.data.neo4j.support.GraphDatabaseContext;
|
||||
import org.springframework.data.neo4j.support.node.NodeEntityStateFactory;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 27.09.11
|
||||
*/
|
||||
public class Neo4jNodeConverterImpl implements Neo4jNodeConverter {
|
||||
private NodeEntityStateFactory nodeEntityStateFactory;
|
||||
|
||||
public Neo4jNodeConverterImpl() {
|
||||
}
|
||||
|
||||
public void setNodeEntityStateFactory(NodeEntityStateFactory nodeEntityStateFactory) {
|
||||
this.nodeEntityStateFactory = nodeEntityStateFactory;
|
||||
nodeEntityStateFactory.setCreateDetachableEntities(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingContext<? extends Neo4jPersistentEntity<?>, Neo4jPersistentProperty> getMappingContext() {
|
||||
return nodeEntityStateFactory.getMappingContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConversionService getConversionService() {
|
||||
return getGraphDatabaseContext().getConversionService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R read(Class<R> targetType, Node node) {
|
||||
Assert.notNull(targetType);
|
||||
Assert.notNull(node);
|
||||
@SuppressWarnings("unchecked") final Neo4jPersistentEntity<R> persistentEntity = (Neo4jPersistentEntity<R>) getMappingContext().getPersistentEntity(targetType);
|
||||
final GraphDatabaseContext graphDatabaseContext = nodeEntityStateFactory.getGraphDatabaseContext();
|
||||
final R entity = graphDatabaseContext.createEntityFromState(node, targetType);
|
||||
final BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper = BeanWrapper.create(entity, getConversionService());
|
||||
final Transaction tx = getGraphDatabaseContext().beginTx();
|
||||
try {
|
||||
//final Node targetNode = useGetOrCreateNode(node, persistentEntity, wrapper);
|
||||
final EntityState<Node> nodeState = nodeEntityStateFactory.getEntityState(entity);
|
||||
nodeState.setPersistentState(node);
|
||||
nodeState.persist();
|
||||
persistentEntity.doWithProperties(new PropertyHandler<Neo4jPersistentProperty>() {
|
||||
@Override
|
||||
public void doWithPersistentProperty(Neo4jPersistentProperty property) {
|
||||
getEntityStateValue(property, nodeState, wrapper);
|
||||
}
|
||||
});
|
||||
persistentEntity.doWithAssociations(new AssociationHandler<Neo4jPersistentProperty>() {
|
||||
@Override
|
||||
public void doWithAssociation(Association<Neo4jPersistentProperty> association) {
|
||||
final Neo4jPersistentProperty property = association.getInverse();
|
||||
getEntityStateValue(property, nodeState, wrapper);
|
||||
}
|
||||
});
|
||||
tx.success();
|
||||
return entity;
|
||||
} finally {
|
||||
tx.finish();
|
||||
}
|
||||
}
|
||||
|
||||
private <R> void getEntityStateValue(Neo4jPersistentProperty property, EntityState<Node> nodeState, BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper) {
|
||||
final Object value = nodeState.getValue(property.getField());
|
||||
setProperty(wrapper, property, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(Object source, final Node node) {
|
||||
Assert.notNull(source);
|
||||
final Neo4jPersistentEntity<?> persistentEntity = getMappingContext().getPersistentEntity(source.getClass());
|
||||
final BeanWrapper<Neo4jPersistentEntity<Object>, Object> wrapper = BeanWrapper.create(source, getConversionService());
|
||||
final Transaction tx = getGraphDatabaseContext().beginTx();
|
||||
try {
|
||||
//final Node targetNode = useGetOrCreateNode(node, persistentEntity, wrapper);
|
||||
final EntityState<Node> nodeState = nodeEntityStateFactory.getEntityState(source);
|
||||
nodeState.setPersistentState(node);
|
||||
nodeState.persist();
|
||||
persistentEntity.doWithProperties(new PropertyHandler<Neo4jPersistentProperty>() {
|
||||
@Override
|
||||
public void doWithPersistentProperty(Neo4jPersistentProperty property) {
|
||||
setEntityStateValue(property, nodeState, wrapper);
|
||||
}
|
||||
});
|
||||
persistentEntity.doWithAssociations(new AssociationHandler<Neo4jPersistentProperty>() {
|
||||
@Override
|
||||
public void doWithAssociation(Association<Neo4jPersistentProperty> association) {
|
||||
final Neo4jPersistentProperty property = association.getInverse();
|
||||
setEntityStateValue(property, nodeState, wrapper);
|
||||
}
|
||||
});
|
||||
tx.success();
|
||||
} finally {
|
||||
tx.finish();
|
||||
}
|
||||
}
|
||||
|
||||
private void setEntityStateValue(Neo4jPersistentProperty property, EntityState<Node> nodeState, BeanWrapper<Neo4jPersistentEntity<Object>, Object> wrapper) {
|
||||
if (!nodeState.isWritable(property.getField())) return;
|
||||
final Object value = getProperty(wrapper, property);
|
||||
nodeState.setValue(property, value);
|
||||
}
|
||||
|
||||
private Node useGetOrCreateNode(Node node, Neo4jPersistentEntity<?> persistentEntity, BeanWrapper<Neo4jPersistentEntity<Object>, Object> wrapper) {
|
||||
if (node != null) return node;
|
||||
final Neo4jPersistentProperty idProperty = persistentEntity.getIdProperty();
|
||||
final Long id = getProperty(wrapper, idProperty, Long.class, true);
|
||||
if (id == null) {
|
||||
final Node newNode = getGraphDatabaseContext().createNode();
|
||||
setProperty(wrapper, idProperty, newNode.getId());
|
||||
return newNode;
|
||||
}
|
||||
try {
|
||||
return getGraphDatabaseContext().getNodeById(id);
|
||||
} catch (NotFoundException nfe) {
|
||||
throw new MappingException("Could not find node with id " + id);
|
||||
}
|
||||
}
|
||||
|
||||
private GraphDatabaseContext getGraphDatabaseContext() {
|
||||
return nodeEntityStateFactory.getGraphDatabaseContext();
|
||||
}
|
||||
|
||||
private <T> T getProperty(BeanWrapper<Neo4jPersistentEntity<Object>, Object> wrapper, Neo4jPersistentProperty property, Class<T> type, boolean fieldAccessOnly) {
|
||||
try {
|
||||
return wrapper.getProperty(property, type, fieldAccessOnly);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new MappingException("Error retrieving property " + property.getName() + " from " + wrapper.getBean(), e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new MappingException("Error retrieving property " + property.getName() + " from " + wrapper.getBean(), e.getTargetException());
|
||||
}
|
||||
}
|
||||
|
||||
private Object getProperty(BeanWrapper<Neo4jPersistentEntity<Object>, Object> wrapper, Neo4jPersistentProperty property) {
|
||||
try {
|
||||
return wrapper.getProperty(property);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new MappingException("Error retrieving property " + property.getName() + " from " + wrapper.getBean(), e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new MappingException("Error retrieving property " + property.getName() + " from " + wrapper.getBean(), e.getTargetException());
|
||||
}
|
||||
}
|
||||
|
||||
private <R> void setProperty(BeanWrapper<Neo4jPersistentEntity<R>, ?> wrapper, Neo4jPersistentProperty property, Object value) {
|
||||
try {
|
||||
wrapper.setProperty(property, DoReturn.unwrap(value));
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new MappingException("Setting property " + property.getName() + " to " + value + " on " + wrapper.getBean(), e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new MappingException("Setting property " + property.getName() + " to " + value + " on " + wrapper.getBean(), e.getTargetException());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,4 +36,6 @@ public interface Neo4jPersistentEntity<T> extends PersistentEntity<T, Neo4jPersi
|
||||
void setPersistentState(Object entity, PropertyContainer pc);
|
||||
|
||||
Object getPersistentId(Object entity);
|
||||
|
||||
RelationshipProperties getRelationshipProperties();
|
||||
}
|
||||
|
||||
@@ -19,10 +19,11 @@ package org.springframework.data.neo4j.mapping;
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.PropertyContainer;
|
||||
import org.neo4j.graphdb.Relationship;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.model.BasicPersistentEntity;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.neo4j.annotation.NodeEntity;
|
||||
import org.springframework.data.neo4j.annotation.RelationshipEntity;
|
||||
import org.springframework.data.neo4j.annotation.*;
|
||||
import org.springframework.data.neo4j.support.ManagedEntity;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
@@ -34,9 +35,13 @@ import java.util.Map;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class Neo4jPersistentEntityImpl<T> extends BasicPersistentEntity<T, Neo4jPersistentProperty> implements Neo4jPersistentEntity<T> {
|
||||
public class Neo4jPersistentEntityImpl<T> extends BasicPersistentEntity<T, Neo4jPersistentProperty> implements Neo4jPersistentEntity<T>, RelationshipProperties {
|
||||
|
||||
private Map<Class<? extends Annotation>,Annotation> annotations=new IdentityHashMap<Class<? extends Annotation>,Annotation>();
|
||||
private final boolean managed;
|
||||
private Neo4jPersistentProperty startNodeProperty;
|
||||
private Neo4jPersistentProperty endNodeProperty;
|
||||
private Neo4jPersistentProperty relationshipType;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Neo4jPersistentEntityImpl} instance.
|
||||
@@ -48,6 +53,7 @@ public class Neo4jPersistentEntityImpl<T> extends BasicPersistentEntity<T, Neo4j
|
||||
for (Annotation annotation : information.getType().getAnnotations()) {
|
||||
annotations.put(annotation.annotationType(),annotation);
|
||||
}
|
||||
managed = ManagedEntity.class.isAssignableFrom(information.getType());
|
||||
}
|
||||
|
||||
public boolean useShortNames() {
|
||||
@@ -103,7 +109,51 @@ public class Neo4jPersistentEntityImpl<T> extends BasicPersistentEntity<T, Neo4j
|
||||
return idProperty.getValue(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RelationshipProperties getRelationshipProperties() {
|
||||
return isRelationshipEntity() ? this : null;
|
||||
}
|
||||
|
||||
public String getEntityName() {
|
||||
return getType().getName();
|
||||
}
|
||||
|
||||
public boolean isManaged() {
|
||||
return managed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPersistentProperty(Neo4jPersistentProperty property) {
|
||||
super.addPersistentProperty(property);
|
||||
if (property.isAnnotationPresent(RelationshipType.class)) {
|
||||
this.relationshipType = property;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAssociation(Association<Neo4jPersistentProperty> neo4jPersistentPropertyAssociation) {
|
||||
super.addAssociation(neo4jPersistentPropertyAssociation);
|
||||
final Neo4jPersistentProperty property = neo4jPersistentPropertyAssociation.getInverse();
|
||||
if (property.isAnnotationPresent(StartNode.class)) {
|
||||
this.startNodeProperty = property;
|
||||
}
|
||||
if (property.isAnnotationPresent(EndNode.class)) {
|
||||
this.endNodeProperty = property;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Neo4jPersistentProperty getStartNodeProperty() {
|
||||
return startNodeProperty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Neo4jPersistentProperty getEndeNodeProperty() {
|
||||
return endNodeProperty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Neo4jPersistentProperty getTypeProperty() {
|
||||
return relationshipType;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.mapping;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 07.10.11
|
||||
*/
|
||||
public interface RelationshipProperties {
|
||||
Neo4jPersistentProperty getStartNodeProperty();
|
||||
Neo4jPersistentProperty getEndeNodeProperty();
|
||||
Neo4jPersistentProperty getTypeProperty();
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/**
|
||||
* 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.mapping;
|
||||
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.NotFoundException;
|
||||
import org.neo4j.graphdb.PropertyContainer;
|
||||
import org.neo4j.graphdb.Transaction;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.AssociationHandler;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
import org.springframework.data.mapping.model.BeanWrapper;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.neo4j.core.EntityState;
|
||||
import org.springframework.data.neo4j.support.DoReturn;
|
||||
import org.springframework.data.neo4j.support.GraphDatabaseContext;
|
||||
import org.springframework.data.neo4j.support.node.EntityStateFactory;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 07.10.11
|
||||
*/
|
||||
public class SourceStateTransmitter<S extends PropertyContainer> {
|
||||
private final EntityStateFactory<S> entityStateFactory;
|
||||
|
||||
public SourceStateTransmitter(EntityStateFactory<S> entityStateFactory) {
|
||||
this.entityStateFactory = entityStateFactory;
|
||||
}
|
||||
|
||||
public <R> R copyPropertiesFrom(final BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper, S source, Neo4jPersistentEntity<R> persistentEntity) {
|
||||
final R entity = wrapper.getBean();
|
||||
final Transaction tx = getGraphDatabaseContext().beginTx();
|
||||
try {
|
||||
final EntityState<S> entityState = entityStateFactory.getEntityState(entity, false);
|
||||
entityState.setPersistentState(source);
|
||||
entityState.persist();
|
||||
persistentEntity.doWithProperties(new PropertyHandler<Neo4jPersistentProperty>() {
|
||||
@Override
|
||||
public void doWithPersistentProperty(Neo4jPersistentProperty property) {
|
||||
copyEntityStatePropertyValue(property, entityState, wrapper);
|
||||
}
|
||||
});
|
||||
persistentEntity.doWithAssociations(new AssociationHandler<Neo4jPersistentProperty>() {
|
||||
@Override
|
||||
public void doWithAssociation(Association<Neo4jPersistentProperty> association) {
|
||||
final Neo4jPersistentProperty property = association.getInverse();
|
||||
copyEntityStatePropertyValue(property, entityState, wrapper);
|
||||
}
|
||||
});
|
||||
tx.success();
|
||||
return entity;
|
||||
} finally {
|
||||
tx.finish();
|
||||
}
|
||||
}
|
||||
|
||||
private <R> void setEntityStateValue(Neo4jPersistentProperty property, EntityState<S> entityState, BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper) {
|
||||
if (!entityState.isWritable(property.getField())) return;
|
||||
final Object value = getProperty(wrapper, property);
|
||||
entityState.setValue(property, value);
|
||||
}
|
||||
|
||||
private GraphDatabaseContext getGraphDatabaseContext() {
|
||||
return entityStateFactory.getGraphDatabaseContext();
|
||||
}
|
||||
|
||||
private <T> T getProperty(BeanWrapper<Neo4jPersistentEntity<Object>, Object> wrapper, Neo4jPersistentProperty property, Class<T> type, boolean fieldAccessOnly) {
|
||||
try {
|
||||
return wrapper.getProperty(property, type, fieldAccessOnly);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new MappingException("Error retrieving property " + property.getName() + " from " + wrapper.getBean(), e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new MappingException("Error retrieving property " + property.getName() + " from " + wrapper.getBean(), e.getTargetException());
|
||||
}
|
||||
}
|
||||
|
||||
private <R> Object getProperty(BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper, Neo4jPersistentProperty property) {
|
||||
try {
|
||||
return wrapper.getProperty(property);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new MappingException("Error retrieving property " + property.getName() + " from " + wrapper.getBean(), e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new MappingException("Error retrieving property " + property.getName() + " from " + wrapper.getBean(), e.getTargetException());
|
||||
}
|
||||
}
|
||||
|
||||
public <R> void setProperty(BeanWrapper<Neo4jPersistentEntity<R>, ?> wrapper, Neo4jPersistentProperty property, Object value) {
|
||||
try {
|
||||
wrapper.setProperty(property,value);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new MappingException("Setting property " + property.getName() + " to " + value + " on " + wrapper.getBean(), e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new MappingException("Setting property " + property.getName() + " to " + value + " on " + wrapper.getBean(), e.getTargetException());
|
||||
}
|
||||
}
|
||||
|
||||
private <R> Object copyEntityStatePropertyValue(Neo4jPersistentProperty property, EntityState<S> nodeState, BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper) {
|
||||
final Object value = DoReturn.unwrap(nodeState.getValue(property.getField()));
|
||||
setProperty(wrapper, property, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public <R> void copyPropertiesTo(final BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper, S target, Neo4jPersistentEntity<R> persistentEntity) {
|
||||
final Transaction tx = getGraphDatabaseContext().beginTx();
|
||||
try {
|
||||
//final Node targetNode = useGetOrCreateNode(node, persistentEntity, wrapper);
|
||||
final EntityState<S> entityState = entityStateFactory.getEntityState(wrapper.getBean(), false);
|
||||
entityState.setPersistentState(target);
|
||||
entityState.persist();
|
||||
persistentEntity.doWithProperties(new PropertyHandler<Neo4jPersistentProperty>() {
|
||||
@Override
|
||||
public void doWithPersistentProperty(Neo4jPersistentProperty property) {
|
||||
setEntityStateValue(property, entityState, wrapper);
|
||||
}
|
||||
});
|
||||
persistentEntity.doWithAssociations(new AssociationHandler<Neo4jPersistentProperty>() {
|
||||
@Override
|
||||
public void doWithAssociation(Association<Neo4jPersistentProperty> association) {
|
||||
final Neo4jPersistentProperty property = association.getInverse();
|
||||
setEntityStateValue(property, entityState, wrapper);
|
||||
}
|
||||
});
|
||||
tx.success();
|
||||
} finally {
|
||||
tx.finish();
|
||||
}
|
||||
}
|
||||
|
||||
private Node useGetOrCreateNode(Node node, Neo4jPersistentEntity<?> persistentEntity, BeanWrapper<Neo4jPersistentEntity<Object>, Object> wrapper) {
|
||||
if (node != null) return node;
|
||||
final Neo4jPersistentProperty idProperty = persistentEntity.getIdProperty();
|
||||
final Long id = getProperty(wrapper, idProperty, Long.class, true);
|
||||
if (id == null) {
|
||||
final Node newNode = getGraphDatabaseContext().createNode();
|
||||
setProperty(wrapper, idProperty, newNode.getId());
|
||||
return newNode;
|
||||
}
|
||||
try {
|
||||
return getGraphDatabaseContext().getNodeById(id);
|
||||
} catch (NotFoundException nfe) {
|
||||
throw new MappingException("Could not find node with id " + id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* 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.mapping;
|
||||
|
||||
import org.neo4j.graphdb.PropertyContainer;
|
||||
import org.springframework.data.convert.TypeAliasAccessor;
|
||||
import org.springframework.data.convert.TypeInformationMapper;
|
||||
import org.springframework.data.neo4j.core.TypeRepresentationStrategy;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 08.10.11
|
||||
*/
|
||||
public class TRSTypeAliasAccessor<S extends PropertyContainer> implements TypeAliasAccessor<S> {
|
||||
private final TypeRepresentationStrategy<S> typeRepresentationStrategy;
|
||||
|
||||
public TRSTypeAliasAccessor(TypeRepresentationStrategy<S> typeRepresentationStrategy) {
|
||||
this.typeRepresentationStrategy = typeRepresentationStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readAliasFrom(S source) {
|
||||
try {
|
||||
return typeRepresentationStrategy.getJavaType(source);
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTypeTo(S sink, Object alias) {
|
||||
typeRepresentationStrategy.postEntityCreation(sink, (Class) alias);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -42,4 +42,9 @@ public class ProvidedClassPathXmlApplicationContext extends ClassPathXmlApplicat
|
||||
beanFactory.registerResolvableDependency(GraphDatabaseService.class, database);
|
||||
beanFactory.registerSingleton("graphDatabaseService", database);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
|
||||
super.postProcessBeanFactory(beanFactory);
|
||||
}
|
||||
}
|
||||
@@ -15,10 +15,10 @@
|
||||
*/
|
||||
package org.springframework.data.neo4j.support;
|
||||
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.graphdb.PropertyContainer;
|
||||
import org.neo4j.graphdb.*;
|
||||
import org.springframework.data.neo4j.mapping.Neo4jMappingContext;
|
||||
import org.springframework.data.neo4j.mapping.Neo4jPersistentEntityImpl;
|
||||
import org.springframework.data.neo4j.mapping.RelationshipProperties;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
@@ -40,7 +40,7 @@ public class EntityStateHandler {
|
||||
return;
|
||||
}
|
||||
if (isManaged(entity)) {
|
||||
((ManagedEntity<S,Object>) entity).setPersistentState(state);
|
||||
((ManagedEntity<S, Object>) entity).setPersistentState(state);
|
||||
return;
|
||||
}
|
||||
final Class<?> type = entity.getClass();
|
||||
@@ -51,6 +51,7 @@ public class EntityStateHandler {
|
||||
public boolean isManaged(Object entity) {
|
||||
return entity instanceof ManagedEntity;
|
||||
}
|
||||
|
||||
public boolean isManaged(Class type) {
|
||||
return ManagedEntity.class.isAssignableFrom(type);
|
||||
}
|
||||
@@ -61,7 +62,7 @@ public class EntityStateHandler {
|
||||
return (S) entity;
|
||||
}
|
||||
if (isManaged(entity)) {
|
||||
return ((ManagedEntity<S,Object>) entity).getPersistentState();
|
||||
return ((ManagedEntity<S, Object>) entity).getPersistentState();
|
||||
}
|
||||
final Class<?> type = entity.getClass();
|
||||
final Neo4jPersistentEntityImpl<?> persistentEntity = mappingContext.getPersistentEntity(type);
|
||||
@@ -86,4 +87,32 @@ public class EntityStateHandler {
|
||||
public boolean isRelationshipEntity(Class targetType) {
|
||||
return mappingContext.isRelationshipEntity(targetType);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <S extends PropertyContainer> S useOrCreateState(Object entity, S state) {
|
||||
if (state != null) return state;
|
||||
final S containedState = getPersistentState(entity);
|
||||
if (containedState == null) return containedState;
|
||||
final Class<?> type = entity.getClass();
|
||||
final Neo4jPersistentEntityImpl<?> persistentEntity = mappingContext.getPersistentEntity(type);
|
||||
if (persistentEntity.isNodeEntity()) {
|
||||
return (S) service.createNode();
|
||||
}
|
||||
if (persistentEntity.isRelationshipEntity()) {
|
||||
return createRelationship(entity, persistentEntity);
|
||||
}
|
||||
throw new IllegalArgumentException("The entity " + persistentEntity.getEntityName() + " has to be either annotated with @NodeEntity or @RelationshipEntity");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <S extends PropertyContainer> S createRelationship(Object entity, Neo4jPersistentEntityImpl<?> persistentEntity) {
|
||||
final RelationshipProperties relationshipProperties = persistentEntity.getRelationshipProperties();
|
||||
Node startNode = (Node) relationshipProperties.getStartNodeProperty().getValue(entity);
|
||||
Node endNode = (Node) relationshipProperties.getStartNodeProperty().getValue(entity);
|
||||
Object relType = relationshipProperties.getTypeProperty().getValue(entity);
|
||||
if (relType instanceof RelationshipType) {
|
||||
return (S) startNode.createRelationshipTo(endNode, (RelationshipType) relType);
|
||||
}
|
||||
return (S) startNode.createRelationshipTo(endNode, DynamicRelationshipType.withName(relType.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,12 @@ import org.neo4j.helpers.collection.IterableWrapper;
|
||||
import org.neo4j.index.impl.lucene.LuceneIndexImplementation;
|
||||
import org.neo4j.kernel.AbstractGraphDatabase;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.convert.EntityConverter;
|
||||
import org.springframework.data.neo4j.annotation.Indexed;
|
||||
import org.springframework.data.neo4j.annotation.NodeEntity;
|
||||
import org.springframework.data.neo4j.annotation.RelationshipEntity;
|
||||
import org.springframework.data.neo4j.core.*;
|
||||
import org.springframework.data.neo4j.mapping.Neo4jEntityConverter;
|
||||
import org.springframework.data.neo4j.mapping.Neo4jMappingContext;
|
||||
import org.springframework.data.neo4j.mapping.Neo4jNodeConverter;
|
||||
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
|
||||
@@ -60,11 +64,11 @@ public class GraphDatabaseContext {
|
||||
|
||||
private GraphDatabaseService graphDatabaseService;
|
||||
private ConversionService conversionService;
|
||||
private Neo4jNodeConverter converter;
|
||||
private Neo4jEntityConverter<Object,Node> converter;
|
||||
private Validator validator;
|
||||
private NodeTypeRepresentationStrategy nodeTypeRepresentationStrategy;
|
||||
private TypeRepresentationStrategy<Node> nodeTypeRepresentationStrategy;
|
||||
|
||||
private RelationshipTypeRepresentationStrategy relationshipTypeRepresentationStrategy;
|
||||
private TypeRepresentationStrategy<Relationship> relationshipTypeRepresentationStrategy;
|
||||
|
||||
private Neo4jMappingContext mappingContext;
|
||||
private CypherQueryExecutor cypherQueryExecutor;
|
||||
@@ -313,19 +317,19 @@ public class GraphDatabaseContext {
|
||||
this.cypherQueryExecutor = new CypherQueryExecutor(this);
|
||||
}
|
||||
|
||||
public NodeTypeRepresentationStrategy getNodeTypeRepresentationStrategy() {
|
||||
public TypeRepresentationStrategy<Node> getNodeTypeRepresentationStrategy() {
|
||||
return nodeTypeRepresentationStrategy;
|
||||
}
|
||||
|
||||
public void setNodeTypeRepresentationStrategy(NodeTypeRepresentationStrategy nodeTypeRepresentationStrategy) {
|
||||
public void setNodeTypeRepresentationStrategy(TypeRepresentationStrategy<Node> nodeTypeRepresentationStrategy) {
|
||||
this.nodeTypeRepresentationStrategy = nodeTypeRepresentationStrategy;
|
||||
}
|
||||
|
||||
public RelationshipTypeRepresentationStrategy getRelationshipTypeRepresentationStrategy() {
|
||||
public TypeRepresentationStrategy<Relationship> getRelationshipTypeRepresentationStrategy() {
|
||||
return relationshipTypeRepresentationStrategy;
|
||||
}
|
||||
|
||||
public void setRelationshipTypeRepresentationStrategy(RelationshipTypeRepresentationStrategy relationshipTypeRepresentationStrategy) {
|
||||
public void setRelationshipTypeRepresentationStrategy(TypeRepresentationStrategy<Relationship> relationshipTypeRepresentationStrategy) {
|
||||
this.relationshipTypeRepresentationStrategy = relationshipTypeRepresentationStrategy;
|
||||
}
|
||||
|
||||
@@ -350,11 +354,13 @@ public class GraphDatabaseContext {
|
||||
}
|
||||
|
||||
public boolean isNodeEntity(Class<?> targetType) {
|
||||
return mappingContext.isNodeEntity(targetType);
|
||||
return targetType.isAnnotationPresent(NodeEntity.class);
|
||||
//return mappingContext.isNodeEntity(targetType);
|
||||
}
|
||||
|
||||
public boolean isRelationshipEntity(Class targetType) {
|
||||
return mappingContext.isRelationshipEntity(targetType);
|
||||
return targetType.isAnnotationPresent(RelationshipEntity.class);
|
||||
// return mappingContext.isRelationshipEntity(targetType);
|
||||
}
|
||||
|
||||
public Object save(Object entity) {
|
||||
@@ -371,7 +377,7 @@ public class GraphDatabaseContext {
|
||||
return entityStateHandler.isManaged(entity);
|
||||
}
|
||||
|
||||
public void setConverter(Neo4jNodeConverter converter) {
|
||||
public void setNodeEntityConverter(Neo4jEntityConverter<Object, Node> converter) {
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.support.node;
|
||||
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.PropertyContainer;
|
||||
import org.springframework.data.neo4j.core.EntityState;
|
||||
import org.springframework.data.neo4j.support.GraphDatabaseContext;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 07.10.11
|
||||
*/
|
||||
public interface EntityStateFactory<S extends PropertyContainer> {
|
||||
EntityState<S> getEntityState(final Object entity, boolean detachable);
|
||||
|
||||
GraphDatabaseContext getGraphDatabaseContext();
|
||||
}
|
||||
@@ -17,7 +17,6 @@
|
||||
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.fieldaccess.DelegatingFieldAccessorFactory;
|
||||
@@ -26,7 +25,7 @@ import org.springframework.data.neo4j.mapping.Neo4jMappingContext;
|
||||
import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity;
|
||||
import org.springframework.data.neo4j.support.GraphDatabaseContext;
|
||||
|
||||
public class NodeEntityStateFactory {
|
||||
public class NodeEntityStateFactory implements EntityStateFactory<Node> {
|
||||
|
||||
protected GraphDatabaseContext graphDatabaseContext;
|
||||
|
||||
@@ -34,16 +33,16 @@ public class NodeEntityStateFactory {
|
||||
|
||||
protected Neo4jMappingContext mappingContext;
|
||||
|
||||
private boolean createDetachableEntities = true;
|
||||
|
||||
public EntityState<Node> getEntityState(final Object entity) {
|
||||
public EntityState<Node> getEntityState(final Object entity, boolean detachable) {
|
||||
final Class<?> entityType = entity.getClass();
|
||||
final NodeEntity graphEntityAnnotation = entityType.getAnnotation(NodeEntity.class); // todo cache ??
|
||||
final Neo4jPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(entityType);
|
||||
NodeEntityState nodeEntityState = new NodeEntityState(null, entity, entityType, graphDatabaseContext, nodeDelegatingFieldAccessorFactory, (Neo4jPersistentEntity) persistentEntity);
|
||||
// alternative was return new NestedTransactionEntityState<NodeBacked, Node>(nodeEntityState,graphDatabaseContext);
|
||||
if (createDetachableEntities) return new DetachedEntityState<Node>(nodeEntityState, graphDatabaseContext);
|
||||
return nodeEntityState;
|
||||
@SuppressWarnings("unchecked") final Neo4jPersistentEntity<Object> persistentEntity =
|
||||
(Neo4jPersistentEntity<Object>) mappingContext.getPersistentEntity(entityType);
|
||||
NodeEntityState nodeEntityState = new NodeEntityState(null, entity, entityType, graphDatabaseContext,
|
||||
nodeDelegatingFieldAccessorFactory, persistentEntity);
|
||||
if (!detachable) {
|
||||
return nodeEntityState;
|
||||
}
|
||||
return new DetachedEntityState<Node>(nodeEntityState, graphDatabaseContext);
|
||||
}
|
||||
|
||||
public void setNodeDelegatingFieldAccessorFactory(
|
||||
@@ -67,7 +66,4 @@ public class NodeEntityStateFactory {
|
||||
return graphDatabaseContext;
|
||||
}
|
||||
|
||||
public void setCreateDetachableEntities(boolean createDetachableEntities) {
|
||||
this.createDetachableEntities = createDetachableEntities;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
/**
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.neo4j.support.query;
|
||||
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.Relationship;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.neo4j.core.TypeRepresentationStrategy;
|
||||
import org.springframework.data.neo4j.conversion.ResultConverter;
|
||||
import org.springframework.data.neo4j.support.GraphDatabaseContext;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 28.06.11
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class EntityResultConverter2<R> implements ResultConverter<Object,R> {
|
||||
private final TypeRepresentationStrategy nodeTypeRepresentationStrategy;
|
||||
private final TypeRepresentationStrategy relationshipTypeRepresentationStrategy;
|
||||
private final ConversionService conversionService;
|
||||
|
||||
public EntityResultConverter2(GraphDatabaseContext ctx) {
|
||||
this.conversionService = ctx.getConversionService();
|
||||
this.nodeTypeRepresentationStrategy = ctx.getNodeTypeRepresentationStrategy();
|
||||
relationshipTypeRepresentationStrategy = ctx.getRelationshipTypeRepresentationStrategy();
|
||||
}
|
||||
|
||||
public R convert(Object value, Class<R> type) {
|
||||
if (type == null) return (R) convertValue(value);
|
||||
if (type.isInstance(value)) return type.cast(value);
|
||||
if (value instanceof Node) {
|
||||
return (R) nodeTypeRepresentationStrategy.createEntity((Node) value, type);
|
||||
}
|
||||
if (value instanceof Relationship) {
|
||||
return (R) relationshipTypeRepresentationStrategy.createEntity((Relationship) value, type);
|
||||
}
|
||||
return conversionService.convert(value, type);
|
||||
}
|
||||
|
||||
private Object convertValue(Object value) {
|
||||
if (value instanceof Node) {
|
||||
return nodeTypeRepresentationStrategy.createEntity((Node) value);
|
||||
}
|
||||
if (value instanceof Relationship) {
|
||||
return relationshipTypeRepresentationStrategy.createEntity((Relationship) value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -23,8 +23,9 @@ import org.springframework.data.neo4j.fieldaccess.DelegatingFieldAccessorFactory
|
||||
import org.springframework.data.neo4j.mapping.Neo4jMappingContext;
|
||||
import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity;
|
||||
import org.springframework.data.neo4j.support.GraphDatabaseContext;
|
||||
import org.springframework.data.neo4j.support.node.EntityStateFactory;
|
||||
|
||||
public class RelationshipEntityStateFactory {
|
||||
public class RelationshipEntityStateFactory implements EntityStateFactory<Relationship> {
|
||||
|
||||
private GraphDatabaseContext graphDatabaseContext;
|
||||
|
||||
@@ -32,7 +33,7 @@ public class RelationshipEntityStateFactory {
|
||||
private Neo4jMappingContext mappingContext;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public EntityState<Relationship> getEntityState(final Object entity) {
|
||||
public EntityState<Relationship> getEntityState(final Object entity, boolean detachable) {
|
||||
final Class<?> entityType = entity.getClass();
|
||||
return new RelationshipEntityState(null,entity, entityType, graphDatabaseContext, relationshipDelegatingFieldAccessorFactory, (Neo4jPersistentEntity) mappingContext.getPersistentEntity(entityType));
|
||||
}
|
||||
@@ -49,4 +50,9 @@ public class RelationshipEntityStateFactory {
|
||||
public void setMappingContext(Neo4jMappingContext mappingContext) {
|
||||
this.mappingContext = mappingContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphDatabaseContext getGraphDatabaseContext() {
|
||||
return graphDatabaseContext;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,14 @@ import org.neo4j.graphdb.*;
|
||||
import org.neo4j.graphdb.index.Index;
|
||||
import org.neo4j.helpers.collection.IteratorUtil;
|
||||
import org.neo4j.test.ImpermanentGraphDatabase;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.convert.DefaultTypeMapper;
|
||||
import org.springframework.data.convert.TypeMapper;
|
||||
import org.springframework.data.neo4j.core.TypeRepresentationStrategy;
|
||||
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.model.Friendship;
|
||||
import org.springframework.data.neo4j.model.Group;
|
||||
import org.springframework.data.neo4j.model.Person;
|
||||
import org.springframework.data.neo4j.model.Personality;
|
||||
@@ -31,7 +37,10 @@ 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;
|
||||
import org.springframework.data.neo4j.support.relationship.RelationshipEntityInstantiator;
|
||||
import org.springframework.data.neo4j.support.relationship.RelationshipEntityStateFactory;
|
||||
import org.springframework.data.neo4j.support.typerepresentation.NoopNodeTypeRepresentationStrategy;
|
||||
import org.springframework.data.neo4j.support.typerepresentation.NoopRelationshipTypeRepresentationStrategy;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -43,10 +52,11 @@ import static org.junit.Assert.assertEquals;
|
||||
* @author mh
|
||||
* @since 19.09.11
|
||||
*/
|
||||
public class Neo4jNodeConverterTest {
|
||||
public class Neo4jEntityConverterTest {
|
||||
|
||||
public static final DynamicRelationshipType PERSONS = DynamicRelationshipType.withName("persons");
|
||||
private Neo4jNodeConverterImpl converter;
|
||||
private static final RelationshipType KNOWS = DynamicRelationshipType.withName("knows");
|
||||
private Neo4jEntityConverterImpl<Object,Node> converter;
|
||||
private Transaction tx;
|
||||
private GraphDatabaseContext gdc;
|
||||
private Group group;
|
||||
@@ -54,24 +64,75 @@ public class Neo4jNodeConverterTest {
|
||||
private Person emil;
|
||||
private Person andres;
|
||||
|
||||
/* OUCH
|
||||
|
||||
[MC]
|
||||
[GDC]->[GDB]
|
||||
[GDC]->[MC]
|
||||
[GDC]->[ESH]
|
||||
[ESH]->[MC]
|
||||
[ESH]->[GDB]
|
||||
[TRS]->[EI]
|
||||
[EI]->[ESH]
|
||||
[GDC]->[CS]
|
||||
[GDC]->[TRS]
|
||||
[GDC]->[ESH]
|
||||
[ESF]->[MC]
|
||||
[ESF]->[GDC]
|
||||
[ESF]->[FAF]
|
||||
[FAF]->[GDC]
|
||||
[GDC]->[EC]
|
||||
[EC]->[ESF]
|
||||
[EC]->[CS]
|
||||
[EC]->[EI]
|
||||
[EC]->[ESH]
|
||||
[EC]->[SST]
|
||||
[EC]->[TRS]
|
||||
[SST]->[ESF]
|
||||
|
||||
*/
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
final Neo4jMappingContext mappingContext = new Neo4jMappingContext();
|
||||
gdc = createContext(mappingContext);
|
||||
tx = gdc.beginTx();
|
||||
final NodeEntityStateFactory nodeEntityStateFactory = new NodeEntityStateFactory();
|
||||
nodeEntityStateFactory.setMappingContext(mappingContext);
|
||||
nodeEntityStateFactory.setGraphDatabaseContext(gdc);
|
||||
nodeEntityStateFactory.setNodeDelegatingFieldAccessorFactory(new NodeDelegatingFieldAccessorFactory(gdc));
|
||||
converter = new Neo4jNodeConverterImpl();
|
||||
converter.setNodeEntityStateFactory(nodeEntityStateFactory);
|
||||
gdc.setConverter(converter);
|
||||
|
||||
final NodeEntityStateFactory nodeEntityStateFactory = createNodeEntityStateFactory(mappingContext);
|
||||
final RelationshipEntityStateFactory relationshipEntityStateFactory = createRelationshipEntityStateFactory(mappingContext);
|
||||
final EntityStateHandler entityStateHandler = new EntityStateHandler(mappingContext, gdc.getGraphDatabaseService());
|
||||
final NodeEntityInstantiator entityInstantiator = new NodeEntityInstantiator(entityStateHandler);
|
||||
final TypeRepresentationStrategy<Node> typeRepresentationStrategy = gdc.getNodeTypeRepresentationStrategy();
|
||||
TypeMapper<Node> typeMapper = new DefaultTypeMapper<Node>(new TRSTypeAliasAccessor<Node>(typeRepresentationStrategy),asList(new ClassValueTypeInformationMapper()));
|
||||
SourceStateTransmitter<Node> nodeStateTransmitter = new SourceStateTransmitter<Node>(nodeEntityStateFactory);
|
||||
SourceStateTransmitter<Relationship> relationshipStateTransmitter = new SourceStateTransmitter<Relationship>(relationshipEntityStateFactory);
|
||||
final ConversionService conversionService = gdc.getConversionService();
|
||||
|
||||
Neo4jEntityFetchHandler fetchHandler=new Neo4jEntityFetchHandler(entityStateHandler, conversionService, relationshipStateTransmitter , nodeStateTransmitter);
|
||||
|
||||
converter = new Neo4jEntityConverterImpl<Object,Node>(mappingContext, conversionService, entityInstantiator, entityStateHandler, typeMapper, nodeStateTransmitter, fetchHandler);
|
||||
gdc.setNodeEntityConverter(converter);
|
||||
group = new Group();
|
||||
michael = new Person("Michael", 37);
|
||||
emil = new Person("Emil", 30);
|
||||
andres = new Person("Andrés", 36);
|
||||
}
|
||||
|
||||
private NodeEntityStateFactory createNodeEntityStateFactory(Neo4jMappingContext mappingContext) {
|
||||
final NodeEntityStateFactory nodeEntityStateFactory = new NodeEntityStateFactory();
|
||||
nodeEntityStateFactory.setMappingContext(mappingContext);
|
||||
nodeEntityStateFactory.setGraphDatabaseContext(gdc);
|
||||
nodeEntityStateFactory.setNodeDelegatingFieldAccessorFactory(new NodeDelegatingFieldAccessorFactory(gdc));
|
||||
return nodeEntityStateFactory;
|
||||
}
|
||||
private RelationshipEntityStateFactory createRelationshipEntityStateFactory(Neo4jMappingContext mappingContext) {
|
||||
final RelationshipEntityStateFactory relationshipEntityStateFactory = new RelationshipEntityStateFactory();
|
||||
relationshipEntityStateFactory.setMappingContext(mappingContext);
|
||||
relationshipEntityStateFactory.setGraphDatabaseContext(gdc);
|
||||
relationshipEntityStateFactory.setRelationshipDelegatingFieldAccessorFactory(new RelationshipDelegatingFieldAccessorFactory(gdc));
|
||||
return relationshipEntityStateFactory;
|
||||
}
|
||||
|
||||
private GraphDatabaseContext createContext(Neo4jMappingContext mappingContext) throws Exception {
|
||||
GraphDatabaseContext gdc = new GraphDatabaseContext();
|
||||
final ImpermanentGraphDatabase gdb = new ImpermanentGraphDatabase();
|
||||
@@ -79,6 +140,7 @@ public class Neo4jNodeConverterTest {
|
||||
gdc.setMappingContext(mappingContext);
|
||||
final EntityStateHandler entityStateHandler = new EntityStateHandler(mappingContext, gdb);
|
||||
gdc.setNodeTypeRepresentationStrategy(new NoopNodeTypeRepresentationStrategy(new NodeEntityInstantiator(entityStateHandler)));
|
||||
gdc.setRelationshipTypeRepresentationStrategy(new NoopRelationshipTypeRepresentationStrategy(new RelationshipEntityInstantiator(entityStateHandler)));
|
||||
gdc.setConversionService(new Neo4jConversionServiceFactoryBean().getObject());
|
||||
gdc.setEntityStateHandler(entityStateHandler);
|
||||
gdc.createCypherExecutor();
|
||||
@@ -155,7 +217,7 @@ public class Neo4jNodeConverterTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadConvertedPropertiesToExistingNode() {
|
||||
public void testReadConvertedPropertiesFromExistingNode() {
|
||||
final Node existingNode = createNewNode();
|
||||
existingNode.setProperty("name", "Michael");
|
||||
existingNode.setProperty("age", 36);
|
||||
@@ -197,16 +259,17 @@ public class Neo4jNodeConverterTest {
|
||||
|
||||
private Group storeInGraph(Group g) {
|
||||
final Long id = g.getId();
|
||||
if (id!=null) {
|
||||
if (id != null) {
|
||||
converter.write(g, gdc.getNodeById(id));
|
||||
} else {
|
||||
converter.write(g, null);
|
||||
}
|
||||
return g;
|
||||
}
|
||||
|
||||
private Person storeInGraph(Person p) {
|
||||
final Long id = p.getId();
|
||||
if (id!=null) {
|
||||
if (id != null) {
|
||||
converter.write(p, gdc.getNodeById(id));
|
||||
} else {
|
||||
converter.write(p, null);
|
||||
@@ -380,4 +443,34 @@ public class Neo4jNodeConverterTest {
|
||||
assertEquals("added member to group", michael.getId(), (Long) michaelNode.getId());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCascadingReadWithProperties() {
|
||||
Node groupNode = createNewNode();
|
||||
Node julianNode = createNewNode();
|
||||
julianNode.setProperty("name", "Julian");
|
||||
groupNode.createRelationshipTo(julianNode, PERSONS);
|
||||
|
||||
Group g = converter.read(Group.class, groupNode);
|
||||
Person julian = IteratorUtil.first(g.getPersons());
|
||||
assertEquals("Julian", julian.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadFriendShipsFromPersons() throws Exception {
|
||||
storeInGraph(michael);
|
||||
storeInGraph(andres);
|
||||
|
||||
Relationship friendshipRelationship = michaelNode().createRelationshipTo(andresNode(), KNOWS);
|
||||
friendshipRelationship.setProperty("Friendship.years", 19);
|
||||
|
||||
Person m = converter.read(Person.class, michaelNode());
|
||||
Friendship friendship = IteratorUtil.first(m.getFriendships());
|
||||
|
||||
assertEquals((Long) friendshipRelationship.getId(), friendship.getId());
|
||||
assertEquals(19, friendship.getYears());
|
||||
assertEquals(friendship.getPerson1(), michael);
|
||||
assertEquals(friendship.getPerson2(), andres);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,6 +24,8 @@ import java.util.Date;
|
||||
|
||||
@RelationshipEntity(useShortNames = false)
|
||||
public class Friendship {
|
||||
@GraphId
|
||||
private Long id;
|
||||
|
||||
public Friendship() {
|
||||
}
|
||||
@@ -110,4 +112,8 @@ public class Friendship {
|
||||
public DynamicProperties getPersonalProperties() {
|
||||
return personalProperties;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ public class Group {
|
||||
public static final String SEARCH_GROUPS_INDEX = "search-groups";
|
||||
|
||||
@RelatedTo(direction = Direction.OUTGOING)
|
||||
@Fetch
|
||||
private Collection<Person> persons;
|
||||
|
||||
@RelatedTo(type = "persons", elementClass = Person.class)
|
||||
|
||||
@@ -67,6 +67,7 @@ public class Person {
|
||||
@RelatedTo(type = "boss", direction = Direction.INCOMING)
|
||||
private Person boss;
|
||||
|
||||
@Fetch
|
||||
@RelatedToVia(type = "knows", elementClass = Friendship.class)
|
||||
private Iterable<Friendship> friendships;
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ public abstract class DocumentingTestBase {
|
||||
StringBuilder snippetText = new StringBuilder();
|
||||
boolean inSnippet = false;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.matches(".*//.+SNIPPET\\s+"+snippet+".*")) {
|
||||
if (line.matches(".*//.+SNIPPET\\s+.*\\b"+snippet+"\\b.*")) {
|
||||
inSnippet = !inSnippet;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -33,4 +33,5 @@
|
||||
</bean>
|
||||
|
||||
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
|
||||
<!--context:load-time-weaver aspectj-weaving="autodetect"/-->
|
||||
</beans>
|
||||
Reference in New Issue
Block a user