converted usage of java.lang.reflect.Field to Neo4jPersistentProperty
This commit is contained in:
@@ -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<ENTITY extends GraphBacked<STATE>,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<ENTITY extends GraphBacked<STATE>,STATE> {
|
||||
STATE getPersistentState();
|
||||
|
||||
ENTITY persist();
|
||||
|
||||
Neo4JPersistentEntity<ENTITY> getPersistentEntity();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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<ENTITY extends GraphBacked,STATE extends PropertyContainer,TARGET extends GraphBacked,TSTATE extends PropertyContainer> implements FieldAccessor<ENTITY> {
|
||||
protected final RelationshipType type;
|
||||
protected final Field field;
|
||||
protected final Neo4JPersistentProperty property;
|
||||
protected final Direction direction;
|
||||
protected final Class<? extends TARGET> relatedType;
|
||||
protected final GraphDatabaseContext graphDatabaseContext;
|
||||
|
||||
public AbstractNodeRelationshipFieldAccessor(Class<? extends TARGET> clazz, GraphDatabaseContext graphDatabaseContext, Direction direction, RelationshipType type, Field field) {
|
||||
public AbstractNodeRelationshipFieldAccessor(Class<? extends TARGET> 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<ENTITY extends Graph
|
||||
}
|
||||
|
||||
protected ManagedFieldAccessorSet<ENTITY,TARGET> createManagedSet(ENTITY entity, Set<TARGET> result) {
|
||||
return new ManagedFieldAccessorSet<ENTITY,TARGET>(entity, result, field);
|
||||
return new ManagedFieldAccessorSet<ENTITY,TARGET>(entity, result, property);
|
||||
}
|
||||
|
||||
protected Set<TARGET> createEntitySetFromRelationshipEndNodes(ENTITY entity) {
|
||||
|
||||
@@ -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<GraphBacked<PropertyContainer>> 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<GraphBacked<PropertyContainer>> 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<ENTITY extends GraphBacked<STATE>, STATE> implements EntityState<ENTITY,STATE> {
|
||||
protected final ENTITY entity;
|
||||
protected final Class<? extends ENTITY> type;
|
||||
private final Map<Field, FieldAccessor<ENTITY>> fieldAccessors = new HashMap<Field, FieldAccessor<ENTITY>>();
|
||||
private final Map<Field,List<FieldAccessListener<ENTITY,?>>> fieldAccessorListeners = new HashMap<Field, List<FieldAccessListener<ENTITY, ?>>>();
|
||||
private final Map<Neo4JPersistentProperty, FieldAccessor<ENTITY>> fieldAccessors = new HashMap<Neo4JPersistentProperty, FieldAccessor<ENTITY>>();
|
||||
private final Map<Neo4JPersistentProperty,List<FieldAccessListener<ENTITY,?>>> fieldAccessorListeners = new HashMap<Neo4JPersistentProperty, List<FieldAccessListener<ENTITY, ?>>>();
|
||||
private STATE state;
|
||||
protected final static Log log= LogFactory.getLog(DefaultEntityState.class);
|
||||
private final FieldAccessorFactoryProviders<ENTITY> fieldAccessorFactoryProviders;
|
||||
private final Neo4JPersistentEntity<?> persistentEntity;
|
||||
private final Neo4JPersistentEntity<ENTITY> persistentEntity;
|
||||
|
||||
public DefaultEntityState(final STATE underlyingState, final ENTITY entity, final Class<? extends ENTITY> type, final DelegatingFieldAccessorFactory delegatingFieldAccessorFactory, Neo4JPersistentEntity<?> persistentEntity) {
|
||||
public DefaultEntityState(final STATE underlyingState, final ENTITY entity, final Class<? extends ENTITY> type, final DelegatingFieldAccessorFactory delegatingFieldAccessorFactory, Neo4JPersistentEntity<ENTITY> 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<ENTITY extends GraphBacked<STATE>, STAT
|
||||
return state;
|
||||
}
|
||||
|
||||
public Neo4JPersistentEntity<ENTITY> getPersistentEntity() {
|
||||
return persistentEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable(Field field) {
|
||||
final FieldAccessor<ENTITY> accessor = accessorFor(field);
|
||||
final FieldAccessor<ENTITY> accessor = accessorFor(property(field));
|
||||
if (accessor == null) return true;
|
||||
return accessor.isWriteable(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(final Field field) {
|
||||
final FieldAccessor<ENTITY> accessor = accessorFor(field);
|
||||
final FieldAccessor<ENTITY> 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<ENTITY> accessor = accessorFor(field);
|
||||
return setValue(property(field),newVal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object setValue(final Neo4JPersistentProperty property, final Object newVal) {
|
||||
final FieldAccessor<ENTITY> 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<ENTITY> accessor = accessorFor(field);
|
||||
final FieldAccessor<ENTITY> accessor = accessorFor(property(field));
|
||||
if (accessor == null) return null;
|
||||
else return accessor.getDefaultImplementation();
|
||||
}
|
||||
protected FieldAccessor<ENTITY> 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<ENTITY> 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<ENTITY, ?> listener : fieldAccessorListeners.get(field)) {
|
||||
listener.valueChanged(entity, null, result); // todo oldValue
|
||||
@@ -117,13 +133,12 @@ public abstract class DefaultEntityState<ENTITY extends GraphBacked<STATE>, 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<T> implements FieldAccessor
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(final Field f) {
|
||||
public boolean accept(final Neo4JPersistentProperty f) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final Collection<FieldAccessorFactory<?>> fieldAccessorFactories = new ArrayList<FieldAccessorFactory<?>>();
|
||||
final Collection<FieldAccessorListenerFactory<?>> fieldAccessorListenerFactories = new ArrayList<FieldAccessorListenerFactory<?>>();
|
||||
|
||||
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 <E> FieldAccessorFactory<E> factoryForField(final Field field) {
|
||||
if (isSyntheticField(field)) return null;
|
||||
private <E> FieldAccessorFactory<E> 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<E>) 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<FieldAccessListener<T, ?>> listenersFor(final Field field) {
|
||||
public List<FieldAccessListener<T, ?>> listenersFor(final Neo4JPersistentProperty property) {
|
||||
final List<FieldAccessListener<T, ?>> result = new ArrayList<FieldAccessListener<T, ?>>();
|
||||
final List<FieldAccessorListenerFactory<T>> fieldAccessListenerFactories = getFieldAccessListenerFactories(field);
|
||||
final List<FieldAccessorListenerFactory<T>> fieldAccessListenerFactories = getFieldAccessListenerFactories(property);
|
||||
for (final FieldAccessorListenerFactory<T> fieldAccessorListenerFactory : fieldAccessListenerFactories) {
|
||||
final FieldAccessListener<T, ?> listener = fieldAccessorListenerFactory.forField(field);
|
||||
final FieldAccessListener<T, ?> listener = fieldAccessorListenerFactory.forField(property);
|
||||
result.add(listener);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private <E> List<FieldAccessorListenerFactory<E>> getFieldAccessListenerFactories(final Field field) {
|
||||
private <E> List<FieldAccessorListenerFactory<E>> getFieldAccessListenerFactories(final Neo4JPersistentProperty property) {
|
||||
final List<FieldAccessorListenerFactory<E>> result = new ArrayList<FieldAccessorListenerFactory<E>>();
|
||||
for (final FieldAccessorListenerFactory<?> fieldAccessorListenerFactory : fieldAccessorListenerFactories) {
|
||||
if (fieldAccessorListenerFactory.accept(field)) {
|
||||
if (fieldAccessorListenerFactory.accept(property)) {
|
||||
result.add((FieldAccessorListenerFactory<E>) fieldAccessorListenerFactory);
|
||||
}
|
||||
}
|
||||
@@ -114,21 +99,32 @@ public abstract class DelegatingFieldAccessorFactory<T> implements FieldAccessor
|
||||
|
||||
|
||||
|
||||
private final Map<Class<?>, FieldAccessorFactoryProviders> accessorFactoryProviderCache = new HashMap<Class<?>, FieldAccessorFactoryProviders>();
|
||||
private final Map<TypeInformation<?>, FieldAccessorFactoryProviders> accessorFactoryProviderCache = new HashMap<TypeInformation<?>, FieldAccessorFactoryProviders>();
|
||||
|
||||
public <T> FieldAccessorFactoryProviders<T> accessorFactoriesFor(final Class<T> type) {
|
||||
public <T> FieldAccessorFactoryProviders<T> accessorFactoriesFor(final Neo4JPersistentEntity<?> type) {
|
||||
synchronized (this) {
|
||||
final FieldAccessorFactoryProviders<T> fieldAccessorFactoryProviders = accessorFactoryProviderCache.get(type);
|
||||
final TypeInformation<?> typeInformation = type.getTypeInformation();
|
||||
final FieldAccessorFactoryProviders<T> fieldAccessorFactoryProviders = accessorFactoryProviderCache.get(typeInformation);
|
||||
if (fieldAccessorFactoryProviders != null) return fieldAccessorFactoryProviders;
|
||||
final FieldAccessorFactoryProviders<T> newFieldAccessorFactories = new FieldAccessorFactoryProviders<T>(type);
|
||||
ReflectionUtils.doWithFields(type, new ReflectionUtils.FieldCallback() {
|
||||
public void doWith(final Field field) throws IllegalArgumentException, IllegalAccessException {
|
||||
final FieldAccessorFactory<?> factory = factoryForField(field);
|
||||
final List<FieldAccessorListenerFactory> listenerFactories = (List<FieldAccessorListenerFactory>) getFieldAccessListenerFactories(field);
|
||||
newFieldAccessorFactories.add(field, factory, listenerFactories);
|
||||
final FieldAccessorFactoryProviders<T> newFieldAccessorFactories = new FieldAccessorFactoryProviders<T>(typeInformation);
|
||||
type.doWithProperties(new PropertyHandler<Neo4JPersistentProperty>() {
|
||||
@Override
|
||||
public void doWithPersistentProperty(Neo4JPersistentProperty property) {
|
||||
final FieldAccessorFactory<?> factory = factoryForField(property);
|
||||
final List<FieldAccessorListenerFactory> listenerFactories = (List<FieldAccessorListenerFactory>) getFieldAccessListenerFactories(property);
|
||||
newFieldAccessorFactories.add(property, factory, listenerFactories);
|
||||
}
|
||||
});
|
||||
accessorFactoryProviderCache.put(type, newFieldAccessorFactories);
|
||||
type.doWithAssociations(new AssociationHandler<Neo4JPersistentProperty>() {
|
||||
@Override
|
||||
public void doWithAssociation(Association<Neo4JPersistentProperty> association) {
|
||||
final Neo4JPersistentProperty property = association.getInverse();
|
||||
final FieldAccessorFactory<?> factory = factoryForField(property);
|
||||
final List<FieldAccessorListenerFactory> listenerFactories = (List<FieldAccessorListenerFactory>) getFieldAccessListenerFactories(property);
|
||||
newFieldAccessorFactories.add(property, factory, listenerFactories);
|
||||
}
|
||||
});
|
||||
accessorFactoryProviderCache.put(typeInformation, newFieldAccessorFactories);
|
||||
return newFieldAccessorFactories;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<ENTITY extends GraphBacked<STATE>, STATE> imple
|
||||
protected final EntityState<ENTITY,STATE> delegate;
|
||||
private final static Log log = LogFactory.getLog(DetachedEntityState.class);
|
||||
private GraphDatabaseContext graphDatabaseContext;
|
||||
private Neo4JPersistentEntity<ENTITY> persistentEntity;
|
||||
|
||||
public DetachedEntityState(final EntityState<ENTITY, STATE> delegate, GraphDatabaseContext graphDatabaseContext) {
|
||||
this.delegate = delegate;
|
||||
this.persistentEntity = delegate.getPersistentEntity();
|
||||
this.graphDatabaseContext = graphDatabaseContext;
|
||||
}
|
||||
|
||||
@@ -67,6 +72,11 @@ public class DetachedEntityState<ENTITY extends GraphBacked<STATE>, STATE> imple
|
||||
return delegate.getPersistentState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Neo4JPersistentEntity<ENTITY> getPersistentEntity() {
|
||||
return persistentEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(final Field field) {
|
||||
if (isDetached()) {
|
||||
@@ -124,7 +134,17 @@ public class DetachedEntityState<ENTITY extends GraphBacked<STATE>, 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<ENTITY extends GraphBacked<STATE>, STATE> imple
|
||||
return newVal;
|
||||
}
|
||||
// flushDirty();
|
||||
return delegate.setValue(field, newVal);
|
||||
return delegate.setValue(property, newVal);
|
||||
}
|
||||
@Override
|
||||
public Object getDefaultImplementation(Field field) {
|
||||
|
||||
@@ -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<GraphBacked<PropertyContainer>> forField(Field field) {
|
||||
public FieldAccessor<GraphBacked<PropertyContainer>> forField(Neo4JPersistentProperty field) {
|
||||
return new DynamicPropertiesFieldAccessor(conversionService,
|
||||
DelegatingFieldAccessorFactory.getNeo4jPropertyName(field), field);
|
||||
field.getNeo4jPropertyName(), field);
|
||||
}
|
||||
|
||||
public static class DynamicPropertiesFieldAccessor implements FieldAccessor<GraphBacked<PropertyContainer>> {
|
||||
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;
|
||||
|
||||
@@ -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<E> {
|
||||
/**
|
||||
*
|
||||
* @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<E> forField(Field f);
|
||||
FieldAccessor<E> forField(Neo4JPersistentProperty f);
|
||||
}
|
||||
|
||||
@@ -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<T> {
|
||||
|
||||
static class FieldAccessorFactoryProvider<E> {
|
||||
private final Field field;
|
||||
private final Neo4JPersistentProperty property;
|
||||
private final FieldAccessorFactory<E> fieldAccessorFactory;
|
||||
private final List<FieldAccessorListenerFactory<E>> fieldAccessorListenerFactories;
|
||||
|
||||
FieldAccessorFactoryProvider(final Field field, final FieldAccessorFactory<E> fieldAccessorFactory, final List<FieldAccessorListenerFactory<E>> 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<E> accessor() {
|
||||
if (fieldAccessorFactory == null) return null;
|
||||
return fieldAccessorFactory.forField(field);
|
||||
return fieldAccessorFactory.forField(property);
|
||||
}
|
||||
|
||||
public List<FieldAccessListener<E, ?>> listeners() {
|
||||
if (fieldAccessorListenerFactories == null) return null;
|
||||
final List<FieldAccessListener<E, ?>> listeners = new ArrayList<FieldAccessListener<E, ?>>(fieldAccessorListenerFactories.size());
|
||||
for (final FieldAccessorListenerFactory<E> 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<T> type;
|
||||
private final TypeInformation<?> type;
|
||||
private final List<FieldAccessorFactoryProvider<T>> fieldAccessorFactoryProviders = new ArrayList<FieldAccessorFactoryProvider<T>>();
|
||||
private final IdFieldAccessorFactory idFieldAccessorFactory;
|
||||
private Field idField;
|
||||
private Neo4JPersistentProperty idProperty;
|
||||
|
||||
FieldAccessorFactoryProviders(Class<T> type) {
|
||||
FieldAccessorFactoryProviders(TypeInformation<?> type) {
|
||||
this.type = type;
|
||||
idFieldAccessorFactory = new IdFieldAccessorFactory();
|
||||
}
|
||||
|
||||
public Map<Field, FieldAccessor<T>> getFieldAccessors() {
|
||||
final Map<Field, FieldAccessor<T>> result = new HashMap<Field, FieldAccessor<T>>(fieldAccessorFactoryProviders.size(),1);
|
||||
public Map<Neo4JPersistentProperty, FieldAccessor<T>> getFieldAccessors() {
|
||||
final Map<Neo4JPersistentProperty, FieldAccessor<T>> result = new HashMap<Neo4JPersistentProperty, FieldAccessor<T>>(fieldAccessorFactoryProviders.size(),1);
|
||||
for (final FieldAccessorFactoryProvider<T> fieldAccessorFactoryProvider : fieldAccessorFactoryProviders) {
|
||||
final FieldAccessor<T> accessor = fieldAccessorFactoryProvider.accessor();
|
||||
result.put(fieldAccessorFactoryProvider.getField(), accessor);
|
||||
result.put(fieldAccessorFactoryProvider.getProperty(), accessor);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Map<Field, List<FieldAccessListener<T,?>>> getFieldAccessListeners() {
|
||||
final Map<Field, List<FieldAccessListener<T,?>>> result = new HashMap<Field, List<FieldAccessListener<T,?>>>(fieldAccessorFactoryProviders.size(),1);
|
||||
public Map<Neo4JPersistentProperty, List<FieldAccessListener<T,?>>> getFieldAccessListeners() {
|
||||
final Map<Neo4JPersistentProperty, List<FieldAccessListener<T,?>>> result = new HashMap<Neo4JPersistentProperty, List<FieldAccessListener<T,?>>>(fieldAccessorFactoryProviders.size(),1);
|
||||
for (final FieldAccessorFactoryProvider<T> fieldAccessorFactoryProvider : fieldAccessorFactoryProviders) {
|
||||
final List<FieldAccessListener<T,?>> listeners = (List<FieldAccessListener<T,?>>) fieldAccessorFactoryProvider.listeners();
|
||||
result.put(fieldAccessorFactoryProvider.getField(), listeners);
|
||||
result.put(fieldAccessorFactoryProvider.getProperty(), listeners);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void add(Field field, FieldAccessorFactory<?> fieldAccessorFactory, List<FieldAccessorListenerFactory> listenerFactories) {
|
||||
fieldAccessorFactoryProviders.add(new FieldAccessorFactoryProvider(field, fieldAccessorFactory, listenerFactories));
|
||||
if (idFieldAccessorFactory.accept(field)) this.idField = field;
|
||||
public void add(Neo4JPersistentProperty property, FieldAccessorFactory<?> fieldAccessorFactory, List<FieldAccessorListenerFactory> listenerFactories) {
|
||||
fieldAccessorFactoryProviders.add(new FieldAccessorFactoryProvider(property, fieldAccessorFactory, listenerFactories));
|
||||
if (property.isIdProperty()) this.idProperty = property;
|
||||
}
|
||||
|
||||
public Field getIdField() {
|
||||
return idField;
|
||||
public Neo4JPersistentProperty getIdProperty() {
|
||||
return idProperty;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<E> {
|
||||
/**
|
||||
* @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<E, ?> forField(Field f);
|
||||
FieldAccessListener<E, ?> forField(Neo4JPersistentProperty property);
|
||||
}
|
||||
|
||||
@@ -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<NodeBacked> {
|
||||
@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<NodeBacked> forField(final Field field) {
|
||||
return new IdFieldAccessor(field);
|
||||
public FieldAccessor<NodeBacked> forField(final Neo4JPersistentProperty property) {
|
||||
return new IdFieldAccessor(property);
|
||||
}
|
||||
|
||||
public static class IdFieldAccessor implements FieldAccessor<NodeBacked> {
|
||||
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
|
||||
|
||||
@@ -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<S extends PropertyCont
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(final Field f) {
|
||||
return isPropertyField(f) && indexProvider.isIndexed(f);
|
||||
public boolean accept(final Neo4JPersistentProperty property) {
|
||||
return isPropertyField(property) && property.isIndexed();
|
||||
}
|
||||
|
||||
|
||||
private boolean isPropertyField(final Field f) {
|
||||
return propertyFieldAccessorFactory.accept(f) || convertingNodePropertyFieldAccessorFactory.accept(f);
|
||||
private boolean isPropertyField(final Neo4JPersistentProperty property) {
|
||||
return propertyFieldAccessorFactory.accept(property) || convertingNodePropertyFieldAccessorFactory.accept(property);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldAccessListener<T, ?> forField(Field field) {
|
||||
return (FieldAccessListener<T, ?>) new IndexingPropertyFieldAccessorListener(field, indexProvider);
|
||||
public FieldAccessListener<T, ?> forField(Neo4JPersistentProperty property) {
|
||||
return (FieldAccessListener<T, ?>) new IndexingPropertyFieldAccessorListener(property, indexProvider);
|
||||
}
|
||||
|
||||
|
||||
@@ -64,36 +65,27 @@ public class IndexingPropertyFieldAccessorListenerFactory<S extends PropertyCont
|
||||
this.graphDatabaseContext = graphDatabaseContext;
|
||||
}
|
||||
|
||||
private boolean isIndexed(final Field f) {
|
||||
final Indexed indexedAnnotation = getIndexedAnnotation(f);
|
||||
return indexedAnnotation != null;
|
||||
}
|
||||
private String getIndexKey(Field field) {
|
||||
Indexed indexed = getIndexedAnnotation(field);
|
||||
if (indexed==null || indexed.fieldName().isEmpty()) return DelegatingFieldAccessorFactory.getNeo4jPropertyName(field);
|
||||
private String getIndexKey(Neo4JPersistentProperty property) {
|
||||
Indexed indexed = property.getAnnotation(Indexed.class);
|
||||
if (indexed==null || indexed.fieldName().isEmpty()) return property.getNeo4jPropertyName();
|
||||
return indexed.fieldName();
|
||||
}
|
||||
|
||||
private boolean isFulltextIndex(Field field) {
|
||||
Indexed indexed = getIndexedAnnotation(field);
|
||||
return indexed!=null && indexed.fulltext();
|
||||
}
|
||||
|
||||
private Indexed getIndexedAnnotation(AnnotatedElement element) {
|
||||
return element.getAnnotation(Indexed.class);
|
||||
}
|
||||
|
||||
private Index<S> getIndex(Field field, T instance) {
|
||||
final Indexed indexedAnnotation = getIndexedAnnotation(field);
|
||||
final Class<T> type = (Class<T>) field.getDeclaringClass();
|
||||
private Index<S> getIndex(Neo4JPersistentProperty property, GraphBacked instance) {
|
||||
final Indexed indexedAnnotation = property.getAnnotation(Indexed.class);
|
||||
final Class<T> type = (Class<T>) 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<S extends PropertyCont
|
||||
private final static Log log = LogFactory.getLog( IndexingPropertyFieldAccessorListener.class );
|
||||
|
||||
protected final String indexKey;
|
||||
private final Field field;
|
||||
private final Neo4JPersistentProperty property;
|
||||
private final IndexProvider indexProvider;
|
||||
|
||||
public IndexingPropertyFieldAccessorListener(final Field field, IndexProvider indexProvider) {
|
||||
this.field = field;
|
||||
public IndexingPropertyFieldAccessorListener(final Neo4JPersistentProperty property, IndexProvider indexProvider) {
|
||||
this.property = property;
|
||||
this.indexProvider = indexProvider;
|
||||
indexKey = indexProvider.getIndexKey(field);
|
||||
indexKey = indexProvider.getIndexKey(property);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void valueChanged(GraphBacked<T> graphBacked, Object oldVal, Object newVal) {
|
||||
Index<T> index = indexProvider.getIndex(field, graphBacked);
|
||||
Index<T> index = indexProvider.getIndex(property, graphBacked);
|
||||
if (newVal instanceof Number) newVal = ValueContext.numeric((Number) newVal);
|
||||
|
||||
final T state = graphBacked.getPersistentState();
|
||||
|
||||
@@ -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<NodeBacked> {
|
||||
@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<NodeBacked, ?> forField(final Field field) {
|
||||
return new JpaIdFieldListener(field);
|
||||
public FieldAccessListener<NodeBacked, ?> forField(final Neo4JPersistentProperty property) {
|
||||
return new JpaIdFieldListener(property);
|
||||
}
|
||||
|
||||
public static class JpaIdFieldListener implements FieldAccessListener<NodeBacked, Object> {
|
||||
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
|
||||
|
||||
@@ -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<ENTITY,T> extends AbstractSet<T> {
|
||||
private final ENTITY entity;
|
||||
final Set<T> 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<T>) newVal;
|
||||
}
|
||||
|
||||
@@ -78,13 +78,12 @@ public class ManagedFieldAccessorSet<ENTITY,T> extends AbstractSet<T> {
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<ENTITY> 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 <E> ManagedPrefixedDynamicProperties<E> create(String prefix, final Field field,
|
||||
public static <E> ManagedPrefixedDynamicProperties<E> create(String prefix, final Neo4JPersistentProperty property,
|
||||
final E entity) {
|
||||
return new ManagedPrefixedDynamicProperties<E>(prefix, field, entity);
|
||||
return new ManagedPrefixedDynamicProperties<E>(prefix, property, entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -73,7 +76,7 @@ public class ManagedPrefixedDynamicProperties<ENTITY> extends PrefixedDynamicPro
|
||||
|
||||
@Override
|
||||
public DynamicProperties createFrom(Map<String, Object> map) {
|
||||
DynamicProperties d = new ManagedPrefixedDynamicProperties<ENTITY>(prefix, map.size(), field, entity);
|
||||
DynamicProperties d = new ManagedPrefixedDynamicProperties<ENTITY>(prefix, map.size(), property, entity);
|
||||
d.setPropertiesFrom(map);
|
||||
return d;
|
||||
}
|
||||
@@ -92,14 +95,15 @@ public class ManagedPrefixedDynamicProperties<ENTITY> 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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<? extends NodeBacked> targetFrom(Field field, RelatedTo relatedTo) {
|
||||
if (relatedTo!=null && relatedTo.elementClass()!=NodeBacked.class) return relatedTo.elementClass();
|
||||
return (Class<? extends NodeBacked>) 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<TARGET extends GraphBacked> extends AbstractNodeRelationshipFieldAccessor<NodeBacked, Node, TARGET, Node> {
|
||||
public NodeToNodesRelationshipFieldAccessor(final Class<? extends TARGET> clazz, final GraphDatabaseContext graphDatabaseContext, final Direction direction, final RelationshipType type, Field field) {
|
||||
super(clazz, graphDatabaseContext, direction, type,field);
|
||||
public NodeToNodesRelationshipFieldAccessor(final Class<? extends TARGET> clazz, final GraphDatabaseContext graphDatabaseContext, final Direction direction, final RelationshipType type, Neo4JPersistentProperty property) {
|
||||
super(clazz, graphDatabaseContext, direction, type,property);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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<NodeBacked> forField(final Field field) {
|
||||
final RelatedToVia relEntityAnnotation = getRelationshipAnnotation(field);
|
||||
return new OneToNRelationshipEntityFieldAccessor(typeFrom(relEntityAnnotation), dirFrom(relEntityAnnotation), targetFrom(relEntityAnnotation), graphDatabaseContext,field);
|
||||
public FieldAccessor<NodeBacked> forField(final Neo4JPersistentProperty property) {
|
||||
final RelationshipInfo relationshipInfo = property.getRelationshipInfo();
|
||||
return new OneToNRelationshipEntityFieldAccessor(relationshipInfo.getRelationshipType(), relationshipInfo.getDirection(), (Class<? extends RelationshipBacked>) relationshipInfo.getTargetType().getType(), graphDatabaseContext,property);
|
||||
}
|
||||
|
||||
private boolean hasValidRelationshipAnnotation(final Field field) {
|
||||
final RelatedToVia relEntityAnnotation = getRelationshipAnnotation(field);
|
||||
if (relEntityAnnotation == null) return false;
|
||||
Class<? extends RelationshipBacked> 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<? extends RelationshipBacked> 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<NodeBacked, Node, RelationshipBacked, Relationship> {
|
||||
|
||||
public OneToNRelationshipEntityFieldAccessor(final RelationshipType type, final Direction direction, final Class<? extends RelationshipBacked> elementClass, final GraphDatabaseContext graphDatabaseContext, Field field) {
|
||||
super(elementClass, graphDatabaseContext, direction, type, field);
|
||||
public OneToNRelationshipEntityFieldAccessor(final RelationshipType type, final Direction direction, final Class<? extends RelationshipBacked> 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<RelationshipBacked> result = createEntitySetFromRelationships(entity);
|
||||
return doReturn(new ManagedFieldAccessorSet<NodeBacked, RelationshipBacked>(entity, result, field));
|
||||
return doReturn(new ManagedFieldAccessorSet<NodeBacked, RelationshipBacked>(entity, result, property));
|
||||
}
|
||||
|
||||
private Set<RelationshipBacked> createEntitySetFromRelationships(final NodeBacked entity) {
|
||||
|
||||
@@ -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<NodeBacked> 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<NodeBacked> forField(final Neo4JPersistentProperty property) {
|
||||
final RelationshipInfo relationshipInfo = property.getRelationshipInfo();
|
||||
final Class<? extends NodeBacked> targetType = (Class<? extends NodeBacked>) relationshipInfo.getTargetType().getType();
|
||||
return new OneToNRelationshipFieldAccessor(relationshipInfo.getRelationshipType(), relationshipInfo.getDirection(), targetType, graphDatabaseContext,property);
|
||||
}
|
||||
|
||||
public static class OneToNRelationshipFieldAccessor extends NodeToNodesRelationshipFieldAccessor<NodeBacked> {
|
||||
|
||||
public OneToNRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class<? extends NodeBacked> elementClass, final GraphDatabaseContext graphDatabaseContext, Field field) {
|
||||
super(elementClass, graphDatabaseContext, direction, type,field);
|
||||
public OneToNRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class<? extends NodeBacked> elementClass, final GraphDatabaseContext graphDatabaseContext, Neo4JPersistentProperty property) {
|
||||
super(elementClass, graphDatabaseContext, direction, type,property);
|
||||
}
|
||||
|
||||
public Object setValue(final NodeBacked entity, final Object newVal) {
|
||||
|
||||
@@ -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<GraphB
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(final Field f) {
|
||||
return isNeo4jPropertyType(f.getType());
|
||||
public boolean accept(final Neo4JPersistentProperty f) {
|
||||
return f.isNeo4jPropertyType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldAccessor<GraphBacked<PropertyContainer>> 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<GraphBacked<PropertyContainer>> forField(final Neo4JPersistentProperty field) {
|
||||
return new PropertyFieldAccessor(conversionService, field);
|
||||
}
|
||||
|
||||
public static class PropertyFieldAccessor implements FieldAccessor<GraphBacked<PropertyContainer>> {
|
||||
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
|
||||
|
||||
@@ -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<NodeBacked> {
|
||||
@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<NodeBacke
|
||||
|
||||
|
||||
@Override
|
||||
public FieldAccessor<NodeBacked> forField(final Field field) {
|
||||
public FieldAccessor<NodeBacked> forField(final Neo4JPersistentProperty field) {
|
||||
return new QueryFieldAccessor(field);
|
||||
}
|
||||
|
||||
@@ -46,27 +48,27 @@ public class QueryFieldAccessorFactory implements FieldAccessorFactory<NodeBacke
|
||||
* @since 12.09.2010
|
||||
*/
|
||||
public static class QueryFieldAccessor implements FieldAccessor<NodeBacked> {
|
||||
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<NodeBacke
|
||||
|
||||
@Override
|
||||
public Object setValue(final NodeBacked nodeBacked, final Object newVal) {
|
||||
throw new InvalidDataAccessApiUsageException("Cannot set readonly query field " + field);
|
||||
throw new InvalidDataAccessApiUsageException("Cannot set readonly query field " + property);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,8 +19,9 @@ package org.springframework.data.neo4j.fieldaccess;
|
||||
import org.neo4j.graphdb.Direction;
|
||||
import org.neo4j.graphdb.RelationshipType;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
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;
|
||||
@@ -32,19 +33,21 @@ public class ReadOnlyOneToNRelationshipFieldAccessorFactory extends NodeRelation
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(final Field f) {
|
||||
return Iterable.class.equals(f.getType()) && hasValidRelationshipAnnotation(f);
|
||||
public boolean accept(final Neo4JPersistentProperty f) {
|
||||
if (!f.isRelationship()) return false;
|
||||
final RelationshipInfo info = f.getRelationshipInfo();
|
||||
return info.isMultiple() && info.targetsNodes() && info.isReadonly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldAccessor<NodeBacked> forField(final Field field) {
|
||||
final RelatedTo relAnnotation = getRelationshipAnnotation(field);
|
||||
return new ReadOnlyOneToNRelationshipFieldAccessor(typeFrom(field, relAnnotation), dirFrom(relAnnotation), targetFrom(field, relAnnotation), graphDatabaseContext,field);
|
||||
public FieldAccessor<NodeBacked> forField(final Neo4JPersistentProperty property) {
|
||||
final RelationshipInfo relationshipInfo = property.getRelationshipInfo();
|
||||
return new ReadOnlyOneToNRelationshipFieldAccessor(relationshipInfo.getRelationshipType(), relationshipInfo.getDirection(), (Class<? extends NodeBacked>) property.getRelationshipInfo().getTargetType().getType(), graphDatabaseContext,property);
|
||||
}
|
||||
|
||||
public static class ReadOnlyOneToNRelationshipFieldAccessor extends OneToNRelationshipFieldAccessorFactory.OneToNRelationshipFieldAccessor {
|
||||
|
||||
public ReadOnlyOneToNRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class<? extends NodeBacked> elementClass, final GraphDatabaseContext graphDatabaseContext, Field field) {
|
||||
public ReadOnlyOneToNRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class<? extends NodeBacked> elementClass, final GraphDatabaseContext graphDatabaseContext, Neo4JPersistentProperty field) {
|
||||
super(type,direction,elementClass, graphDatabaseContext, field);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<RelationshipBacked> forField(final Field f) {
|
||||
if (isStartNodeField(f)) {
|
||||
return new RelationshipNodeFieldAccessor(f, graphDatabaseContext) {
|
||||
public FieldAccessor<RelationshipBacked> 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<RelationshipBacked> {
|
||||
|
||||
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<? extends NodeBacked>) field.getType());
|
||||
final NodeBacked result = graphDatabaseContext.createEntityFromState(node, (Class<? extends NodeBacked>) property.getType());
|
||||
return doReturn(result);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<NodeBacked> 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<NodeBacked> forField(final Neo4JPersistentProperty property) {
|
||||
final RelationshipInfo relationshipInfo = property.getRelationshipInfo();
|
||||
return new SingleRelationshipFieldAccessor(relationshipInfo.getRelationshipType(), relationshipInfo.getDirection(), (Class<? extends NodeBacked>) relationshipInfo.getTargetType().getType(), graphDatabaseContext,property);
|
||||
}
|
||||
|
||||
public static class SingleRelationshipFieldAccessor extends NodeToNodesRelationshipFieldAccessor<NodeBacked> {
|
||||
public SingleRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class<? extends NodeBacked> clazz, final GraphDatabaseContext graphDatabaseContext, Field field) {
|
||||
super(clazz, graphDatabaseContext, direction, type, field);
|
||||
public SingleRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class<? extends NodeBacked> clazz, final GraphDatabaseContext graphDatabaseContext, Neo4JPersistentProperty property) {
|
||||
super(clazz, graphDatabaseContext, direction, type, property);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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<GraphBacked<PropertyContainer>> {
|
||||
@Override
|
||||
public boolean accept(final Field f) {
|
||||
return Modifier.isTransient(f.getModifiers());
|
||||
public boolean accept(final Neo4JPersistentProperty property) {
|
||||
return property.isTransient();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldAccessor<GraphBacked<PropertyContainer>> forField(final Field field) {
|
||||
return new TransientFieldAccessor(field);
|
||||
public FieldAccessor<GraphBacked<PropertyContainer>> forField(final Neo4JPersistentProperty property) {
|
||||
return new TransientFieldAccessor(property);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -38,10 +36,10 @@ public class TransientFieldAccessorFactory implements FieldAccessorFactory<Graph
|
||||
* @since 12.09.2010
|
||||
*/
|
||||
public static class TransientFieldAccessor implements FieldAccessor<GraphBacked<PropertyContainer>> {
|
||||
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
|
||||
|
||||
@@ -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<NodeBacked> {
|
||||
@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<NodeB
|
||||
|
||||
|
||||
@Override
|
||||
public FieldAccessor<NodeBacked> forField(final Field field) {
|
||||
return new TraversalFieldAccessor(field);
|
||||
public FieldAccessor<NodeBacked> forField(final Neo4JPersistentProperty property) {
|
||||
return new TraversalFieldAccessor(property);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,24 +53,24 @@ public class TraversalFieldAccessorFactory implements FieldAccessorFactory<NodeB
|
||||
* @since 12.09.2010
|
||||
*/
|
||||
public static class TraversalFieldAccessor implements FieldAccessor<NodeBacked> {
|
||||
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<NodeB
|
||||
|
||||
@Override
|
||||
public Object setValue(final NodeBacked nodeBacked, final Object newVal) {
|
||||
throw new InvalidDataAccessApiUsageException("Cannot set readonly traversal description field " + field);
|
||||
throw new InvalidDataAccessApiUsageException("Cannot set readonly traversal description field " + property);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(final NodeBacked nodeBacked) {
|
||||
final TraversalDescription traversalDescription = fieldTraversalDescriptionBuilder.build(nodeBacked,field,params);
|
||||
final TraversalDescription traversalDescription = fieldTraversalDescriptionBuilder.build(nodeBacked, property,params);
|
||||
return doReturn(nodeBacked.findAllByTraversal(target, traversalDescription));
|
||||
}
|
||||
|
||||
@@ -105,7 +106,7 @@ public class TraversalFieldAccessorFactory implements FieldAccessorFactory<NodeB
|
||||
constructor.setAccessible(true);
|
||||
return constructor.newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error creating TraversalDescription from " + field,e);
|
||||
throw new RuntimeException("Error creating TraversalDescription from " + property,e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,10 @@ package org.springframework.data.neo4j.fieldaccess;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.neo4j.graphdb.PropertyContainer;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.neo4j.core.GraphBacked;
|
||||
import org.springframework.data.neo4j.mapping.Neo4JPersistentEntity;
|
||||
import org.springframework.data.neo4j.mapping.Neo4JPersistentProperty;
|
||||
import org.springframework.data.neo4j.support.GraphDatabaseContext;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
@@ -40,20 +43,20 @@ class ValidatingNodePropertyFieldAccessorListenerFactory<T extends GraphBacked<?
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(final Field f) {
|
||||
return hasValidationAnnotation(f);
|
||||
public boolean accept(final Neo4JPersistentProperty property) {
|
||||
return hasValidationAnnotation(property);
|
||||
}
|
||||
|
||||
private boolean hasValidationAnnotation(final Field f) {
|
||||
for (Annotation annotation : f.getAnnotations()) {
|
||||
private boolean hasValidationAnnotation(final Neo4JPersistentProperty property) {
|
||||
for (Annotation annotation : property.getAnnotations()) {
|
||||
if (annotation.annotationType().isAnnotationPresent(Constraint.class)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldAccessListener<T, ?> forField(Field field) {
|
||||
return new ValidatingNodePropertyFieldAccessorListener(field,graphDatabaseContext.getValidator());
|
||||
public FieldAccessListener<T, ?> forField(Neo4JPersistentProperty property) {
|
||||
return new ValidatingNodePropertyFieldAccessorListener(property,graphDatabaseContext.getValidator());
|
||||
}
|
||||
|
||||
|
||||
@@ -66,18 +69,18 @@ class ValidatingNodePropertyFieldAccessorListenerFactory<T extends GraphBacked<?
|
||||
private final static Log log = LogFactory.getLog( ValidatingNodePropertyFieldAccessorListener.class );
|
||||
private String propertyName;
|
||||
private Validator validator;
|
||||
private Class<?> 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<T> graphBacked, Object oldVal, Object newVal) {
|
||||
if (validator==null) return;
|
||||
Set<ConstraintViolation<T>> constraintViolations = validator.validateValue((Class<T>)entityType, propertyName, newVal);
|
||||
Set<ConstraintViolation<T>> constraintViolations = validator.validateValue((Class<T>)entityType.getType(), propertyName, newVal);
|
||||
if (!constraintViolations.isEmpty()) throw new ValidationException("Error validating field "+propertyName+ " of "+entityType+": "+constraintViolations);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,4 +25,5 @@ import org.springframework.data.mapping.PersistentEntity;
|
||||
*/
|
||||
public interface Neo4JPersistentEntity<T> extends PersistentEntity<T, Neo4JPersistentProperty> {
|
||||
|
||||
boolean useShortNames();
|
||||
}
|
||||
|
||||
@@ -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<T> extends BasicPersistentEntity<T, Neo4JPersistentProperty> implements Neo4JPersistentEntity<T> {
|
||||
|
||||
private Map<Class<? extends Annotation>,Annotation> annotations=new IdentityHashMap<Class<? extends Annotation>,Annotation>();
|
||||
|
||||
/**
|
||||
* Creates a new {@link Neo4JPersistentEntityImpl} instance.
|
||||
*
|
||||
@@ -33,5 +41,20 @@ class Neo4JPersistentEntityImpl<T> extends BasicPersistentEntity<T, Neo4JPersist
|
||||
*/
|
||||
public Neo4JPersistentEntityImpl(TypeInformation<T> 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 extends Annotation> T getAnnotation(Class<T> annotationType) {
|
||||
return (T) annotations.get(annotationType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Neo4JPersist
|
||||
boolean isIndexed();
|
||||
|
||||
Neo4JPersistentPropertyImpl.IndexInfo getIndexInfo();
|
||||
|
||||
String getNeo4jPropertyName();
|
||||
|
||||
boolean isSimpleValueField();
|
||||
|
||||
boolean isSerializableField(final ConversionService conversionService);
|
||||
|
||||
boolean isDeserializableField(final ConversionService conversionService);
|
||||
|
||||
boolean isNeo4jPropertyType();
|
||||
|
||||
boolean isSyntheticField();
|
||||
|
||||
Collection<? extends Annotation> getAnnotations();
|
||||
|
||||
<T extends Annotation> T getAnnotation(Class<T> annotationType);
|
||||
|
||||
<T extends Annotation> boolean isAnnotationPresent(Class<T> annotationType);
|
||||
|
||||
void setValue(Object entity, Object newValue) throws IllegalAccessException;
|
||||
|
||||
Object getValue(final Object entity) throws IllegalAccessException;
|
||||
}
|
||||
|
||||
@@ -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<Neo4JPersis
|
||||
return annotation!=null ? new IndexInfo(annotation) : null;
|
||||
}
|
||||
|
||||
private <T extends Annotation> T getAnnotation(Class<T> annotationType) {
|
||||
public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
|
||||
return (T) annotations.get(annotationType);
|
||||
}
|
||||
|
||||
@@ -83,12 +86,18 @@ class Neo4JPersistentPropertyImpl extends AbstractPersistentProperty<Neo4JPersis
|
||||
return null;
|
||||
}
|
||||
|
||||
private <T extends Annotation> boolean isAnnotationPresent(Class<T> annotationType) {
|
||||
public <T extends Annotation> boolean isAnnotationPresent(Class<T> 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<NodeEntity> annotationClass) {
|
||||
return typeInformation.getActualType().getClass().isAnnotationPresent(annotationClass);
|
||||
return typeInformation.getActualType().getType().isAnnotationPresent(annotationClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -121,6 +130,58 @@ class Neo4JPersistentPropertyImpl extends AbstractPersistentProperty<Neo4JPersis
|
||||
return indexInfo;
|
||||
}
|
||||
|
||||
public String getNeo4jPropertyName() {
|
||||
final Neo4JPersistentEntity entityClass = (Neo4JPersistentEntity) getOwner();
|
||||
if (entityClass.useShortNames()) return getName();
|
||||
return String.format("%s.%s", entityClass.getType().getSimpleName(), getName());
|
||||
}
|
||||
|
||||
public boolean isSimpleValueField() {
|
||||
final Class<?> 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<? extends Annotation> 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<Neo4JPersis
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getType() +" "+ getName() + " rel: "+isRelationship()+ " idx: "+isIndexed();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,14 +16,18 @@
|
||||
|
||||
package org.springframework.data.neo4j.mapping;
|
||||
|
||||
import org.neo4j.graphdb.Direction;
|
||||
import org.neo4j.graphdb.DynamicRelationshipType;
|
||||
import org.neo4j.graphdb.RelationshipType;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.neo4j.annotation.NodeEntity;
|
||||
import org.springframework.data.neo4j.annotation.RelatedTo;
|
||||
import org.springframework.data.neo4j.annotation.RelatedToVia;
|
||||
import org.springframework.data.neo4j.annotation.RelationshipEntity;
|
||||
import org.springframework.data.neo4j.core.Direction;
|
||||
import org.springframework.data.neo4j.core.NodeBacked;
|
||||
import org.springframework.data.neo4j.core.RelationshipBacked;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import scala.annotation.target.field;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
@@ -33,7 +37,8 @@ public class RelationshipInfo {
|
||||
private final Direction direction;
|
||||
private final String type;
|
||||
private final TypeInformation<?> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ public class GraphDatabaseContext {
|
||||
} else if (state instanceof Relationship && RelationshipBacked.class.isAssignableFrom(type)) {
|
||||
return (TypeRepresentationStrategy<S, T>) relationshipTypeRepresentationStrategy;
|
||||
}
|
||||
throw new IllegalArgumentException("Type is not NodeBacked nor RelationshipBacked.");
|
||||
throw new IllegalArgumentException("Type "+type+" is not NodeBacked nor RelationshipBacked.");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -33,7 +33,7 @@ public class NodeEntityState<ENTITY extends NodeBacked> extends DefaultEntitySta
|
||||
|
||||
private final GraphDatabaseContext graphDatabaseContext;
|
||||
|
||||
public NodeEntityState(final Node underlyingState, final ENTITY entity, final Class<? extends ENTITY> type, final GraphDatabaseContext graphDatabaseContext, final DelegatingFieldAccessorFactory<NodeBacked> nodeDelegatingFieldAccessorFactory, Neo4JPersistentEntity<?> persistentEntity) {
|
||||
public NodeEntityState(final Node underlyingState, final ENTITY entity, final Class<? extends ENTITY> type, final GraphDatabaseContext graphDatabaseContext, final DelegatingFieldAccessorFactory<NodeBacked> nodeDelegatingFieldAccessorFactory, Neo4JPersistentEntity<ENTITY> persistentEntity) {
|
||||
super(underlyingState, entity, type, nodeDelegatingFieldAccessorFactory,persistentEntity);
|
||||
this.graphDatabaseContext = graphDatabaseContext;
|
||||
}
|
||||
|
||||
@@ -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<NodeBacked> partialNodeEntityState = new PartialNodeEntityState<NodeBacked>(null, entity, entityType, graphDatabaseContext, getPersistenceUnitUtils(), delegatingFieldAccessorFactory, persistentEntity);
|
||||
final PartialNodeEntityState<NodeBacked> partialNodeEntityState = new PartialNodeEntityState<NodeBacked>(null, entity, entityType, graphDatabaseContext, getPersistenceUnitUtils(), delegatingFieldAccessorFactory, (Neo4JPersistentEntity<NodeBacked>) persistentEntity);
|
||||
return new DetachedEntityState<NodeBacked, Node>(partialNodeEntityState, graphDatabaseContext) {
|
||||
@Override
|
||||
protected boolean isDetached() {
|
||||
@@ -55,7 +55,7 @@ public class NodeEntityStateFactory {
|
||||
}
|
||||
};
|
||||
} else {
|
||||
NodeEntityState<NodeBacked> nodeEntityState = new NodeEntityState<NodeBacked>(null, entity, entityType, graphDatabaseContext, nodeDelegatingFieldAccessorFactory, persistentEntity);
|
||||
NodeEntityState<NodeBacked> nodeEntityState = new NodeEntityState<NodeBacked>(null, entity, entityType, graphDatabaseContext, nodeDelegatingFieldAccessorFactory, (Neo4JPersistentEntity<NodeBacked>) persistentEntity);
|
||||
// alternative was return new NestedTransactionEntityState<NodeBacked, Node>(nodeEntityState,graphDatabaseContext);
|
||||
return new DetachedEntityState<NodeBacked, Node>(nodeEntityState, graphDatabaseContext);
|
||||
}
|
||||
|
||||
@@ -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<ENTITY extends NodeBacked> extends DefaultEn
|
||||
private final GraphDatabaseContext graphDatabaseContext;
|
||||
private PersistenceUnitUtil persistenceUnitUtil;
|
||||
|
||||
public PartialNodeEntityState(final Node underlyingState, final ENTITY entity, final Class<? extends ENTITY> type, final GraphDatabaseContext graphDatabaseContext, PersistenceUnitUtil persistenceUnitUtil, final PartialNodeDelegatingFieldAccessorFactory delegatingFieldAccessorFactory, final Neo4JPersistentEntity<?> persistentEntity) {
|
||||
public PartialNodeEntityState(final Node underlyingState, final ENTITY entity, final Class<? extends ENTITY> type, final GraphDatabaseContext graphDatabaseContext, PersistenceUnitUtil persistenceUnitUtil, final PartialNodeDelegatingFieldAccessorFactory delegatingFieldAccessorFactory, final Neo4JPersistentEntity<ENTITY> persistentEntity) {
|
||||
super(underlyingState, entity, type, delegatingFieldAccessorFactory, persistentEntity);
|
||||
this.graphDatabaseContext = graphDatabaseContext;
|
||||
this.persistenceUnitUtil = persistenceUnitUtil;
|
||||
@@ -86,7 +87,7 @@ public class PartialNodeEntityState<ENTITY extends NodeBacked> extends DefaultEn
|
||||
|
||||
@Override
|
||||
public boolean isWritable(Field field) {
|
||||
final FieldAccessor<ENTITY> accessor = accessorFor(field);
|
||||
final FieldAccessor<ENTITY> 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<ENTITY extends NodeBacked> 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<ENTITY extends NodeBacked> 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<ENTITY extends NodeBacked> 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<ENTITY extends NodeBacked> 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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -34,7 +34,7 @@ public class RelationshipEntityState<ENTITY extends RelationshipBacked> extends
|
||||
|
||||
private final GraphDatabaseContext graphDatabaseContext;
|
||||
|
||||
public RelationshipEntityState(final Relationship underlyingState, final ENTITY entity, final Class<? extends ENTITY> type, final GraphDatabaseContext graphDatabaseContext, final DelegatingFieldAccessorFactory<RelationshipBacked> delegatingFieldAccessorFactory, Neo4JPersistentEntity<?> persistentEntity) {
|
||||
public RelationshipEntityState(final Relationship underlyingState, final ENTITY entity, final Class<? extends ENTITY> type, final GraphDatabaseContext graphDatabaseContext, final DelegatingFieldAccessorFactory<RelationshipBacked> delegatingFieldAccessorFactory, Neo4JPersistentEntity<ENTITY> persistentEntity) {
|
||||
super(underlyingState, entity, type, delegatingFieldAccessorFactory, persistentEntity);
|
||||
this.graphDatabaseContext = graphDatabaseContext;
|
||||
}
|
||||
|
||||
@@ -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<RelationshipBacked, Relationship> getEntityState(final RelationshipBacked entity) {
|
||||
final Class<? extends RelationshipBacked> entityType = entity.getClass();
|
||||
return new RelationshipEntityState<RelationshipBacked>(null,entity, entityType, graphDatabaseContext, relationshipDelegatingFieldAccessorFactory,mappingContext.getPersistentEntity(entityType));
|
||||
return new RelationshipEntityState<RelationshipBacked>(null,entity, entityType, graphDatabaseContext, relationshipDelegatingFieldAccessorFactory, (Neo4JPersistentEntity<RelationshipBacked>) mappingContext.getPersistentEntity(entityType));
|
||||
}
|
||||
|
||||
public void setGraphDatabaseContext(GraphDatabaseContext graphDatabaseContext) {
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user