mapping policy is provided through all method calls

This commit is contained in:
Michael Hunger
2011-11-09 23:24:32 +01:00
parent a279b7d4a2
commit 71257fc564
78 changed files with 915 additions and 511 deletions

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -129,7 +129,7 @@ public class IndexTest extends EntityTestBase {
group.setIndexLevelName("indexLevelNameValue");
Index<Node> 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);
}

View File

@@ -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<Person> finder = neo4jTemplate.repositoryFor(Person.class);

View File

@@ -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"));
}

View File

@@ -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<String> result = IteratorUtil.asCollection(queryEngine.query(queryString, michaelsName()).to(String.class, new ResultConverter<Map<String, Object>, String>() {
final Collection<String> result = IteratorUtil.asCollection(queryEngine.query(queryString, michaelsName()).to(String.class, new ResultConverter.ResultConverterAdapter<Map<String, Object>, String>() {
@Override
public String convert(Map<String, Object> row, Class<String> target) {
return (String) ((Node) row.get("boss")).getProperty("name");

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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<Node
* this node is created by the original {@link org.springframework.data.neo4j.mapping.EntityInstantiator}.
* @param n Node to instantiate an entity for
* @param entityClass type of the entity
* @param mappingPolicy
* @param <T> generic type of the entity
* @return
*/
public <T> T createEntityFromState(Node n, Class<T> entityClass) {
public <T> T createEntityFromState(Node n, Class<T> 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() {

View File

@@ -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<ENTITY extends NodeBacked> 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);
}

View File

@@ -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";

View File

@@ -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";

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -47,5 +47,4 @@ class SpringEndResult<R> implements EndResult<R> {
public Iterator<R> iterator() {
return result.iterator();
}
}

View File

@@ -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<T> implements Result<T> {
org.neo4j.rest.graphdb.util.QueryResult<T> queryResult;
private MappingPolicy mappingPolicy;
SpringRestResult(org.neo4j.rest.graphdb.util.QueryResult<T> queryResult) {
this.queryResult = queryResult;
@@ -39,7 +41,7 @@ class SpringRestResult<T> implements Result<T> {
ConvertedResult<R> result = queryResult.to(type, new ResultConverter<T, R>() {
@Override
public R convert(T value, Class<R> type) {
return converter.convert(value,type);
return converter.convert(value,type,mappingPolicy);
}
});
return new SpringEndResult<R>(result);
@@ -66,4 +68,10 @@ class SpringRestResult<T> implements Result<T> {
public T single() {
return (T) to(Object.class).single();
}
@Override
public Result<T> with(MappingPolicy mappingPolicy) {
this.mappingPolicy = mappingPolicy;
return this;
}
}

View File

@@ -67,7 +67,7 @@ public class TestServerPlugin extends ServerPlugin {
@PluginTarget(Node.class)
public Iterable<Node> 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<Node, Friendship>(person.getFriendships()) {
@Override
protected Node underlyingObjectToObject(Friendship friendship) {

View File

@@ -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<T,R> implements ResultConverter<T,R> {
@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<T,R> implements ResultConverter<T,R> {
}
@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);
}

View File

@@ -24,5 +24,4 @@ public interface EndResult<R> extends Iterable<R> {
R single();
R singleOrNull();
void handle(Handler<R> handler);
}

View File

@@ -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<T> implements ResultConverter<Map<String, Ob
this.template = template;
}
@SuppressWarnings("unchecked")
@Override
public T convert(Map<String, Object> value, Class<T> 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<String, Object> value, Class<T> type) {
final Map<String, Object> 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<Object> 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);
}
}

View File

@@ -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<T> implements Result<T> {
private final ResultConverter defaultConverter;
private final boolean isClosableIterable;
private boolean isClosed;
private MappingPolicy mappingPolicy;
@SuppressWarnings("unchecked")
public QueryResultBuilder(Iterable<T> result) {
@@ -74,7 +76,7 @@ public class QueryResultBuilder<T> implements Result<T> {
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<T> implements Result<T> {
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<R> 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<T> implements Result<T> {
public Iterator<R> iterator() {
return new IteratorWrapper<R, T>(result.iterator()) {
protected R underlyingObjectToObject(T value) {
return resultConverter.convert(value, type);
return convert(value);
}
};
}
@@ -138,4 +144,9 @@ public class QueryResultBuilder<T> implements Result<T> {
public Iterator<T> iterator() {
return result.iterator();
}
public Result<T> with(MappingPolicy mappingPolicy) {
this.mappingPolicy = mappingPolicy;
return this;
}
}

View File

@@ -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<T> extends EndResult<T> {
<R> EndResult<R> to(Class<R> type);
<R> EndResult<R> to(Class<R> type, ResultConverter<T, R> resultConverter);
Result<T> with(MappingPolicy mappingPolicy);
}

View File

@@ -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<T, R> {
R convert(T value, Class<R> type);
R convert(T value, Class<R> type, MappingPolicy mappingPolicy);
ResultConverter NO_OP_RESULT_CONVERTER = new ResultConverter() {
public class ResultConverterAdapter<T,R> implements ResultConverter<T,R> {
@Override
public Object convert(Object value, Class type) {
public R convert(T value, Class<R> type) {
return null;
}
@Override
public R convert(T value, Class<R> type, MappingPolicy mappingPolicy) {
return convert(value,type);
}
};
}

View File

@@ -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<STATE> {
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

View File

@@ -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<STATE extends Proper
this.property = property;
}
protected MappingPolicy updateMappingPolicy(MappingPolicy mappingPolicy) {
if (mappingPolicy !=null) return mappingPolicy;
return property.getMappingPolicy();
}
@Override
public boolean isWriteable(Object entity) {
return true;
@@ -94,15 +100,15 @@ public abstract class AbstractNodeRelationshipFieldAccessor<STATE extends Proper
return newState;
}
protected <T> ManagedFieldAccessorSet<T> createManagedSet(Object entity, Set<T> result) {
return new ManagedFieldAccessorSet<T>(entity, result, property, template,this);
protected <T> ManagedFieldAccessorSet<T> createManagedSet(Object entity, Set<T> result, MappingPolicy mappingPolicy) {
return new ManagedFieldAccessorSet<T>(entity, result, property, template,this, mappingPolicy);
}
protected Set<Object> createEntitySetFromRelationshipEndNodes(Object entity) {
protected Set<Object> createEntitySetFromRelationshipEndNodes(Object entity, final MappingPolicy mappingPolicy) {
final Iterable<TSTATE> nodes = getStatesFromEntity(entity);
final Set<Object> result = new HashSet<Object>();
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<STATE extends Proper
}
}
public Object getDefaultImplementation() {
public Object getDefaultValue() {
return null;
}

View File

@@ -18,6 +18,7 @@ package org.springframework.data.neo4j.fieldaccess;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.neo4j.mapping.MappingPolicy;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
import org.springframework.data.neo4j.support.Neo4jTemplate;
@@ -62,8 +63,8 @@ public class ConvertingNodePropertyFieldAccessorFactory implements FieldAccessor
}
@Override
public Object setValue(final Object entity, final Object newVal) {
super.setValue(entity, propertyConverter.serializePropertyValue(newVal,targetType));
public Object setValue(final Object entity, final Object newVal, MappingPolicy mappingPolicy) {
super.setValue(entity, propertyConverter.serializePropertyValue(newVal,targetType), mappingPolicy);
return newVal;
}

View File

@@ -19,6 +19,7 @@ package org.springframework.data.neo4j.fieldaccess;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.data.neo4j.core.EntityState;
import org.springframework.data.neo4j.mapping.MappingPolicy;
import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
@@ -33,7 +34,7 @@ import java.util.Map;
*/
public abstract class DefaultEntityState<STATE> implements EntityState<STATE> {
protected final Object entity;
protected final Class<? extends Object> type;
protected final Class<?> type;
private final Map<Neo4jPersistentProperty, FieldAccessor> fieldAccessors = new HashMap<Neo4jPersistentProperty, FieldAccessor>();
private final Map<Neo4jPersistentProperty,List<FieldAccessListener>> fieldAccessorListeners = new HashMap<Neo4jPersistentProperty, List<FieldAccessListener>>();
private STATE state;
@@ -41,7 +42,7 @@ public abstract class DefaultEntityState<STATE> implements EntityState<STATE> {
private final FieldAccessorFactoryProviders<Object> fieldAccessorFactoryProviders;
protected final Neo4jPersistentEntity<?> persistentEntity;
public DefaultEntityState(final STATE underlyingState, final Object entity, final Class<? extends Object> 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<STATE> implements EntityState<STATE> {
}
@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<STATE> implements EntityState<STATE> {
protected Object getIdFromEntity() {
final Neo4jPersistentProperty idProperty = fieldAccessorFactoryProviders.getIdProperty();
if (idProperty==null) return null;
return idProperty.getValue(entity);
return idProperty.getValue(entity, idProperty.getMappingPolicy());
}
}

View File

@@ -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<STATE> implements EntityState<STATE> {
private final Map<Field, ExistingValue> dirty = new HashMap<Field, ExistingValue>();
private final Map<Neo4jPersistentProperty, ExistingValue> dirty = new HashMap<Neo4jPersistentProperty, ExistingValue>();
protected final EntityState<STATE> delegate;
private final static Log log = LogFactory.getLog(DetachedEntityState.class);
private Neo4jTemplate template;
@@ -50,8 +51,8 @@ public class DetachedEntityState<STATE> implements EntityState<STATE> {
}
@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<STATE> implements EntityState<STATE> {
}
@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<STATE> implements EntityState<STATE> {
}
}
@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<STATE> implements EntityState<STATE> {
}
@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<STATE> implements EntityState<STATE> {
}
if (isDirty()) {
final Map<Field, ExistingValue> dirtyCopy = new HashMap<Field, ExistingValue>(dirty);
final Map<Neo4jPersistentProperty, ExistingValue> dirtyCopy = new HashMap<Neo4jPersistentProperty, ExistingValue>(dirty);
clearDirty();
for (final Map.Entry<Field, ExistingValue> entry : dirtyCopy.entrySet()) {
final Field field = entry.getKey();
Object valueFromEntity = getValueFromEntity(field);
for (final Map.Entry<Neo4jPersistentProperty, ExistingValue> 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<STATE> implements EntityState<STATE> {
}
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<Field, ExistingValue> entry, final Field field) {
private void checkConcurrentModification(final Object entity, final Map.Entry<Neo4jPersistentProperty, ExistingValue> 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<STATE> implements EntityState<STATE> {
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<STATE> implements EntityState<STATE> {
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));
}

View File

@@ -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();
}
}

View File

@@ -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

View File

@@ -35,7 +35,7 @@ public class GraphBackedEntityIterableWrapper<STATE extends PropertyContainer, E
@Override
protected ENTITY underlyingObjectToObject(STATE s) {
return template.createEntityFromState(s, targetType);
return template.createEntityFromState(s, targetType, template.getMappingPolicy(targetType));
}
public static <S extends PropertyContainer, E> GraphBackedEntityIterableWrapper<S, E> create(

View File

@@ -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;
}

View File

@@ -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<T> extends AbstractSet<T> {
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<T>) newVal;
}
this.mappingPolicy = mappingPolicy;
}
@Override
public Iterator<T> iterator() {
@@ -77,14 +80,14 @@ public class ManagedFieldAccessorSet<T> extends AbstractSet<T> {
}
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;

View File

@@ -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<String, Object> 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;

View File

@@ -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<Node, Object> 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<Relationship, ?> 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);

View File

@@ -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<Node> 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();
}
}

View File

@@ -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;
}

View File

@@ -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<Object> 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<String, Object> params) {
return template.query(queryString, params, property.getTypeInformation());
private Object executeQuery(Object entity, String queryString, Map<String, Object> params, MappingPolicy mappingPolicy) {
final TypeInformation<?> typeInformation = property.getTypeInformation();
final TypeInformation<?> actualType = typeInformation.getActualType();
final Class<?> targetType = actualType.getType();
final Result<Object> 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<String, Object> createPlaceholderParams(Object entity) {
@@ -108,7 +125,7 @@ public class QueryFieldAccessorFactory implements FieldAccessorFactory {
}
@Override
public Object getDefaultImplementation() {
public Object getDefaultValue() {
return null;
}
}

View File

@@ -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.");
}

View File

@@ -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;
}
}

View File

@@ -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.<Node>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<Object> result = createEntitySetFromRelationshipEndNodes(entity);
final Set<Object> result = createEntitySetFromRelationshipEndNodes(entity, updateMappingPolicy(mappingPolicy));
final Object singleEntity = result.isEmpty() ? null : result.iterator().next();
return doReturn(singleEntity);
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -39,6 +39,6 @@ public interface EntityInstantiator<STATE> {
* code to instantiate entities without invoking a constructor.
*/
<T> T createEntityFromState(STATE s, Class<T> c);
<T> T createEntityFromState(STATE s, Class<T> c, final MappingPolicy mappingPolicy);
}

View File

@@ -24,8 +24,10 @@ import org.neo4j.graphdb.PropertyContainer;
public interface EntityPersister {
<T> T projectTo(Object entity, Class<T> targetType);
<S extends PropertyContainer, T> T createEntityFromState(S state, Class<T> type);
<S extends PropertyContainer, T> T createEntityFromStoredType(S state);
<T> T projectTo(Object entity, Class<T> targetType, MappingPolicy mappingPolicy);
<S extends PropertyContainer, T> T createEntityFromState(S state, Class<T> type, MappingPolicy mappingPolicy);
<S extends PropertyContainer, T> T createEntityFromStoredType(S state, MappingPolicy mappingPolicy);
boolean isNodeEntity(Class<?> targetType);
boolean isRelationshipEntity(Class<?> targetType);
MappingPolicy getMappingPolicy(Class<?> targetType);
}

View File

@@ -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<Option> options;
public DefaultMappingPolicy(Option... options) {
this(asList(options));
}
public DefaultMappingPolicy(final Collection<Option> options) {
this.options = options.isEmpty() ? EnumSet.noneOf(Option.class) : EnumSet.copyOf(options);
}
@Override
public boolean accessField() {
return options.contains(Option.FIELD_DIRECT);
}
@Override
public boolean shouldLoad() {
return options.contains(Option.SHOULD_LOAD);
}
public MappingPolicy with(Option...options) {
return with(asList(options));
}
private MappingPolicy with(Collection<Option> optionsList) {
Collection<Option> combined =new HashSet<Option>(optionsList);
combined.addAll(this.options);
combined.remove(null);
return new DefaultMappingPolicy(combined);
}
public MappingPolicy withOut(Option...options) {
Collection<Option> combined =new HashSet<Option>(this.options);
combined.removeAll(asList(options));
return new DefaultMappingPolicy(combined);
}
@Override
public MappingPolicy combineWith(MappingPolicy mappingPolicy) {
if (mappingPolicy instanceof DefaultMappingPolicy) {
return with(((DefaultMappingPolicy)mappingPolicy).options);
}
return with(mappingPolicy.accessField() ? Option.FIELD_DIRECT : null, mappingPolicy.shouldLoad() ? Option.SHOULD_LOAD : null);
}
@Override
public String toString() {
return "Policy: "+options.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DefaultMappingPolicy that = (DefaultMappingPolicy) o;
return options.equals(that.options);
}
@Override
public int hashCode() {
return options.hashCode();
}
}
public MappingPolicy LOAD_POLICY = new DefaultMappingPolicy(Option.SHOULD_LOAD);
public MappingPolicy DEFAULT_POLICY = new DefaultMappingPolicy();
public MappingPolicy MAP_FIELD_DIRECT_POLICY = new DefaultMappingPolicy(Option.FIELD_DIRECT);
}

View File

@@ -15,17 +15,18 @@
*/
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;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.mapping.context.MappingContext;
/**
* @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> {
public interface Neo4jEntityConverter<T, S extends PropertyContainer> {
<R extends T> R read(Class<R> type, S source, MappingPolicy mappingPolicy);
void write(T source, S sink, MappingPolicy mappingPolicy);
MappingContext<? extends Neo4jPersistentEntity<?>, Neo4jPersistentProperty> getMappingContext();
ConversionService getConversionService();
}

View File

@@ -37,4 +37,6 @@ public interface Neo4jPersistentEntity<T> extends PersistentEntity<T, Neo4jPersi
Object getPersistentId(Object entity);
RelationshipProperties getRelationshipProperties();
MappingPolicy getMappingPolicy();
}

View File

@@ -66,9 +66,15 @@ public interface Neo4jPersistentProperty extends PersistentProperty<Neo4jPersist
void setValue(Object entity, Object newValue);
Object getValue(final Object entity);
Object getValue(final Object entity, final MappingPolicy mappingPolicy);
Neo4jPersistentEntity<?> getOwner();
String getIndexKey();
MappingPolicy getMappingPolicy();
boolean isReallyTransient();
Object getValueFromEntity(Object entity, MappingPolicy mappingPolicy);
}

View File

@@ -23,7 +23,6 @@ import org.springframework.data.neo4j.annotation.RelatedTo;
import org.springframework.data.neo4j.annotation.RelatedToVia;
import org.springframework.data.neo4j.annotation.RelationshipEntity;
import org.springframework.data.neo4j.support.mapping.Neo4jMappingContext;
import org.springframework.data.neo4j.support.mapping.Neo4jPersistentEntityImpl;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
@@ -57,7 +56,6 @@ public class RelationshipInfo {
public RelationshipInfo(String type, Direction direction, TypeInformation<?> typeInformation, TypeInformation<?> concreteActualType, Neo4jMappingContext ctx) {
this.type = type;
this.direction = direction;
this.targetEntity = targetEntity;
isMultiple = typeInformation.isCollectionLike();
targetType = concreteActualType!=null ? concreteActualType : typeInformation.getActualType();
this.targetEntity = ctx.getPersistentEntity(targetType);
@@ -75,18 +73,19 @@ public class RelationshipInfo {
annotation.direction(),
typeInformation,
annotation.elementClass() != Object.class ? ClassTypeInformation.from(annotation.elementClass()) : null,
ctx);
ctx
);
}
public static RelationshipInfo fromField(Field field, RelatedToVia annotation, TypeInformation<?> typeInformation, Neo4jMappingContext ctx) {
final TypeInformation<?> elementClass = elementClass(annotation, typeInformation);
final Neo4jPersistentEntityImpl<?> targetEntity = ctx.getPersistentEntity(elementClass);
return new RelationshipInfo(
relationshipType(field,annotation,typeInformation),
annotation.direction(),
typeInformation,
elementClass,
ctx);
ctx
);
}
private static String relationshipType(Field field, RelatedToVia annotation, TypeInformation<?> typeInformation) {

View File

@@ -21,7 +21,7 @@ package org.springframework.data.neo4j.mapping;
*/
public interface RelationshipProperties {
Neo4jPersistentProperty getStartNodeProperty();
Neo4jPersistentProperty getEndeNodeProperty();
Neo4jPersistentProperty getEndNodeProperty();
Neo4jPersistentProperty getTypeProperty();
String getRelationshipType();

View File

@@ -17,10 +17,8 @@
package org.springframework.data.neo4j.repository;
import org.apache.lucene.search.NumericRangeQuery;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.NotFoundException;
import org.neo4j.graphdb.PropertyContainer;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.index.IndexHits;
import org.neo4j.graphdb.index.ReadableIndex;
import org.neo4j.helpers.collection.ClosableIterable;
@@ -184,7 +182,7 @@ public abstract class AbstractGraphRepository<S extends PropertyContainer, T> im
}
protected T createEntity(S node) {
return template.createEntityFromState(node, clazz);
return template.createEntityFromState(node, clazz, template.getMappingPolicy(clazz));
}
/**

View File

@@ -29,10 +29,12 @@ import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.neo4j.annotation.QueryType;
import org.springframework.data.neo4j.conversion.QueryResultBuilder;
import org.springframework.data.neo4j.conversion.Result;
import org.springframework.data.neo4j.conversion.ResultConverter;
import org.springframework.data.neo4j.core.GraphDatabase;
import org.springframework.data.neo4j.core.TypeRepresentationStrategy;
import org.springframework.data.neo4j.core.UncategorizedGraphStoreException;
import org.springframework.data.neo4j.mapping.EntityPersister;
import org.springframework.data.neo4j.mapping.MappingPolicy;
import org.springframework.data.neo4j.mapping.RelationshipResult;
import org.springframework.data.neo4j.support.index.IndexType;
import org.springframework.data.neo4j.support.mapping.EntityStateHandler;
@@ -46,6 +48,7 @@ import org.springframework.data.neo4j.support.mapping.EntityCreatingClosableIter
import org.springframework.data.neo4j.support.query.QueryEngine;
import org.springframework.data.neo4j.template.GraphCallback;
import org.springframework.data.neo4j.template.Neo4jOperations;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
@@ -134,15 +137,16 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
@Override
public <T> T findOne(long id, final Class<T> entityClass) {
if (isNodeEntity(entityClass)) {
final Neo4jPersistentEntityImpl<?> persistentEntity = getPersistentEntity(entityClass);
if (persistentEntity.isNodeEntity()) {
final Node node = getNode(id);
if (node==null) return null;
return infrastructure.getEntityPersister().createEntityFromState(node, entityClass);
return infrastructure.getEntityPersister().createEntityFromState(node, entityClass, persistentEntity.getMappingPolicy());
}
if (isRelationshipEntity(entityClass)) {
if (persistentEntity.isRelationshipEntity()) {
final Relationship relationship = getRelationship(id);
if (relationship==null) return null;
return infrastructure.getEntityPersister().createEntityFromState(relationship, entityClass);
return infrastructure.getEntityPersister().createEntityFromState(relationship, entityClass, persistentEntity.getMappingPolicy());
}
throw new IllegalArgumentException("provided entity type is not annotated with @NodeEntiy nor @RelationshipEntity");
}
@@ -161,15 +165,20 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
}
@Override
public <S extends PropertyContainer, T> T createEntityFromStoredType(S state) {
public <S extends PropertyContainer, T> T createEntityFromStoredType(S state, MappingPolicy mappingPolicy) {
notNull(state,"node or relationship");
return infrastructure.getEntityPersister().createEntityFromStoredType(state);
return infrastructure.getEntityPersister().createEntityFromStoredType(state, mappingPolicy);
}
@Override
public <S extends PropertyContainer, T> T createEntityFromState(S state, Class<T> type) {
public <S extends PropertyContainer, T> T createEntityFromState(S state, Class<T> type, MappingPolicy mappingPolicy) {
notNull(state,"node or relationship",type,"entity class");
return infrastructure.getEntityPersister().createEntityFromState(state, type);
return infrastructure.getEntityPersister().createEntityFromState(state, type, mappingPolicy);
}
@Override
public <S extends PropertyContainer, T> T load(S state, Class<T> type) {
notNull(state,"node or relationship",type,"entity class");
return infrastructure.getEntityPersister().createEntityFromState(state, type, getMappingPolicy(type));
}
@Override
@@ -177,6 +186,11 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
notNull(entity,"entity",targetType,"new entity class");
return infrastructure.getEntityPersister().projectTo(entity, targetType);
}
@Override
public <T> T projectTo(Object entity, Class<T> targetType, MappingPolicy mappingPolicy) {
notNull(entity,"entity",targetType,"new entity class");
return infrastructure.getEntityPersister().projectTo(entity, targetType, mappingPolicy);
}
/**
* just sets the persistent state (i.e. Node or id) to the entity, doesn't copy any values/properties.
@@ -186,12 +200,12 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
*/
@Override
public <S extends PropertyContainer> S getPersistentState(Object entity) {
notNull(entity,"entity");
notNull(entity, "entity");
return infrastructure.getEntityPersister().getPersistentState(entity);
}
public <S extends PropertyContainer, T> T setPersistentState(T entity, S state) {
notNull(entity,"entity",state,"node or relationship");
notNull(entity, "entity", state, "node or relationship");
infrastructure.getEntityPersister().setPersistentState(entity, state);
return entity;
}
@@ -274,7 +288,7 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
@Override
@SuppressWarnings("unchecked")
public <T> T save(T entity) {
return (T) infrastructure.getEntityPersister().persist(entity);
return (T) infrastructure.getEntityPersister().persist(entity, getMappingPolicy(entity));
}
public boolean isManaged(Object entity) {
@@ -285,12 +299,12 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
final TypeInformation<?> actualType = typeInformation.getActualType();
final Class<?> targetType = actualType.getType();
if (actualType.isMap()) {
return infrastructure.getCypherQueryExecutor().queryForList(statement, params);
return queryEngineFor(QueryType.Cypher).query(statement, params);
}
if (typeInformation.isCollectionLike()) {
return infrastructure.getCypherQueryExecutor().query(statement, targetType, params);
return queryEngineFor(QueryType.Cypher).query(statement, params).to(targetType);
}
return infrastructure.getCypherQueryExecutor().queryForObject(statement, targetType, params);
return queryEngineFor(QueryType.Cypher).query(statement, params).to(targetType).single();
}
@Override
@@ -299,7 +313,8 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
final Relationship relationship = infrastructure.getEntityStateHandler().getRelationshipBetween(start, end, relationshipType);
if (relationship == null) return null;
if (Relationship.class.isAssignableFrom(relationshipEntityClass)) return (R)relationship;
return infrastructure.getEntityPersister().createEntityFromState(relationship, relationshipEntityClass);
final Neo4jPersistentEntityImpl<?> persistentEntity = getPersistentEntity(relationshipEntityClass);
return infrastructure.getEntityPersister().createEntityFromState(relationship, relationshipEntityClass, persistentEntity.getMappingPolicy());
}
@Override
@@ -321,7 +336,7 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
// TODO
postEntityCreation(result.relationship, relationshipEntityClass);
}
return createEntityFromState(result.relationship, relationshipEntityClass);
return createEntityFromState(result.relationship, relationshipEntityClass, getMappingPolicy(relationshipEntityClass));
}
@Override
@@ -415,30 +430,46 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
return element;
}
@Override
@SuppressWarnings("unchecked")
public <T> T fetch(T value) {
final PropertyContainer state = getPersistentState(value);
if (state != null) {
return (T) infrastructure.getEntityPersister().createEntityFromState(state, value.getClass());
final Class<?> targetType = value.getClass();
final TypeInformation<?> targetTypeInformation = ClassTypeInformation.from(targetType);
if (targetTypeInformation.isCollectionLike()) {
return (T) infrastructure.getEntityPersister().createEntityFromState(state, targetType, getMappingPolicy(targetTypeInformation.getActualType().getType())); // todo handle collections
}
return (T) infrastructure.getEntityPersister().createEntityFromState(state, targetType, getMappingPolicy(targetType)); // todo handle collections
}
throw new MappingException("No state information available in "+ value);
}
@Override
public MappingPolicy getMappingPolicy(Class<?> targetType) {
return getPersistentEntity(targetType).getMappingPolicy();
}
@Override
@SuppressWarnings("unchecked")
public <T> Result<T> convert(Iterable<T> iterable) {
return new QueryResultBuilder<T>(iterable, infrastructure.getResultConverter());
return new QueryResultBuilder<T>(iterable, getDefaultConverter());
}
@Override
@SuppressWarnings("unchecked")
public <T> T convert(Object value, Class<T> type) {
return (T) infrastructure.getResultConverter().convert(value, type);
return (T) getDefaultConverter().convert(value, type);
}
@Override
public ResultConverter getDefaultConverter() {
return infrastructure.getResultConverter();
}
@Override
public <T> QueryEngine<T> queryEngineFor(QueryType type) {
return infrastructure.getGraphDatabase().queryEngineFor(type, infrastructure.getResultConverter());
return infrastructure.getGraphDatabase().queryEngineFor(type, getDefaultConverter());
}
@Override
@@ -502,7 +533,7 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
}
public <T extends PropertyContainer> Index<T> getIndex(String indexName, Class<?> indexedType) {
return getIndexProvider().getIndex(indexedType,indexName);
return getIndexProvider().getIndex(indexedType, indexName);
}
public <T extends PropertyContainer> Index<T> getIndex(Class<?> indexedType, String propertyName) {
@@ -572,4 +603,9 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
return getIndexProvider().getIndex(property, instanceType);
}
public MappingPolicy getMappingPolicy(Object entity) {
ParameterCheck.notNull(entity,"entity");
return getMappingPolicy(entity.getClass());
}
}

View File

@@ -18,18 +18,13 @@ package org.springframework.data.neo4j.support.conversion;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.neo4j.annotation.MapResult;
import org.springframework.data.neo4j.annotation.ResultColumn;
import org.springframework.data.neo4j.conversion.DefaultConverter;
import org.springframework.data.neo4j.conversion.QueryResultBuilder;
import org.springframework.data.neo4j.core.EntityPath;
import org.springframework.data.neo4j.mapping.EntityPersister;
import org.springframework.data.neo4j.mapping.MappingPolicy;
import org.springframework.data.neo4j.support.path.ConvertingEntityPath;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
@@ -48,17 +43,17 @@ public class EntityResultConverter<T, R> extends DefaultConverter<T, R> {
@SuppressWarnings("unchecked")
@Override
protected Object doConvert(Object value, Class<?> sourceType, Class targetType) {
protected Object doConvert(Object value, Class<?> sourceType, Class targetType, MappingPolicy mappingPolicy) {
if (EntityPath.class.isAssignableFrom(targetType)) {
return new ConvertingEntityPath(entityPersister, toPath(value, sourceType));
}
if (entityPersister.isNodeEntity(targetType)) {
return entityPersister.projectTo(toNode(value, sourceType), targetType);
return entityPersister.projectTo(toNode(value, sourceType), targetType, mappingPolicy);
}
if (entityPersister.isRelationshipEntity(targetType)) {
return entityPersister.projectTo(toRelationship(value, sourceType), targetType);
return entityPersister.projectTo(toRelationship(value, sourceType), targetType, mappingPolicy);
}
final Object result = super.doConvert(value, sourceType, targetType);
final Object result = super.doConvert(value, sourceType, targetType, mappingPolicy);
if (result != null) return result;
@@ -69,83 +64,22 @@ public class EntityResultConverter<T, R> extends DefaultConverter<T, R> {
}
@SuppressWarnings("unchecked")
public R extractMapResult(Object value, Class returnType) {
public R extractMapResult(Object value, Class returnType, MappingPolicy mappingPolicy) {
if (!Map.class.isAssignableFrom(value.getClass())) {
throw new RuntimeException("MapResult can only be extracted from Map<String,Object>.");
}
InvocationHandler handler = new QueryResultProxy((Map<String, Object>) value);
InvocationHandler handler = new QueryResultProxy((Map<String, Object>) value,mappingPolicy,this);
return (R) Proxy.newProxyInstance(returnType.getClassLoader(), new Class[]{returnType}, handler);
}
@Override
public R convert(Object value, Class type) {
public R convert(Object value, Class type, MappingPolicy mappingPolicy) {
if (type.isAnnotationPresent(MapResult.class)) {
return extractMapResult(value, type);
return extractMapResult(value, type,mappingPolicy);
} else
return super.convert(value, type);
return super.convert(value, type,mappingPolicy);
}
private class QueryResultProxy implements InvocationHandler {
private final Map<String, Object> map;
private QueryResultProxy(Map<String,Object> map) {
this.map = map;
}
@SuppressWarnings("unchecked")
@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(!map.containsKey( columnName )) {
throw new NoSuchColumnFoundException( columnName );
}
Object columnValue = map.get( columnName );
if(columnValue==null) return null;
// If the returned value is a Scala iterable, transform it to a Java iterable first
Class iterableLikeInterface = implementsInterface("scala.collection.Iterable", columnValue.getClass());
if (iterableLikeInterface!=null) {
columnValue = transformScalaIterableToJavaIterable(columnValue, iterableLikeInterface);
}
if (returnType.isCollectionLike())
return new QueryResultBuilder((Iterable)columnValue, EntityResultConverter.this).to(returnType.getActualType().getType());
else
return convert(columnValue, returnType.getType());
}
}
public Object transformScalaIterableToJavaIterable(Object scalaIterable, Class iterableLikeIface) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// This is equivalent to doing this:
// JavaConversions.asJavaIterable(((IterableLike) columnValue).toIterable());
Class<?> javaConversions = iterableLikeIface.getClassLoader().loadClass("scala.collection.JavaConversions");
Method asJavaIterable = javaConversions.getMethod("asJavaIterable", iterableLikeIface);
Iterable<?> javaIterable = (Iterable<?>) asJavaIterable.invoke(null, scalaIterable);
return javaIterable;
}
private Class implementsInterface(String interfaceName, Class clazz) {
if(clazz.getCanonicalName().equals(interfaceName)) return clazz;
Class superclass = clazz.getSuperclass();
if(superclass != null) {
Class iface = implementsInterface(interfaceName, superclass);
if (iface!= null) return iface;
}
for(Class iface : clazz.getInterfaces()) {
Class superIface = implementsInterface(interfaceName, iface);
if(superIface!=null)
return superIface;
}
return null;
}
}

View File

@@ -0,0 +1,96 @@
/**
* 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.conversion;
import org.springframework.data.neo4j.annotation.ResultColumn;
import org.springframework.data.neo4j.conversion.QueryResultBuilder;
import org.springframework.data.neo4j.conversion.ResultConverter;
import org.springframework.data.neo4j.mapping.MappingPolicy;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
/**
* @author mh
* @since 10.11.11
*/
public class QueryResultProxy implements InvocationHandler {
private final Map<String, Object> map;
private final MappingPolicy mappingPolicy;
private final ResultConverter converter;
public QueryResultProxy(Map<String, Object> map, MappingPolicy mappingPolicy, ResultConverter converter) {
this.map = map;
this.mappingPolicy = mappingPolicy;
this.converter = converter;
}
@SuppressWarnings("unchecked")
@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(!map.containsKey( columnName )) {
throw new NoSuchColumnFoundException( columnName );
}
Object columnValue = map.get( columnName );
if(columnValue==null) return null;
// If the returned value is a Scala iterable, transform it to a Java iterable first
Class iterableLikeInterface = implementsInterface("scala.collection.Iterable", columnValue.getClass());
if (iterableLikeInterface!=null) {
columnValue = transformScalaIterableToJavaIterable(columnValue, iterableLikeInterface);
}
if (returnType.isCollectionLike())
return new QueryResultBuilder((Iterable)columnValue, converter).to(returnType.getActualType().getType());
else
return converter.convert(columnValue, returnType.getType(), mappingPolicy);
}
public Object transformScalaIterableToJavaIterable(Object scalaIterable, Class iterableLikeIface) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// This is equivalent to doing this:
// JavaConversions.asJavaIterable(((IterableLike) columnValue).toIterable());
Class<?> javaConversions = iterableLikeIface.getClassLoader().loadClass("scala.collection.JavaConversions");
Method asJavaIterable = javaConversions.getMethod("asJavaIterable", iterableLikeIface);
Iterable<?> javaIterable = (Iterable<?>) asJavaIterable.invoke(null, scalaIterable);
return javaIterable;
}
private Class implementsInterface(String interfaceName, Class clazz) {
if(clazz.getCanonicalName().equals(interfaceName)) return clazz;
Class superclass = clazz.getSuperclass();
if(superclass != null) {
Class iface = implementsInterface(interfaceName, superclass);
if (iface!= null) return iface;
}
for(Class iface : clazz.getInterfaces()) {
Class superIface = implementsInterface(interfaceName, iface);
if(superIface!=null)
return superIface;
}
return null;
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.data.neo4j.support.mapping;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.data.neo4j.mapping.EntityInstantiator;
import org.springframework.data.neo4j.mapping.MappingPolicy;
import org.springframework.data.persistence.StateBackedCreator;
import org.springframework.data.persistence.StateProvider;
import org.springframework.util.ClassUtils;
@@ -39,7 +40,7 @@ public abstract class AbstractConstructorEntityInstantiator<STATE> implements En
private final Map<Class<?>, StateBackedCreator<?, STATE>> cache = new HashMap<Class<?>, StateBackedCreator<?, STATE>>();
@SuppressWarnings("unchecked")
public <T> T createEntityFromState(STATE n, Class<T> c) {
public <T> T createEntityFromState(STATE n, Class<T> c, final MappingPolicy mappingPolicy) {
try {
StateBackedCreator<T, STATE> creator = (StateBackedCreator<T, STATE>) cache.get(c);
if (creator != null)

View File

@@ -18,6 +18,7 @@ package org.springframework.data.neo4j.support.mapping;
import org.neo4j.graphdb.PropertyContainer;
import org.neo4j.helpers.collection.ClosableIterable;
import org.neo4j.helpers.collection.IterableWrapper;
import org.springframework.data.neo4j.mapping.MappingPolicy;
/**
* @author mh
@@ -27,17 +28,19 @@ public class EntityCreatingClosableIterable<T> extends IterableWrapper<T,Propert
private final ClosableIterable<PropertyContainer> iterable;
private final Class<T> entityClass;
private final Neo4jEntityPersister entityPersister;
private final MappingPolicy mappingPolicy;
public EntityCreatingClosableIterable(ClosableIterable<PropertyContainer> iterable, Class<T> entityClass, Neo4jEntityPersister entityPersister) {
super(iterable);
this.iterable = iterable;
this.entityClass = entityClass;
this.entityPersister = entityPersister;
mappingPolicy = this.entityPersister.getMappingPolicy(this.entityClass);
}
@Override
protected T underlyingObjectToObject(PropertyContainer state) {
return entityPersister.createEntityFromState(state, entityClass);
return entityPersister.createEntityFromState(state, entityClass, mappingPolicy);
}
@Override

View File

@@ -17,9 +17,7 @@ package org.springframework.data.neo4j.support.mapping;
import org.neo4j.graphdb.*;
import org.springframework.data.neo4j.core.GraphDatabase;
import org.springframework.data.neo4j.mapping.ManagedEntity;
import org.springframework.data.neo4j.mapping.RelationshipResult;
import org.springframework.data.neo4j.mapping.RelationshipProperties;
import org.springframework.data.neo4j.mapping.*;
/**
* @author mh
@@ -110,6 +108,8 @@ public class EntityStateHandler {
if (containedState != null) return containedState;
final Class<?> type = entity.getClass();
final Neo4jPersistentEntityImpl<?> persistentEntity = mappingContext.getPersistentEntity(type);
final MappingPolicy mappingPolicy = persistentEntity.getMappingPolicy();
// todo observer load policy
if (persistentEntity.isNodeEntity()) {
return (S) graphDatabase.createNode(null);
}
@@ -122,9 +122,12 @@ public class EntityStateHandler {
@SuppressWarnings("unchecked")
private <S extends PropertyContainer> S createRelationship(Object entity, Neo4jPersistentEntityImpl<?> persistentEntity) {
final RelationshipProperties relationshipProperties = persistentEntity.getRelationshipProperties();
Node startNode = (Node) getPersistentState(relationshipProperties.getStartNodeProperty().getValue(entity));
Node endNode = (Node) getPersistentState(relationshipProperties.getEndeNodeProperty().getValue(entity));
Object relType = relationshipProperties.getTypeProperty().getValue(entity);
final Neo4jPersistentProperty startNodeProperty = relationshipProperties.getStartNodeProperty();
Node startNode = (Node) getPersistentState(startNodeProperty.getValue(entity, startNodeProperty.getMappingPolicy()));
final Neo4jPersistentProperty endNodeProperty = relationshipProperties.getEndNodeProperty();
Node endNode = (Node) getPersistentState(endNodeProperty.getValue(entity, endNodeProperty.getMappingPolicy()));
final Neo4jPersistentProperty typeProperty = relationshipProperties.getTypeProperty();
Object relType = typeProperty.getValue(entity, typeProperty.getMappingPolicy());
if (relType instanceof RelationshipType) {
return (S) startNode.createRelationshipTo(endNode, (RelationshipType) relType);
}

View File

@@ -17,23 +17,21 @@
package org.springframework.data.neo4j.support.mapping;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.annotation.Transient;
import org.springframework.data.mapping.Association;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.model.AbstractPersistentProperty;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.neo4j.annotation.*;
import org.springframework.data.neo4j.mapping.IndexInfo;
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.*;
import org.springframework.data.neo4j.support.DoReturn;
import org.springframework.data.util.TypeInformation;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.Map;
@@ -50,6 +48,7 @@ class Neo4jPersistentPropertyImpl extends AbstractPersistentProperty<Neo4jPersis
private final boolean isIdProperty;
private IndexInfo indexInfo;
private Map<Class<? extends Annotation>, ? extends Annotation> annotations;
private Association<Neo4jPersistentProperty> myAssociation;
public Neo4jPersistentPropertyImpl(Field field, PropertyDescriptor propertyDescriptor,
PersistentEntity<?, Neo4jPersistentProperty> owner, SimpleTypeHolder simpleTypeHolder, Neo4jMappingContext ctx) {
@@ -58,6 +57,12 @@ class Neo4jPersistentPropertyImpl extends AbstractPersistentProperty<Neo4jPersis
this.relationshipInfo = extractRelationshipInfo(field,ctx);
this.indexInfo = extractIndexInfo();
this.isIdProperty = annotations.containsKey(GraphId.class);
this.myAssociation = isAssociation() ? super.getAssociation() == null ? createAssociation() : super.getAssociation() : null;
}
@Override
public Association<Neo4jPersistentProperty> getAssociation() {
return myAssociation;
}
private Map<Class<? extends Annotation>,? extends Annotation> extractAnnotations(Field field) {
@@ -120,6 +125,11 @@ class Neo4jPersistentPropertyImpl extends AbstractPersistentProperty<Neo4jPersis
return new Association<Neo4jPersistentProperty>(this, null);
}
@Override
public boolean isAssociation() {
return super.isAssociation() || isRelationship();
}
@Override
public boolean isRelationship() {
return this.relationshipInfo != null;
@@ -151,7 +161,9 @@ class Neo4jPersistentPropertyImpl extends AbstractPersistentProperty<Neo4jPersis
if (isRelationship()) return false;
final Class<?> type = getType();
final Class<String> targetType = String.class;
if (getTypeInformation().isCollectionLike()) return isConvertibleBetween(conversionService, getComponentType(), targetType);
if (getTypeInformation().isCollectionLike()) {
return isConvertibleBetween(conversionService, getComponentType(), targetType);
}
return isConvertibleBetween(conversionService, type, targetType);
}
@@ -183,7 +195,15 @@ class Neo4jPersistentPropertyImpl extends AbstractPersistentProperty<Neo4jPersis
return annotations.values();
}
public Object getValue(final Object entity) {
public Object getValue(final Object entity, final MappingPolicy mappingPolicy) {
if (entity instanceof ManagedEntity && !mappingPolicy.accessField()) {
return DoReturn.unwrap(((ManagedEntity) entity).getEntityState().getValue(this, mappingPolicy));
}
return getValueFromEntity(entity, mappingPolicy);
}
@Override
public Object getValueFromEntity(Object entity, final MappingPolicy mappingPolicy) {
try {
final Field field = getField();
if (!field.isAccessible()) field.setAccessible(true);
@@ -218,4 +238,31 @@ class Neo4jPersistentPropertyImpl extends AbstractPersistentProperty<Neo4jPersis
public String getIndexKey() {
return getIndexInfo().getIndexKey();
}
@Override
public MappingPolicy getMappingPolicy() {
if (isAnnotationPresent(Fetch.class))
return MappingPolicy.LOAD_POLICY;
else
return MappingPolicy.DEFAULT_POLICY;
}
/**
* @deprecated todo remove when SD-Commons handles transient properties differently
*/
public boolean isReallyTransient() {
return Modifier.isTransient(field.getModifiers()) || isAnnotationPresent(Transient.class) || isAnnotationPresent("javax.persistence.Transient");
}
private boolean isAnnotationPresent(String className) {
for (Class<? extends Annotation> annotationType : annotations.keySet()) {
if (annotationType.getName().equals(className)) return true;
}
return false;
}
@Override
public boolean isTransient() {
return false;
}
}

View File

@@ -66,7 +66,7 @@ public class Neo4jEntityConverterImpl<T,S extends PropertyContainer> implements
}
@Override
public <R extends T> R read(Class<R> requestedType, S source) {
public <R extends T> R read(Class<R> requestedType, S source, MappingPolicy mappingPolicy) {
// 1) source -> type alias
// 2) type alias -> type
// 3) check for subtype matching / enforcement
@@ -77,31 +77,33 @@ public class Neo4jEntityConverterImpl<T,S extends PropertyContainer> implements
@SuppressWarnings("unchecked") final Neo4jPersistentEntityImpl<R> persistentEntity = (Neo4jPersistentEntityImpl<R>) mappingContext.getPersistentEntity(targetType);
// 4) create object instance
final R createdEntity = entityInstantiator.createEntityFromState(source, targetType.getType());
final R createdEntity = entityInstantiator.createEntityFromState(source, targetType.getType(), mappingPolicy);
// 5) connect state
entityStateHandler.setPersistentState(createdEntity,source);
if (!persistentEntity.isManaged()) {
// 5a) depending on mode -> copy data
if (persistentEntity.isManaged()) return createdEntity;
if (mappingPolicy.shouldLoad()) {
final BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper = BeanWrapper.create(createdEntity, conversionService);
sourceStateTransmitter.copyPropertiesFrom(wrapper, source, persistentEntity);
sourceStateTransmitter.copyPropertiesFrom(wrapper, source, persistentEntity,mappingPolicy);
// 6) handle cascading fetches
cascadeFetch(persistentEntity, wrapper);
cascadeFetch(persistentEntity, wrapper, mappingPolicy);
}
return createdEntity;
}
private <R extends T> void cascadeFetch(Neo4jPersistentEntityImpl<R> persistentEntity, final BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper) {
private <R extends T> void cascadeFetch(Neo4jPersistentEntityImpl<R> persistentEntity, final BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper, final MappingPolicy policy) {
persistentEntity.doWithAssociations(new AssociationHandler<Neo4jPersistentProperty>() {
@Override
public void doWithAssociation(Association<Neo4jPersistentProperty> association) {
final Neo4jPersistentProperty property = association.getInverse();
if (property.isRelationship()) {
// MappingPolicy mappingPolicy = policy.combineWith(property.getMappingPolicy());
final MappingPolicy mappingPolicy = property.getMappingPolicy();
if (mappingPolicy.shouldLoad() && 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);
final Object fetchedValue = entityFetchHandler.fetch(value, persistentEntity, property, mappingPolicy);
// replace fetched one-time iterables and similiar managed values
sourceStateTransmitter.setProperty(wrapper, property, fetchedValue);
}
@@ -120,7 +122,7 @@ public class Neo4jEntityConverterImpl<T,S extends PropertyContainer> implements
}
@Override
public void write(T source, S sink) {
public void write(T source, S sink, MappingPolicy mappingPolicy) {
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 ??
@@ -134,7 +136,7 @@ public class Neo4jEntityConverterImpl<T,S extends PropertyContainer> implements
entityStateHandler.setPersistentState(source, sink);
typeMapper.writeType(sourceType, sink);
}
sourceStateTransmitter.copyPropertiesTo(wrapper, sink, persistentEntity);
sourceStateTransmitter.copyPropertiesTo(wrapper, sink, persistentEntity,mappingPolicy);
}
/*
private Node useGetOrCreateNode(S node, Neo4jPersistentEntity<?> persistentEntity, BeanWrapper<Neo4jPersistentEntity<Object>, Object> wrapper) {

View File

@@ -20,7 +20,7 @@ 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.mapping.MappingPolicy;
import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
@@ -46,14 +46,17 @@ public class Neo4jEntityFetchHandler {
// todo actually cascade !!
public Object fetch(final Object value, Neo4jPersistentEntity<Object> persistentEntity, Neo4jPersistentProperty property) {
if (value == null || !property.isAnnotationPresent(Fetch.class)) return value;
public Object fetch(final Object value, Neo4jPersistentEntity<Object> persistentEntity, Neo4jPersistentProperty property, final MappingPolicy policy) {
if (value == null) return value;
//MappingPolicy mappingPolicy = mappingPolicy.combineWith(property.getMappingPolicy());
final MappingPolicy mappingPolicy = property.getMappingPolicy();
if (!mappingPolicy.shouldLoad()) 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);
fetchValue(innerWrapper, state, persistentEntity, mappingPolicy);
replacement.add(inner);
//sourceStateTransmitter.copyPropertiesFrom(innerWrapper, entityStateHandler.<S>getPersistentState(inner), persistentEntity);
}
@@ -61,17 +64,17 @@ public class Neo4jEntityFetchHandler {
} else {
final BeanWrapper<Neo4jPersistentEntity<Object>, Object> innerWrapper = BeanWrapper.create(value, conversionService);
final PropertyContainer state = entityStateHandler.getPersistentState(value);
fetchValue(innerWrapper, state, persistentEntity);
fetchValue(innerWrapper, state, persistentEntity, mappingPolicy);
// sourceStateTransmitter.copyPropertiesFrom(innerWrapper, entityStateHandler.<S>getPersistentState(value), persistentEntity);
}
return value;
}
public void fetchValue(final BeanWrapper<Neo4jPersistentEntity<Object>, Object> wrapper, PropertyContainer source, Neo4jPersistentEntity<Object> persistentEntity) {
public void fetchValue(final BeanWrapper<Neo4jPersistentEntity<Object>, Object> wrapper, PropertyContainer source, Neo4jPersistentEntity<Object> persistentEntity, final MappingPolicy mappingPolicy) {
if (persistentEntity.isNodeEntity()) {
nodeStateTransmitter.copyPropertiesFrom(wrapper, (Node) source,persistentEntity);
nodeStateTransmitter.copyPropertiesFrom(wrapper, (Node) source,persistentEntity, mappingPolicy);
}
if (persistentEntity.isRelationshipEntity()) {
relationshipStateTransmitter.copyPropertiesFrom(wrapper, (Relationship) source, persistentEntity);
relationshipStateTransmitter.copyPropertiesFrom(wrapper, (Relationship) source, persistentEntity, mappingPolicy);
}
}
}

View File

@@ -21,7 +21,6 @@ import org.neo4j.graphdb.Relationship;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.neo4j.mapping.*;
import org.springframework.data.neo4j.mapping.ManagedEntity;
import java.util.HashMap;
import java.util.Map;
@@ -48,14 +47,40 @@ public class Neo4jEntityPersister implements EntityPersister, Neo4jEntityConvert
}
public <S extends PropertyContainer, T> T createEntityFromStoredType(S state) {
return createEntityFromState(state,null);
public <S extends PropertyContainer, T> T createEntityFromStoredType(S state, MappingPolicy mappingPolicy) {
return createEntityFromState(state,null, mappingPolicy);
}
static class StackedEntityCache {
private static class Entry {
PropertyContainer state;
//MappingPolicy mappingPolicy;
Entry(PropertyContainer state, MappingPolicy mappingPolicy) {
// ParameterCheck.notNull(state, "state",mappingPolicy,"mappingPolicy");
// this.mappingPolicy = mappingPolicy;
this.state = state;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Entry entry = (Entry) o;
// mappingPolicy.equals(entry.mappingPolicy) &&
return state.equals(entry.state);
}
@Override
public int hashCode() {
return 31 * state.hashCode(); //+ mappingPolicy.hashCode();
}
}
private long depth;
private final Map<PropertyContainer,Object> objects =new HashMap<PropertyContainer, Object>();
private final Map<Entry,Object> objects =new HashMap<Entry,Object>();
private static ThreadLocal<StackedEntityCache> stackedEntityCache = new ThreadLocal<StackedEntityCache>() {
@Override
protected StackedEntityCache initialValue() {
@@ -72,11 +97,11 @@ public class Neo4jEntityPersister implements EntityPersister, Neo4jEntityConvert
}
}
@SuppressWarnings("unchecked")
public static <T> T get(PropertyContainer state) {
return (T) cache().objects.get(state);
public static <T> T get(PropertyContainer state, MappingPolicy mappingPolicy) {
return (T) cache().objects.get(new Entry(state, mappingPolicy));
}
public static <T> T add(PropertyContainer state, T value) {
cache().objects.put(state, value);
public static <T> T add(PropertyContainer state, T value, MappingPolicy mappingPolicy) {
cache().objects.put(new Entry(state, mappingPolicy), value);
return value;
}
@@ -84,8 +109,8 @@ public class Neo4jEntityPersister implements EntityPersister, Neo4jEntityConvert
return stackedEntityCache.get();
}
public static boolean contains(PropertyContainer state) {
return cache().objects.containsKey(state);
public static boolean contains(PropertyContainer state, MappingPolicy mappingPolicy) {
return cache().objects.containsKey(new Entry(state,mappingPolicy));
}
}
public static class CachedInstantiator<S extends PropertyContainer> implements EntityInstantiator<S> {
@@ -96,12 +121,13 @@ public class Neo4jEntityPersister implements EntityPersister, Neo4jEntityConvert
}
@Override
public <T> T createEntityFromState(S state, Class<T> type) {
public <T> T createEntityFromState(S state, Class<T> type, final MappingPolicy mappingPolicy) {
try {
if (state==null) throw new IllegalArgumentException("State must not be null");
StackedEntityCache.push();
if (StackedEntityCache.contains(state)) return StackedEntityCache.get(state);
return StackedEntityCache.add(state, delegate.createEntityFromState(state, type));
if (StackedEntityCache.contains(state, mappingPolicy)) return StackedEntityCache.get(state, mappingPolicy);
final T newInstance = delegate.createEntityFromState(state, type, mappingPolicy);
return StackedEntityCache.add(state, newInstance, mappingPolicy);
} finally {
StackedEntityCache.pop();
}
@@ -125,31 +151,33 @@ public class Neo4jEntityPersister implements EntityPersister, Neo4jEntityConvert
}
@Override
public <R> R read(Class<R> type, S state) {
public <R> R read(Class<R> type, S state, MappingPolicy mappingPolicy) {
try {
if (state==null) throw new IllegalArgumentException("State must not be null");
StackedEntityCache.push();
if (StackedEntityCache.contains(state)) return StackedEntityCache.get(state);
return StackedEntityCache.add(state, delegate.read(type, state));
if (StackedEntityCache.contains(state, mappingPolicy)) return StackedEntityCache.get(state,mappingPolicy);
return StackedEntityCache.add(state, delegate.read(type, state,mappingPolicy),mappingPolicy);
} finally {
StackedEntityCache.pop();
}
}
@Override
public void write(Object source, S sink) {
delegate.write(source,sink);
public void write(Object source, S sink,MappingPolicy mappingPolicy) {
delegate.write(source,sink,mappingPolicy);
}
}
@SuppressWarnings("unchecked")
public <S extends PropertyContainer, T> T createEntityFromState(S state, Class<T> type) {
if (state == null) throw new IllegalArgumentException("state has to be either a Node or Relationship");
public <S extends PropertyContainer, T> T createEntityFromState(S state, Class<T> type, MappingPolicy mappingPolicy) {
if (state == null) {
throw new IllegalArgumentException("state has to be either a Node or Relationship, but is null");
}
if (isNode(state)) {
return nodeConverter.read(type, (Node) state);
return nodeConverter.read(type, (Node) state,mappingPolicy);
}
if (isRelationship(state)) {
return relationshipConverter.read(type, (Relationship) state);
return relationshipConverter.read(type, (Relationship) state,mappingPolicy);
}
throw new IllegalArgumentException("state has to be either a Node or Relationship");
}
@@ -163,8 +191,13 @@ public class Neo4jEntityPersister implements EntityPersister, Neo4jEntityConvert
}
public <T> T projectTo(Object entity, Class<T> targetType) {
return projectTo(entity,targetType,getMappingPolicy(targetType));
}
public <T> T projectTo(Object entity, Class<T> targetType, MappingPolicy mappingPolicy) {
PropertyContainer state = getPersistentState(entity);
return createEntityFromState(state, targetType);
final MappingPolicy newPolicy = mappingPolicy == null ? getMappingPolicy(targetType) : mappingPolicy;
return createEntityFromState(state, targetType, newPolicy);
}
@SuppressWarnings("unchecked")
@@ -173,12 +206,12 @@ public class Neo4jEntityPersister implements EntityPersister, Neo4jEntityConvert
}
public Object persist(Object entity) {
public Object persist(Object entity, final MappingPolicy mappingPolicy) {
final Class<?> type = entity.getClass();
if (isManaged(entity)) {
return ((ManagedEntity)entity).persist();
} else {
return persist(entity, type);
return persist(entity, type, mappingPolicy);
}
}
@@ -186,16 +219,18 @@ public class Neo4jEntityPersister implements EntityPersister, Neo4jEntityConvert
return entityStateHandler.isManaged(entity);
}
private Object persist(Object entity, Class<?> type) {
private Object persist(Object entity, Class<?> type,MappingPolicy mappingPolicy) {
if (isNodeEntity(type)) {
final Node node = this.<Node>getPersistentState(entity);
this.nodeConverter.write(entity, node);
return entity; // TODO ?
this.nodeConverter.write(entity, node,mappingPolicy);
return createEntityFromState(getPersistentState(entity),type, getMappingPolicy(type));
//return entity; // TODO ?
}
if (isRelationshipEntity(type)) {
final Relationship relationship = this.<Relationship>getPersistentState(entity);
this.relationshipConverter.write(entity, relationship);
return entity; // TODO ?
this.relationshipConverter.write(entity, relationship,mappingPolicy);
return createEntityFromState(getPersistentState(entity),type, getMappingPolicy(type));
// return entity; // TODO ?
}
throw new IllegalArgumentException("@NodeEntity or @RelationshipEntity annotation required on domain class"+type);
}
@@ -204,6 +239,15 @@ public class Neo4jEntityPersister implements EntityPersister, Neo4jEntityConvert
return mappingContext.isNodeEntity(targetType);
}
@Override
public MappingPolicy getMappingPolicy(Class<?> targetType) {
return getPersistentEntity(targetType).getMappingPolicy();
}
private Neo4jPersistentEntityImpl<?> getPersistentEntity(Class<?> targetType) {
return mappingContext.getPersistentEntity(targetType);
}
public boolean isRelationshipEntity(Class targetType) {
return mappingContext.isRelationshipEntity(targetType);
}
@@ -223,13 +267,13 @@ public class Neo4jEntityPersister implements EntityPersister, Neo4jEntityConvert
}
@Override
public <R> R read(Class<R> type, Node source) {
return createEntityFromState(source, type);
public <R> R read(Class<R> type, Node source, MappingPolicy mappingPolicy) {
return createEntityFromState(source, type, mappingPolicy);
}
@Override
public void write(Object source, Node sink) {
nodeConverter.write(source,sink);
public void write(Object source, Node sink, MappingPolicy mappingPolicy) {
nodeConverter.write(source,sink,mappingPolicy);
}
}

View File

@@ -23,10 +23,7 @@ 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.*;
import org.springframework.data.neo4j.mapping.ManagedEntity;
import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
import org.springframework.data.neo4j.mapping.RelationshipProperties;
import org.springframework.data.neo4j.mapping.*;
import org.springframework.data.util.TypeInformation;
import java.lang.annotation.Annotation;
@@ -115,7 +112,7 @@ public class Neo4jPersistentEntityImpl<T> extends BasicPersistentEntity<T, Neo4j
public Object getPersistentId(Object entity) {
final Neo4jPersistentProperty idProperty = getIdProperty();
if (idProperty==null) throw new MappingException("No field annotated with @GraphId found in "+ getEntityName());
return idProperty.getValue(entity);
return idProperty.getValue(entity, idProperty.getMappingPolicy());
}
@Override
@@ -157,7 +154,7 @@ public class Neo4jPersistentEntityImpl<T> extends BasicPersistentEntity<T, Neo4j
}
@Override
public Neo4jPersistentProperty getEndeNodeProperty() {
public Neo4jPersistentProperty getEndNodeProperty() {
return endNodeProperty;
}
@@ -177,4 +174,9 @@ public class Neo4jPersistentEntityImpl<T> extends BasicPersistentEntity<T, Neo4j
public String toString() {
return String.format("%s %smanaged @%sEntity Annotations: %s", getType(), isManaged() ? "" : "un", isNodeEntity() ? "Node" : "Relationship", annotations.keySet());
}
@Override
public MappingPolicy getMappingPolicy() {
return MappingPolicy.LOAD_POLICY;
}
}

View File

@@ -23,6 +23,7 @@ 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.mapping.MappingPolicy;
import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
import org.springframework.data.neo4j.support.DoReturn;
@@ -42,37 +43,39 @@ public class SourceStateTransmitter<S extends PropertyContainer> {
this.entityStateFactory = entityStateFactory;
}
public <R> R copyPropertiesFrom(final BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper, S source, Neo4jPersistentEntity<R> persistentEntity) {
public <R> R copyPropertiesFrom(final BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper, S source, Neo4jPersistentEntity<R> persistentEntity, final MappingPolicy mappingPolicy) {
final R entity = wrapper.getBean();
final Transaction tx = getTemplate().beginTx();
/* final Transaction tx = getTemplate().beginTx();
try {
*/
final EntityState<S> entityState = entityStateFactory.getEntityState(entity, false);
entityState.setPersistentState(source);
entityState.persist();
// entityState.persist();
persistentEntity.doWithProperties(new PropertyHandler<Neo4jPersistentProperty>() {
@Override
public void doWithPersistentProperty(Neo4jPersistentProperty property) {
copyEntityStatePropertyValue(property, entityState, wrapper);
copyEntityStatePropertyValue(property, entityState, wrapper, property.getMappingPolicy()); // TODO intelligent mappingPolicy.combineWith(property.getMappingPolicy())
}
});
persistentEntity.doWithAssociations(new AssociationHandler<Neo4jPersistentProperty>() {
@Override
public void doWithAssociation(Association<Neo4jPersistentProperty> association) {
final Neo4jPersistentProperty property = association.getInverse();
copyEntityStatePropertyValue(property, entityState, wrapper);
copyEntityStatePropertyValue(property, entityState, wrapper, property.getMappingPolicy()); // TODO intelligent mappingPolicy.combineWith(property.getMappingPolicy())
}
});
tx.success();
// tx.success();
return entity;
} finally {
/* } finally {
tx.finish();
}
*/
}
private <R> void setEntityStateValue(Neo4jPersistentProperty property, EntityState<S> entityState, BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper) {
if (!entityState.isWritable(property.getField())) return;
private <R> void setEntityStateValue(Neo4jPersistentProperty property, EntityState<S> entityState, BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper, final MappingPolicy mappingPolicy) {
if (!entityState.isWritable(property)) return;
final Object value = getProperty(wrapper, property);
entityState.setValue(property, value);
entityState.setValue(property, value, mappingPolicy);
}
private Neo4jTemplate getTemplate() {
@@ -109,30 +112,32 @@ public class SourceStateTransmitter<S extends PropertyContainer> {
}
}
private <R> Object copyEntityStatePropertyValue(Neo4jPersistentProperty property, EntityState<S> nodeState, BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper) {
final Object value = DoReturn.unwrap(nodeState.getValue(property.getField()));
private <R> Object copyEntityStatePropertyValue(Neo4jPersistentProperty property, EntityState<S> nodeState, BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper, final MappingPolicy mappingPolicy) {
final Object value = DoReturn.unwrap(nodeState.getValue(property, mappingPolicy));
setProperty(wrapper, property, value);
return value;
}
public <R> void copyPropertiesTo(final BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper, S target, Neo4jPersistentEntity<R> persistentEntity) {
public <R> void copyPropertiesTo(final BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper, S target, Neo4jPersistentEntity<R> persistentEntity, MappingPolicy mappingPolicy) {
final Transaction tx = getTemplate().beginTx();
try {
//final Node targetNode = useGetOrCreateNode(node, persistentEntity, wrapper);
final EntityState<S> entityState = entityStateFactory.getEntityState(wrapper.getBean(), false);
entityState.setPersistentState(target);
entityState.persist();
// todo take mapping policies for attributes into account
persistentEntity.doWithProperties(new PropertyHandler<Neo4jPersistentProperty>() {
@Override
public void doWithPersistentProperty(Neo4jPersistentProperty property) {
setEntityStateValue(property, entityState, wrapper);
setEntityStateValue(property, entityState, wrapper, property.getMappingPolicy());
}
});
// todo take mapping policies for relationships into account
persistentEntity.doWithAssociations(new AssociationHandler<Neo4jPersistentProperty>() {
@Override
public void doWithAssociation(Association<Neo4jPersistentProperty> association) {
final Neo4jPersistentProperty property = association.getInverse();
setEntityStateValue(property, entityState, wrapper);
setEntityStateValue(property, entityState, wrapper, property.getMappingPolicy());
}
});
tx.success();

View File

@@ -23,6 +23,7 @@ import org.neo4j.graphdb.Relationship;
import org.neo4j.helpers.collection.IterableWrapper;
import org.springframework.data.neo4j.core.EntityPath;
import org.springframework.data.neo4j.mapping.EntityPersister;
import org.springframework.data.neo4j.mapping.MappingPolicy;
import java.util.Iterator;
@@ -40,7 +41,7 @@ public class ConvertingEntityPath<S,E> implements EntityPath<S,E> {
private <T> T projectEntityToFirstParameterOrCreateFromStoredType(Node node, Class<T>... types) {
if (node==null) return null;
if (types==null || types.length==0) return persister.createEntityFromStoredType(node);
if (types==null || types.length==0) return persister.createEntityFromStoredType(node, MappingPolicy.LOAD_POLICY);
return persister.projectTo(node, types[0]);
}
@@ -65,7 +66,7 @@ public class ConvertingEntityPath<S,E> implements EntityPath<S,E> {
return new IterableWrapper<T,Node>(nodes()) {
@Override
protected T underlyingObjectToObject(Node node) {
return persister.createEntityFromStoredType(node);
return persister.createEntityFromStoredType(node, null);
}
};
}

View File

@@ -18,6 +18,7 @@ package org.springframework.data.neo4j.support.query;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.neo4j.conversion.DefaultConverter;
import org.springframework.data.neo4j.mapping.MappingPolicy;
/**
* @author mh
@@ -32,7 +33,7 @@ public class ConversionServiceQueryResultConverter<R> extends DefaultConverter<O
@SuppressWarnings("unchecked")
@Override
protected Object doConvert(Object value, Class<?> sourceType, Class type) {
protected Object doConvert(Object value, Class<?> sourceType, Class type, MappingPolicy mappingPolicy) {
if (conversionService.canConvert(sourceType, type)) {
return conversionService.convert(value, type);
}

View File

@@ -24,6 +24,7 @@ import org.neo4j.graphdb.RelationshipType;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.data.neo4j.fieldaccess.DefaultEntityState;
import org.springframework.data.neo4j.fieldaccess.DelegatingFieldAccessorFactory;
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.mapping.RelationshipProperties;
@@ -38,10 +39,12 @@ import org.springframework.data.neo4j.support.ParameterCheck;
public class RelationshipEntityState extends DefaultEntityState<Relationship> {
private final Neo4jTemplate template;
private MappingPolicy mappingPolicy;
public RelationshipEntityState(final Relationship underlyingState, final Object entity, final Class<? extends Object> type, final Neo4jTemplate template, final DelegatingFieldAccessorFactory delegatingFieldAccessorFactory, Neo4jPersistentEntity<Object> persistentEntity) {
super(underlyingState, entity, type, delegatingFieldAccessorFactory, persistentEntity);
this.template = template;
this.mappingPolicy = persistentEntity.getMappingPolicy();
}
@Override
@@ -68,8 +71,8 @@ public class RelationshipEntityState extends DefaultEntityState<Relationship> {
private Relationship createRelationshipFromEntity() {
final RelationshipProperties relationshipProperties = getPersistentEntity().getRelationshipProperties();
final Node startNode = template.getPersistentState(relationshipProperties.getStartNodeProperty().getValue(entity));
final Node endNode = template.getPersistentState(relationshipProperties.getEndeNodeProperty().getValue(entity));
final Node startNode = template.getPersistentState(relationshipProperties.getStartNodeProperty().getValue(entity, mappingPolicy));
final Node endNode = template.getPersistentState(relationshipProperties.getEndNodeProperty().getValue(entity, mappingPolicy));
final String type = getRelationshipTypeFromEntity(getPersistentEntity());
ParameterCheck.notNull(startNode,"start node property",endNode,"end node property",type, "relationship type property from field or annotation");
return template.createRelationshipBetween(startNode, endNode,type,null);
@@ -78,7 +81,7 @@ public class RelationshipEntityState extends DefaultEntityState<Relationship> {
private String getRelationshipTypeFromEntity(Neo4jPersistentEntity<?> persistentEntity) {
final RelationshipProperties relationshipProperties = persistentEntity.getRelationshipProperties();
final Neo4jPersistentProperty typeProperty = relationshipProperties.getTypeProperty();
final Object value = typeProperty!=null ? typeProperty.getValue(entity) : null;
final Object value = typeProperty!=null ? typeProperty.getValue(entity, mappingPolicy) : null;
if (value==null) {
return relationshipProperties.getRelationshipType();
}

View File

@@ -22,7 +22,9 @@ import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.helpers.collection.ClosableIterable;
import org.springframework.data.neo4j.annotation.QueryType;
import org.springframework.data.neo4j.conversion.Result;
import org.springframework.data.neo4j.conversion.ResultConverter;
import org.springframework.data.neo4j.core.GraphDatabase;
import org.springframework.data.neo4j.mapping.MappingPolicy;
import org.springframework.data.neo4j.repository.GraphRepository;
import org.springframework.data.neo4j.support.query.QueryEngine;
@@ -256,4 +258,13 @@ public interface Neo4jOperations {
* @return the graph database used by the template
*/
GraphDatabase getGraphDatabase();
<T> T fetch(T value);
<S extends PropertyContainer, T> T load(S state, Class<T> type);
MappingPolicy getMappingPolicy(Class<?> targetType);
ResultConverter getDefaultConverter();
}

View File

@@ -16,7 +16,10 @@
package org.springframework.data.neo4j.mapping;
import org.junit.Test;
import org.neo4j.graphdb.*;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.DynamicRelationshipType;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.index.Index;
import org.neo4j.helpers.collection.IteratorUtil;
import org.springframework.data.neo4j.model.Friendship;
@@ -24,11 +27,15 @@ import org.springframework.data.neo4j.model.Group;
import org.springframework.data.neo4j.model.Person;
import org.springframework.data.neo4j.model.Personality;
import java.util.*;
import java.util.Collection;
import java.util.Date;
import static java.util.Arrays.asList;
import static java.util.Collections.singleton;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.neo4j.helpers.collection.IteratorUtil.first;
/**
* @author mh
@@ -71,6 +78,25 @@ public class Neo4jEntityConverterTest extends Neo4jPersistentTestBase {
assertEquals("Michael", michaelNode().getProperty("name"));
}
@Test
public void testLoadPolicy() {
storeInGraph(emil);
michael.setHeight((short)182);
michael.setPersonality(Personality.EXTROVERT);
michael.setBoss(emil);
storeInGraph(michael);
final Person loaded = template.findOne(michael.getId(), Person.class);
assertEquals("loaded id", michael.getId(),loaded.getId());
assertEquals("loaded simple property", michael.getName(),loaded.getName());
assertEquals("loaded simple short property", michael.getHeight(),loaded.getHeight());
assertEquals("loaded simple converted property", michael.getPersonality(),loaded.getPersonality());
final Person boss = loaded.getBoss();
assertNotNull("instance non-fetch relationship", boss);
assertEquals("id of non-fetch relationship", emil.getId(), boss.getId());
assertNull("no properties of non-fetch relationship", boss.getName());
}
@Test
public void testFindNewlyWrittenNodeInIndex() {
storeInGraph(michael);
@@ -78,6 +104,7 @@ public class Neo4jEntityConverterTest extends Neo4jPersistentTestBase {
final Index<Node> index = template.getIndex(Person.NAME_INDEX, Person.class);
final Node found = index.get("name", "Michael").getSingle();
assertEquals("node found in index", createdNode, found);
assertEquals("node property loaded", michael.getName() , found.getProperty("name"));
}
@Test
@@ -282,15 +309,26 @@ public class Neo4jEntityConverterTest extends Neo4jPersistentTestBase {
@Test
public void testCascadingReadWithProperties() {
public void testCascadingReadWithOutProperties() {
Node groupNode = createNewNode();
Node julianNode = createNewNode();
julianNode.setProperty("name", "Julian");
groupNode.createRelationshipTo(julianNode, PERSONS);
Group g = readGroup(groupNode);
Person julian = IteratorUtil.first(g.getPersons());
assertEquals("Julian", julian.getName());
assertNull(first(g.getPersons()).getName());
}
@Test
public void testCascadingReadWithProperties() {
Node groupNode = createNewNode();
Node julianNode = createNewNode();
julianNode.setProperty("name", "Julian");
groupNode.createRelationshipTo(julianNode, DynamicRelationshipType.withName("fetchedPersons"));
Group g = readGroup(groupNode);
assertEquals("Julian", first(g.getFetchedPersons()).getName());
}
@Test
@@ -301,7 +339,7 @@ public class Neo4jEntityConverterTest extends Neo4jPersistentTestBase {
Relationship friendshipRelationship = makeFriends(michaelNode(), andresNode(), 19);
Person m = readPerson(michaelNode());
Friendship friendship = IteratorUtil.first(m.getFriendships());
Friendship friendship = first(m.getFriendships());
assertEquals((Long) friendshipRelationship.getId(), friendship.getId());
assertEquals(19, friendship.getYears());

View File

@@ -33,7 +33,7 @@ public class Neo4jEntityPersisterTest extends Neo4jPersistentTestBase {
public void testCreateEntityFromStoredType() throws Exception {
final Node personNode = template.createNode();
personNode.setProperty("name","Michael");
final Person person = entityPersister.createEntityFromState(personNode, Person.class);
final Person person = entityPersister.createEntityFromState(personNode, Person.class, template.getMappingPolicy(Person.class));
assertEquals("Michael",person.getName());
}
@@ -58,7 +58,7 @@ public class Neo4jEntityPersisterTest extends Neo4jPersistentTestBase {
@Test
public void testPersist() throws Exception {
entityPersister.persist(michael);
entityPersister.persist(michael, template.getMappingPolicy(michael));
assertEquals((Long) michaelNode().getId(), michael.getId());
assertEquals(michaelNode(), entityPersister.getPersistentState(michael));
assertEquals(michaelNode().getProperty("name"), michael.getName());

View File

@@ -195,7 +195,7 @@ public class Neo4jPersistentTestBase {
}
protected Object write(Object entity, Node node) {
entityPersister.write(entity, node);
entityPersister.write(entity, node, template.getMappingPolicy(entity));
return entity;
}
@@ -225,7 +225,7 @@ public class Neo4jPersistentTestBase {
}
public Person readPerson(Node node) {
return entityPersister.read(Person.class, node);
return entityPersister.read(Person.class, node, template.getMappingPolicy(Person.class));
}
protected Relationship makeFriends(Node from, Node to, int years) {
@@ -235,7 +235,7 @@ public class Neo4jPersistentTestBase {
}
public Group readGroup(Node node) {
return entityPersister.read(Group.class, node);
return entityPersister.read(Group.class, node,template.getMappingPolicy(Group.class));
}
protected List<Node> getRelatedNodes(Node startNode, String type, Direction direction) {

View File

@@ -16,26 +16,21 @@
package org.springframework.data.neo4j.model;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.DynamicRelationshipType;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.kernel.Traversal;
import org.neo4j.kernel.impl.traversal.TraversalDescriptionImpl;
import org.springframework.data.neo4j.annotation.GraphId;
import org.springframework.data.neo4j.annotation.GraphProperty;
import org.springframework.data.neo4j.annotation.GraphTraversal;
import org.springframework.data.neo4j.annotation.Indexed;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.data.neo4j.annotation.RelatedTo;
import org.springframework.data.neo4j.annotation.*;
import org.springframework.data.neo4j.core.FieldTraversalDescriptionBuilder;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
import org.springframework.data.neo4j.support.index.IndexType;
import org.springframework.util.ObjectUtils;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
@NodeEntity
public class Group {
@@ -44,12 +39,15 @@ public class Group {
public static final String SEARCH_GROUPS_INDEX_BUG = "search-groups";
@RelatedTo(direction = Direction.OUTGOING)
private Collection<Person> persons = new HashSet<Person>();
private Collection<Person> persons;
@Fetch @RelatedTo
private Collection<Person> fetchedPersons;
@RelatedTo(type = "persons", elementClass = Person.class)
private Iterable<Person> readOnlyPersons;
@GraphTraversal(traversal = PeopleTraversalBuilder.class, elementClass = Person.class, params = "persons")
@GraphTraversal(traversal = PeopleTraversalBuilder.class, params = "persons")
private Iterable<Person> people;
@GraphProperty
@@ -117,6 +115,7 @@ public class Group {
}
public void addPerson(Person person) {
if (persons==null) persons=new HashSet<Person>();
persons.add(person);
}
@@ -215,4 +214,8 @@ public class Group {
public int hashCode() {
return ObjectUtils.nullSafeHashCode(this.id);
}
public Collection<Person> getFetchedPersons() {
return fetchedPersons;
}
}

View File

@@ -72,7 +72,7 @@ public class EntityNeo4jTemplateTest extends EntityTestBase {
@Before
public void setUp() throws Exception {
createTeam();
neo4jOperations = neo4jTemplate;
neo4jOperations = template;
}
@Test @Transactional
@@ -96,14 +96,14 @@ public class EntityNeo4jTemplateTest extends EntityTestBase {
@Test @Transactional
public void testGetIndexForType() throws Exception {
final Index<PropertyContainer> personIndex = neo4jTemplate.getIndex(Person.class);
final Index<PropertyContainer> personIndex = template.getIndex(Person.class);
assertEquals("Person",personIndex.getName());
}
@Test @Transactional
public void testGetIndexForName() throws Exception {
final Index<PropertyContainer> nameIndex = neo4jTemplate.getIndex(Person.NAME_INDEX);
final Index<PropertyContainer> nameIndex = template.getIndex(Person.NAME_INDEX);
assertEquals(Person.NAME_INDEX, nameIndex.getName());
}
@@ -152,7 +152,7 @@ public class EntityNeo4jTemplateTest extends EntityTestBase {
public void testCreateRelationshipEntityFromStoredType() throws Exception {
final Relationship friendshipRelationship = getRelationshipState(testTeam.friendShip);
Friendship found = neo4jTemplate.createEntityFromStoredType(friendshipRelationship);
Friendship found = template.createEntityFromStoredType(friendshipRelationship, template.getMappingPolicy(testTeam.michael));
assertEquals(testTeam.friendShip.getId(),found.getId());
}
@@ -160,7 +160,7 @@ public class EntityNeo4jTemplateTest extends EntityTestBase {
public void testCreateNodeEntityFromStoredType() throws Exception {
final Node michaelNode = getNodeState(testTeam.michael);
Person found = neo4jTemplate.createEntityFromStoredType(michaelNode);
Person found = template.createEntityFromStoredType(michaelNode, template.getMappingPolicy(testTeam.michael));
assertEquals(testTeam.michael.getId(),found.getId());
}
@@ -168,7 +168,7 @@ public class EntityNeo4jTemplateTest extends EntityTestBase {
public void testCreateEntityFromState() throws Exception {
final PropertyContainer michaelNode = getNodeState(testTeam.michael);
Person found = neo4jTemplate.createEntityFromStoredType(michaelNode);
Person found = template.createEntityFromStoredType(michaelNode, template.getMappingPolicy(testTeam.michael));
assertEquals(testTeam.michael.getId(),found.getId());
}
@@ -186,7 +186,7 @@ public class EntityNeo4jTemplateTest extends EntityTestBase {
@Test @Transactional
public void testSetPersistentState() throws Exception {
final Person clone = new Person();
neo4jTemplate.setPersistentState(clone, neo4jOperations.getPersistentState(testTeam.david));
template.setPersistentState(clone, neo4jOperations.getPersistentState(testTeam.david));
assertEquals(testTeam.david.getId(), clone.getId());
}
@@ -206,7 +206,7 @@ public class EntityNeo4jTemplateTest extends EntityTestBase {
final Long id = testTeam.michael.getId();
new TransactionTemplate(transactionManager).execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
neo4jTemplate.removeNodeEntity(testTeam.michael);
template.removeNodeEntity(testTeam.michael);
}
});
assertNull(neo4jOperations.getNode(id));
@@ -217,7 +217,7 @@ public class EntityNeo4jTemplateTest extends EntityTestBase {
final Long id = testTeam.friendShip.getId();
new TransactionTemplate(transactionManager).execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
neo4jTemplate.removeRelationshipEntity(testTeam.friendShip);
template.removeRelationshipEntity(testTeam.friendShip);
}
});
assertNull(neo4jOperations.getRelationship(id));
@@ -229,22 +229,22 @@ public class EntityNeo4jTemplateTest extends EntityTestBase {
public void testCreateNodeAs() throws Exception {
final Person thomas = neo4jOperations.createNodeAs(Person.class, map("name", "Thomas"));
assertEquals("Thomas",neo4jOperations.getNode(thomas.getId()).getProperty("name"));
final Person found = neo4jTemplate.createEntityFromStoredType(getNodeState(thomas));
final Person found = template.createEntityFromStoredType(getNodeState(thomas), template.getMappingPolicy(Person.class));
assertEquals("Thomas",found.getName());
}
@Test @Transactional
public void testIsNodeEntity() throws Exception {
assertEquals(true,neo4jTemplate.isNodeEntity(Person.class));
assertEquals(false,neo4jTemplate.isNodeEntity(Friendship.class));
assertEquals(false,neo4jTemplate.isNodeEntity(Object.class));
assertEquals(true, template.isNodeEntity(Person.class));
assertEquals(false, template.isNodeEntity(Friendship.class));
assertEquals(false, template.isNodeEntity(Object.class));
}
@Test @Transactional
public void testIsRelationshipEntity() throws Exception {
assertEquals(true,neo4jTemplate.isRelationshipEntity(Friendship.class));
assertEquals(false,neo4jTemplate.isRelationshipEntity(Person.class));
assertEquals(false,neo4jTemplate.isRelationshipEntity(Object.class));
assertEquals(true, template.isRelationshipEntity(Friendship.class));
assertEquals(false, template.isRelationshipEntity(Person.class));
assertEquals(false, template.isRelationshipEntity(Object.class));
}
@Test @Transactional
@@ -260,11 +260,11 @@ public class EntityNeo4jTemplateTest extends EntityTestBase {
static abstract class ManagedTestEntity implements ManagedEntity {}
@Test @Transactional
public void testIsManaged() throws Exception {
assertEquals(true,neo4jTemplate.isManaged(Mockito.mock(ManagedEntity.class)));
assertEquals(true,neo4jTemplate.isManaged(Mockito.mock(ManagedTestEntity.class)));
assertEquals(false,neo4jTemplate.isManaged(testTeam.michael));
assertEquals(false,neo4jTemplate.isManaged(testTeam.friendShip));
assertEquals(false,neo4jTemplate.isManaged(new Object()));
assertEquals(true, template.isManaged(Mockito.mock(ManagedEntity.class)));
assertEquals(true, template.isManaged(Mockito.mock(ManagedTestEntity.class)));
assertEquals(false, template.isManaged(testTeam.michael));
assertEquals(false, template.isManaged(testTeam.friendShip));
assertEquals(false, template.isManaged(new Object()));
}
@Test @Transactional

View File

@@ -42,7 +42,7 @@ import java.util.Set;
public class EntityTestBase {
protected final Log log = LogFactory.getLog(getClass());
@Autowired protected Neo4jTemplate neo4jTemplate;
@Autowired protected Neo4jTemplate template;
@Autowired protected ConversionService conversionService;
@Autowired protected GraphDatabaseService graphDatabaseService;
@@ -57,28 +57,28 @@ public class EntityTestBase {
}
protected Node getNodeState(Object entity) {
return neo4jTemplate.getPersistentState(entity);
return template.getPersistentState(entity);
}
protected Long getNodeId(Object entity) {
final Node node = neo4jTemplate.getPersistentState(entity);
final Node node = template.getPersistentState(entity);
return node == null ? null : node.getId();
}
protected Long getRelationshipId(Object entity) {
final Relationship rel = neo4jTemplate.getPersistentState(entity);
final Relationship rel = template.getPersistentState(entity);
return rel == null ? null : rel.getId();
}
protected boolean hasPersistentState(Object entity) {
return neo4jTemplate.getPersistentState(entity)!=null;
return template.getPersistentState(entity)!=null;
}
protected Relationship getRelationshipState(Object entity) {
return neo4jTemplate.getPersistentState(entity);
return template.getPersistentState(entity);
}
@SuppressWarnings("unchecked")
public <T> T persist(T entity) {
return (T) neo4jTemplate.save(entity);
return (T) template.save(entity);
}
protected <T> Set<T> set(T... values) {
@@ -97,11 +97,11 @@ public class EntityTestBase {
@Before
public void cleanDbBeforeTest() {
Neo4jHelper.cleanDb(neo4jTemplate);
Neo4jHelper.cleanDb(template);
}
@BeforeTransaction
public void cleanDb() {
Neo4jHelper.cleanDb(neo4jTemplate);
Neo4jHelper.cleanDb(template);
}
}

View File

@@ -325,28 +325,28 @@ public class FullNeo4jTemplateTest {
assertEquals("rel2", relationship.getProperty("name", "not set"));
}
private static class PathRelationshipNameMapper implements ResultConverter<Path, String> {
private static class PathRelationshipNameMapper extends ResultConverter.ResultConverterAdapter<Path, String> {
@Override
public String convert(Path path, Class<String> type) {
return (String) path.lastRelationship().getProperty("name", "not set");
}
}
private static class PathNodeNameMapper implements ResultConverter<Path, String> {
private static class PathNodeNameMapper extends ResultConverter.ResultConverterAdapter<Path, String> {
@Override
public String convert(Path path, Class<String> type) {
return (String) path.endNode().getProperty("name", "not set");
}
}
private static class RelationshipNameConverter implements ResultConverter<Relationship, String> {
private static class RelationshipNameConverter extends ResultConverter.ResultConverterAdapter<Relationship, String> {
@Override
public String convert(Relationship value, Class<String> type) {
return (String) value.getProperty("name");
}
}
private static class PropertyContainerNameConverter implements ResultConverter<PropertyContainer, String> {
private static class PropertyContainerNameConverter extends ResultConverter.ResultConverterAdapter<PropertyContainer, String> {
@Override
public String convert(PropertyContainer value, Class<String> type) {
return (String) value.getProperty("name");

View File

@@ -327,27 +327,27 @@ public class Neo4jTemplateApiTest {
assertEquals("rel2",relationship.getProperty("name","not set"));
}
private static class PathRelationshipNameMapper implements ResultConverter<Path,String> {
private static class PathRelationshipNameMapper extends ResultConverter.ResultConverterAdapter<Path,String> {
@Override
public String convert(Path path, Class<String> type) {
return (String) path.lastRelationship().getProperty("name","not set");
}
}
private static class PathNodeNameMapper implements ResultConverter<Path,String> {
private static class PathNodeNameMapper extends ResultConverter.ResultConverterAdapter<Path,String> {
@Override
public String convert(Path path, Class<String> type) {
return (String) path.endNode().getProperty("name","not set");
}
}
private static class RelationshipNameConverter implements ResultConverter<Relationship,String> {
private static class RelationshipNameConverter extends ResultConverter.ResultConverterAdapter<Relationship,String> {
@Override
public String convert(Relationship value, Class<String> type) {
return (String) value.getProperty("name");
}
}
private static class PropertyContainerNameConverter implements ResultConverter<PropertyContainer, String> {
private static class PropertyContainerNameConverter extends ResultConverter.ResultConverterAdapter<PropertyContainer, String> {
@Override
public String convert(PropertyContainer value, Class<String> type) {
return (String) value.getProperty("name");

View File

@@ -83,7 +83,7 @@ public class SnippetNeo4jTemplateMethodsTest extends DocumentingTestBase {
assertEquals(thomas, neo.lookup("devs", "name", "Thomas").to(Node.class).single());
// Index lookup with Result Converter
assertEquals("Thomas", neo.lookup("devs", "name", "Thomas").to(String.class, new ResultConverter<PropertyContainer, String>() {
assertEquals("Thomas", neo.lookup("devs", "name", "Thomas").to(String.class, new ResultConverter.ResultConverterAdapter<PropertyContainer, String>() {
public String convert(PropertyContainer element, Class<String> type) {
return (String) element.getProperty("name");
}