From 7d5d85a4d0635d3d535540cdda2f61049cef269e Mon Sep 17 00:00:00 2001 From: Michael Hunger Date: Tue, 27 Sep 2011 01:01:09 +0200 Subject: [PATCH] converted usage of java.lang.reflect.Field to Neo4jPersistentProperty --- .../data/neo4j/core/EntityState.java | 6 ++ .../FieldTraversalDescriptionBuilder.java | 8 +- ...AbstractNodeRelationshipFieldAccessor.java | 10 +-- ...rtingNodePropertyFieldAccessorFactory.java | 33 ++----- .../neo4j/fieldaccess/DefaultEntityState.java | 51 +++++++---- .../DelegatingFieldAccessorFactory.java | 86 +++++++++---------- .../fieldaccess/DetachedEntityState.java | 22 ++++- ...DynamicPropertiesFieldAccessorFactory.java | 15 ++-- .../fieldaccess/FieldAccessorFactory.java | 8 +- .../FieldAccessorFactoryProviders.java | 45 +++++----- .../FieldAccessorListenerFactory.java | 14 +-- .../fieldaccess/IdFieldAccessorFactory.java | 24 ++---- ...gPropertyFieldAccessorListenerFactory.java | 50 +++++------ .../JpaIdFieldAccessListenerFactory.java | 16 ++-- .../fieldaccess/ManagedFieldAccessorSet.java | 15 ++-- .../ManagedPrefixedDynamicProperties.java | 24 +++--- .../NodeRelationshipFieldAccessorFactory.java | 35 +------- .../NodeToNodesRelationshipFieldAccessor.java | 5 +- ...elationshipEntityFieldAccessorFactory.java | 46 +++------- ...neToNRelationshipFieldAccessorFactory.java | 28 +++--- .../PropertyFieldAccessorFactory.java | 29 +++---- .../QueryFieldAccessorFactory.java | 24 +++--- ...neToNRelationshipFieldAccessorFactory.java | 17 ++-- .../RelationshipNodeFieldAccessorFactory.java | 27 +++--- ...ingleRelationshipFieldAccessorFactory.java | 18 ++-- .../TransientFieldAccessorFactory.java | 18 ++-- .../TraversalFieldAccessorFactory.java | 29 ++++--- ...ePropertyFieldAccessorListenerFactory.java | 23 ++--- .../neo4j/mapping/Neo4JPersistentEntity.java | 1 + .../mapping/Neo4JPersistentEntityImpl.java | 23 +++++ .../mapping/Neo4JPersistentProperty.java | 28 ++++++ .../mapping/Neo4JPersistentPropertyImpl.java | 73 +++++++++++++++- .../data/neo4j/mapping/RelationshipInfo.java | 52 ++++++++--- .../neo4j/support/GraphDatabaseContext.java | 2 +- .../neo4j/support/node/NodeEntityState.java | 2 +- .../support/node/NodeEntityStateFactory.java | 4 +- .../support/node/PartialNodeEntityState.java | 17 ++-- .../relationship/RelationshipEntityState.java | 2 +- .../RelationshipEntityStateFactory.java | 3 +- .../org/springframework/data/neo4j/Group.java | 4 +- .../neo4j/support/GraphRepositoryTest.java | 5 ++ 41 files changed, 524 insertions(+), 418 deletions(-) diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/EntityState.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/EntityState.java index 7bdf99de7..d2cd24560 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/EntityState.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/EntityState.java @@ -19,6 +19,8 @@ package org.springframework.data.neo4j.core; import java.lang.reflect.Field; import org.springframework.data.neo4j.fieldaccess.FieldAccessor; +import org.springframework.data.neo4j.mapping.Neo4JPersistentEntity; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; /** * Interface for classes encapsulating and delegating read and write field access of an GraphBacked entity to a number of field accessors. @@ -50,11 +52,13 @@ public interface EntityState,STATE> { boolean isWritable(Field field); /** + * * @param field * @param newVal * @return sets the value in the entity and/or the state */ Object setValue(Field field, Object newVal); + Object setValue(Neo4JPersistentProperty property, Object newVal); /** * callback for creating and initializing an initial state @@ -67,4 +71,6 @@ public interface EntityState,STATE> { STATE getPersistentState(); ENTITY persist(); + + Neo4JPersistentEntity getPersistentEntity(); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/FieldTraversalDescriptionBuilder.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/FieldTraversalDescriptionBuilder.java index e6df9d077..47487bb84 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/FieldTraversalDescriptionBuilder.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/FieldTraversalDescriptionBuilder.java @@ -17,8 +17,7 @@ package org.springframework.data.neo4j.core; import org.neo4j.graphdb.traversal.TraversalDescription; - -import java.lang.reflect.Field; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; /** * Interface for classes that build traversal descriptions. Those classes can be referred to by @@ -31,9 +30,10 @@ import java.lang.reflect.Field; public interface FieldTraversalDescriptionBuilder { /** * Builder method for traversal description. + * * @param start the Entity that contains the field with the dynamic traversal. Used for the parametrization of the traversal description. - * @param field the concrete field that will provide the traversal. Used for the parametrization of the traversal description. + * @param property * @return the TraversalDescription to apply on fieldaccess, the start node is the current entity node */ - TraversalDescription build(NodeBacked start, Field field, String...params); + TraversalDescription build(NodeBacked start, Neo4JPersistentProperty property, String...params); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/AbstractNodeRelationshipFieldAccessor.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/AbstractNodeRelationshipFieldAccessor.java index 013c1fdac..2502ca1b6 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/AbstractNodeRelationshipFieldAccessor.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/AbstractNodeRelationshipFieldAccessor.java @@ -19,9 +19,9 @@ package org.springframework.data.neo4j.fieldaccess; import org.neo4j.graphdb.*; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.neo4j.core.GraphBacked; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; import org.springframework.data.neo4j.support.GraphDatabaseContext; -import java.lang.reflect.Field; import java.util.HashSet; import java.util.Set; @@ -31,17 +31,17 @@ import java.util.Set; */ public abstract class AbstractNodeRelationshipFieldAccessor implements FieldAccessor { protected final RelationshipType type; - protected final Field field; + protected final Neo4JPersistentProperty property; protected final Direction direction; protected final Class relatedType; protected final GraphDatabaseContext graphDatabaseContext; - public AbstractNodeRelationshipFieldAccessor(Class clazz, GraphDatabaseContext graphDatabaseContext, Direction direction, RelationshipType type, Field field) { + public AbstractNodeRelationshipFieldAccessor(Class clazz, GraphDatabaseContext graphDatabaseContext, Direction direction, RelationshipType type, Neo4JPersistentProperty property) { this.relatedType = clazz; this.graphDatabaseContext = graphDatabaseContext; this.direction = direction; this.type = type; - this.field = field; + this.property = property; } @Override @@ -84,7 +84,7 @@ public abstract class AbstractNodeRelationshipFieldAccessor createManagedSet(ENTITY entity, Set result) { - return new ManagedFieldAccessorSet(entity, result, field); + return new ManagedFieldAccessorSet(entity, result, property); } protected Set createEntitySetFromRelationshipEndNodes(ENTITY entity) { diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ConvertingNodePropertyFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ConvertingNodePropertyFieldAccessorFactory.java index 218fabb68..0ddf6def3 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ConvertingNodePropertyFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ConvertingNodePropertyFieldAccessorFactory.java @@ -20,10 +20,8 @@ import org.neo4j.graphdb.PropertyContainer; import org.springframework.beans.factory.annotation.Configurable; import org.springframework.core.convert.ConversionService; import org.springframework.data.neo4j.core.GraphBacked; -import org.springframework.data.neo4j.core.NodeBacked; -import org.springframework.data.neo4j.core.RelationshipBacked; - -import java.lang.reflect.Field; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; +import scala.annotation.target.field; /** * @author Michael Hunger @@ -40,35 +38,20 @@ public class ConvertingNodePropertyFieldAccessorFactory implements FieldAccessor @Override - public boolean accept(final Field field) { - return isSerializableField(field) && isDeserializableField(field); + public boolean accept(final Neo4JPersistentProperty field) { + return field.isSerializableField(conversionService) && field.isDeserializableField(conversionService); } @Override - public FieldAccessor> forField(final Field field) { - return new ConvertingNodePropertyFieldAccessor(conversionService, DelegatingFieldAccessorFactory.getNeo4jPropertyName(field),field.getType()); - } - - private boolean isSerializableField(final Field field) { - return isSimpleValueField(field) && conversionService.canConvert(field.getType(), String.class); - } - - private boolean isDeserializableField(final Field field) { - return isSimpleValueField(field) && conversionService.canConvert(String.class, field.getType()); - } - - private boolean isSimpleValueField(final Field field) { - final Class type = field.getType(); - if (Iterable.class.isAssignableFrom(type) || NodeBacked.class.isAssignableFrom(type) || RelationshipBacked.class.isAssignableFrom(type)) - return false; - return true; + public FieldAccessor> forField(final Neo4JPersistentProperty property) { + return new ConvertingNodePropertyFieldAccessor(conversionService,property); } public static class ConvertingNodePropertyFieldAccessor extends PropertyFieldAccessorFactory.PropertyFieldAccessor { private final ConversionService conversionService; - public ConvertingNodePropertyFieldAccessor(ConversionService conversionService, String propertyName, Class fieldType) { - super(conversionService,propertyName,fieldType); + public ConvertingNodePropertyFieldAccessor(ConversionService conversionService, Neo4JPersistentProperty property) { + super(conversionService, property); this.conversionService = conversionService; } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/DefaultEntityState.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/DefaultEntityState.java index 2c9a0da57..0043b4df7 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/DefaultEntityState.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/DefaultEntityState.java @@ -21,6 +21,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.data.neo4j.core.EntityState; import org.springframework.data.neo4j.core.GraphBacked; import org.springframework.data.neo4j.mapping.Neo4JPersistentEntity; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; import java.lang.reflect.Field; import java.util.HashMap; @@ -34,20 +35,20 @@ import java.util.Map; public abstract class DefaultEntityState, STATE> implements EntityState { protected final ENTITY entity; protected final Class type; - private final Map> fieldAccessors = new HashMap>(); - private final Map>> fieldAccessorListeners = new HashMap>>(); + private final Map> fieldAccessors = new HashMap>(); + private final Map>> fieldAccessorListeners = new HashMap>>(); private STATE state; protected final static Log log= LogFactory.getLog(DefaultEntityState.class); private final FieldAccessorFactoryProviders fieldAccessorFactoryProviders; - private final Neo4JPersistentEntity persistentEntity; + private final Neo4JPersistentEntity persistentEntity; - public DefaultEntityState(final STATE underlyingState, final ENTITY entity, final Class type, final DelegatingFieldAccessorFactory delegatingFieldAccessorFactory, Neo4JPersistentEntity persistentEntity) { + public DefaultEntityState(final STATE underlyingState, final ENTITY entity, final Class type, final DelegatingFieldAccessorFactory delegatingFieldAccessorFactory, Neo4JPersistentEntity persistentEntity) { this.state = underlyingState; this.entity = entity; this.type = type; this.persistentEntity = persistentEntity; if (delegatingFieldAccessorFactory!=null) { - fieldAccessorFactoryProviders = delegatingFieldAccessorFactory.accessorFactoriesFor(type); + fieldAccessorFactoryProviders = delegatingFieldAccessorFactory.accessorFactoriesFor(persistentEntity); this.fieldAccessors.putAll(fieldAccessorFactoryProviders.getFieldAccessors()); this.fieldAccessorListeners.putAll(fieldAccessorFactoryProviders.getFieldAccessListeners()); } else { @@ -78,38 +79,53 @@ public abstract class DefaultEntityState, STAT return state; } + public Neo4JPersistentEntity getPersistentEntity() { + return persistentEntity; + } + @Override public boolean isWritable(Field field) { - final FieldAccessor accessor = accessorFor(field); + final FieldAccessor accessor = accessorFor(property(field)); if (accessor == null) return true; return accessor.isWriteable(entity); } @Override public Object getValue(final Field field) { - final FieldAccessor accessor = accessorFor(field); + final FieldAccessor accessor = accessorFor(property(field)); if (accessor == null) return null; else return accessor.getValue(entity); } @Override public Object setValue(final Field field, final Object newVal) { - final FieldAccessor accessor = accessorFor(field); + return setValue(property(field),newVal); + } + + @Override + public Object setValue(final Neo4JPersistentProperty property, final Object newVal) { + final FieldAccessor accessor = accessorFor(property); final Object result=accessor!=null ? accessor.setValue(entity, newVal) : newVal; - notifyListeners(field, result); + notifyListeners(property, result); return result; } + @Override public Object getDefaultImplementation(Field field) { - final FieldAccessor accessor = accessorFor(field); + final FieldAccessor accessor = accessorFor(property(field)); if (accessor == null) return null; else return accessor.getDefaultImplementation(); } - protected FieldAccessor accessorFor(final Field field) { - return fieldAccessors.get(field); + + protected Neo4JPersistentProperty property(Field field) { + return persistentEntity.getPersistentProperty(field.getName()); } - private void notifyListeners(final Field field, final Object result) { + protected FieldAccessor accessorFor(final Neo4JPersistentProperty property) { + return fieldAccessors.get(property); + } + + private void notifyListeners(final Neo4JPersistentProperty field, final Object result) { if (!fieldAccessorListeners.containsKey(field) || fieldAccessorListeners.get(field) == null) return; for (final FieldAccessListener listener : fieldAccessorListeners.get(field)) { listener.valueChanged(entity, null, result); // todo oldValue @@ -117,13 +133,12 @@ public abstract class DefaultEntityState, STAT } protected Object getIdFromEntity() { - final Field idField = fieldAccessorFactoryProviders.getIdField(); - if (idField==null) return null; + final Neo4JPersistentProperty idProperty = fieldAccessorFactoryProviders.getIdProperty(); + if (idProperty==null) return null; try { - idField.setAccessible(true); - return idField.get(entity); + return idProperty.getValue(entity); } catch (IllegalAccessException e) { - log.warn("Error accessing id field "+idField); + log.warn("Error accessing id field "+idProperty); return null; } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/DelegatingFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/DelegatingFieldAccessorFactory.java index 53c67ca63..7a142e5df 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/DelegatingFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/DelegatingFieldAccessorFactory.java @@ -18,10 +18,13 @@ package org.springframework.data.neo4j.fieldaccess; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.data.neo4j.annotation.NodeEntity; -import org.springframework.data.neo4j.annotation.RelationshipEntity; +import org.springframework.data.mapping.Association; +import org.springframework.data.mapping.AssociationHandler; +import org.springframework.data.mapping.PropertyHandler; +import org.springframework.data.neo4j.mapping.Neo4JPersistentEntity; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; import org.springframework.data.neo4j.support.GraphDatabaseContext; -import org.springframework.util.ReflectionUtils; +import org.springframework.data.util.TypeInformation; import java.lang.reflect.Field; import java.util.*; @@ -49,62 +52,44 @@ public abstract class DelegatingFieldAccessorFactory implements FieldAccessor } @Override - public boolean accept(final Field f) { + public boolean accept(final Neo4JPersistentProperty f) { return true; } final Collection> fieldAccessorFactories = new ArrayList>(); final Collection> fieldAccessorListenerFactories = new ArrayList>(); - public FieldAccessor forField(final Field field) { - final FieldAccessorFactory factory = factoryForField(field); - return factory != null ? factory.forField(field) : null; + public FieldAccessor forField(final Neo4JPersistentProperty property) { + final FieldAccessorFactory factory = factoryForField(property); + return factory != null ? factory.forField(property) : null; } - private FieldAccessorFactory factoryForField(final Field field) { - if (isSyntheticField(field)) return null; + private FieldAccessorFactory factoryForField(final Neo4JPersistentProperty property) { + if (property.isSyntheticField()) return null; for (final FieldAccessorFactory fieldAccessorFactory : fieldAccessorFactories) { - if (fieldAccessorFactory.accept(field)) { - if (log.isInfoEnabled()) log.info("Factory " + fieldAccessorFactory + " used for field: " + field); + if (fieldAccessorFactory.accept(property)) { + if (log.isInfoEnabled()) log.info("Factory " + fieldAccessorFactory + " used for field: " + property); return (FieldAccessorFactory) fieldAccessorFactory; } } - if (log.isWarnEnabled()) log.warn("No FieldAccessor configured for field: " + field); + if (log.isWarnEnabled()) log.warn("No FieldAccessor configured for field: " + property); return null; } - private boolean isSyntheticField(final Field field) { - return field.getName().contains("$"); - } - - public static String getNeo4jPropertyName(final Field field) { - final Class entityClass = field.getDeclaringClass(); - if (useShortNames(entityClass)) return field.getName(); - return String.format("%s.%s", entityClass.getSimpleName(), field.getName()); - } - - private static boolean useShortNames(final Class entityClass) { - final NodeEntity graphEntity = entityClass.getAnnotation(NodeEntity.class); - if (graphEntity != null) return graphEntity.useShortNames(); - final RelationshipEntity graphRelationship = entityClass.getAnnotation(RelationshipEntity.class); - if (graphRelationship != null) return graphRelationship.useShortNames(); - return false; - } - - public List> listenersFor(final Field field) { + public List> listenersFor(final Neo4JPersistentProperty property) { final List> result = new ArrayList>(); - final List> fieldAccessListenerFactories = getFieldAccessListenerFactories(field); + final List> fieldAccessListenerFactories = getFieldAccessListenerFactories(property); for (final FieldAccessorListenerFactory fieldAccessorListenerFactory : fieldAccessListenerFactories) { - final FieldAccessListener listener = fieldAccessorListenerFactory.forField(field); + final FieldAccessListener listener = fieldAccessorListenerFactory.forField(property); result.add(listener); } return result; } - private List> getFieldAccessListenerFactories(final Field field) { + private List> getFieldAccessListenerFactories(final Neo4JPersistentProperty property) { final List> result = new ArrayList>(); for (final FieldAccessorListenerFactory fieldAccessorListenerFactory : fieldAccessorListenerFactories) { - if (fieldAccessorListenerFactory.accept(field)) { + if (fieldAccessorListenerFactory.accept(property)) { result.add((FieldAccessorListenerFactory) fieldAccessorListenerFactory); } } @@ -114,21 +99,32 @@ public abstract class DelegatingFieldAccessorFactory implements FieldAccessor - private final Map, FieldAccessorFactoryProviders> accessorFactoryProviderCache = new HashMap, FieldAccessorFactoryProviders>(); + private final Map, FieldAccessorFactoryProviders> accessorFactoryProviderCache = new HashMap, FieldAccessorFactoryProviders>(); - public FieldAccessorFactoryProviders accessorFactoriesFor(final Class type) { + public FieldAccessorFactoryProviders accessorFactoriesFor(final Neo4JPersistentEntity type) { synchronized (this) { - final FieldAccessorFactoryProviders fieldAccessorFactoryProviders = accessorFactoryProviderCache.get(type); + final TypeInformation typeInformation = type.getTypeInformation(); + final FieldAccessorFactoryProviders fieldAccessorFactoryProviders = accessorFactoryProviderCache.get(typeInformation); if (fieldAccessorFactoryProviders != null) return fieldAccessorFactoryProviders; - final FieldAccessorFactoryProviders newFieldAccessorFactories = new FieldAccessorFactoryProviders(type); - ReflectionUtils.doWithFields(type, new ReflectionUtils.FieldCallback() { - public void doWith(final Field field) throws IllegalArgumentException, IllegalAccessException { - final FieldAccessorFactory factory = factoryForField(field); - final List listenerFactories = (List) getFieldAccessListenerFactories(field); - newFieldAccessorFactories.add(field, factory, listenerFactories); + final FieldAccessorFactoryProviders newFieldAccessorFactories = new FieldAccessorFactoryProviders(typeInformation); + type.doWithProperties(new PropertyHandler() { + @Override + public void doWithPersistentProperty(Neo4JPersistentProperty property) { + final FieldAccessorFactory factory = factoryForField(property); + final List listenerFactories = (List) getFieldAccessListenerFactories(property); + newFieldAccessorFactories.add(property, factory, listenerFactories); } }); - accessorFactoryProviderCache.put(type, newFieldAccessorFactories); + type.doWithAssociations(new AssociationHandler() { + @Override + public void doWithAssociation(Association association) { + final Neo4JPersistentProperty property = association.getInverse(); + final FieldAccessorFactory factory = factoryForField(property); + final List listenerFactories = (List) getFieldAccessListenerFactories(property); + newFieldAccessorFactories.add(property, factory, listenerFactories); + } + }); + accessorFactoryProviderCache.put(typeInformation, newFieldAccessorFactories); return newFieldAccessorFactories; } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/DetachedEntityState.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/DetachedEntityState.java index 0854827e2..977d94c47 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/DetachedEntityState.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/DetachedEntityState.java @@ -22,6 +22,8 @@ import org.neo4j.graphdb.Transaction; import org.springframework.data.neo4j.core.EntityState; import org.springframework.data.neo4j.core.GraphBacked; import org.springframework.data.neo4j.core.NodeBacked; +import org.springframework.data.neo4j.mapping.Neo4JPersistentEntity; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; import org.springframework.data.neo4j.support.GraphDatabaseContext; import org.springframework.util.ObjectUtils; @@ -42,8 +44,11 @@ public class DetachedEntityState, STATE> imple protected final EntityState delegate; private final static Log log = LogFactory.getLog(DetachedEntityState.class); private GraphDatabaseContext graphDatabaseContext; + private Neo4JPersistentEntity persistentEntity; + public DetachedEntityState(final EntityState delegate, GraphDatabaseContext graphDatabaseContext) { this.delegate = delegate; + this.persistentEntity = delegate.getPersistentEntity(); this.graphDatabaseContext = graphDatabaseContext; } @@ -67,6 +72,11 @@ public class DetachedEntityState, STATE> imple return delegate.getPersistentState(); } + @Override + public Neo4JPersistentEntity getPersistentEntity() { + return persistentEntity; + } + @Override public Object getValue(final Field field) { if (isDetached()) { @@ -124,7 +134,17 @@ public class DetachedEntityState, STATE> imple } @Override public Object setValue(final Field field, final Object newVal) { + return setValue(property(field),newVal); + } + + private Neo4JPersistentProperty property(Field field) { + return persistentEntity.getPersistentProperty(field.getName()); + } + + @Override + public Object setValue(final Neo4JPersistentProperty property, final Object newVal) { if (isDetached()) { + final Field field = property.getField(); if (!isDirty(field) && isWritable(field)) { Object existingValue; if (hasPersistentState()) { @@ -139,7 +159,7 @@ public class DetachedEntityState, STATE> imple return newVal; } // flushDirty(); - return delegate.setValue(field, newVal); + return delegate.setValue(property, newVal); } @Override public Object getDefaultImplementation(Field field) { diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/DynamicPropertiesFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/DynamicPropertiesFieldAccessorFactory.java index 3cdef97f0..91f66589e 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/DynamicPropertiesFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/DynamicPropertiesFieldAccessorFactory.java @@ -16,17 +16,14 @@ package org.springframework.data.neo4j.fieldaccess; import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Collection; import java.util.HashSet; -import java.util.Iterator; import java.util.Set; -import org.apache.commons.collections.CollectionUtils; import org.neo4j.graphdb.PropertyContainer; import org.neo4j.helpers.collection.IteratorUtil; import org.springframework.core.convert.ConversionService; import org.springframework.data.neo4j.core.GraphBacked; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; import org.springframework.data.neo4j.support.DoReturn; /** @@ -42,22 +39,22 @@ public class DynamicPropertiesFieldAccessorFactory implements FieldAccessorFacto } @Override - public boolean accept(Field f) { + public boolean accept(Neo4JPersistentProperty f) { return DynamicProperties.class.isAssignableFrom(f.getType()); } @Override - public FieldAccessor> forField(Field field) { + public FieldAccessor> forField(Neo4JPersistentProperty field) { return new DynamicPropertiesFieldAccessor(conversionService, - DelegatingFieldAccessorFactory.getNeo4jPropertyName(field), field); + field.getNeo4jPropertyName(), field); } public static class DynamicPropertiesFieldAccessor implements FieldAccessor> { private final ConversionService conversionService; private final String propertyNamePrefix; - private final Field field; + private final Neo4JPersistentProperty field; - public DynamicPropertiesFieldAccessor(ConversionService conversionService, String propertyName, Field field) { + public DynamicPropertiesFieldAccessor(ConversionService conversionService, String propertyName, Neo4JPersistentProperty field) { this.conversionService = conversionService; this.propertyNamePrefix = propertyName; this.field = field; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/FieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/FieldAccessorFactory.java index dc4f9d61a..d0f2060d0 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/FieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/FieldAccessorFactory.java @@ -16,6 +16,8 @@ package org.springframework.data.neo4j.fieldaccess; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; + import java.lang.reflect.Field; /** @@ -27,14 +29,16 @@ import java.lang.reflect.Field; */ public interface FieldAccessorFactory { /** + * * @param f field to check * @return true if this factory is responsible for creating a accessor for this field */ - boolean accept(Field f); + boolean accept(Neo4JPersistentProperty f); /** + * * @param f the field to create an accessor for * @return a field accessor for the field or null if none can be created */ - FieldAccessor forField(Field f); + FieldAccessor forField(Neo4JPersistentProperty f); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/FieldAccessorFactoryProviders.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/FieldAccessorFactoryProviders.java index 07d68e111..04d61174e 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/FieldAccessorFactoryProviders.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/FieldAccessorFactoryProviders.java @@ -16,6 +16,9 @@ package org.springframework.data.neo4j.fieldaccess; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; +import org.springframework.data.util.TypeInformation; + import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; @@ -29,69 +32,69 @@ import java.util.Map; public class FieldAccessorFactoryProviders { static class FieldAccessorFactoryProvider { - private final Field field; + private final Neo4JPersistentProperty property; private final FieldAccessorFactory fieldAccessorFactory; private final List> fieldAccessorListenerFactories; - FieldAccessorFactoryProvider(final Field field, final FieldAccessorFactory fieldAccessorFactory, final List> fieldAccessorListenerFactories) { - this.field = field; + FieldAccessorFactoryProvider(final Neo4JPersistentProperty property, final FieldAccessorFactory fieldAccessorFactory, final List fieldAccessorListenerFactories) { + this.property = property; this.fieldAccessorFactory = fieldAccessorFactory; this.fieldAccessorListenerFactories = fieldAccessorListenerFactories; } public FieldAccessor accessor() { if (fieldAccessorFactory == null) return null; - return fieldAccessorFactory.forField(field); + return fieldAccessorFactory.forField(property); } public List> listeners() { if (fieldAccessorListenerFactories == null) return null; final List> listeners = new ArrayList>(fieldAccessorListenerFactories.size()); for (final FieldAccessorListenerFactory fieldAccessorListenerFactory : fieldAccessorListenerFactories) { - listeners.add(fieldAccessorListenerFactory.forField(field)); + listeners.add(fieldAccessorListenerFactory.forField(property)); } return listeners; } - public Field getField() { - return field; + public Neo4JPersistentProperty getProperty() { + return property; } } - private final Class type; + private final TypeInformation type; private final List> fieldAccessorFactoryProviders = new ArrayList>(); private final IdFieldAccessorFactory idFieldAccessorFactory; - private Field idField; + private Neo4JPersistentProperty idProperty; - FieldAccessorFactoryProviders(Class type) { + FieldAccessorFactoryProviders(TypeInformation type) { this.type = type; idFieldAccessorFactory = new IdFieldAccessorFactory(); } - public Map> getFieldAccessors() { - final Map> result = new HashMap>(fieldAccessorFactoryProviders.size(),1); + public Map> getFieldAccessors() { + final Map> result = new HashMap>(fieldAccessorFactoryProviders.size(),1); for (final FieldAccessorFactoryProvider fieldAccessorFactoryProvider : fieldAccessorFactoryProviders) { final FieldAccessor accessor = fieldAccessorFactoryProvider.accessor(); - result.put(fieldAccessorFactoryProvider.getField(), accessor); + result.put(fieldAccessorFactoryProvider.getProperty(), accessor); } return result; } - public Map>> getFieldAccessListeners() { - final Map>> result = new HashMap>>(fieldAccessorFactoryProviders.size(),1); + public Map>> getFieldAccessListeners() { + final Map>> result = new HashMap>>(fieldAccessorFactoryProviders.size(),1); for (final FieldAccessorFactoryProvider fieldAccessorFactoryProvider : fieldAccessorFactoryProviders) { final List> listeners = (List>) fieldAccessorFactoryProvider.listeners(); - result.put(fieldAccessorFactoryProvider.getField(), listeners); + result.put(fieldAccessorFactoryProvider.getProperty(), listeners); } return result; } - public void add(Field field, FieldAccessorFactory fieldAccessorFactory, List listenerFactories) { - fieldAccessorFactoryProviders.add(new FieldAccessorFactoryProvider(field, fieldAccessorFactory, listenerFactories)); - if (idFieldAccessorFactory.accept(field)) this.idField = field; + public void add(Neo4JPersistentProperty property, FieldAccessorFactory fieldAccessorFactory, List listenerFactories) { + fieldAccessorFactoryProviders.add(new FieldAccessorFactoryProvider(property, fieldAccessorFactory, listenerFactories)); + if (property.isIdProperty()) this.idProperty = property; } - public Field getIdField() { - return idField; + public Neo4JPersistentProperty getIdProperty() { + return idProperty; } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/FieldAccessorListenerFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/FieldAccessorListenerFactory.java index d1dbeeb45..f6d65350d 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/FieldAccessorListenerFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/FieldAccessorListenerFactory.java @@ -16,7 +16,7 @@ package org.springframework.data.neo4j.fieldaccess; -import java.lang.reflect.Field; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; /** * factory interface for field accessor listeners. Provides means to check if a field is eligible for this factory @@ -27,14 +27,14 @@ import java.lang.reflect.Field; */ public interface FieldAccessorListenerFactory { /** - * @param f field to check - * @return true if this factory is able to create a listener for the field + * + * @param property@return true if this factory is able to create a listener for the field */ - boolean accept(Field f); + boolean accept(Neo4JPersistentProperty property); /** - * @param f field to create a listener for - * @return newly created field listener + * + * @param property@return newly created field listener */ - FieldAccessListener forField(Field f); + FieldAccessListener forField(Neo4JPersistentProperty property); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/IdFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/IdFieldAccessorFactory.java index d92090d1f..02af6fa4f 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/IdFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/IdFieldAccessorFactory.java @@ -16,11 +16,8 @@ package org.springframework.data.neo4j.fieldaccess; -import org.springframework.data.neo4j.annotation.GraphId; import org.springframework.data.neo4j.core.NodeBacked; - -import javax.persistence.Id; -import java.lang.reflect.Field; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; import static org.springframework.data.neo4j.support.DoReturn.doReturn; @@ -30,25 +27,20 @@ import static org.springframework.data.neo4j.support.DoReturn.doReturn; */ public class IdFieldAccessorFactory implements FieldAccessorFactory { @Override - public boolean accept(final Field f) { - return isIdField(f); - } - - private boolean isIdField(Field field) { - final Class type = field.getType(); - return (type.equals(Long.class) || type.equals(long.class)) && (field.isAnnotationPresent(GraphId.class) || field.isAnnotationPresent(Id.class)); + public boolean accept(final Neo4JPersistentProperty property) { + return property.isIdProperty(); } @Override - public FieldAccessor forField(final Field field) { - return new IdFieldAccessor(field); + public FieldAccessor forField(final Neo4JPersistentProperty property) { + return new IdFieldAccessor(property); } public static class IdFieldAccessor implements FieldAccessor { - protected final Field field; + protected final Neo4JPersistentProperty property; - public IdFieldAccessor(final Field field) { - this.field = field; + public IdFieldAccessor(final Neo4JPersistentProperty property) { + this.property = property; } @Override diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/IndexingPropertyFieldAccessorListenerFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/IndexingPropertyFieldAccessorListenerFactory.java index 5a215953a..b7fe33c53 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/IndexingPropertyFieldAccessorListenerFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/IndexingPropertyFieldAccessorListenerFactory.java @@ -23,6 +23,7 @@ import org.neo4j.graphdb.index.Index; import org.neo4j.index.lucene.ValueContext; import org.springframework.data.neo4j.annotation.Indexed; import org.springframework.data.neo4j.core.GraphBacked; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; import org.springframework.data.neo4j.support.GraphDatabaseContext; import java.lang.reflect.AnnotatedElement; @@ -42,18 +43,18 @@ public class IndexingPropertyFieldAccessorListenerFactory forField(Field field) { - return (FieldAccessListener) new IndexingPropertyFieldAccessorListener(field, indexProvider); + public FieldAccessListener forField(Neo4JPersistentProperty property) { + return (FieldAccessListener) new IndexingPropertyFieldAccessorListener(property, indexProvider); } @@ -64,36 +65,27 @@ public class IndexingPropertyFieldAccessorListenerFactory getIndex(Field field, T instance) { - final Indexed indexedAnnotation = getIndexedAnnotation(field); - final Class type = (Class) field.getDeclaringClass(); + private Index getIndex(Neo4JPersistentProperty property, GraphBacked instance) { + final Indexed indexedAnnotation = property.getAnnotation(Indexed.class); + final Class type = (Class) property.getOwner().getType(); final String providedIndexName = indexedAnnotation.indexName().isEmpty() ? null : indexedAnnotation.indexName(); String indexName = Indexed.Name.get(indexedAnnotation.level(), type, providedIndexName, instance.getClass()); - if (!isFulltextIndex(field)) { + if (!property.getIndexInfo().isFulltext()) { return graphDatabaseContext.getIndex(type, indexName, false); } - if (providedIndexName == null) throw new IllegalStateException("@Indexed(fullext=true) on "+field+" requires an providedIndexName too "); + if (providedIndexName == null) throw new IllegalStateException("@Indexed(fullext=true) on "+property+" requires an providedIndexName too "); String defaultIndexName = Indexed.Name.get(indexedAnnotation.level(), type, null, instance.getClass()); - if (providedIndexName.equals(defaultIndexName)) throw new IllegalStateException("Full-index name for "+field+" must differ from the default name: "+defaultIndexName); + if (providedIndexName.equals(defaultIndexName)) throw new IllegalStateException("Full-index name for "+property+" must differ from the default name: "+defaultIndexName); return graphDatabaseContext.getIndex(type, indexName, true); } } @@ -107,18 +99,18 @@ public class IndexingPropertyFieldAccessorListenerFactory graphBacked, Object oldVal, Object newVal) { - Index index = indexProvider.getIndex(field, graphBacked); + Index index = indexProvider.getIndex(property, graphBacked); if (newVal instanceof Number) newVal = ValueContext.numeric((Number) newVal); final T state = graphBacked.getPersistentState(); diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/JpaIdFieldAccessListenerFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/JpaIdFieldAccessListenerFactory.java index f8178590a..1645c8635 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/JpaIdFieldAccessListenerFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/JpaIdFieldAccessListenerFactory.java @@ -18,9 +18,9 @@ package org.springframework.data.neo4j.fieldaccess; import org.springframework.data.neo4j.core.EntityState; import org.springframework.data.neo4j.core.NodeBacked; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; import javax.persistence.Id; -import java.lang.reflect.Field; /** * @author Michael Hunger @@ -28,20 +28,20 @@ import java.lang.reflect.Field; */ public class JpaIdFieldAccessListenerFactory implements FieldAccessorListenerFactory { @Override - public boolean accept(final Field f) { - return f.isAnnotationPresent(Id.class); + public boolean accept(final Neo4JPersistentProperty property) { + return property.isAnnotationPresent(Id.class); } @Override - public FieldAccessListener forField(final Field field) { - return new JpaIdFieldListener(field); + public FieldAccessListener forField(final Neo4JPersistentProperty property) { + return new JpaIdFieldListener(property); } public static class JpaIdFieldListener implements FieldAccessListener { - protected final Field field; + protected final Neo4JPersistentProperty property; - public JpaIdFieldListener(final Field field) { - this.field = field; + public JpaIdFieldListener(final Neo4JPersistentProperty property) { + this.property = property; } @Override diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedFieldAccessorSet.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedFieldAccessorSet.java index c5fc53bd6..a1026d1ed 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedFieldAccessorSet.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedFieldAccessorSet.java @@ -20,9 +20,9 @@ import org.neo4j.graphdb.Node; import org.springframework.data.neo4j.core.EntityState; import org.springframework.data.neo4j.core.NodeBacked; import org.springframework.data.neo4j.core.RelationshipBacked; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; import org.springframework.data.neo4j.support.DoReturn; -import java.lang.reflect.Field; import java.util.AbstractSet; import java.util.Collection; import java.util.Iterator; @@ -34,11 +34,11 @@ import java.util.Set; public class ManagedFieldAccessorSet extends AbstractSet { private final ENTITY entity; final Set delegate; - private final Field field; + private final Neo4JPersistentProperty property; - public ManagedFieldAccessorSet(final ENTITY entity, final Object newVal, final Field field) { + public ManagedFieldAccessorSet(final ENTITY entity, final Object newVal, final Neo4JPersistentProperty property) { this.entity = entity; - this.field = field; + this.property = property; delegate = (Set) newVal; } @@ -78,13 +78,12 @@ public class ManagedFieldAccessorSet extends AbstractSet { private Object updateValue(EntityState entityState) { try { - final Object newValue = entityState.setValue(field, delegate); + final Object newValue = entityState.setValue(property, delegate); if (newValue instanceof DoReturn) return DoReturn.unwrap(newValue); - field.setAccessible(true); - field.set(entity,newValue); + property.setValue(entity, newValue); return newValue; } catch (IllegalAccessException e) { - throw new RuntimeException("Could not update field "+field+" to new value of type "+delegate.getClass()); + throw new RuntimeException("Could not update field "+ property +" to new value of type "+delegate.getClass()); } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedPrefixedDynamicProperties.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedPrefixedDynamicProperties.java index 86fe472c9..74514cf11 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedPrefixedDynamicProperties.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedPrefixedDynamicProperties.java @@ -19,9 +19,12 @@ import java.lang.reflect.Field; import java.util.Map; import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.PropertyContainer; import org.springframework.data.neo4j.core.EntityState; +import org.springframework.data.neo4j.core.GraphBacked; import org.springframework.data.neo4j.core.NodeBacked; import org.springframework.data.neo4j.core.RelationshipBacked; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; import org.springframework.data.neo4j.support.DoReturn; /** @@ -33,23 +36,23 @@ import org.springframework.data.neo4j.support.DoReturn; */ public class ManagedPrefixedDynamicProperties extends PrefixedDynamicProperties { private final ENTITY entity; - private final Field field; + private final Neo4JPersistentProperty property; - public ManagedPrefixedDynamicProperties(String prefix, final Field field, final ENTITY entity) { + public ManagedPrefixedDynamicProperties(String prefix, final Neo4JPersistentProperty property, final ENTITY entity) { super(prefix); - this.field = field; + this.property = property; this.entity = entity; } - public ManagedPrefixedDynamicProperties(String prefix, int initialCapacity, final Field field, final ENTITY entity) { + public ManagedPrefixedDynamicProperties(String prefix, int initialCapacity, final Neo4JPersistentProperty property, final ENTITY entity) { super(prefix, initialCapacity); - this.field = field; + this.property = property; this.entity = entity; } - public static ManagedPrefixedDynamicProperties create(String prefix, final Field field, + public static ManagedPrefixedDynamicProperties create(String prefix, final Neo4JPersistentProperty property, final E entity) { - return new ManagedPrefixedDynamicProperties(prefix, field, entity); + return new ManagedPrefixedDynamicProperties(prefix, property, entity); } @Override @@ -73,7 +76,7 @@ public class ManagedPrefixedDynamicProperties extends PrefixedDynamicPro @Override public DynamicProperties createFrom(Map map) { - DynamicProperties d = new ManagedPrefixedDynamicProperties(prefix, map.size(), field, entity); + DynamicProperties d = new ManagedPrefixedDynamicProperties(prefix, map.size(), property, entity); d.setPropertiesFrom(map); return d; } @@ -92,14 +95,15 @@ public class ManagedPrefixedDynamicProperties extends PrefixedDynamicPro private Object updateValue(EntityState entityState) { try { - final Object newValue = entityState.setValue(field, this); + final Object newValue = entityState.setValue(property, this); if (newValue instanceof DoReturn) return DoReturn.unwrap(newValue); + final Field field = this.property.getField(); field.setAccessible(true); field.set(entity, newValue); return newValue; } catch (IllegalAccessException e) { - throw new RuntimeException("Could not update field " + field + " to new value of type " + throw new RuntimeException("Could not update field " + property + " to new value of type " + this.getClass()); } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/NodeRelationshipFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/NodeRelationshipFieldAccessorFactory.java index 788010753..b2444a2fa 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/NodeRelationshipFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/NodeRelationshipFieldAccessorFactory.java @@ -20,6 +20,7 @@ import org.neo4j.graphdb.Direction; import org.neo4j.graphdb.DynamicRelationshipType; import org.springframework.data.neo4j.annotation.RelatedTo; import org.springframework.data.neo4j.core.NodeBacked; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; import org.springframework.data.neo4j.support.GenericTypeExtractor; import org.springframework.data.neo4j.support.GraphDatabaseContext; @@ -33,40 +34,8 @@ public abstract class NodeRelationshipFieldAccessorFactory implements FieldAcces protected GraphDatabaseContext graphDatabaseContext; - public NodeRelationshipFieldAccessorFactory( - GraphDatabaseContext graphDatabaseContext) { - super(); + public NodeRelationshipFieldAccessorFactory(GraphDatabaseContext graphDatabaseContext) { this.graphDatabaseContext = graphDatabaseContext; } - @SuppressWarnings({"unchecked"}) - protected Class targetFrom(Field field, RelatedTo relatedTo) { - if (relatedTo!=null && relatedTo.elementClass()!=NodeBacked.class) return relatedTo.elementClass(); - return (Class) GenericTypeExtractor.resolveFieldType(field); - } - - protected Direction dirFrom(RelatedTo relAnnotation) { - return relAnnotation.direction().toNeo4jDir(); - } - - protected DynamicRelationshipType typeFrom(Field field) { - return DynamicRelationshipType.withName(DelegatingFieldAccessorFactory.getNeo4jPropertyName(field)); - } - - protected DynamicRelationshipType typeFrom(RelatedTo relAnnotation) { - return DynamicRelationshipType.withName(relAnnotation.type()); - } - - protected DynamicRelationshipType typeFrom(Field field, RelatedTo relAnnotation) { - return "".equals(relAnnotation.type()) ? typeFrom(field) : typeFrom(relAnnotation); - } - - protected RelatedTo getRelationshipAnnotation(Field field) { - return field.getAnnotation(RelatedTo.class); - } - - protected boolean hasValidRelationshipAnnotation(Field field) { - final RelatedTo relAnnotation = getRelationshipAnnotation(field); - return (relAnnotation != null); - } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/NodeToNodesRelationshipFieldAccessor.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/NodeToNodesRelationshipFieldAccessor.java index 6436860ed..5aaf17043 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/NodeToNodesRelationshipFieldAccessor.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/NodeToNodesRelationshipFieldAccessor.java @@ -22,6 +22,7 @@ import org.neo4j.graphdb.Relationship; import org.neo4j.graphdb.RelationshipType; import org.springframework.data.neo4j.core.GraphBacked; import org.springframework.data.neo4j.core.NodeBacked; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; import org.springframework.data.neo4j.support.GraphDatabaseContext; import java.lang.reflect.Field; @@ -33,8 +34,8 @@ import java.util.Set; * @since 12.09.2010 */ public abstract class NodeToNodesRelationshipFieldAccessor extends AbstractNodeRelationshipFieldAccessor { - public NodeToNodesRelationshipFieldAccessor(final Class clazz, final GraphDatabaseContext graphDatabaseContext, final Direction direction, final RelationshipType type, Field field) { - super(clazz, graphDatabaseContext, direction, type,field); + public NodeToNodesRelationshipFieldAccessor(final Class clazz, final GraphDatabaseContext graphDatabaseContext, final Direction direction, final RelationshipType type, Neo4JPersistentProperty property) { + super(clazz, graphDatabaseContext, direction, type,property); } @Override diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessorFactory.java index d19fedc0e..3a65cf1f4 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessorFactory.java @@ -21,6 +21,8 @@ import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.neo4j.annotation.RelatedToVia; import org.springframework.data.neo4j.core.NodeBacked; import org.springframework.data.neo4j.core.RelationshipBacked; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; +import org.springframework.data.neo4j.mapping.RelationshipInfo; import org.springframework.data.neo4j.support.GraphDatabaseContext; import java.lang.reflect.Field; @@ -40,47 +42,19 @@ public class OneToNRelationshipEntityFieldAccessorFactory implements FieldAccess } @Override - public boolean accept(final Field f) { - return Iterable.class.isAssignableFrom(f.getType()) && hasValidRelationshipAnnotation(f); + public boolean accept(final Neo4JPersistentProperty property) { + return property.isRelationship() && !property.getRelationshipInfo().targetsNodes() && property.getRelationshipInfo().isMultiple(); } @Override - public FieldAccessor forField(final Field field) { - final RelatedToVia relEntityAnnotation = getRelationshipAnnotation(field); - return new OneToNRelationshipEntityFieldAccessor(typeFrom(relEntityAnnotation), dirFrom(relEntityAnnotation), targetFrom(relEntityAnnotation), graphDatabaseContext,field); + public FieldAccessor forField(final Neo4JPersistentProperty property) { + final RelationshipInfo relationshipInfo = property.getRelationshipInfo(); + return new OneToNRelationshipEntityFieldAccessor(relationshipInfo.getRelationshipType(), relationshipInfo.getDirection(), (Class) relationshipInfo.getTargetType().getType(), graphDatabaseContext,property); } - - private boolean hasValidRelationshipAnnotation(final Field field) { - final RelatedToVia relEntityAnnotation = getRelationshipAnnotation(field); - if (relEntityAnnotation == null) return false; - Class elementClass = relEntityAnnotation.elementClass(); - boolean hasElementClass = elementClass != null && !RelationshipBacked.class.equals(elementClass); - if (!hasElementClass) throw new InvalidDataAccessApiUsageException(String.format( - "Missing mandatory attribute @RelatedTo.elementClass for one-to-N relationship field %s in class: %s", - field.getName(), field.getDeclaringClass().getName())); - return hasElementClass; - } - - private RelatedToVia getRelationshipAnnotation(final Field field) { - return field.getAnnotation(RelatedToVia.class); - } - - private Class targetFrom(final RelatedToVia relEntityAnnotation) { - return relEntityAnnotation.elementClass(); - } - - private Direction dirFrom(final RelatedToVia relEntityAnnotation) { - return relEntityAnnotation.direction().toNeo4jDir(); - } - - private DynamicRelationshipType typeFrom(final RelatedToVia relEntityAnnotation) { - return DynamicRelationshipType.withName(relEntityAnnotation.type()); - } - public static class OneToNRelationshipEntityFieldAccessor extends AbstractNodeRelationshipFieldAccessor { - public OneToNRelationshipEntityFieldAccessor(final RelationshipType type, final Direction direction, final Class elementClass, final GraphDatabaseContext graphDatabaseContext, Field field) { - super(elementClass, graphDatabaseContext, direction, type, field); + public OneToNRelationshipEntityFieldAccessor(final RelationshipType type, final Direction direction, final Class elementClass, final GraphDatabaseContext graphDatabaseContext, Neo4JPersistentProperty property) { + super(elementClass, graphDatabaseContext, direction, type, property); } @Override @@ -97,7 +71,7 @@ public class OneToNRelationshipEntityFieldAccessorFactory implements FieldAccess public Object getValue(final NodeBacked entity) { checkUnderlyingNode(entity); final Set result = createEntitySetFromRelationships(entity); - return doReturn(new ManagedFieldAccessorSet(entity, result, field)); + return doReturn(new ManagedFieldAccessorSet(entity, result, property)); } private Set createEntitySetFromRelationships(final NodeBacked entity) { diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipFieldAccessorFactory.java index 5cd57aec2..0db6d82e4 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipFieldAccessorFactory.java @@ -19,12 +19,11 @@ 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.annotation.RelatedTo; import org.springframework.data.neo4j.core.NodeBacked; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; +import org.springframework.data.neo4j.mapping.RelationshipInfo; import org.springframework.data.neo4j.support.GraphDatabaseContext; -import java.lang.reflect.Field; -import java.util.Collection; import java.util.Collections; import java.util.Set; @@ -36,21 +35,24 @@ public class OneToNRelationshipFieldAccessorFactory extends NodeRelationshipFiel super(graphDatabaseContext); } - @Override - public boolean accept(final Field f) { - return Collection.class.isAssignableFrom(f.getType()) && hasValidRelationshipAnnotation(f); - } + @Override + public boolean accept(final Neo4JPersistentProperty property) { + if (!property.isRelationship()) return false; + final RelationshipInfo info = property.getRelationshipInfo(); + return info.isMultiple() && info.targetsNodes() && !info.isReadonly(); + } - @Override - public FieldAccessor forField(final Field field) { - final RelatedTo relAnnotation = getRelationshipAnnotation(field); - return new OneToNRelationshipFieldAccessor(typeFrom(field, relAnnotation), dirFrom(relAnnotation), targetFrom(field, relAnnotation), graphDatabaseContext,field); + @Override + public FieldAccessor forField(final Neo4JPersistentProperty property) { + final RelationshipInfo relationshipInfo = property.getRelationshipInfo(); + final Class targetType = (Class) relationshipInfo.getTargetType().getType(); + return new OneToNRelationshipFieldAccessor(relationshipInfo.getRelationshipType(), relationshipInfo.getDirection(), targetType, graphDatabaseContext,property); } public static class OneToNRelationshipFieldAccessor extends NodeToNodesRelationshipFieldAccessor { - public OneToNRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class elementClass, final GraphDatabaseContext graphDatabaseContext, Field field) { - super(elementClass, graphDatabaseContext, direction, type,field); + public OneToNRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class elementClass, final GraphDatabaseContext graphDatabaseContext, Neo4JPersistentProperty property) { + super(elementClass, graphDatabaseContext, direction, type,property); } public Object setValue(final NodeBacked entity, final Object newVal) { diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/PropertyFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/PropertyFieldAccessorFactory.java index 5a8b0e6aa..6153f7202 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/PropertyFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/PropertyFieldAccessorFactory.java @@ -19,8 +19,7 @@ package org.springframework.data.neo4j.fieldaccess; import org.neo4j.graphdb.PropertyContainer; import org.springframework.core.convert.ConversionService; import org.springframework.data.neo4j.core.GraphBacked; - -import java.lang.reflect.Field; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; import static org.springframework.data.neo4j.support.DoReturn.doReturn; @@ -37,34 +36,26 @@ public class PropertyFieldAccessorFactory implements FieldAccessorFactory> forField(final Field field) { - return new PropertyFieldAccessor(conversionService,DelegatingFieldAccessorFactory.getNeo4jPropertyName(field),field.getType()); - } - - private boolean isNeo4jPropertyType(final Class fieldType) { - // todo: add array support - return fieldType.isPrimitive() - || fieldType.equals(String.class) - || fieldType.equals(Character.class) - || fieldType.equals(Boolean.class) - || (fieldType.getName().startsWith("java.lang") && Number.class.isAssignableFrom(fieldType)) - || (fieldType.isArray() && !fieldType.getComponentType().isArray() && isNeo4jPropertyType(fieldType.getComponentType())); + public FieldAccessor> forField(final Neo4JPersistentProperty field) { + return new PropertyFieldAccessor(conversionService, field); } public static class PropertyFieldAccessor implements FieldAccessor> { private final ConversionService conversionService; + private final Neo4JPersistentProperty property; protected final String propertyName; protected final Class fieldType; - public PropertyFieldAccessor(ConversionService conversionService, String propertyName, Class fieldType) { + public PropertyFieldAccessor(ConversionService conversionService, Neo4JPersistentProperty property) { this.conversionService = conversionService; - this.propertyName = propertyName; - this.fieldType = fieldType; + this.property = property; + this.propertyName = property.getNeo4jPropertyName(); + this.fieldType = property.getType() ; } @Override diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/QueryFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/QueryFieldAccessorFactory.java index 08b81e6ca..acb35a657 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/QueryFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/QueryFieldAccessorFactory.java @@ -19,7 +19,9 @@ package org.springframework.data.neo4j.fieldaccess; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.neo4j.annotation.Query; import org.springframework.data.neo4j.core.NodeBacked; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; import org.springframework.data.neo4j.support.GenericTypeExtractor; +import org.springframework.data.util.TypeInformation; import java.lang.reflect.Field; import java.util.HashMap; @@ -29,7 +31,7 @@ import static org.springframework.data.neo4j.support.DoReturn.doReturn; public class QueryFieldAccessorFactory implements FieldAccessorFactory { @Override - public boolean accept(final Field f) { + public boolean accept(final Neo4JPersistentProperty f) { final Query query = f.getAnnotation(Query.class); return query != null && !query.value().isEmpty(); @@ -37,7 +39,7 @@ public class QueryFieldAccessorFactory implements FieldAccessorFactory forField(final Field field) { + public FieldAccessor forField(final Neo4JPersistentProperty field) { return new QueryFieldAccessor(field); } @@ -46,27 +48,27 @@ public class QueryFieldAccessorFactory implements FieldAccessorFactory { - protected final Field field; + protected final Neo4JPersistentProperty property; private final String query; private Class target; protected String[] annotationParams; private boolean iterableResult; - public QueryFieldAccessor(final Field field) { - this.field = field; - final Query query = field.getAnnotation(Query.class); + public QueryFieldAccessor(final Neo4JPersistentProperty property) { + this.property = property; + final Query query = property.getAnnotation(Query.class); this.annotationParams = query.params(); if ((this.annotationParams.length % 2) != 0) { throw new IllegalArgumentException("Number of parameters has to be even to construct a parameter map"); } this.query = query.value(); - this.iterableResult = Iterable.class.isAssignableFrom(field.getType()); - this.target = resolveTarget(query,field); + this.iterableResult = Iterable.class.isAssignableFrom(property.getType()); + this.target = resolveTarget(query,property); } - private Class resolveTarget(Query query, Field field) { + private Class resolveTarget(Query query, Neo4JPersistentProperty property) { if (!query.elementClass().equals(Object.class)) return query.elementClass(); - return GenericTypeExtractor.resolveFieldType(field); + return property.getTypeInformation().getActualType().getType(); } @Override @@ -76,7 +78,7 @@ public class QueryFieldAccessorFactory implements FieldAccessorFactory forField(final Field field) { - final RelatedTo relAnnotation = getRelationshipAnnotation(field); - return new ReadOnlyOneToNRelationshipFieldAccessor(typeFrom(field, relAnnotation), dirFrom(relAnnotation), targetFrom(field, relAnnotation), graphDatabaseContext,field); + public FieldAccessor forField(final Neo4JPersistentProperty property) { + final RelationshipInfo relationshipInfo = property.getRelationshipInfo(); + return new ReadOnlyOneToNRelationshipFieldAccessor(relationshipInfo.getRelationshipType(), relationshipInfo.getDirection(), (Class) property.getRelationshipInfo().getTargetType().getType(), graphDatabaseContext,property); } public static class ReadOnlyOneToNRelationshipFieldAccessor extends OneToNRelationshipFieldAccessorFactory.OneToNRelationshipFieldAccessor { - public ReadOnlyOneToNRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class elementClass, final GraphDatabaseContext graphDatabaseContext, Field field) { + public ReadOnlyOneToNRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class elementClass, final GraphDatabaseContext graphDatabaseContext, Neo4JPersistentProperty field) { super(type,direction,elementClass, graphDatabaseContext, field); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/RelationshipNodeFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/RelationshipNodeFieldAccessorFactory.java index 78887ba14..e131a45ff 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/RelationshipNodeFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/RelationshipNodeFieldAccessorFactory.java @@ -23,10 +23,9 @@ import org.springframework.data.neo4j.annotation.EndNode; import org.springframework.data.neo4j.annotation.StartNode; import org.springframework.data.neo4j.core.NodeBacked; import org.springframework.data.neo4j.core.RelationshipBacked; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; import org.springframework.data.neo4j.support.GraphDatabaseContext; -import java.lang.reflect.Field; - import static org.springframework.data.neo4j.support.DoReturn.doReturn; /** @@ -43,22 +42,22 @@ public class RelationshipNodeFieldAccessorFactory implements FieldAccessorFactor } @Override - public boolean accept(final Field f) { + public boolean accept(final Neo4JPersistentProperty f) { return isStartNodeField(f) || isEndNodeField(f); } - private boolean isEndNodeField(final Field f) { + private boolean isEndNodeField(final Neo4JPersistentProperty f) { return f.isAnnotationPresent(EndNode.class); } - private boolean isStartNodeField(final Field f) { + private boolean isStartNodeField(final Neo4JPersistentProperty f) { return f.isAnnotationPresent(StartNode.class); } @Override - public FieldAccessor forField(final Field f) { - if (isStartNodeField(f)) { - return new RelationshipNodeFieldAccessor(f, graphDatabaseContext) { + public FieldAccessor forField(final Neo4JPersistentProperty property) { + if (isStartNodeField(property)) { + return new RelationshipNodeFieldAccessor(property, graphDatabaseContext) { @Override protected Node getNode(final Relationship relationship) { return relationship.getStartNode(); @@ -66,8 +65,8 @@ public class RelationshipNodeFieldAccessorFactory implements FieldAccessorFactor }; } - if (isEndNodeField(f)) { - return new RelationshipNodeFieldAccessor(f, graphDatabaseContext) { + if (isEndNodeField(property)) { + return new RelationshipNodeFieldAccessor(property, graphDatabaseContext) { @Override protected Node getNode(final Relationship relationship) { return relationship.getEndNode(); @@ -79,11 +78,11 @@ public class RelationshipNodeFieldAccessorFactory implements FieldAccessorFactor public static abstract class RelationshipNodeFieldAccessor implements FieldAccessor { - private final Field field; + private final Neo4JPersistentProperty property; private final GraphDatabaseContext graphDatabaseContext; - public RelationshipNodeFieldAccessor(final Field field, final GraphDatabaseContext graphDatabaseContext) { - this.field = field; + public RelationshipNodeFieldAccessor(final Neo4JPersistentProperty property, final GraphDatabaseContext graphDatabaseContext) { + this.property = property; this.graphDatabaseContext = graphDatabaseContext; } @@ -99,7 +98,7 @@ public class RelationshipNodeFieldAccessorFactory implements FieldAccessorFactor if (node == null) { return null; } - final NodeBacked result = graphDatabaseContext.createEntityFromState(node, (Class) field.getType()); + final NodeBacked result = graphDatabaseContext.createEntityFromState(node, (Class) property.getType()); return doReturn(result); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/SingleRelationshipFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/SingleRelationshipFieldAccessorFactory.java index 137304388..ac5b114af 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/SingleRelationshipFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/SingleRelationshipFieldAccessorFactory.java @@ -21,6 +21,8 @@ import org.neo4j.graphdb.Node; import org.neo4j.graphdb.RelationshipType; import org.springframework.data.neo4j.annotation.RelatedTo; import org.springframework.data.neo4j.core.NodeBacked; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; +import org.springframework.data.neo4j.mapping.RelationshipInfo; import org.springframework.data.neo4j.support.GraphDatabaseContext; import java.lang.reflect.Field; @@ -36,21 +38,19 @@ public class SingleRelationshipFieldAccessorFactory extends NodeRelationshipFiel } @Override - public boolean accept(final Field f) { - return NodeBacked.class.isAssignableFrom(f.getType()); + public boolean accept(final Neo4JPersistentProperty property) { + return property.isRelationship() && property.getRelationshipInfo().targetsNodes() && !property.getRelationshipInfo().isMultiple(); } @Override - public FieldAccessor forField(final Field field) { - final RelatedTo relAnnotation = getRelationshipAnnotation(field); - if (relAnnotation == null) - return new SingleRelationshipFieldAccessor(typeFrom(field), Direction.OUTGOING, targetFrom(field, relAnnotation), graphDatabaseContext, field); - return new SingleRelationshipFieldAccessor(typeFrom(field, relAnnotation), dirFrom(relAnnotation), targetFrom(field, relAnnotation), graphDatabaseContext,field); + public FieldAccessor forField(final Neo4JPersistentProperty property) { + final RelationshipInfo relationshipInfo = property.getRelationshipInfo(); + return new SingleRelationshipFieldAccessor(relationshipInfo.getRelationshipType(), relationshipInfo.getDirection(), (Class) relationshipInfo.getTargetType().getType(), graphDatabaseContext,property); } public static class SingleRelationshipFieldAccessor extends NodeToNodesRelationshipFieldAccessor { - public SingleRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class clazz, final GraphDatabaseContext graphDatabaseContext, Field field) { - super(clazz, graphDatabaseContext, direction, type, field); + public SingleRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class clazz, final GraphDatabaseContext graphDatabaseContext, Neo4JPersistentProperty property) { + super(clazz, graphDatabaseContext, direction, type, property); } @Override diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/TransientFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/TransientFieldAccessorFactory.java index 6af02297e..d0fe090ac 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/TransientFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/TransientFieldAccessorFactory.java @@ -18,19 +18,17 @@ package org.springframework.data.neo4j.fieldaccess; import org.neo4j.graphdb.PropertyContainer; import org.springframework.data.neo4j.core.GraphBacked; - -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; public class TransientFieldAccessorFactory implements FieldAccessorFactory> { @Override - public boolean accept(final Field f) { - return Modifier.isTransient(f.getModifiers()); + public boolean accept(final Neo4JPersistentProperty property) { + return property.isTransient(); } @Override - public FieldAccessor> forField(final Field field) { - return new TransientFieldAccessor(field); + public FieldAccessor> forField(final Neo4JPersistentProperty property) { + return new TransientFieldAccessor(property); } /** @@ -38,10 +36,10 @@ public class TransientFieldAccessorFactory implements FieldAccessorFactory> { - protected final Field field; + protected final Neo4JPersistentProperty property; - public TransientFieldAccessor(final Field field) { - this.field = field; + public TransientFieldAccessor(final Neo4JPersistentProperty property) { + this.property = property; } @Override diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/TraversalFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/TraversalFieldAccessorFactory.java index da36e4063..30cb98074 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/TraversalFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/TraversalFieldAccessorFactory.java @@ -25,6 +25,7 @@ import org.springframework.data.neo4j.annotation.GraphTraversal; import org.springframework.data.neo4j.core.FieldTraversalDescriptionBuilder; import org.springframework.data.neo4j.core.NodeBacked; import org.springframework.data.neo4j.core.RelationshipBacked; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; import org.springframework.data.neo4j.support.GenericTypeExtractor; import java.lang.reflect.Constructor; @@ -34,7 +35,7 @@ import static org.springframework.data.neo4j.support.DoReturn.doReturn; public class TraversalFieldAccessorFactory implements FieldAccessorFactory { @Override - public boolean accept(final Field f) { + public boolean accept(final Neo4JPersistentProperty f) { final GraphTraversal graphEntityTraversal = f.getAnnotation(GraphTraversal.class); return graphEntityTraversal != null && graphEntityTraversal.traversalBuilder() != FieldTraversalDescriptionBuilder.class @@ -43,8 +44,8 @@ public class TraversalFieldAccessorFactory implements FieldAccessorFactory forField(final Field field) { - return new TraversalFieldAccessor(field); + public FieldAccessor forField(final Neo4JPersistentProperty property) { + return new TraversalFieldAccessor(property); } /** @@ -52,24 +53,24 @@ public class TraversalFieldAccessorFactory implements FieldAccessorFactory { - protected final Field field; + protected final Neo4JPersistentProperty property; private final FieldTraversalDescriptionBuilder fieldTraversalDescriptionBuilder; private Class target; protected String[] params; - public TraversalFieldAccessor(final Field field) { - this.field = field; - final GraphTraversal graphEntityTraversal = field.getAnnotation(GraphTraversal.class); - this.target = resolveTarget(graphEntityTraversal,field); + public TraversalFieldAccessor(final Neo4JPersistentProperty property) { + this.property = property; + final GraphTraversal graphEntityTraversal = property.getAnnotation(GraphTraversal.class); + this.target = resolveTarget(graphEntityTraversal,property); this.params = graphEntityTraversal.params(); this.fieldTraversalDescriptionBuilder = createTraversalDescription(graphEntityTraversal); } - private Class resolveTarget(GraphTraversal graphTraversal, Field field) { + private Class resolveTarget(GraphTraversal graphTraversal, Neo4JPersistentProperty property) { if (!graphTraversal.elementClass().equals(NodeBacked.class)) return graphTraversal.elementClass(); - final Class result = GenericTypeExtractor.resolveFieldType(field); + final Class result = property.getTypeInformation().getActualType().getType(); Class[] allowedTypes={NodeBacked.class,RelationshipBacked.class,Node.class,Relationship.class, Path.class}; - if (!checkTypes(result,allowedTypes)) throw new IllegalArgumentException("The target result type "+result+" of the traversal is no subclass of the allowed types: "+field+" "+allowedTypes); + if (!checkTypes(result,allowedTypes)) throw new IllegalArgumentException("The target result type "+result+" of the traversal is no subclass of the allowed types: "+property+" "+allowedTypes); return result; } @@ -88,12 +89,12 @@ public class TraversalFieldAccessorFactory implements FieldAccessorFactory forField(Field field) { - return new ValidatingNodePropertyFieldAccessorListener(field,graphDatabaseContext.getValidator()); + public FieldAccessListener forField(Neo4JPersistentProperty property) { + return new ValidatingNodePropertyFieldAccessorListener(property,graphDatabaseContext.getValidator()); } @@ -66,18 +69,18 @@ class ValidatingNodePropertyFieldAccessorListenerFactory entityType; + private Neo4JPersistentEntity entityType; - public ValidatingNodePropertyFieldAccessorListener(final Field field, Validator validator) { + public ValidatingNodePropertyFieldAccessorListener(final Neo4JPersistentProperty field, Validator validator) { this.propertyName = field.getName(); - this.entityType = field.getDeclaringClass(); + this.entityType = (Neo4JPersistentEntity) field.getOwner(); this.validator = validator; } @Override public void valueChanged(GraphBacked graphBacked, Object oldVal, Object newVal) { if (validator==null) return; - Set> constraintViolations = validator.validateValue((Class)entityType, propertyName, newVal); + Set> constraintViolations = validator.validateValue((Class)entityType.getType(), propertyName, newVal); if (!constraintViolations.isEmpty()) throw new ValidationException("Error validating field "+propertyName+ " of "+entityType+": "+constraintViolations); } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4JPersistentEntity.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4JPersistentEntity.java index 64608a98a..99d30469a 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4JPersistentEntity.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4JPersistentEntity.java @@ -25,4 +25,5 @@ import org.springframework.data.mapping.PersistentEntity; */ public interface Neo4JPersistentEntity extends PersistentEntity { + boolean useShortNames(); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4JPersistentEntityImpl.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4JPersistentEntityImpl.java index 6aa29adac..4dfc3c0f2 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4JPersistentEntityImpl.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4JPersistentEntityImpl.java @@ -17,8 +17,14 @@ package org.springframework.data.neo4j.mapping; import org.springframework.data.mapping.model.BasicPersistentEntity; +import org.springframework.data.neo4j.annotation.NodeEntity; +import org.springframework.data.neo4j.annotation.RelationshipEntity; import org.springframework.data.util.TypeInformation; +import java.lang.annotation.Annotation; +import java.util.IdentityHashMap; +import java.util.Map; + /** * Implementation of {@link Neo4JPersistentEntity}. * @@ -26,6 +32,8 @@ import org.springframework.data.util.TypeInformation; */ class Neo4JPersistentEntityImpl extends BasicPersistentEntity implements Neo4JPersistentEntity { + private Map,Annotation> annotations=new IdentityHashMap,Annotation>(); + /** * Creates a new {@link Neo4JPersistentEntityImpl} instance. * @@ -33,5 +41,20 @@ class Neo4JPersistentEntityImpl extends BasicPersistentEntity information) { super(information); + for (Annotation annotation : information.getType().getAnnotations()) { + annotations.put(annotation.annotationType(),annotation); + } + } + + public boolean useShortNames() { + final NodeEntity graphEntity = getAnnotation(NodeEntity.class); + if (graphEntity != null) return graphEntity.useShortNames(); + final RelationshipEntity graphRelationship = getAnnotation(RelationshipEntity.class); + if (graphRelationship != null) return graphRelationship.useShortNames(); + return false; + } + + private T getAnnotation(Class annotationType) { + return (T) annotations.get(annotationType); } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4JPersistentProperty.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4JPersistentProperty.java index de6ba6f19..d4c2ca3dc 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4JPersistentProperty.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4JPersistentProperty.java @@ -16,7 +16,13 @@ package org.springframework.data.neo4j.mapping; +import org.springframework.core.convert.ConversionService; import org.springframework.data.mapping.PersistentProperty; +import org.springframework.data.neo4j.annotation.Indexed; + +import javax.persistence.Id; +import java.lang.annotation.Annotation; +import java.util.Collection; /** * Interface for Neo4J specific {@link PersistentProperty}s. Declares additional metadata to lookup relationship @@ -45,4 +51,26 @@ public interface Neo4JPersistentProperty extends PersistentProperty getAnnotations(); + + T getAnnotation(Class annotationType); + + boolean isAnnotationPresent(Class annotationType); + + void setValue(Object entity, Object newValue) throws IllegalAccessException; + + Object getValue(final Object entity) throws IllegalAccessException; } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4JPersistentPropertyImpl.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4JPersistentPropertyImpl.java index c2f8f931b..13a09873a 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4JPersistentPropertyImpl.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4JPersistentPropertyImpl.java @@ -16,17 +16,20 @@ package org.springframework.data.neo4j.mapping; +import org.springframework.core.convert.ConversionService; 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.SimpleTypeHolder; import org.springframework.data.neo4j.annotation.*; -import org.springframework.data.neo4j.core.Direction; +import org.springframework.data.neo4j.core.NodeBacked; +import org.springframework.data.neo4j.core.RelationshipBacked; import org.springframework.data.util.TypeInformation; import java.beans.PropertyDescriptor; import java.lang.annotation.Annotation; import java.lang.reflect.Field; +import java.util.Collection; import java.util.IdentityHashMap; import java.util.Map; @@ -65,7 +68,7 @@ class Neo4JPersistentPropertyImpl extends AbstractPersistentProperty T getAnnotation(Class annotationType) { + public T getAnnotation(Class annotationType) { return (T) annotations.get(annotationType); } @@ -83,12 +86,18 @@ class Neo4JPersistentPropertyImpl extends AbstractPersistentProperty boolean isAnnotationPresent(Class annotationType) { + public boolean isAnnotationPresent(Class annotationType) { return annotations.containsKey(annotationType); } + @Override + public void setValue(Object entity, Object newValue) throws IllegalAccessException { + field.setAccessible(true); + field.set(entity, newValue); + } + private static boolean hasAnnotation(TypeInformation typeInformation, final Class annotationClass) { - return typeInformation.getActualType().getClass().isAnnotationPresent(annotationClass); + return typeInformation.getActualType().getType().isAnnotationPresent(annotationClass); } @Override @@ -121,6 +130,58 @@ class Neo4JPersistentPropertyImpl extends AbstractPersistentProperty type = getType(); + if (Iterable.class.isAssignableFrom(type) || NodeBacked.class.isAssignableFrom(type) || RelationshipBacked.class.isAssignableFrom(type)) + return false; + return true; + } + + public boolean isSerializableField(final ConversionService conversionService) { + return isSimpleValueField() && conversionService.canConvert(getType(), String.class); + } + + public boolean isDeserializableField(final ConversionService conversionService) { + return isSimpleValueField() && conversionService.canConvert(String.class, getType()); + } + + @Override + public boolean isNeo4jPropertyType() { + return isNeo4jPropertyType(getType()); + } + + private static boolean isNeo4jPropertyType(final Class fieldType) { + // todo: add array support + return fieldType.isPrimitive() + || fieldType.equals(String.class) + || fieldType.equals(Character.class) + || fieldType.equals(Boolean.class) + || (fieldType.getName().startsWith("java.lang") && Number.class.isAssignableFrom(fieldType)) + || (fieldType.isArray() && !fieldType.getComponentType().isArray() && isNeo4jPropertyType(fieldType.getComponentType())); + } + + public boolean isSyntheticField() { + return getName().contains("$"); + } + + @Override + public Collection getAnnotations() { + return annotations.values(); + } + + public Object getValue(final Object entity) throws IllegalAccessException { + final Field field = getField(); + field.setAccessible(true); + return field.get(entity); + } + + public static class IndexInfo { private String indexName; private boolean fulltext; @@ -143,4 +204,8 @@ class Neo4JPersistentPropertyImpl extends AbstractPersistentProperty targetType; - private final boolean isNodeRelationship; + private final boolean targetsNodes; + private boolean readonly; public Direction getDirection() { return direction; @@ -42,38 +47,61 @@ public class RelationshipInfo { public String getType() { return type; } + public RelationshipType getRelationshipType() { + return DynamicRelationshipType.withName(type); + } + public boolean isMultiple() { return isMultiple; } - public RelationshipInfo(String type, Direction direction, TypeInformation typeInformation) { + public RelationshipInfo(String type, Direction direction, TypeInformation typeInformation, TypeInformation concreteActualType, boolean targetsNode) { this.type = type; this.direction = direction; isMultiple = typeInformation.isCollectionLike(); - targetType = typeInformation.getActualType(); - isNodeRelationship = isNodeEntity(targetType); + targetType = concreteActualType!=null ? concreteActualType : typeInformation.getActualType(); + targetsNodes = isNodeEntity(targetType); + this.readonly = isMultiple() && typeInformation.getType().equals(Iterable.class); } private boolean isNodeEntity(TypeInformation targetType) { final Class type = targetType.getType(); if (type.isAnnotationPresent(NodeEntity.class)) return true; if (type.isAnnotationPresent(RelationshipEntity.class)) return false; - throw new MappingException("Target type for relationship "+ this.type +" field is invalid "+type); + throw new MappingException("Target type for relationship " + this.type + " field is invalid " + type); } public static RelationshipInfo fromField(Field field, TypeInformation typeInformation) { - return new RelationshipInfo(field.getName(), Direction.OUTGOING, typeInformation); + return new RelationshipInfo(field.getName(), Direction.OUTGOING, typeInformation,null,true); } + public static RelationshipInfo fromField(Field field, RelatedTo annotation, TypeInformation typeInformation) { return new RelationshipInfo( annotation.type().isEmpty() ? field.getName() : annotation.type(), - annotation.direction(), - typeInformation); + annotation.direction().toNeo4jDir(), + typeInformation, + annotation.elementClass() != NodeBacked.class ? ClassTypeInformation.from(annotation.elementClass()) : null, + true); } + public static RelationshipInfo fromField(Field field, RelatedToVia annotation, TypeInformation typeInformation) { return new RelationshipInfo( annotation.type().isEmpty() ? field.getName() : annotation.type(), - annotation.direction(), - typeInformation); + annotation.direction().toNeo4jDir(), + typeInformation, + annotation.elementClass() != RelationshipBacked.class ? ClassTypeInformation.from(annotation.elementClass()) : null, + false); + } + + public TypeInformation getTargetType() { + return targetType; + } + + public boolean targetsNodes() { + return targetsNodes; + } + + public boolean isReadonly() { + return readonly; } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/GraphDatabaseContext.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/GraphDatabaseContext.java index 90110cfde..38d065539 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/GraphDatabaseContext.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/GraphDatabaseContext.java @@ -183,7 +183,7 @@ public class GraphDatabaseContext { } else if (state instanceof Relationship && RelationshipBacked.class.isAssignableFrom(type)) { return (TypeRepresentationStrategy) relationshipTypeRepresentationStrategy; } - throw new IllegalArgumentException("Type is not NodeBacked nor RelationshipBacked."); + throw new IllegalArgumentException("Type "+type+" is not NodeBacked nor RelationshipBacked."); } @SuppressWarnings("unchecked") diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/node/NodeEntityState.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/node/NodeEntityState.java index 912f52538..0c665f2d8 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/node/NodeEntityState.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/node/NodeEntityState.java @@ -33,7 +33,7 @@ public class NodeEntityState extends DefaultEntitySta private final GraphDatabaseContext graphDatabaseContext; - public NodeEntityState(final Node underlyingState, final ENTITY entity, final Class type, final GraphDatabaseContext graphDatabaseContext, final DelegatingFieldAccessorFactory nodeDelegatingFieldAccessorFactory, Neo4JPersistentEntity persistentEntity) { + public NodeEntityState(final Node underlyingState, final ENTITY entity, final Class type, final GraphDatabaseContext graphDatabaseContext, final DelegatingFieldAccessorFactory nodeDelegatingFieldAccessorFactory, Neo4JPersistentEntity persistentEntity) { super(underlyingState, entity, type, nodeDelegatingFieldAccessorFactory,persistentEntity); this.graphDatabaseContext = graphDatabaseContext; } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/node/NodeEntityStateFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/node/NodeEntityStateFactory.java index 96f400ac5..9bc1b3265 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/node/NodeEntityStateFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/node/NodeEntityStateFactory.java @@ -47,7 +47,7 @@ public class NodeEntityStateFactory { final NodeEntity graphEntityAnnotation = entityType.getAnnotation(NodeEntity.class); // todo cache ?? final Neo4JPersistentEntity persistentEntity = mappingContext.getPersistentEntity(entityType); if (graphEntityAnnotation.partial()) { - final PartialNodeEntityState partialNodeEntityState = new PartialNodeEntityState(null, entity, entityType, graphDatabaseContext, getPersistenceUnitUtils(), delegatingFieldAccessorFactory, persistentEntity); + final PartialNodeEntityState partialNodeEntityState = new PartialNodeEntityState(null, entity, entityType, graphDatabaseContext, getPersistenceUnitUtils(), delegatingFieldAccessorFactory, (Neo4JPersistentEntity) persistentEntity); return new DetachedEntityState(partialNodeEntityState, graphDatabaseContext) { @Override protected boolean isDetached() { @@ -55,7 +55,7 @@ public class NodeEntityStateFactory { } }; } else { - NodeEntityState nodeEntityState = new NodeEntityState(null, entity, entityType, graphDatabaseContext, nodeDelegatingFieldAccessorFactory, persistentEntity); + NodeEntityState nodeEntityState = new NodeEntityState(null, entity, entityType, graphDatabaseContext, nodeDelegatingFieldAccessorFactory, (Neo4JPersistentEntity) persistentEntity); // alternative was return new NestedTransactionEntityState(nodeEntityState,graphDatabaseContext); return new DetachedEntityState(nodeEntityState, graphDatabaseContext); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/node/PartialNodeEntityState.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/node/PartialNodeEntityState.java index f1cdeb249..2824d5611 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/node/PartialNodeEntityState.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/node/PartialNodeEntityState.java @@ -26,6 +26,7 @@ import org.springframework.data.neo4j.annotation.RelatedTo; import org.springframework.data.neo4j.core.NodeBacked; import org.springframework.data.neo4j.fieldaccess.*; import org.springframework.data.neo4j.mapping.Neo4JPersistentEntity; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; import org.springframework.data.neo4j.support.GraphDatabaseContext; import javax.persistence.PersistenceUnitUtil; @@ -45,7 +46,7 @@ public class PartialNodeEntityState extends DefaultEn private final GraphDatabaseContext graphDatabaseContext; private PersistenceUnitUtil persistenceUnitUtil; - public PartialNodeEntityState(final Node underlyingState, final ENTITY entity, final Class type, final GraphDatabaseContext graphDatabaseContext, PersistenceUnitUtil persistenceUnitUtil, final PartialNodeDelegatingFieldAccessorFactory delegatingFieldAccessorFactory, final Neo4JPersistentEntity persistentEntity) { + public PartialNodeEntityState(final Node underlyingState, final ENTITY entity, final Class type, final GraphDatabaseContext graphDatabaseContext, PersistenceUnitUtil persistenceUnitUtil, final PartialNodeDelegatingFieldAccessorFactory delegatingFieldAccessorFactory, final Neo4JPersistentEntity persistentEntity) { super(underlyingState, entity, type, delegatingFieldAccessorFactory, persistentEntity); this.graphDatabaseContext = graphDatabaseContext; this.persistenceUnitUtil = persistenceUnitUtil; @@ -86,7 +87,7 @@ public class PartialNodeEntityState extends DefaultEn @Override public boolean isWritable(Field field) { - final FieldAccessor accessor = accessorFor(field); + final FieldAccessor accessor = accessorFor(property(field)); if (accessor == null) return false; // difference to default behaviour, we don't care for non-managed fields here return accessor.isWriteable(entity); } @@ -125,8 +126,8 @@ public class PartialNodeEntityState extends DefaultEn newPropertyFieldAccessorFactory(), newConvertingNodePropertyFieldAccessorFactory()) { @Override - public boolean accept(Field f) { - return f.isAnnotationPresent(GraphProperty.class) && super.accept(f); + public boolean accept(Neo4JPersistentProperty property) { + return property.isAnnotationPresent(GraphProperty.class) && super.accept(property); } }, new JpaIdFieldAccessListenerFactory()); @@ -143,8 +144,8 @@ public class PartialNodeEntityState extends DefaultEn newConvertingNodePropertyFieldAccessorFactory(), new SingleRelationshipFieldAccessorFactory(getGraphDatabaseContext()) { @Override - public boolean accept(Field f) { - return f.isAnnotationPresent(RelatedTo.class) && super.accept(f); + public boolean accept(Neo4JPersistentProperty property) { + return property.isAnnotationPresent(RelatedTo.class) && super.accept(property); } }, new OneToNRelationshipFieldAccessorFactory(getGraphDatabaseContext()), @@ -156,7 +157,7 @@ public class PartialNodeEntityState extends DefaultEn private ConvertingNodePropertyFieldAccessorFactory newConvertingNodePropertyFieldAccessorFactory() { return new ConvertingNodePropertyFieldAccessorFactory(getGraphDatabaseContext().getConversionService()) { @Override - public boolean accept(Field f) { + public boolean accept(Neo4JPersistentProperty f) { return f.isAnnotationPresent(GraphProperty.class) && super.accept(f); } }; @@ -165,7 +166,7 @@ public class PartialNodeEntityState extends DefaultEn private PropertyFieldAccessorFactory newPropertyFieldAccessorFactory() { return new PropertyFieldAccessorFactory(getGraphDatabaseContext().getConversionService()) { @Override - public boolean accept(Field f) { + public boolean accept(Neo4JPersistentProperty f) { return f.isAnnotationPresent(GraphProperty.class) && super.accept(f); } }; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/relationship/RelationshipEntityState.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/relationship/RelationshipEntityState.java index acca51930..83905bb02 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/relationship/RelationshipEntityState.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/relationship/RelationshipEntityState.java @@ -34,7 +34,7 @@ public class RelationshipEntityState extends private final GraphDatabaseContext graphDatabaseContext; - public RelationshipEntityState(final Relationship underlyingState, final ENTITY entity, final Class type, final GraphDatabaseContext graphDatabaseContext, final DelegatingFieldAccessorFactory delegatingFieldAccessorFactory, Neo4JPersistentEntity persistentEntity) { + public RelationshipEntityState(final Relationship underlyingState, final ENTITY entity, final Class type, final GraphDatabaseContext graphDatabaseContext, final DelegatingFieldAccessorFactory delegatingFieldAccessorFactory, Neo4JPersistentEntity persistentEntity) { super(underlyingState, entity, type, delegatingFieldAccessorFactory, persistentEntity); this.graphDatabaseContext = graphDatabaseContext; } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/relationship/RelationshipEntityStateFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/relationship/RelationshipEntityStateFactory.java index 4199f0a93..d529d6a62 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/relationship/RelationshipEntityStateFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/relationship/RelationshipEntityStateFactory.java @@ -21,6 +21,7 @@ import org.springframework.data.neo4j.core.EntityState; import org.springframework.data.neo4j.core.RelationshipBacked; import org.springframework.data.neo4j.fieldaccess.DelegatingFieldAccessorFactory; import org.springframework.data.neo4j.mapping.Neo4JMappingContext; +import org.springframework.data.neo4j.mapping.Neo4JPersistentEntity; import org.springframework.data.neo4j.support.GraphDatabaseContext; public class RelationshipEntityStateFactory { @@ -32,7 +33,7 @@ public class RelationshipEntityStateFactory { public EntityState getEntityState(final RelationshipBacked entity) { final Class entityType = entity.getClass(); - return new RelationshipEntityState(null,entity, entityType, graphDatabaseContext, relationshipDelegatingFieldAccessorFactory,mappingContext.getPersistentEntity(entityType)); + return new RelationshipEntityState(null,entity, entityType, graphDatabaseContext, relationshipDelegatingFieldAccessorFactory, (Neo4JPersistentEntity) mappingContext.getPersistentEntity(entityType)); } public void setGraphDatabaseContext(GraphDatabaseContext graphDatabaseContext) { diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/Group.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/Group.java index acaa12b01..842bb7020 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/Group.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/Group.java @@ -24,8 +24,8 @@ import org.springframework.data.neo4j.annotation.*; import org.springframework.data.neo4j.core.Direction; import org.springframework.data.neo4j.core.FieldTraversalDescriptionBuilder; import org.springframework.data.neo4j.core.NodeBacked; +import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty; -import java.lang.reflect.Field; import java.util.Collection; @NodeEntity @@ -114,7 +114,7 @@ public class Group { private static class PeopleTraversalBuilder implements FieldTraversalDescriptionBuilder { @Override - public TraversalDescription build(NodeBacked start, Field field, String...params) { + public TraversalDescription build(NodeBacked start, Neo4JPersistentProperty property, String...params) { return new TraversalDescriptionImpl() .relationships(DynamicRelationshipType.withName(params[0])) .filter(Traversal.returnAllButStartNode()); diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/support/GraphRepositoryTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/support/GraphRepositoryTest.java index faf7bd6ad..784e5be50 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/support/GraphRepositoryTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/support/GraphRepositoryTest.java @@ -30,9 +30,13 @@ import org.springframework.data.neo4j.*; import org.springframework.data.neo4j.Person; import org.springframework.data.neo4j.PersonRepository; import org.springframework.data.neo4j.support.node.Neo4jHelper; +import org.springframework.test.context.CleanContextCacheTestExecutionListener; import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestExecutionListeners; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; import org.springframework.test.context.transaction.BeforeTransaction; +import org.springframework.test.context.transaction.TransactionalTestExecutionListener; import org.springframework.transaction.annotation.Transactional; import java.util.Map; @@ -47,6 +51,7 @@ import static org.neo4j.helpers.collection.IteratorUtil.asCollection; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:repository-namespace-config-context.xml"}) +@TestExecutionListeners({CleanContextCacheTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class}) public class GraphRepositoryTest { protected final Log log = LogFactory.getLog(getClass());