DATAGRAPH-452 - Adapted to changes in BeanWrapper generics.

Also improved auditing setup by referring to the AuditingHandler via an ObjectFactory (which is causing a break-up of the initialization cycle). Simplified the configuration setup as the handler now works with a MappingContext directly now.

Related issues: DATACMNS-468, DATACMNS-365.
This commit is contained in:
Oliver Gierke
2014-03-19 12:58:13 +01:00
parent 6947592c58
commit ba337ab918
10 changed files with 119 additions and 150 deletions

View File

@@ -15,95 +15,63 @@
*/
package org.springframework.data.neo4j.config;
import org.springframework.aop.target.LazyInitTargetSource;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.config.BeanComponentDefinitionBuilder;
import org.springframework.data.config.IsNewAwareAuditingHandlerBeanDefinitionParser;
import org.springframework.data.mapping.context.MappingContextIsNewStrategyFactory;
import org.springframework.data.auditing.config.AuditingHandlerBeanDefinitionParser;
import org.springframework.data.auditing.config.IsNewAwareAuditingHandlerBeanDefinitionParser;
import org.springframework.data.config.ParsingUtils;
import org.springframework.data.neo4j.lifecycle.AuditingEventListener;
import org.springframework.data.support.IsNewStrategyFactory;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* {@link BeanDefinitionParser} to register a {@link AuditingEventListener} to transparently set auditing information on
* an entity.
*
*
* @author Oliver Gierke
*/
public class Neo4jAuditingBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
return AuditingEventListener.class;
}
private static final String MAPPING_CONTEXT = "neo4jMappingContext";
@Override
protected boolean shouldGenerateId() {
return true;
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#getBeanClass(org.w3c.dom.Element)
*/
@Override
protected Class<?> getBeanClass(Element element) {
return AuditingEventListener.class;
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#doParse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext, org.springframework.beans.factory.support.BeanDefinitionBuilder)
*/
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder auditingListenerBuilder) {
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#shouldGenerateId()
*/
@Override
protected boolean shouldGenerateId() {
return true;
}
BeanDefinitionRegistry registry = parserContext.getRegistry();
if (!registry.containsBeanDefinition(IS_NEW_STRATEGY_FACTORY)) {
String templateName = MAPPING_CONTEXT;
if (!registry.containsBeanDefinition(MAPPING_CONTEXT)) {
templateName = resolveMappingContextRef(element);
}
createIsNewStrategyFactoryBeanDefinition(templateName, parserContext, element);
}
BeanDefinitionParser isNewStrategyParser = new IsNewAwareAuditingHandlerBeanDefinitionParser(IS_NEW_STRATEGY_FACTORY);
BeanDefinition isNewStrategyBeanDefinition = isNewStrategyParser.parse(element, parserContext);
// TODO
// BeanDefinitionBuilder lazyInitTS = BeanDefinitionBuilder.genericBeanDefinition(LazyInitTargetSource.class);
// lazyInitTS.addPropertyValue("targetBeanName", isNewStrategyBeanDefinition);
// lazyInitTS.addPropertyValue("targetClass", IsNewStrategyFactory.class.getName());
//
// auditingListenerBuilder.addConstructorArgValue(lazyInitTS);
auditingListenerBuilder.addConstructorArgValue(isNewStrategyBeanDefinition);
}
static String resolveMappingContextRef(Element element) {
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#doParse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext, org.springframework.beans.factory.support.BeanDefinitionBuilder)
*/
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder auditingListenerBuilder) {
String ctxRef = element.getAttribute("mapping-context-ref");
if (StringUtils.hasText(ctxRef)) {
return ctxRef;
if (!StringUtils.hasText(ctxRef)) {
ctxRef = MAPPING_CONTEXT;
}
return MAPPING_CONTEXT;
}
private String createIsNewStrategyFactoryBeanDefinition(String mappingContextRef, ParserContext context,
Element element) {
AuditingHandlerBeanDefinitionParser auditingHandlerParser = new IsNewAwareAuditingHandlerBeanDefinitionParser(
ctxRef);
auditingHandlerParser.parse(element, parserContext);
BeanDefinitionBuilder mappingContextStrategyFactoryBuilder = BeanDefinitionBuilder
.rootBeanDefinition(MappingContextIsNewStrategyFactory.class);
mappingContextStrategyFactoryBuilder.addConstructorArgReference(mappingContextRef);
BeanComponentDefinitionBuilder builder = new BeanComponentDefinitionBuilder(element, context);
context.registerBeanComponent(builder.getComponent(mappingContextStrategyFactoryBuilder, IS_NEW_STRATEGY_FACTORY));
return IS_NEW_STRATEGY_FACTORY;
}
static final String MAPPING_CONTEXT = "neo4jMappingContext";
static final String IS_NEW_STRATEGY_FACTORY = "isNewStrategyFactory";
auditingListenerBuilder.addConstructorArgValue(ParsingUtils.getObjectFactoryBeanDefinition(
auditingHandlerParser.getResolvedBeanName(), parserContext.extractSource(element)));
}
}

View File

@@ -15,11 +15,11 @@
*/
package org.springframework.data.neo4j.lifecycle;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.util.Assert;
import org.springframework.data.auditing.AuditingHandler;
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
import org.springframework.util.Assert;
/**
* Event listener to populate auditing related fields on an entity about to be saved.
@@ -28,14 +28,14 @@ import org.springframework.data.auditing.IsNewAwareAuditingHandler;
*/
public class AuditingEventListener implements ApplicationListener<BeforeSaveEvent<Object>> {
private final IsNewAwareAuditingHandler auditingHandler;
private final ObjectFactory<IsNewAwareAuditingHandler> auditingHandler;
/**
* Creates a new {@link AuditingEventListener} using the given {@link org.springframework.data.mapping.context.MappingContext} and {@link AuditingHandler}.
*
* @param auditingHandler must not be {@literal null}.
*/
public AuditingEventListener(IsNewAwareAuditingHandler auditingHandler) {
public AuditingEventListener(ObjectFactory<IsNewAwareAuditingHandler> auditingHandler) {
Assert.notNull(auditingHandler, "IsNewAwareAuditingHandler must not be null!");
this.auditingHandler = auditingHandler;
@@ -48,6 +48,6 @@ public class AuditingEventListener implements ApplicationListener<BeforeSaveEven
public void onApplicationEvent(BeforeSaveEvent<Object> event) {
Object entity = event.getEntity();
auditingHandler.markAudited(entity);
auditingHandler.getObject().markAudited(entity);
}
}

View File

@@ -141,7 +141,7 @@ class Neo4jPersistentPropertyImpl extends AnnotationBasedPersistentProperty<Neo4
@Override
public void setValue(Object entity, Object newValue) {
BeanWrapper<PersistentEntity<Object,?>,Object> wrapper = BeanWrapper.create(entity, null);
BeanWrapper<Object> wrapper = BeanWrapper.create(entity, null);
wrapper.setProperty(this, newValue);
}
@@ -256,7 +256,7 @@ class Neo4jPersistentPropertyImpl extends AnnotationBasedPersistentProperty<Neo4
@Override
public Object getValueFromEntity(Object entity, final MappingPolicy mappingPolicy) {
BeanWrapper<PersistentEntity<Object,?>, Object> wrapper = BeanWrapper.create(entity, null);
BeanWrapper<Object> wrapper = BeanWrapper.create(entity, null);
return wrapper.getProperty(this);
}

View File

@@ -108,7 +108,7 @@ public class Neo4jEntityConverterImpl<T,S extends PropertyContainer> implements
@Override
public <R extends T> R loadEntity(R entity, S source, MappingPolicy mappingPolicy, Neo4jPersistentEntityImpl<R> persistentEntity, final Neo4jTemplate template) {
if (mappingPolicy.shouldLoad()) {
final BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper = BeanWrapper.<Neo4jPersistentEntity<R>, R>create(entity, conversionService);
final BeanWrapper<R> wrapper = BeanWrapper.create(entity, conversionService);
sourceStateTransmitter.copyPropertiesFrom(wrapper, source, persistentEntity,mappingPolicy, template);
// 6) handle cascading fetches
cascadeFetch(persistentEntity, wrapper, mappingPolicy, template);
@@ -121,7 +121,7 @@ public class Neo4jEntityConverterImpl<T,S extends PropertyContainer> implements
return requestedType.isAssignableFrom(storedType.getType());
}
private <R extends T> void cascadeFetch(Neo4jPersistentEntityImpl<R> persistentEntity, final BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper, final MappingPolicy policy, final Neo4jTemplate template) {
private <R extends T> void cascadeFetch(Neo4jPersistentEntityImpl<R> persistentEntity, final BeanWrapper<R> wrapper, final MappingPolicy policy, final Neo4jTemplate template) {
persistentEntity.doWithAssociations(new AssociationHandler<Neo4jPersistentProperty>() {
@Override
public void doWithAssociation(Association<Neo4jPersistentProperty> association) {
@@ -140,7 +140,7 @@ public class Neo4jEntityConverterImpl<T,S extends PropertyContainer> implements
});
}
private <R> Object getProperty(BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper, Neo4jPersistentProperty property) {
private <R> Object getProperty(BeanWrapper<R> wrapper, Neo4jPersistentProperty property) {
try {
return wrapper.getProperty(property);
} catch (Exception e) {
@@ -158,7 +158,7 @@ public class Neo4jEntityConverterImpl<T,S extends PropertyContainer> implements
return;
}
final BeanWrapper<Neo4jPersistentEntity<T>, T> wrapper = BeanWrapper.<Neo4jPersistentEntity<T>, T>create(source, conversionService);
final BeanWrapper<T> wrapper = BeanWrapper.create(source, conversionService);
if (sink == null) {
sink = entityStateHandler.useOrCreateState(source,sink, annotationProvidedRelationshipType ); // todo handling of changed state
entityStateHandler.setPersistentState(source, sink);

View File

@@ -55,7 +55,7 @@ public class Neo4jEntityFetchHandler {
if (property.getTypeInformation().isCollectionLike()) {
List<Object> replacement = new ArrayList<Object>();
for (Object inner : ((Iterable) value)) {
final BeanWrapper<Neo4jPersistentEntity<Object>, Object> innerWrapper = BeanWrapper.<Neo4jPersistentEntity<Object>, Object>create(inner, conversionService);
final BeanWrapper<Object> innerWrapper = BeanWrapper.create(inner, conversionService);
final PropertyContainer state = entityStateHandler.getPersistentState(inner);
fetchValue(innerWrapper, state, persistentEntity, mappingPolicy, template);
replacement.add(inner);
@@ -63,14 +63,14 @@ public class Neo4jEntityFetchHandler {
}
return replacement;
} else {
final BeanWrapper<Neo4jPersistentEntity<Object>, Object> innerWrapper = BeanWrapper.<Neo4jPersistentEntity<Object>, Object>create(value, conversionService);
final BeanWrapper<Object> innerWrapper = BeanWrapper.create(value, conversionService);
final PropertyContainer state = entityStateHandler.getPersistentState(value);
fetchValue(innerWrapper, state, persistentEntity, mappingPolicy, template);
// sourceStateTransmitter.copyPropertiesFrom(innerWrapper, entityStateHandler.<S>getPersistentState(value), persistentEntity);
}
return value;
}
public void fetchValue(final BeanWrapper<Neo4jPersistentEntity<Object>, Object> wrapper, PropertyContainer source, Neo4jPersistentEntity<Object> persistentEntity, final MappingPolicy mappingPolicy, final Neo4jTemplate template) {
public void fetchValue(final BeanWrapper<Object> wrapper, PropertyContainer source, Neo4jPersistentEntity<Object> persistentEntity, final MappingPolicy mappingPolicy, final Neo4jTemplate template) {
if (persistentEntity.isNodeEntity()) {
nodeStateTransmitter.copyPropertiesFrom(wrapper, (Node) source,persistentEntity, mappingPolicy, template);
}

View File

@@ -44,7 +44,7 @@ public class SourceStateTransmitter<S extends PropertyContainer> {
this.entityStateFactory = entityStateFactory;
}
public <R> R copyPropertiesFrom(final BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper, S source, Neo4jPersistentEntity<R> persistentEntity, final MappingPolicy mappingPolicy, final Neo4jTemplate template) {
public <R> R copyPropertiesFrom(final BeanWrapper<R> wrapper, S source, Neo4jPersistentEntity<R> persistentEntity, final MappingPolicy mappingPolicy, final Neo4jTemplate template) {
final R entity = wrapper.getBean();
final EntityState<S> entityState = entityStateFactory.getEntityState(entity, false, template);
entityState.setPersistentState(source);
@@ -64,13 +64,13 @@ public class SourceStateTransmitter<S extends PropertyContainer> {
return entity;
}
private <R> void setEntityStateValue(Neo4jPersistentProperty property, EntityState<S> entityState, BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper, final MappingPolicy mappingPolicy) {
private <R> void setEntityStateValue(Neo4jPersistentProperty property, EntityState<S> entityState, BeanWrapper<R> wrapper, final MappingPolicy mappingPolicy) {
if (!entityState.isWritable(property)) return;
final Object value = getProperty(wrapper, property);
entityState.setValue(property, value, mappingPolicy);
}
private <R> Object getProperty(BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper, Neo4jPersistentProperty property) {
private <R> Object getProperty(BeanWrapper<R> wrapper, Neo4jPersistentProperty property) {
try {
return wrapper.getProperty(property);
} catch (Exception e) {
@@ -78,7 +78,7 @@ public class SourceStateTransmitter<S extends PropertyContainer> {
}
}
public <R> void setProperty(BeanWrapper<Neo4jPersistentEntity<R>, ?> wrapper, Neo4jPersistentProperty property, Object value) {
public <R> void setProperty(BeanWrapper<?> wrapper, Neo4jPersistentProperty property, Object value) {
try {
wrapper.setProperty(property,value);
} catch (Exception e) {
@@ -86,13 +86,13 @@ public class SourceStateTransmitter<S extends PropertyContainer> {
}
}
private <R> Object copyEntityStatePropertyValue(Neo4jPersistentProperty property, EntityState<S> nodeState, BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper, final MappingPolicy mappingPolicy) {
private <R> Object copyEntityStatePropertyValue(Neo4jPersistentProperty property, EntityState<S> nodeState, BeanWrapper<R> wrapper, final MappingPolicy mappingPolicy) {
final Object value = DoReturn.unwrap(nodeState.getValue(property, mappingPolicy));
setProperty(wrapper, property, value);
return value;
}
public <R> void copyPropertiesTo(final BeanWrapper<Neo4jPersistentEntity<R>, R> wrapper, S target, Neo4jPersistentEntity<R> persistentEntity, MappingPolicy mappingPolicy, final Neo4jTemplate template) {
public <R> void copyPropertiesTo(final BeanWrapper<R> wrapper, S target, Neo4jPersistentEntity<R> persistentEntity, MappingPolicy mappingPolicy, final Neo4jTemplate template) {
final Transaction tx = template.getGraphDatabase().beginTx();
try {
final EntityState<S> entityState = entityStateFactory.getEntityState(wrapper.getBean(), false, template);

View File

@@ -15,66 +15,69 @@
*/
package org.springframework.data.neo4j.config;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.joda.time.DateTime;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.neo4j.annotation.GraphId;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.data.neo4j.lifecycle.BeforeSaveEvent;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;
@Ignore
/**
* Integration tests for Neo4j auditing.
*
* @author Michael Hunger
* @author Oliver Gierke
*/
public class AuditingIntegrationTests {
/**
* @see DATAGRAPH-328
*/
@Test
public void enablesAuditingAndSetsPropertiesAccordingly() throws InterruptedException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("auditing.xml", getClass());
runTest(context);
context.close();
runTest(new ClassPathXmlApplicationContext("auditing.xml", getClass())).close();
}
/**
* @see DATAGRAPH-328
*/
@Test
public void enablesAuditingWithBeanConfigAndSetsPropertiesAccordingly() throws InterruptedException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("auditing-bean.xml", getClass());
runTest(context);
context.close();
runTest(new ClassPathXmlApplicationContext("auditing-bean.xml", getClass())).close();
}
private void runTest(ApplicationContext context) throws InterruptedException {
Entity entity = new Entity();
BeforeSaveEvent<Entity> event = new BeforeSaveEvent<Entity>(this,entity);
context.publishEvent(event);
private <T extends ApplicationEventPublisher> T runTest(T context) throws InterruptedException {
assertThat(entity.created, is(notNullValue()));
assertThat(entity.modified, is(entity.created));
Thread.sleep(10);
entity.id = 1L;
event = new BeforeSaveEvent<Entity>(this,entity);
context.publishEvent(event);
Entity entity = new Entity();
BeforeSaveEvent<Entity> event = new BeforeSaveEvent<Entity>(this, entity);
context.publishEvent(event);
assertThat(entity.created, is(notNullValue()));
assertThat(entity.modified, is(not(entity.created)));
}
assertThat(entity.created, is(notNullValue()));
assertThat(entity.modified, is(entity.created));
Thread.sleep(10);
entity.id = 1L;
event = new BeforeSaveEvent<Entity>(this, entity);
context.publishEvent(event);
@NodeEntity
class Entity {
assertThat(entity.created, is(notNullValue()));
assertThat(entity.modified, is(not(entity.created)));
@CreatedDate
DateTime created;
return context;
}
@LastModifiedDate
DateTime modified;
@NodeEntity
public static class Entity {
@GraphId
Long id;
@GraphId Long id;
@CreatedDate DateTime created;
@LastModifiedDate DateTime modified;
}
}

View File

@@ -15,17 +15,16 @@
*/
package org.springframework.data.neo4j.lifecycle;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
import org.springframework.data.mapping.context.MappingContextIsNewStrategyFactory;
import org.springframework.data.neo4j.annotation.GraphId;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.data.neo4j.support.mapping.Neo4jMappingContext;
@@ -47,14 +46,14 @@ public class AuditingEventListenerUnitTests {
@Before
public void setUp() {
Neo4jMappingContext mappingContext = new Neo4jMappingContext();
factory = new MappingContextIsNewStrategyFactory(mappingContext);
handler = spy(new IsNewAwareAuditingHandler(new Neo4jMappingContext()));
listener = new AuditingEventListener(new ObjectFactory<IsNewAwareAuditingHandler>() {
handler = spy(new IsNewAwareAuditingHandler(factory));
doNothing().when(handler).markCreated(Mockito.any(Object.class));
doNothing().when(handler).markModified(Mockito.any(Object.class));
listener = new AuditingEventListener(handler);
@Override
public IsNewAwareAuditingHandler getObject() throws BeansException {
return handler;
}
});
}
@Test(expected = IllegalArgumentException.class)
@@ -66,7 +65,7 @@ public class AuditingEventListenerUnitTests {
public void triggersCreationMarkForObjectWithEmptyId() {
Sample sample = new Sample();
listener.onApplicationEvent(new BeforeSaveEvent<Object>(this,sample));
listener.onApplicationEvent(new BeforeSaveEvent<Object>(this, sample));
verify(handler, times(1)).markCreated(sample);
verify(handler, times(0)).markModified(any(Sample.class));
@@ -77,16 +76,15 @@ public class AuditingEventListenerUnitTests {
Sample sample = new Sample();
sample.id = "id";
listener.onApplicationEvent(new BeforeSaveEvent<Object>(this,sample));
listener.onApplicationEvent(new BeforeSaveEvent<Object>(this, sample));
verify(handler, times(0)).markCreated(any(Sample.class));
verify(handler, times(1)).markModified(sample);
}
@NodeEntity
@NodeEntity
static class Sample {
@GraphId
String id;
@GraphId String id;
}
}

View File

@@ -1,19 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:neo4j="http://www.springframework.org/schema/data/neo4j"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:neo4j="http://www.springframework.org/schema/data/neo4j"
xsi:schemaLocation="http://www.springframework.org/schema/data/neo4j http://www.springframework.org/schema/data/neo4j/spring-neo4j-2.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<neo4j:config graphDatabaseService="graphDatabaseService" base-package="org.springframework.data.neo4j.config"/>
<neo4j:config graphDatabaseService="graphDatabaseService"
base-package="org.springframework.data.neo4j.config" />
<bean class="org.springframework.data.neo4j.lifecycle.AuditingEventListener" autowire="constructor" />
<bean id="auditingHandler" class="org.springframework.data.auditing.IsNewAwareAuditingHandler">
<constructor-arg ref="neo4jMappingContext" />
</bean>
<bean id="graphDatabaseService" class="org.neo4j.test.ImpermanentGraphDatabase"
destroy-method="shutdown" />
<bean class="org.springframework.data.neo4j.lifecycle.AuditingEventListener">
<constructor-arg>
<bean class="org.springframework.data.auditing.IsNewAwareAuditingHandler">
<constructor-arg ref="isNewStrategyFactory"/>
</bean>
</constructor-arg>
</bean>
<bean id="graphDatabaseService" class="org.neo4j.test.ImpermanentGraphDatabase" destroy-method="shutdown"/>
</beans>

View File

@@ -5,7 +5,7 @@
xsi:schemaLocation="http://www.springframework.org/schema/data/neo4j http://www.springframework.org/schema/data/neo4j/spring-neo4j-2.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<neo4j:config graphDatabaseService="graphDatabaseService" base-package="org.springframework.data.neo4j.config.model" />
<neo4j:config graphDatabaseService="graphDatabaseService" base-package="org.springframework.data.neo4j.config" />
<neo4j:auditing />