diff --git a/spring-data-neo4j-aspects/src/main/java/org/springframework/data/neo4j/aspects/support/node/Neo4jNodeBacking.aj b/spring-data-neo4j-aspects/src/main/java/org/springframework/data/neo4j/aspects/support/node/Neo4jNodeBacking.aj index 89f76341e..b2e80ec2e 100644 --- a/spring-data-neo4j-aspects/src/main/java/org/springframework/data/neo4j/aspects/support/node/Neo4jNodeBacking.aj +++ b/spring-data-neo4j-aspects/src/main/java/org/springframework/data/neo4j/aspects/support/node/Neo4jNodeBacking.aj @@ -245,7 +245,7 @@ public privileged aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMix */ Object around(NodeBacked entity): entityFieldGet(entity) { if (entity.entityState==null) return proceed(entity); - Object result=entity.entityState.getValue(field(thisJoinPoint)); + Object result=entity.entityState.getValue(field(thisJoinPoint),null); if (result instanceof DoReturn) return unwrap(result); return proceed(entity); } @@ -255,7 +255,7 @@ public privileged aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMix */ Object around(NodeBacked entity, Object newVal) : entityFieldSet(entity, newVal) { if (entity.entityState==null) return proceed(entity,newVal); - Object result=entity.entityState.setValue(field(thisJoinPoint),newVal); + Object result=entity.entityState.setValue(field(thisJoinPoint),newVal,null); if (result instanceof DoReturn) return unwrap(result); return proceed(entity,result); } diff --git a/spring-data-neo4j-aspects/src/main/java/org/springframework/data/neo4j/aspects/support/relationship/Neo4jRelationshipBacking.aj b/spring-data-neo4j-aspects/src/main/java/org/springframework/data/neo4j/aspects/support/relationship/Neo4jRelationshipBacking.aj index 633c68c93..359780eac 100644 --- a/spring-data-neo4j-aspects/src/main/java/org/springframework/data/neo4j/aspects/support/relationship/Neo4jRelationshipBacking.aj +++ b/spring-data-neo4j-aspects/src/main/java/org/springframework/data/neo4j/aspects/support/relationship/Neo4jRelationshipBacking.aj @@ -160,14 +160,14 @@ public aspect Neo4jRelationshipBacking { Object around(RelationshipBacked entity): entityFieldGet(entity) { if (entity.entityState == null) return proceed(entity); - Object result = entity.entityState.getValue(field(thisJoinPoint)); + Object result = entity.entityState.getValue(field(thisJoinPoint),null); if (result instanceof DoReturn) return unwrap(result); return proceed(entity); } Object around(RelationshipBacked entity, Object newVal) : entityFieldSet(entity, newVal) { if (entity.entityState == null) return proceed(entity,newVal); - Object result=entity.entityState.setValue(field(thisJoinPoint),newVal); + Object result=entity.entityState.setValue(field(thisJoinPoint),newVal,null); if (result instanceof DoReturn) return unwrap(result); return proceed(entity,result); } diff --git a/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/IndexTest.java b/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/IndexTest.java index 90be05afe..dbaeb79d6 100644 --- a/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/IndexTest.java +++ b/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/IndexTest.java @@ -129,7 +129,7 @@ public class IndexTest extends EntityTestBase { group.setIndexLevelName("indexLevelNameValue"); Index subGroupIndex = neo4jTemplate.getIndex(SubGroup.class); final Node found = subGroupIndex.get("indexLevelName", "indexLevelNameValue").getSingle(); - final SubGroup foundEntity = neo4jTemplate.createEntityFromState(found, SubGroup.class); + final SubGroup foundEntity = neo4jTemplate.createEntityFromState(found, SubGroup.class, neo4jTemplate.getMappingPolicy(SubGroup.class)); assertEquals(group, foundEntity); } diff --git a/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/NodeEntityInstantiationTest.java b/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/NodeEntityInstantiationTest.java index 661860429..81f316284 100644 --- a/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/NodeEntityInstantiationTest.java +++ b/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/NodeEntityInstantiationTest.java @@ -20,6 +20,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.neo4j.graphdb.Node; import org.springframework.data.neo4j.aspects.Person; +import org.springframework.data.neo4j.mapping.MappingPolicy; import org.springframework.data.neo4j.repository.GraphRepository; import org.springframework.test.context.CleanContextCacheTestExecutionListener; import org.springframework.test.context.ContextConfiguration; @@ -47,9 +48,10 @@ public class NodeEntityInstantiationTest extends EntityTestBase { long nodeId = getNodeId(p); Node node = neo4jTemplate.getNode(nodeId); - Person person1 = (Person) neo4jTemplate.createEntityFromStoredType(node); + final MappingPolicy mappingPolicy = neo4jTemplate.getMappingPolicy(Person.class); + Person person1 = (Person) neo4jTemplate.createEntityFromStoredType(node, mappingPolicy); assertEquals("Rod", person1.getName()); - Person person2 = neo4jTemplate.createEntityFromState(node,Person.class); + Person person2 = neo4jTemplate.createEntityFromState(node,Person.class, mappingPolicy); assertEquals("Rod", person2.getName()); GraphRepository finder = neo4jTemplate.repositoryFor(Person.class); diff --git a/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/NodeEntityTest.java b/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/NodeEntityTest.java index 32ff87038..74d769141 100644 --- a/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/NodeEntityTest.java +++ b/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/NodeEntityTest.java @@ -48,7 +48,7 @@ public class NodeEntityTest extends EntityTestBase { Person p = persistedPerson("Rod", 39); assertEquals(p.getName(), getNodeState(p).getProperty("name")); assertEquals(p.getAge(), getNodeState(p).getProperty("age")); - Person found = neo4jTemplate.createEntityFromState(neo4jTemplate.getNode(getNodeId(p)), Person.class); + Person found = neo4jTemplate.createEntityFromState(neo4jTemplate.getNode(getNodeId(p)), Person.class, neo4jTemplate.getMappingPolicy(p)); assertEquals("Rod", getNodeState(found).getProperty("name")); assertEquals(39, getNodeState(found).getProperty("age")); } diff --git a/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/query/QueryEngineTest.java b/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/query/QueryEngineTest.java index c63cdc2a0..dad612220 100644 --- a/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/query/QueryEngineTest.java +++ b/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/query/QueryEngineTest.java @@ -116,7 +116,7 @@ public class QueryEngineTest extends EntityTestBase { @Test public void testQueryListWithCustomConverter() throws Exception { final String queryString = "start person=node:name_index(name={name}) match (person) <-[:boss]- (boss) return boss"; - final Collection result = IteratorUtil.asCollection(queryEngine.query(queryString, michaelsName()).to(String.class, new ResultConverter, String>() { + final Collection result = IteratorUtil.asCollection(queryEngine.query(queryString, michaelsName()).to(String.class, new ResultConverter.ResultConverterAdapter, String>() { @Override public String convert(Map row, Class target) { return (String) ((Node) row.get("boss")).getProperty("name"); diff --git a/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/typerepresentation/IndexingNodeTypeRepresentationStrategyTest.java b/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/typerepresentation/IndexingNodeTypeRepresentationStrategyTest.java index 07f7dcb59..443142e66 100644 --- a/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/typerepresentation/IndexingNodeTypeRepresentationStrategyTest.java +++ b/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/typerepresentation/IndexingNodeTypeRepresentationStrategyTest.java @@ -148,14 +148,14 @@ public class IndexingNodeTypeRepresentationStrategyTest extends EntityTestBase { @Test @Transactional public void testCreateEntityAndInferType() throws Exception { - Thing newThing = neo4jTemplate.createEntityFromStoredType(node(thing)); + Thing newThing = neo4jTemplate.createEntityFromStoredType(node(thing), neo4jTemplate.getMappingPolicy(thing)); assertEquals(thing, newThing); } @Test @Transactional public void testCreateEntityAndSpecifyType() throws Exception { - Thing newThing = neo4jTemplate.createEntityFromState(node(subThing), Thing.class); + Thing newThing = neo4jTemplate.createEntityFromState(node(subThing), Thing.class, neo4jTemplate.getMappingPolicy(subThing)); assertEquals(subThing, newThing); } diff --git a/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/typerepresentation/IndexingRelationshipTypeRepresentationStrategyTest.java b/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/typerepresentation/IndexingRelationshipTypeRepresentationStrategyTest.java index ed5521c65..0dc535beb 100644 --- a/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/typerepresentation/IndexingRelationshipTypeRepresentationStrategyTest.java +++ b/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/typerepresentation/IndexingRelationshipTypeRepresentationStrategyTest.java @@ -129,14 +129,14 @@ public class IndexingRelationshipTypeRepresentationStrategyTest extends EntityTe @Test @Transactional public void testCreateEntityAndInferType() throws Exception { - Link newLink = neo4jTemplate.createEntityFromStoredType(rel(link)); + Link newLink = neo4jTemplate.createEntityFromStoredType(rel(link), neo4jTemplate.getMappingPolicy(link)); assertEquals(link, newLink); } @Test @Transactional public void testCreateEntityAndSpecifyType() throws Exception { - Link newLink = neo4jTemplate.createEntityFromState(rel(link), Link.class); + Link newLink = neo4jTemplate.createEntityFromState(rel(link), Link.class, neo4jTemplate.getMappingPolicy(link)); assertEquals(link, newLink); } diff --git a/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/typerepresentation/SubReferenceNodeTypeRepresentationStrategyTest.java b/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/typerepresentation/SubReferenceNodeTypeRepresentationStrategyTest.java index f42296f6a..8ac72d604 100644 --- a/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/typerepresentation/SubReferenceNodeTypeRepresentationStrategyTest.java +++ b/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/typerepresentation/SubReferenceNodeTypeRepresentationStrategyTest.java @@ -202,14 +202,14 @@ public class SubReferenceNodeTypeRepresentationStrategyTest extends EntityTestBa @Test @Transactional public void testCreateEntityAndInferType() throws Exception { - Thing newThing = neo4jTemplate.createEntityFromStoredType(node(thing)); + Thing newThing = neo4jTemplate.createEntityFromStoredType(node(thing), neo4jTemplate.getMappingPolicy(thing)); assertEquals(thing, newThing); } @Test @Transactional public void testCreateEntityAndSpecifyType() throws Exception { - Thing newThing = neo4jTemplate.createEntityFromState(node(subThing), Thing.class); + Thing newThing = neo4jTemplate.createEntityFromState(node(subThing), Thing.class, neo4jTemplate.getMappingPolicy(subThing)); assertEquals(subThing, newThing); } diff --git a/spring-data-neo4j-cross-store/src/main/java/org/springframework/data/neo4j/cross_store/support/node/CrossStoreNodeEntityInstantiator.java b/spring-data-neo4j-cross-store/src/main/java/org/springframework/data/neo4j/cross_store/support/node/CrossStoreNodeEntityInstantiator.java index 9ad16156b..83d2ea0a3 100644 --- a/spring-data-neo4j-cross-store/src/main/java/org/springframework/data/neo4j/cross_store/support/node/CrossStoreNodeEntityInstantiator.java +++ b/spring-data-neo4j-cross-store/src/main/java/org/springframework/data/neo4j/cross_store/support/node/CrossStoreNodeEntityInstantiator.java @@ -19,6 +19,7 @@ package org.springframework.data.neo4j.cross_store.support.node; import org.neo4j.graphdb.Node; import org.springframework.data.neo4j.aspects.core.NodeBacked; import org.springframework.data.neo4j.mapping.EntityInstantiator; +import org.springframework.data.neo4j.mapping.MappingPolicy; import org.springframework.data.neo4j.support.node.NodeEntityInstantiator; import org.springframework.orm.jpa.EntityManagerFactoryUtils; @@ -48,17 +49,18 @@ public class CrossStoreNodeEntityInstantiator implements EntityInstantiator generic type of the entity * @return */ - public T createEntityFromState(Node n, Class entityClass) { + public T createEntityFromState(Node n, Class entityClass, final MappingPolicy mappingPolicy) { if (n.hasProperty(CrossStoreNodeEntityState.FOREIGN_ID)) { final Object foreignId = n.getProperty(CrossStoreNodeEntityState.FOREIGN_ID); final T result = entityManager().find(entityClass, foreignId); ((NodeBacked)result).setPersistentState(n); return result; } - return delegate.createEntityFromState(n, entityClass); + return delegate.createEntityFromState(n, entityClass, mappingPolicy); } private EntityManager entityManager() { diff --git a/spring-data-neo4j-cross-store/src/main/java/org/springframework/data/neo4j/cross_store/support/node/CrossStoreNodeEntityState.java b/spring-data-neo4j-cross-store/src/main/java/org/springframework/data/neo4j/cross_store/support/node/CrossStoreNodeEntityState.java index 3ec92e69f..5579ea0dd 100644 --- a/spring-data-neo4j-cross-store/src/main/java/org/springframework/data/neo4j/cross_store/support/node/CrossStoreNodeEntityState.java +++ b/spring-data-neo4j-cross-store/src/main/java/org/springframework/data/neo4j/cross_store/support/node/CrossStoreNodeEntityState.java @@ -32,7 +32,6 @@ import org.springframework.data.neo4j.support.Neo4jTemplate; import org.springframework.data.neo4j.support.index.IndexType; import javax.persistence.PersistenceUnitUtil; -import java.lang.reflect.Field; import java.util.Arrays; import java.util.Collection; @@ -90,8 +89,8 @@ public class CrossStoreNodeEntityState extends Defaul } @Override - public boolean isWritable(Field field) { - final FieldAccessor accessor = accessorFor(property(field)); + public boolean isWritable(Neo4jPersistentProperty property) { + final FieldAccessor accessor = accessorFor(property); if (accessor == null) return false; // difference to default behaviour, we don't care for non-managed fields here return accessor.isWriteable(entity); } diff --git a/spring-data-neo4j-examples/cineasts-aspects/src/test/java/org/neo4j/cineasts/movieimport/MovieDbApiClientTest.java b/spring-data-neo4j-examples/cineasts-aspects/src/test/java/org/neo4j/cineasts/movieimport/MovieDbApiClientTest.java index 935c56c29..0f1dc4b8f 100644 --- a/spring-data-neo4j-examples/cineasts-aspects/src/test/java/org/neo4j/cineasts/movieimport/MovieDbApiClientTest.java +++ b/spring-data-neo4j-examples/cineasts-aspects/src/test/java/org/neo4j/cineasts/movieimport/MovieDbApiClientTest.java @@ -1,5 +1,6 @@ package org.neo4j.cineasts.movieimport; +import org.junit.Ignore; import org.junit.Test; import java.util.Map; @@ -10,6 +11,7 @@ import static org.junit.Assert.assertEquals; * @author mh * @since 13.03.11 */ +@Ignore public class MovieDbApiClientTest { private static final String API_KEY = "926d2a79e82920b62f03b1cb57e532e6"; diff --git a/spring-data-neo4j-examples/cineasts-rest/src/test/java/org/neo4j/cineasts/movieimport/MovieDbApiClientTest.java b/spring-data-neo4j-examples/cineasts-rest/src/test/java/org/neo4j/cineasts/movieimport/MovieDbApiClientTest.java index 935c56c29..0f1dc4b8f 100644 --- a/spring-data-neo4j-examples/cineasts-rest/src/test/java/org/neo4j/cineasts/movieimport/MovieDbApiClientTest.java +++ b/spring-data-neo4j-examples/cineasts-rest/src/test/java/org/neo4j/cineasts/movieimport/MovieDbApiClientTest.java @@ -1,5 +1,6 @@ package org.neo4j.cineasts.movieimport; +import org.junit.Ignore; import org.junit.Test; import java.util.Map; @@ -10,6 +11,7 @@ import static org.junit.Assert.assertEquals; * @author mh * @since 13.03.11 */ +@Ignore public class MovieDbApiClientTest { private static final String API_KEY = "926d2a79e82920b62f03b1cb57e532e6"; diff --git a/spring-data-neo4j-examples/imdb/src/main/java/org/neo4j/examples/imdb/domain/ImdbServiceImpl.java b/spring-data-neo4j-examples/imdb/src/main/java/org/neo4j/examples/imdb/domain/ImdbServiceImpl.java index 0e6ba745a..03341658a 100644 --- a/spring-data-neo4j-examples/imdb/src/main/java/org/neo4j/examples/imdb/domain/ImdbServiceImpl.java +++ b/spring-data-neo4j-examples/imdb/src/main/java/org/neo4j/examples/imdb/domain/ImdbServiceImpl.java @@ -81,9 +81,9 @@ class ImdbServiceImpl implements ImdbService { int mod = 0; for (Node node : list.nodes()) { if (mod++ % 2 == 0) { - actorAndMovieList.add(template.createEntityFromState(node, Actor.class)); + actorAndMovieList.add(template.load(node, Actor.class)); } else { - actorAndMovieList.add(template.createEntityFromState(node, Movie.class)); + actorAndMovieList.add(template.load(node, Movie.class)); } } return actorAndMovieList; diff --git a/spring-data-neo4j-examples/myrestaurants-social/src/main/java/com/springone/myrestaurants/domain/TopRatedRestaurantFinder.java b/spring-data-neo4j-examples/myrestaurants-social/src/main/java/com/springone/myrestaurants/domain/TopRatedRestaurantFinder.java index f2fded795..e984f0003 100644 --- a/spring-data-neo4j-examples/myrestaurants-social/src/main/java/com/springone/myrestaurants/domain/TopRatedRestaurantFinder.java +++ b/spring-data-neo4j-examples/myrestaurants-social/src/main/java/com/springone/myrestaurants/domain/TopRatedRestaurantFinder.java @@ -64,9 +64,9 @@ public class TopRatedRestaurantFinder { } private RatedRestaurant toRatedRestaurant(final CalculateRatingPredicate calculateRatingPredicate) { - final RatedRestaurant ratedRestaurant = new RatedRestaurant(template.createEntityFromState(restaurant, Restaurant.class)); + final RatedRestaurant ratedRestaurant = new RatedRestaurant(template.load(restaurant, Restaurant.class)); for (final Relationship recommendation : recommendations) { - ratedRestaurant.add(template.createEntityFromState(recommendation, Recommendation.class)); + ratedRestaurant.add(template.load(recommendation, Recommendation.class)); } return ratedRestaurant; } diff --git a/spring-data-neo4j-rest/src/main/java/org/springframework/data/neo4j/rest/SpringEndResult.java b/spring-data-neo4j-rest/src/main/java/org/springframework/data/neo4j/rest/SpringEndResult.java index 592dd6688..945204835 100644 --- a/spring-data-neo4j-rest/src/main/java/org/springframework/data/neo4j/rest/SpringEndResult.java +++ b/spring-data-neo4j-rest/src/main/java/org/springframework/data/neo4j/rest/SpringEndResult.java @@ -47,5 +47,4 @@ class SpringEndResult implements EndResult { public Iterator iterator() { return result.iterator(); } - } diff --git a/spring-data-neo4j-rest/src/main/java/org/springframework/data/neo4j/rest/SpringRestResult.java b/spring-data-neo4j-rest/src/main/java/org/springframework/data/neo4j/rest/SpringRestResult.java index 8778de9fb..b823d8df0 100644 --- a/spring-data-neo4j-rest/src/main/java/org/springframework/data/neo4j/rest/SpringRestResult.java +++ b/spring-data-neo4j-rest/src/main/java/org/springframework/data/neo4j/rest/SpringRestResult.java @@ -19,12 +19,14 @@ import org.neo4j.rest.graphdb.util.ConvertedResult; import org.neo4j.rest.graphdb.util.ResultConverter; import org.springframework.data.neo4j.conversion.EndResult; import org.springframework.data.neo4j.conversion.Result; +import org.springframework.data.neo4j.mapping.MappingPolicy; import java.util.Iterator; class SpringRestResult implements Result { org.neo4j.rest.graphdb.util.QueryResult queryResult; + private MappingPolicy mappingPolicy; SpringRestResult(org.neo4j.rest.graphdb.util.QueryResult queryResult) { this.queryResult = queryResult; @@ -39,7 +41,7 @@ class SpringRestResult implements Result { ConvertedResult result = queryResult.to(type, new ResultConverter() { @Override public R convert(T value, Class type) { - return converter.convert(value,type); + return converter.convert(value,type,mappingPolicy); } }); return new SpringEndResult(result); @@ -66,4 +68,10 @@ class SpringRestResult implements Result { public T single() { return (T) to(Object.class).single(); } + + @Override + public Result with(MappingPolicy mappingPolicy) { + this.mappingPolicy = mappingPolicy; + return this; + } } diff --git a/spring-data-neo4j-rest/src/test/java/org/springframework/data/neo4j/rest/support/TestServerPlugin.java b/spring-data-neo4j-rest/src/test/java/org/springframework/data/neo4j/rest/support/TestServerPlugin.java index 704172aac..bef5accbb 100644 --- a/spring-data-neo4j-rest/src/test/java/org/springframework/data/neo4j/rest/support/TestServerPlugin.java +++ b/spring-data-neo4j-rest/src/test/java/org/springframework/data/neo4j/rest/support/TestServerPlugin.java @@ -67,7 +67,7 @@ public class TestServerPlugin extends ServerPlugin { @PluginTarget(Node.class) public Iterable allFriendsOf(@Source Node target) { context(target.getGraphDatabase()); - final Person person = template.createEntityFromState(target, Person.class); + final Person person = template.load(target, Person.class); return new IterableWrapper(person.getFriendships()) { @Override protected Node underlyingObjectToObject(Friendship friendship) { diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/DefaultConverter.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/DefaultConverter.java index 8152dedc8..0e7fb2fda 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/DefaultConverter.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/DefaultConverter.java @@ -19,6 +19,7 @@ package org.springframework.data.neo4j.conversion; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Path; import org.neo4j.graphdb.Relationship; +import org.springframework.data.neo4j.mapping.MappingPolicy; import org.springframework.data.neo4j.support.path.NodePath; import org.springframework.data.neo4j.support.path.RelationshipPath; @@ -32,11 +33,14 @@ import java.util.Map; public class DefaultConverter implements ResultConverter { @SuppressWarnings("unchecked") public R convert(Object value, Class type) { + return convert(value,type, null); + } + public R convert(Object value, Class type, MappingPolicy mappingPolicy) { if (value == null || type.isInstance(value)) return (R) value; Object singleValue = extractValue(value); if (singleValue == null || type.isInstance(singleValue)) return (R) singleValue; final Class sourceType = singleValue.getClass(); - Object result = doConvert(singleValue, sourceType, type); + Object result = doConvert(singleValue, sourceType, type,mappingPolicy); if (result == null) throw new RuntimeException("Cannot automatically convert " + sourceType + " to " + type + " please use a custom converter"); return (R) result; @@ -58,7 +62,7 @@ public class DefaultConverter implements ResultConverter { } @SuppressWarnings("unchecked") - protected Object doConvert(Object value, Class sourceType, Class type) { + protected Object doConvert(Object value, Class sourceType, Class type, MappingPolicy mappingPolicy) { if (Node.class.isAssignableFrom(type)) { return toNode(value, sourceType); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/EndResult.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/EndResult.java index 398f23d93..9b4d73ef1 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/EndResult.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/EndResult.java @@ -24,5 +24,4 @@ public interface EndResult extends Iterable { R single(); R singleOrNull(); void handle(Handler handler); - } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/QueryMapResulConverter.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/QueryMapResulConverter.java index da6b13562..1d65f7dd8 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/QueryMapResulConverter.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/QueryMapResulConverter.java @@ -15,14 +15,10 @@ */ package org.springframework.data.neo4j.conversion; -import org.springframework.data.neo4j.annotation.ResultColumn; -import org.springframework.data.neo4j.support.conversion.NoSuchColumnFoundException; +import org.springframework.data.neo4j.mapping.MappingPolicy; +import org.springframework.data.neo4j.support.conversion.QueryResultProxy; import org.springframework.data.neo4j.template.Neo4jOperations; -import org.springframework.data.util.ClassTypeInformation; -import org.springframework.data.util.TypeInformation; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Map; @@ -33,35 +29,15 @@ public class QueryMapResulConverter implements ResultConverter value, Class type, MappingPolicy mappingPolicy) { + return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{type}, new QueryResultProxy(value,mappingPolicy,template.getDefaultConverter())); + } + + @SuppressWarnings("unchecked") @Override public T convert(Map value, Class type) { - final Map valueCopy = value; - - - T resultProxy = (T) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{type}, new InvocationHandler() { - @Override - public Object invoke(Object o, Method method, Object[] objects) throws Throwable { - ResultColumn column = method.getAnnotation(ResultColumn.class); - TypeInformation returnType = ClassTypeInformation.fromReturnTypeOf(method); - - String columnName = column.value(); - if(!valueCopy.containsKey( columnName )) { - throw new NoSuchColumnFoundException( columnName ); - } - - Object columnValue = valueCopy.get( columnName ); - - - Object result; - if (returnType.isCollectionLike()) - result = template.convert((Iterable) columnValue).to(returnType.getActualType().getType()); - else - result = template.convert(columnValue, returnType.getType()); - - - return result; - } - }); - return resultProxy; + return convert(value,type,null); } } \ No newline at end of file diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/QueryResultBuilder.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/QueryResultBuilder.java index 039c9cfb8..5fe43e78e 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/QueryResultBuilder.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/QueryResultBuilder.java @@ -20,6 +20,7 @@ import org.neo4j.graphdb.index.IndexHits; import org.neo4j.helpers.collection.ClosableIterable; import org.neo4j.helpers.collection.IteratorUtil; import org.neo4j.helpers.collection.IteratorWrapper; +import org.springframework.data.neo4j.mapping.MappingPolicy; import java.util.Iterator; @@ -32,6 +33,7 @@ public class QueryResultBuilder implements Result { private final ResultConverter defaultConverter; private final boolean isClosableIterable; private boolean isClosed; + private MappingPolicy mappingPolicy; @SuppressWarnings("unchecked") public QueryResultBuilder(Iterable result) { @@ -74,7 +76,7 @@ public class QueryResultBuilder implements Result { public R single() { try { final T value = IteratorUtil.single(result); - return resultConverter.convert(value, type); + return convert(value); } finally { closeIfNeeded(); } @@ -83,17 +85,21 @@ public class QueryResultBuilder implements Result { public R singleOrNull() { try { final T value = IteratorUtil.singleOrNull(result); - return resultConverter.convert(value, type); + return convert(value); } finally { closeIfNeeded(); } } + private R convert(T value) { + return resultConverter.convert(value, type, mappingPolicy); + } + @Override public void handle(Handler handler) { try { for (T value : result) { - handler.handle(resultConverter.convert(value, type)); + handler.handle(convert(value)); } } finally { closeIfNeeded(); @@ -104,7 +110,7 @@ public class QueryResultBuilder implements Result { public Iterator iterator() { return new IteratorWrapper(result.iterator()) { protected R underlyingObjectToObject(T value) { - return resultConverter.convert(value, type); + return convert(value); } }; } @@ -138,4 +144,9 @@ public class QueryResultBuilder implements Result { public Iterator iterator() { return result.iterator(); } + + public Result with(MappingPolicy mappingPolicy) { + this.mappingPolicy = mappingPolicy; + return this; + } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/Result.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/Result.java index 162be74da..5e1c3429a 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/Result.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/Result.java @@ -16,6 +16,8 @@ package org.springframework.data.neo4j.conversion; +import org.springframework.data.neo4j.mapping.MappingPolicy; + /** * @author mh * @since 28.06.11 @@ -23,4 +25,6 @@ package org.springframework.data.neo4j.conversion; public interface Result extends EndResult { EndResult to(Class type); EndResult to(Class type, ResultConverter resultConverter); + Result with(MappingPolicy mappingPolicy); + } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/ResultConverter.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/ResultConverter.java index 7fd1371b9..c40518f95 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/ResultConverter.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/ResultConverter.java @@ -16,18 +16,26 @@ package org.springframework.data.neo4j.conversion; +import org.springframework.data.neo4j.mapping.MappingPolicy; + /** * @author mh * @since 28.06.11 */ public interface ResultConverter { R convert(T value, Class type); + R convert(T value, Class type, MappingPolicy mappingPolicy); - ResultConverter NO_OP_RESULT_CONVERTER = new ResultConverter() { + public class ResultConverterAdapter implements ResultConverter { @Override - public Object convert(Object value, Class type) { + public R convert(T value, Class type) { return null; } + + @Override + public R convert(T value, Class type, MappingPolicy mappingPolicy) { + return convert(value,type); + } }; } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/EntityState.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/EntityState.java index 04d7f59a6..0d70a67cc 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/EntityState.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/EntityState.java @@ -17,6 +17,7 @@ package org.springframework.data.neo4j.core; import org.springframework.data.neo4j.fieldaccess.FieldAccessor; +import org.springframework.data.neo4j.mapping.MappingPolicy; import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity; import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty; @@ -34,35 +35,39 @@ public interface EntityState { void setPersistentState(STATE state); /** - * @param field field of the entity class - * @return a default value for the given field by its {@link FieldAccessor} or {@code null} if none is provided. + * + * @param property@return a default value for the given field by its {@link FieldAccessor} or {@code null} if none is provided. */ - Object getDefaultImplementation(Field field); + Object getDefaultValue(Neo4jPersistentProperty property); - /** - * @param field - * @return value of the field either from the state and/or the entity - */ - Object getValue(Field field); - /** - * @return value of the property either from the state and/or the entity - */ - Object getValue(Neo4jPersistentProperty property); - - /** - * @param field - * @return true if the field can be written - */ - boolean isWritable(Field field); - /** + * + * @param field + * @param mappingPolicy + * @return value of the field either from the state and/or the entity + */ + Object getValue(Field field, MappingPolicy mappingPolicy); + /** + * @return value of the property either from the state and/or the entity + */ + Object getValue(Neo4jPersistentProperty property, MappingPolicy mappingPolicy); + + /** + * + * @param property@return true if the field can be written + */ + boolean isWritable(Neo4jPersistentProperty property); + + /** + * * * @param field * @param newVal + * @param mappingPolicy * @return sets the value in the entity and/or the state */ - Object setValue(Field field, Object newVal); - Object setValue(Neo4jPersistentProperty property, Object newVal); + Object setValue(Field field, Object newVal, MappingPolicy mappingPolicy); + Object setValue(Neo4jPersistentProperty property, Object newVal, MappingPolicy mappingPolicy); /** * callback for creating and initializing an initial state diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/AbstractNodeRelationshipFieldAccessor.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/AbstractNodeRelationshipFieldAccessor.java index 34d35dbdf..8db12bb53 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/AbstractNodeRelationshipFieldAccessor.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/AbstractNodeRelationshipFieldAccessor.java @@ -19,6 +19,7 @@ package org.springframework.data.neo4j.fieldaccess; import org.neo4j.graphdb.*; import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.data.neo4j.mapping.MappingPolicy; import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty; import org.springframework.data.neo4j.support.Neo4jTemplate; import org.springframework.util.Assert; @@ -45,6 +46,11 @@ public abstract class AbstractNodeRelationshipFieldAccessor ManagedFieldAccessorSet createManagedSet(Object entity, Set result) { - return new ManagedFieldAccessorSet(entity, result, property, template,this); + protected ManagedFieldAccessorSet createManagedSet(Object entity, Set result, MappingPolicy mappingPolicy) { + return new ManagedFieldAccessorSet(entity, result, property, template,this, mappingPolicy); } - protected Set createEntitySetFromRelationshipEndNodes(Object entity) { + protected Set createEntitySetFromRelationshipEndNodes(Object entity, final MappingPolicy mappingPolicy) { final Iterable nodes = getStatesFromEntity(entity); final Set result = new HashSet(); for (final TSTATE otherNode : nodes) { - Object target= template.createEntityFromState(otherNode, relatedType); + Object target= template.createEntityFromState(otherNode, relatedType, mappingPolicy); result.add(target); } return result; @@ -125,7 +131,7 @@ public abstract class AbstractNodeRelationshipFieldAccessor implements EntityState { protected final Object entity; - protected final Class type; + protected final Class type; private final Map fieldAccessors = new HashMap(); private final Map> fieldAccessorListeners = new HashMap>(); private STATE state; @@ -41,7 +42,7 @@ public abstract class DefaultEntityState implements EntityState { private final FieldAccessorFactoryProviders fieldAccessorFactoryProviders; protected final Neo4jPersistentEntity persistentEntity; - public DefaultEntityState(final STATE underlyingState, final Object entity, final Class type, final DelegatingFieldAccessorFactory delegatingFieldAccessorFactory, Neo4jPersistentEntity persistentEntity) { + public DefaultEntityState(final STATE underlyingState, final Object entity, final Class type, final DelegatingFieldAccessorFactory delegatingFieldAccessorFactory, Neo4jPersistentEntity persistentEntity) { this.state = underlyingState; this.entity = entity; this.type = type; @@ -83,43 +84,43 @@ public abstract class DefaultEntityState implements EntityState { } @Override - public boolean isWritable(Field field) { - final FieldAccessor accessor = accessorFor(property(field)); + public boolean isWritable(Neo4jPersistentProperty property) { + final FieldAccessor accessor = accessorFor(property); if (accessor == null) return true; return accessor.isWriteable(entity); } @Override - public Object getValue(final Neo4jPersistentProperty property) { + public Object getValue(final Neo4jPersistentProperty property, MappingPolicy mappingPolicy) { final FieldAccessor accessor = accessorFor(property); if (accessor == null) return null; - else return accessor.getValue(entity); + else return accessor.getValue(entity, mappingPolicy); } @Override - public Object getValue(final Field field) { - return getValue(property(field)); + public Object getValue(final Field field, MappingPolicy mappingPolicy) { + return getValue(property(field), mappingPolicy); } @Override - public Object setValue(final Field field, final Object newVal) { - return setValue(property(field),newVal); + public Object setValue(final Field field, final Object newVal, MappingPolicy mappingPolicy) { + return setValue(property(field),newVal, mappingPolicy); } @Override - public Object setValue(final Neo4jPersistentProperty property, final Object newVal) { + public Object setValue(final Neo4jPersistentProperty property, final Object newVal, MappingPolicy mappingPolicy) { final FieldAccessor accessor = accessorFor(property); - final Object result=accessor!=null ? accessor.setValue(entity, newVal) : newVal; + final Object result=accessor!=null ? accessor.setValue(entity, newVal, mappingPolicy) : newVal; notifyListeners(property, result); return result; } @Override - public Object getDefaultImplementation(Field field) { - final FieldAccessor accessor = accessorFor(property(field)); + public Object getDefaultValue(Neo4jPersistentProperty property) { + final FieldAccessor accessor = accessorFor(property); if (accessor == null) return null; - else return accessor.getDefaultImplementation(); + else return accessor.getDefaultValue(); } protected Neo4jPersistentProperty property(Field field) { @@ -140,6 +141,6 @@ public abstract class DefaultEntityState implements EntityState { protected Object getIdFromEntity() { final Neo4jPersistentProperty idProperty = fieldAccessorFactoryProviders.getIdProperty(); if (idProperty==null) return null; - return idProperty.getValue(entity); + return idProperty.getValue(entity, idProperty.getMappingPolicy()); } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/DetachedEntityState.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/DetachedEntityState.java index 4375eb2e5..2a16ff4eb 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/DetachedEntityState.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/DetachedEntityState.java @@ -20,6 +20,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.neo4j.graphdb.Transaction; import org.springframework.data.neo4j.core.EntityState; +import org.springframework.data.neo4j.mapping.MappingPolicy; import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity; import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty; import org.springframework.data.neo4j.support.Neo4jTemplate; @@ -37,7 +38,7 @@ import static org.springframework.data.neo4j.support.DoReturn.unwrap; * @since 15.09.2010 */ public class DetachedEntityState implements EntityState { - private final Map dirty = new HashMap(); + private final Map dirty = new HashMap(); protected final EntityState delegate; private final static Log log = LogFactory.getLog(DetachedEntityState.class); private Neo4jTemplate template; @@ -50,8 +51,8 @@ public class DetachedEntityState implements EntityState { } @Override - public boolean isWritable(final Field field) { - return delegate.isWritable(field); + public boolean isWritable(Neo4jPersistentProperty property) { + return delegate.isWritable(property); } @Override @@ -75,37 +76,33 @@ public class DetachedEntityState implements EntityState { } @Override - public Object getValue(Neo4jPersistentProperty property) { - return getValue(property.getField()); - } - - @Override - public Object getValue(final Field field) { + public Object getValue(Neo4jPersistentProperty property, MappingPolicy mappingPolicy) { + mappingPolicy = mappingPolicy == null ? property.getMappingPolicy() : mappingPolicy; if (isDetached()) { - if (template.getPersistentState(getEntity())==null || isDirty(field)) { - if (log.isDebugEnabled()) log.debug("Outside of transaction, GET value from field " + field); - Object entityValue = getValueFromEntity(field); + if (template.getPersistentState(getEntity())==null || isDirty(property)) { + if (log.isDebugEnabled()) log.debug("Outside of transaction, GET value from field " + property); + Object entityValue = getValueFromEntity(property, MappingPolicy.MAP_FIELD_DIRECT_POLICY); if (entityValue != null) { return entityValue; } - - Object defaultValue = getDefaultImplementation(field); + + Object defaultValue = getDefaultValue(property); if (defaultValue != null) { final Object entity = getEntity(); - try { - field.setAccessible(true); - field.set(entity, defaultValue); - addDirty(field, defaultValue, false); - } catch(IllegalAccessException e) { - throw new RuntimeException("Error setting default value for field " + field + " in " + entity.getClass(), e); - } + property.setValue(entity, defaultValue); + addDirty(property, defaultValue, false); } return defaultValue; } } else { // flushDirty(); } - return delegate.getValue(field); + return delegate.getValue(property, mappingPolicy); + } + + @Override + public Object getValue(final Field field, MappingPolicy mappingPolicy) { + return getValue(property(field), mappingPolicy); } protected boolean isDetached() { @@ -135,8 +132,8 @@ public class DetachedEntityState implements EntityState { } } @Override - public Object setValue(final Field field, final Object newVal) { - return setValue(property(field),newVal); + public Object setValue(final Field field, final Object newVal, MappingPolicy mappingPolicy) { + return setValue(property(field),newVal, mappingPolicy); } private Neo4jPersistentProperty property(Field field) { @@ -144,25 +141,24 @@ public class DetachedEntityState implements EntityState { } @Override - public Object setValue(final Neo4jPersistentProperty property, final Object newVal) { + public Object setValue(final Neo4jPersistentProperty property, final Object newVal, MappingPolicy mappingPolicy) { if (isDetached()) { - final Field field = property.getField(); - if (!isDirty(field) && isWritable(field)) { + if (!isDirty(property) && isWritable(property)) { if (hasPersistentState()) { - addDirty(field, unwrap(delegate.getValue(field)), true); + addDirty(property, unwrap(delegate.getValue(property, MappingPolicy.MAP_FIELD_DIRECT_POLICY)), true); } else { - addDirty(field, newVal, false); + addDirty(property, newVal, false); } } return newVal; } // flushDirty(); - return delegate.setValue(property, newVal); + return delegate.setValue(property, newVal, mappingPolicy); } @Override - public Object getDefaultImplementation(Field field) { - return delegate.getDefaultImplementation(field); + public Object getDefaultValue(Neo4jPersistentProperty property) { + return delegate.getDefaultValue(property); } private Object getDefaultValue(final Class type) { if (type.isPrimitive()) { @@ -193,15 +189,16 @@ public class DetachedEntityState implements EntityState { } if (isDirty()) { - final Map dirtyCopy = new HashMap(dirty); + final Map dirtyCopy = new HashMap(dirty); clearDirty(); - for (final Map.Entry entry : dirtyCopy.entrySet()) { - final Field field = entry.getKey(); - Object valueFromEntity = getValueFromEntity(field); + for (final Map.Entry entry : dirtyCopy.entrySet()) { + final Neo4jPersistentProperty property = entry.getKey(); + final MappingPolicy mappingPolicy = property.getMappingPolicy(); + Object valueFromEntity = getValueFromEntity(property, MappingPolicy.MAP_FIELD_DIRECT_POLICY); cascadePersist(valueFromEntity); - if (log.isDebugEnabled()) log.debug("Flushing dirty Entity new node " + entity + " field " + field+ " with value "+ valueFromEntity); - checkConcurrentModification(entity, entry, field); - delegate.setValue(field, valueFromEntity); + if (log.isDebugEnabled()) log.debug("Flushing dirty Entity new node " + entity + " field " + property+ " with value "+ valueFromEntity); + checkConcurrentModification(entity, entry, property, mappingPolicy); + delegate.setValue(property, valueFromEntity, mappingPolicy); } } } @@ -227,22 +224,17 @@ public class DetachedEntityState implements EntityState { } - private Object getValueFromEntity(final Field field) { + private Object getValueFromEntity(final Neo4jPersistentProperty property, MappingPolicy mappingPolicy) { final Object entity = getEntity(); - try { - field.setAccessible(true); - return field.get(entity); - } catch (IllegalAccessException e) { - throw new RuntimeException("Error accessing field " + field + " in " + entity.getClass(), e); - } + return property.getValue(entity, mappingPolicy); } - private void checkConcurrentModification(final Object entity, final Map.Entry entry, final Field field) { + private void checkConcurrentModification(final Object entity, final Map.Entry entry, final Neo4jPersistentProperty property, final MappingPolicy mappingPolicy) { final ExistingValue previousValue = entry.getValue(); if (previousValue.mustCheckConcurrentModification()) { - final Object nodeValue = unwrap(delegate.getValue(field)); + final Object nodeValue = unwrap(delegate.getValue(property, mappingPolicy)); if (!ObjectUtils.nullSafeEquals(nodeValue, previousValue.value)) { - throw new ConcurrentModificationException("Node " + entity + " field " + field + " changed in between previous " + previousValue + " current " + nodeValue); // todo or just overwrite + throw new ConcurrentModificationException("Node " + entity + " field " + property + " changed in between previous " + previousValue + " current " + nodeValue); // todo or just overwrite } } } @@ -251,8 +243,8 @@ public class DetachedEntityState implements EntityState { return !this.dirty.isEmpty(); } - private boolean isDirty(final Field f) { - return this.dirty.containsKey(f); + private boolean isDirty(final Neo4jPersistentProperty property) { + return this.dirty.containsKey(property); } private void clearDirty() { @@ -263,8 +255,8 @@ public class DetachedEntityState implements EntityState { this.dirty.remove(f); } - private void addDirty(final Field f, final Object previousValue, boolean fromGraph) { - this.dirty.put(f, new ExistingValue(previousValue,fromGraph)); + private void addDirty(final Neo4jPersistentProperty property, final Object previousValue, boolean fromGraph) { + this.dirty.put(property, new ExistingValue(previousValue,fromGraph)); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/DynamicPropertiesFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/DynamicPropertiesFieldAccessorFactory.java index 8b99b6108..13d0b4341 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/DynamicPropertiesFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/DynamicPropertiesFieldAccessorFactory.java @@ -15,16 +15,16 @@ */ package org.springframework.data.neo4j.fieldaccess; -import java.util.HashSet; -import java.util.Set; - import org.neo4j.graphdb.PropertyContainer; import org.neo4j.helpers.collection.IteratorUtil; - +import org.springframework.data.neo4j.mapping.MappingPolicy; import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty; import org.springframework.data.neo4j.support.DoReturn; import org.springframework.data.neo4j.support.Neo4jTemplate; +import java.util.HashSet; +import java.util.Set; + /** * This accessor factory creates {@link DynamicPropertiesFieldAccessor}s for @NodeEntity properties of type * {@link DynamicProperties}. @@ -60,7 +60,7 @@ public class DynamicPropertiesFieldAccessorFactory implements FieldAccessorFacto } @Override - public Object setValue(final Object entity, final Object newVal) { + public Object setValue(final Object entity, final Object newVal, MappingPolicy mappingPolicy) { final PropertyContainer propertyContainer = template.getPersistentState(entity); PrefixedDynamicProperties dynamicProperties; if (newVal instanceof ManagedPrefixedDynamicProperties) { @@ -106,9 +106,9 @@ public class DynamicPropertiesFieldAccessorFactory implements FieldAccessorFacto } @Override - public Object getValue(final Object entity) { + public Object getValue(final Object entity, MappingPolicy mappingPolicy) { PropertyContainer element = template.getPersistentState(entity); - ManagedPrefixedDynamicProperties props = ManagedPrefixedDynamicProperties.create(propertyNamePrefix, field, entity, template,this); + ManagedPrefixedDynamicProperties props = ManagedPrefixedDynamicProperties.create(propertyNamePrefix, field, entity, template,this, field.getMappingPolicy()); for (String key : element.getPropertyKeys()) { props.setPropertyIfPrefixed(key, element.getProperty(key)); } @@ -121,7 +121,7 @@ public class DynamicPropertiesFieldAccessorFactory implements FieldAccessorFacto } @Override - public Object getDefaultImplementation() { + public Object getDefaultValue() { return new DynamicPropertiesContainer(); } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/FieldAccessor.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/FieldAccessor.java index 69f25338d..418f0fd4c 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/FieldAccessor.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/FieldAccessor.java @@ -16,6 +16,8 @@ package org.springframework.data.neo4j.fieldaccess; +import org.springframework.data.neo4j.mapping.MappingPolicy; + /** * interface for field accessors, encapsulates reading and writing from fields and write support information about the field. * It is used by the {@link org.springframework.data.neo4j.core.EntityState}. @@ -29,23 +31,27 @@ public interface FieldAccessor { * when the value of the field is get. * @return a default implementation for a field or {@code null} if none is provided. */ - Object getDefaultImplementation(); + Object getDefaultValue(); /** * handles field write modification. + * * @param entity * @param newVal + * @param mappingPolicy * @return the written value or a DoReturn wrapper with the written value or null. * DoReturn indicates that the aspect should not proceed to the original field access but instead return immediately. */ - Object setValue(Object entity, Object newVal); + Object setValue(Object entity, Object newVal, MappingPolicy mappingPolicy); /** + * * @param entity + * @param mappingPolicy * @return the value or a DoReturn wrapper with the value for the field. * DoReturn indicates that the aspect should not proceed to the original field access but instead return immediately. */ - Object getValue(Object entity); + Object getValue(Object entity, MappingPolicy mappingPolicy); /** * @param entity diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/GraphBackedEntityIterableWrapper.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/GraphBackedEntityIterableWrapper.java index d17686bea..3b93c5e1e 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/GraphBackedEntityIterableWrapper.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/GraphBackedEntityIterableWrapper.java @@ -35,7 +35,7 @@ public class GraphBackedEntityIterableWrapper GraphBackedEntityIterableWrapper create( diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/IdFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/IdFieldAccessorFactory.java index 3790586ff..1120c25ae 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/IdFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/IdFieldAccessorFactory.java @@ -21,6 +21,7 @@ import org.neo4j.graphdb.Node; import org.neo4j.graphdb.PropertyContainer; import org.neo4j.graphdb.Relationship; import org.springframework.data.mapping.model.MappingException; +import org.springframework.data.neo4j.mapping.MappingPolicy; import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty; import org.springframework.data.neo4j.support.Neo4jTemplate; @@ -62,12 +63,12 @@ public class IdFieldAccessorFactory implements FieldAccessorFactory { } @Override - public Object setValue(final Object entity, final Object newVal) { + public Object setValue(final Object entity, final Object newVal, MappingPolicy mappingPolicy) { return newVal; } @Override - public Object getValue(final Object entity) { + public Object getValue(final Object entity, MappingPolicy mappingPolicy) { final PropertyContainer state = template.getPersistentState(entity); if (state instanceof Node) { return doReturn(((Node)state).getId()); @@ -79,7 +80,7 @@ public class IdFieldAccessorFactory implements FieldAccessorFactory { } @Override - public Object getDefaultImplementation() { + public Object getDefaultValue() { return null; } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedFieldAccessorSet.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedFieldAccessorSet.java index 657884383..fe52dfdc8 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedFieldAccessorSet.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedFieldAccessorSet.java @@ -17,6 +17,7 @@ package org.springframework.data.neo4j.fieldaccess; import org.springframework.data.neo4j.core.EntityState; +import org.springframework.data.neo4j.mapping.MappingPolicy; import org.springframework.data.neo4j.mapping.ManagedEntity; import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty; import org.springframework.data.neo4j.support.DoReturn; @@ -36,15 +37,17 @@ public class ManagedFieldAccessorSet extends AbstractSet { private final Neo4jPersistentProperty property; private final Neo4jTemplate ctx; private final FieldAccessor fieldAccessor; + private final MappingPolicy mappingPolicy; @SuppressWarnings("unchecked") - public ManagedFieldAccessorSet(final Object entity, final Object newVal, final Neo4jPersistentProperty property, Neo4jTemplate ctx, FieldAccessor fieldAccessor) { + public ManagedFieldAccessorSet(final Object entity, final Object newVal, final Neo4jPersistentProperty property, Neo4jTemplate ctx, FieldAccessor fieldAccessor, final MappingPolicy mappingPolicy) { this.entity = entity; this.property = property; this.ctx = ctx; this.fieldAccessor = fieldAccessor; delegate = (Set) newVal; - } + this.mappingPolicy = mappingPolicy; + } @Override public Iterator iterator() { @@ -77,14 +80,14 @@ public class ManagedFieldAccessorSet extends AbstractSet { } private Object updateValueWithState(EntityState entityState) { - final Object newValue = entityState.setValue(property, delegate); + final Object newValue = entityState.setValue(property, delegate, mappingPolicy); if (newValue instanceof DoReturn) return DoReturn.unwrap(newValue); property.setValue(entity, newValue); return newValue; } private Object updateValue() { - final Object newValue = fieldAccessor.setValue(entity,delegate); + final Object newValue = fieldAccessor.setValue(entity,delegate, mappingPolicy); if (newValue instanceof DoReturn) return DoReturn.unwrap(newValue); property.setValue(entity, newValue); return newValue; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedPrefixedDynamicProperties.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedPrefixedDynamicProperties.java index fac6f968b..75d90e10d 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedPrefixedDynamicProperties.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedPrefixedDynamicProperties.java @@ -16,6 +16,7 @@ package org.springframework.data.neo4j.fieldaccess; import org.springframework.data.neo4j.core.EntityState; +import org.springframework.data.neo4j.mapping.MappingPolicy; import org.springframework.data.neo4j.mapping.ManagedEntity; import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty; import org.springframework.data.neo4j.support.DoReturn; @@ -33,22 +34,24 @@ public class ManagedPrefixedDynamicProperties extends PrefixedDynamicProperties private final FieldAccessor fieldAccessor; private final Neo4jPersistentProperty property; private boolean isNode; + private MappingPolicy mappingPolicy; - public ManagedPrefixedDynamicProperties(String prefix, final Neo4jPersistentProperty property, final Object entity, Neo4jTemplate template, FieldAccessor fieldAccessor) { - this(prefix,10,property,entity, template,fieldAccessor); + public ManagedPrefixedDynamicProperties(String prefix, final Neo4jPersistentProperty property, final Object entity, Neo4jTemplate template, FieldAccessor fieldAccessor, final MappingPolicy mappingPolicy) { + this(prefix,10,property,entity, template,fieldAccessor, mappingPolicy); } - public ManagedPrefixedDynamicProperties(String prefix, int initialCapacity, final Neo4jPersistentProperty property, final Object entity, Neo4jTemplate template, FieldAccessor fieldAccessor) { + public ManagedPrefixedDynamicProperties(String prefix, int initialCapacity, final Neo4jPersistentProperty property, final Object entity, Neo4jTemplate template, FieldAccessor fieldAccessor, final MappingPolicy mappingPolicy) { super(prefix, initialCapacity); this.property = property; this.entity = entity; this.template = template; this.fieldAccessor = fieldAccessor; this.isNode = property.getOwner().isNodeEntity(); + this.mappingPolicy = mappingPolicy; } - public static ManagedPrefixedDynamicProperties create(String prefix, final Neo4jPersistentProperty property, final Object entity, Neo4jTemplate template, FieldAccessor fieldAccessor) { - return new ManagedPrefixedDynamicProperties(prefix, property, entity, template,fieldAccessor); + public static ManagedPrefixedDynamicProperties create(String prefix, final Neo4jPersistentProperty property, final Object entity, Neo4jTemplate template, FieldAccessor fieldAccessor, final MappingPolicy mappingPolicy) { + return new ManagedPrefixedDynamicProperties(prefix, property, entity, template,fieldAccessor, mappingPolicy); } @Override @@ -72,13 +75,13 @@ public class ManagedPrefixedDynamicProperties extends PrefixedDynamicProperties @Override public DynamicProperties createFrom(Map map) { - DynamicProperties d = new ManagedPrefixedDynamicProperties(prefix, map.size(), property, entity, template,fieldAccessor); + DynamicProperties d = new ManagedPrefixedDynamicProperties(prefix, map.size(), property, entity, template,fieldAccessor, property.getMappingPolicy()); d.setPropertiesFrom(map); return d; } private Object updateValue() { - final Object newValue = fieldAccessor.setValue(entity, this); + final Object newValue = fieldAccessor.setValue(entity, this, mappingPolicy); if (newValue instanceof DoReturn) return DoReturn.unwrap(newValue); property.setValue(entity, newValue); @@ -94,7 +97,7 @@ public class ManagedPrefixedDynamicProperties extends PrefixedDynamicProperties } private Object updateValueWithState(EntityState entityState) { - final Object newValue = entityState.setValue(property, this); + final Object newValue = entityState.setValue(property, this, mappingPolicy); if (newValue instanceof DoReturn) return DoReturn.unwrap(newValue); property.setValue(entity, newValue); return newValue; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessorFactory.java index adfca13f0..081f3b019 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessorFactory.java @@ -22,10 +22,7 @@ import org.neo4j.graphdb.Relationship; import org.neo4j.graphdb.RelationshipType; import org.neo4j.helpers.collection.IteratorUtil; import org.springframework.dao.InvalidDataAccessApiUsageException; -import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity; -import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty; -import org.springframework.data.neo4j.mapping.RelationshipInfo; -import org.springframework.data.neo4j.mapping.RelationshipProperties; +import org.springframework.data.neo4j.mapping.*; import org.springframework.data.neo4j.support.Neo4jTemplate; import java.util.HashMap; @@ -65,7 +62,7 @@ public class OneToNRelationshipEntityFieldAccessorFactory implements FieldAccess } @Override - public Object setValue(final Object entity, final Object newVal) { + public Object setValue(final Object entity, final Object newVal, MappingPolicy mappingPolicy) { if (!isEditableSet) throw new InvalidDataAccessApiUsageException("Cannot set read-only relationship entity field."); final Node startNode = checkUnderlyingState(entity); if (newVal == null) { @@ -75,7 +72,7 @@ public class OneToNRelationshipEntityFieldAccessorFactory implements FieldAccess removeMissingRelationships(startNode, targetNodes.keySet()); //createAddedRelationships(startNode, targetNodes.keySet()); persistEntities(targetNodes); - return createManagedSet(entity, (Set) newVal); + return createManagedSet(entity, (Set) newVal, updateMappingPolicy(mappingPolicy)); } private void persistEntities(Map targetNodes) { @@ -95,11 +92,14 @@ public class OneToNRelationshipEntityFieldAccessorFactory implements FieldAccess } Neo4jPersistentEntity relationshipPEntity = property.getRelationshipInfo().getTargetEntity(); final RelationshipProperties relationshipProperties = relationshipPEntity.getRelationshipProperties(); - final Node endNode = getState(relationshipProperties.getEndeNodeProperty().getValue(entry)); + final Neo4jPersistentProperty endNodeProperty = relationshipProperties.getEndNodeProperty(); + final Object endNodeEntity = endNodeProperty.getValue(entry, endNodeProperty.getMappingPolicy()); + final Node endNode = getState(endNodeEntity); if (!endNode.equals(startNode)) { targetNodes.put(endNode, entry); } else { - final Node otherNode = getState(relationshipProperties.getStartNodeProperty().getValue(entry)); + final Neo4jPersistentProperty startNodeProperty = relationshipProperties.getStartNodeProperty(); + final Node otherNode = getState(startNodeProperty.getValue(entry, startNodeProperty.getMappingPolicy())); targetNodes.put(otherNode, entry); } } @@ -112,11 +112,11 @@ public class OneToNRelationshipEntityFieldAccessorFactory implements FieldAccess } @Override - public Object getValue(final Object entity) { + public Object getValue(final Object entity, MappingPolicy mappingPolicy) { checkUnderlyingState(entity); final GraphBackedEntityIterableWrapper result = iterableFrom(entity); if (isEditableSet) { - @SuppressWarnings("unchecked") final ManagedFieldAccessorSet managedSet = createManagedSet(entity, IteratorUtil.addToCollection(result, new HashSet())); + @SuppressWarnings("unchecked") final ManagedFieldAccessorSet managedSet = createManagedSet(entity, IteratorUtil.addToCollection(result, new HashSet()), updateMappingPolicy(mappingPolicy)); return doReturn(managedSet); } return doReturn(result); diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipFieldAccessorFactory.java index 8caeb6992..5a6b8ad6d 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipFieldAccessorFactory.java @@ -19,6 +19,7 @@ package org.springframework.data.neo4j.fieldaccess; import org.neo4j.graphdb.Direction; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.RelationshipType; +import org.springframework.data.neo4j.mapping.MappingPolicy; import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty; import org.springframework.data.neo4j.mapping.RelationshipInfo; import org.springframework.data.neo4j.support.Neo4jTemplate; @@ -54,7 +55,7 @@ public class OneToNRelationshipFieldAccessorFactory extends NodeRelationshipFiel super(elementClass, template, direction, type,property); } - public Object setValue(final Object entity, final Object newVal) { + public Object setValue(final Object entity, final Object newVal, MappingPolicy mappingPolicy) { final Node node = checkUnderlyingState(entity); if (newVal == null) { /* null should not remove existing relationships but leave them alone @@ -65,18 +66,19 @@ public class OneToNRelationshipFieldAccessorFactory extends NodeRelationshipFiel final Set targetNodes = createSetOfTargetNodes(newVal); removeMissingRelationships(node, targetNodes); createAddedRelationships(node, targetNodes); - return createManagedSet(entity, (Set) newVal); + return createManagedSet(entity, (Set) newVal, updateMappingPolicy(mappingPolicy)); } @Override - public Object getValue(final Object entity) { + public Object getValue(final Object entity, MappingPolicy mappingPolicy) { checkUnderlyingState(entity); - final Set result = createEntitySetFromRelationshipEndNodes(entity); - return doReturn(createManagedSet(entity, result)); + final MappingPolicy currentPolicy = updateMappingPolicy(mappingPolicy); + final Set result = createEntitySetFromRelationshipEndNodes(entity, currentPolicy); + return doReturn(createManagedSet(entity, result, currentPolicy)); } @Override - public Object getDefaultImplementation() { + public Object getDefaultValue() { return new HashSet(); } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/PropertyFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/PropertyFieldAccessorFactory.java index 913048fd0..43b3b7146 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/PropertyFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/PropertyFieldAccessorFactory.java @@ -18,6 +18,7 @@ package org.springframework.data.neo4j.fieldaccess; import org.neo4j.graphdb.PropertyContainer; +import org.springframework.data.neo4j.mapping.MappingPolicy; import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty; import org.springframework.data.neo4j.support.Neo4jTemplate; @@ -64,7 +65,7 @@ public class PropertyFieldAccessorFactory implements FieldAccessorFactory { } @Override - public Object setValue(final Object entity, final Object newVal) { + public Object setValue(final Object entity, final Object newVal, MappingPolicy mappingPolicy) { final PropertyContainer propertyContainer = template.getPersistentState(entity); if (newVal==null) { propertyContainer.removeProperty(propertyName); @@ -75,7 +76,7 @@ public class PropertyFieldAccessorFactory implements FieldAccessorFactory { } @Override - public final Object getValue(final Object entity) { + public final Object getValue(final Object entity, MappingPolicy mappingPolicy) { return doReturn(doGetValue(entity)); } @@ -105,7 +106,7 @@ public class PropertyFieldAccessorFactory implements FieldAccessorFactory { } @Override - public Object getDefaultImplementation() { + public Object getDefaultValue() { return null; } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/QueryFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/QueryFieldAccessorFactory.java index 9be5c481d..47b16d4c6 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/QueryFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/QueryFieldAccessorFactory.java @@ -20,8 +20,13 @@ import org.neo4j.graphdb.Node; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.neo4j.annotation.Query; +import org.springframework.data.neo4j.annotation.QueryType; +import org.springframework.data.neo4j.conversion.Result; +import org.springframework.data.neo4j.mapping.MappingPolicy; import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty; import org.springframework.data.neo4j.support.Neo4jTemplate; +import org.springframework.data.neo4j.support.query.QueryEngine; +import org.springframework.data.util.TypeInformation; import java.util.HashMap; import java.util.Map; @@ -58,6 +63,7 @@ public class QueryFieldAccessorFactory implements FieldAccessorFactory { private Class target; protected String[] annotationParams; private boolean iterableResult; + private final QueryEngine queryEngine; public QueryFieldAccessor(final Neo4jPersistentProperty property, Neo4jTemplate template) { this.property = property; @@ -70,6 +76,7 @@ public class QueryFieldAccessorFactory implements FieldAccessorFactory { this.query = query.value(); this.iterableResult = Iterable.class.isAssignableFrom(property.getType()); this.target = resolveTarget(query,property); + queryEngine = this.template.queryEngineFor(QueryType.Cypher); } private Class resolveTarget(Query query, Neo4jPersistentProperty property) { @@ -83,17 +90,27 @@ public class QueryFieldAccessorFactory implements FieldAccessorFactory { } @Override - public Object setValue(final Object entity, final Object newVal) { + public Object setValue(final Object entity, final Object newVal, MappingPolicy mappingPolicy) { throw new InvalidDataAccessApiUsageException("Cannot set readonly query field " + property); } @Override - public Object getValue(final Object entity) { - return doReturn(executeQuery(entity, this.query, createPlaceholderParams(entity))); + public Object getValue(final Object entity, MappingPolicy mappingPolicy) { + return doReturn(executeQuery(entity, this.query, createPlaceholderParams(entity),mappingPolicy)); } - private Object executeQuery(Object entity, String queryString, Map params) { - return template.query(queryString, params, property.getTypeInformation()); + private Object executeQuery(Object entity, String queryString, Map params, MappingPolicy mappingPolicy) { + final TypeInformation typeInformation = property.getTypeInformation(); + final TypeInformation actualType = typeInformation.getActualType(); + final Class targetType = actualType.getType(); + final Result result = queryEngine.query(queryString, params).with(mappingPolicy); + if (actualType.isMap()) { + return result; + } + if (typeInformation.isCollectionLike()) { + return result.to(targetType); + } + return result.to(targetType).single(); } private Map createPlaceholderParams(Object entity) { @@ -108,7 +125,7 @@ public class QueryFieldAccessorFactory implements FieldAccessorFactory { } @Override - public Object getDefaultImplementation() { + public Object getDefaultValue() { return null; } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ReadOnlyOneToNRelationshipFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ReadOnlyOneToNRelationshipFieldAccessorFactory.java index 1be69f211..39e55cfff 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ReadOnlyOneToNRelationshipFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ReadOnlyOneToNRelationshipFieldAccessorFactory.java @@ -20,6 +20,7 @@ import org.neo4j.graphdb.Direction; import org.neo4j.graphdb.RelationshipType; import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.data.neo4j.mapping.MappingPolicy; import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty; import org.springframework.data.neo4j.mapping.RelationshipInfo; import org.springframework.data.neo4j.support.Neo4jTemplate; @@ -54,7 +55,7 @@ public class ReadOnlyOneToNRelationshipFieldAccessorFactory extends NodeRelation return false; } - public Object setValue(final Object entity, final Object newVal) { + public Object setValue(final Object entity, final Object newVal, MappingPolicy mappingPolicy) { throw new InvalidDataAccessApiUsageException("Cannot set read-only relationship entity field."); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/RelationshipNodeFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/RelationshipNodeFieldAccessorFactory.java index 7964c2e89..fe86f8a5d 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/RelationshipNodeFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/RelationshipNodeFieldAccessorFactory.java @@ -23,6 +23,7 @@ import org.springframework.data.neo4j.annotation.EndNode; import org.springframework.data.neo4j.annotation.StartNode; +import org.springframework.data.neo4j.mapping.MappingPolicy; import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty; import org.springframework.data.neo4j.support.Neo4jTemplate; @@ -87,18 +88,18 @@ public class RelationshipNodeFieldAccessorFactory implements FieldAccessorFactor } @Override - public Object setValue(final Object entity, final Object newVal) { + public Object setValue(final Object entity, final Object newVal, MappingPolicy mappingPolicy) { throw new InvalidDataAccessApiUsageException("Cannot change start or end node of existing relationship."); } @Override - public Object getValue(final Object entity) { + public Object getValue(final Object entity, MappingPolicy mappingPolicy) { final Relationship relationship = template.getPersistentState(entity); final Node node = getNode(relationship); if (node == null) { return null; } - final Object result = template.createEntityFromState(node, (Class) property.getType()); + final Object result = template.createEntityFromState(node, (Class) property.getType(), mappingPolicy); return doReturn(result); } @@ -110,7 +111,7 @@ public class RelationshipNodeFieldAccessorFactory implements FieldAccessorFactor } @Override - public Object getDefaultImplementation() { + public Object getDefaultValue() { return null; } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/SingleRelationshipFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/SingleRelationshipFieldAccessorFactory.java index c45de1233..6c52fc1a0 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/SingleRelationshipFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/SingleRelationshipFieldAccessorFactory.java @@ -20,6 +20,7 @@ import org.neo4j.graphdb.Direction; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.RelationshipType; +import org.springframework.data.neo4j.mapping.MappingPolicy; import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty; import org.springframework.data.neo4j.mapping.RelationshipInfo; import org.springframework.data.neo4j.support.Neo4jTemplate; @@ -52,7 +53,7 @@ public class SingleRelationshipFieldAccessorFactory extends NodeRelationshipFiel } @Override - public Object setValue(final Object entity, final Object newVal) { + public Object setValue(final Object entity, final Object newVal, MappingPolicy mappingPolicy) { final Node node= checkUnderlyingState(entity); if (newVal == null) { removeMissingRelationships(node, Collections.emptySet()); @@ -65,9 +66,9 @@ public class SingleRelationshipFieldAccessorFactory extends NodeRelationshipFiel } @Override - public Object getValue(final Object entity) { + public Object getValue(final Object entity, MappingPolicy mappingPolicy) { checkUnderlyingState(entity); - final Set result = createEntitySetFromRelationshipEndNodes(entity); + final Set result = createEntitySetFromRelationshipEndNodes(entity, updateMappingPolicy(mappingPolicy)); final Object singleEntity = result.isEmpty() ? null : result.iterator().next(); return doReturn(singleEntity); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/TransientFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/TransientFieldAccessorFactory.java index af4b34c03..392a2547f 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/TransientFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/TransientFieldAccessorFactory.java @@ -16,14 +16,13 @@ package org.springframework.data.neo4j.fieldaccess; -import org.neo4j.graphdb.PropertyContainer; - +import org.springframework.data.neo4j.mapping.MappingPolicy; import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty; public class TransientFieldAccessorFactory implements FieldAccessorFactory { @Override public boolean accept(final Neo4jPersistentProperty property) { - return property.isTransient(); + return property.isReallyTransient(); } @Override @@ -43,7 +42,7 @@ public class TransientFieldAccessorFactory implements FieldAccessorFactory { } @Override - public Object setValue(final Object entity, final Object newVal) { + public Object setValue(final Object entity, final Object newVal, MappingPolicy mappingPolicy) { return newVal; } @@ -53,12 +52,12 @@ public class TransientFieldAccessorFactory implements FieldAccessorFactory { } @Override - public Object getValue(final Object entity) { + public Object getValue(final Object entity, MappingPolicy mappingPolicy) { return null; } @Override - public Object getDefaultImplementation() { + public Object getDefaultValue() { return null; } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/TraversalFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/TraversalFieldAccessorFactory.java index 4eae5e582..e6e573a46 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/TraversalFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/TraversalFieldAccessorFactory.java @@ -25,6 +25,7 @@ import org.springframework.data.neo4j.annotation.GraphTraversal; import org.springframework.data.neo4j.core.FieldTraversalDescriptionBuilder; +import org.springframework.data.neo4j.mapping.MappingPolicy; import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty; import org.springframework.data.neo4j.support.Neo4jTemplate; @@ -97,12 +98,12 @@ public class TraversalFieldAccessorFactory implements FieldAccessorFactory { } @Override - public Object setValue(final Object entity, final Object newVal) { + public Object setValue(final Object entity, final Object newVal, MappingPolicy mappingPolicy) { throw new InvalidDataAccessApiUsageException("Cannot set readonly traversal description field " + property); } @Override - public Object getValue(final Object entity) { + public Object getValue(final Object entity, MappingPolicy mappingPolicy) { final TraversalDescription traversalDescription = fieldTraversalDescriptionBuilder.build(entity, property,params); return doReturn(template.traverse(entity, target, traversalDescription)); } @@ -120,7 +121,7 @@ public class TraversalFieldAccessorFactory implements FieldAccessorFactory { } @Override - public Object getDefaultImplementation() { + public Object getDefaultValue() { return null; } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/EntityInstantiator.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/EntityInstantiator.java index 60550e49b..5efe2f96d 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/EntityInstantiator.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/EntityInstantiator.java @@ -39,6 +39,6 @@ public interface EntityInstantiator { * code to instantiate entities without invoking a constructor. */ - T createEntityFromState(STATE s, Class c); + T createEntityFromState(STATE s, Class c, final MappingPolicy mappingPolicy); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/EntityPersister.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/EntityPersister.java index 923771b3e..96053c0fa 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/EntityPersister.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/EntityPersister.java @@ -24,8 +24,10 @@ import org.neo4j.graphdb.PropertyContainer; public interface EntityPersister { T projectTo(Object entity, Class targetType); - T createEntityFromState(S state, Class type); - T createEntityFromStoredType(S state); + T projectTo(Object entity, Class targetType, MappingPolicy mappingPolicy); + T createEntityFromState(S state, Class type, MappingPolicy mappingPolicy); + T createEntityFromStoredType(S state, MappingPolicy mappingPolicy); boolean isNodeEntity(Class targetType); boolean isRelationshipEntity(Class targetType); + MappingPolicy getMappingPolicy(Class targetType); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/MappingPolicy.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/MappingPolicy.java new file mode 100644 index 000000000..3c645f670 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/MappingPolicy.java @@ -0,0 +1,106 @@ +/** + * 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 java.util.*; + +import static java.util.Arrays.asList; + +/** + * @author mh + * @since 09.11.11 + */ +public interface MappingPolicy { + + enum Option { + FIELD_DIRECT, SHOULD_LOAD + } + boolean accessField(); + boolean shouldLoad(); + MappingPolicy combineWith(MappingPolicy mappingPolicy); + + public class DefaultMappingPolicy implements MappingPolicy { + private Set