DATAGRAPH-241 - base-package for entities, fix for alias lookup of loaded but not registered entities
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/data/neo4j
|
||||
http://www.springframework.org/schema/data/neo4j/spring-neo4j-2.0.xsd
|
||||
http://www.springframework.org/schema/data/neo4j/spring-neo4j-2.0.xsd
|
||||
http://www.springframework.org/schema/tx
|
||||
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
|
||||
|
||||
|
||||
@@ -16,23 +16,30 @@
|
||||
|
||||
package org.springframework.data.neo4j.config;
|
||||
|
||||
import antlr.StringUtils;
|
||||
import org.neo4j.kernel.EmbeddedGraphDatabase;
|
||||
import org.springframework.beans.factory.annotation.Autowire;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.*;
|
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.data.annotation.Persistent;
|
||||
import org.springframework.data.neo4j.annotation.NodeEntity;
|
||||
import org.springframework.data.neo4j.annotation.RelationshipEntity;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static org.springframework.util.StringUtils.hasText;
|
||||
|
||||
public class DataGraphBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
||||
|
||||
private static final String GRAPH_DATABASE_SERVICE = "graphDatabaseService";
|
||||
private static final String BASE_PACKAGE = "base-package";
|
||||
public static final String ASPECTJ_CONFIG = "org.springframework.data.neo4j.aspects.config.Neo4jAspectConfiguration";
|
||||
public static final String CROSS_STORE_CONFIG = "org.springframework.data.neo4j.cross_store.config.CrossStoreNeo4jConfiguration";
|
||||
|
||||
@@ -41,10 +48,40 @@ public class DataGraphBeanDefinitionParser extends AbstractBeanDefinitionParser
|
||||
BeanDefinitionBuilder configBuilder = createConfigurationBeanDefinition(element);
|
||||
setupGraphDatabase(element, context, configBuilder);
|
||||
setupEntityManagerFactory(element, configBuilder);
|
||||
setupBaseEntities(element, configBuilder);
|
||||
setupConfigurationClassPostProcessor(context);
|
||||
return getSourcedBeanDefinition(configBuilder, element, context);
|
||||
}
|
||||
|
||||
private void setupBaseEntities(Element element, BeanDefinitionBuilder configBuilder) {
|
||||
Set<String> initialEntityClasses = getInitialEntityClasses(element);
|
||||
if (initialEntityClasses!=null) {
|
||||
configBuilder.addPropertyValue("initialEntitySet", initialEntityClasses);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Set<String> getInitialEntityClasses(Element element) {
|
||||
|
||||
String basePackage = element.getAttribute(BASE_PACKAGE);
|
||||
|
||||
if (!hasText(basePackage)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(false);
|
||||
componentProvider.addIncludeFilter(new AnnotationTypeFilter(NodeEntity.class));
|
||||
componentProvider.addIncludeFilter(new AnnotationTypeFilter(RelationshipEntity.class));
|
||||
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Persistent.class));
|
||||
|
||||
Set<String> classes = new ManagedSet<String>();
|
||||
for (BeanDefinition candidate : componentProvider.findCandidateComponents(basePackage)) {
|
||||
classes.add(candidate.getBeanClassName());
|
||||
}
|
||||
|
||||
return classes;
|
||||
}
|
||||
|
||||
|
||||
private BeanDefinitionBuilder createConfigurationBeanDefinition(Element element) {
|
||||
BeanDefinitionBuilder configBuilder = createConfigBuilderByMode(element);
|
||||
|
||||
@@ -65,6 +65,9 @@ import org.springframework.transaction.jta.UserTransactionAdapter;
|
||||
import javax.transaction.TransactionManager;
|
||||
import javax.validation.Validator;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
/**
|
||||
@@ -79,6 +82,8 @@ public abstract class Neo4jConfiguration {
|
||||
|
||||
private ConversionService conversionService;
|
||||
|
||||
private Set<? extends Class<?>> initialEntitySet;
|
||||
|
||||
@Autowired(required = false)
|
||||
private Validator validator;
|
||||
|
||||
@@ -197,6 +202,9 @@ public abstract class Neo4jConfiguration {
|
||||
@Bean
|
||||
public Neo4jMappingContext neo4jMappingContext() throws Exception {
|
||||
final Neo4jMappingContext mappingContext = new Neo4jMappingContext();
|
||||
if (initialEntitySet!=null) {
|
||||
mappingContext.setInitialEntitySet(initialEntitySet);
|
||||
}
|
||||
mappingContext.setEntityAlias(entityAlias());
|
||||
return mappingContext;
|
||||
}
|
||||
@@ -275,4 +283,11 @@ public abstract class Neo4jConfiguration {
|
||||
return new IndexProviderImpl(neo4jMappingContext(), graphDatabase());
|
||||
}
|
||||
|
||||
public Set<? extends Class<?>> getInitialEntitySet() {
|
||||
return initialEntitySet;
|
||||
}
|
||||
|
||||
public void setInitialEntitySet(Set<? extends Class<?>> initialEntitySet) {
|
||||
this.initialEntitySet = initialEntitySet;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.neo4j.support.mapping;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
import org.springframework.data.mapping.event.MappingContextEvent;
|
||||
@@ -23,13 +24,17 @@ import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
|
||||
import org.springframework.data.neo4j.support.Neo4jTemplate;
|
||||
import org.springframework.data.neo4j.support.index.IndexType;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 12.04.12
|
||||
*/
|
||||
public class IndexCreationMappingEventListener implements ApplicationListener<MappingContextEvent<Neo4jPersistentEntity<?>, Neo4jPersistentProperty>> {
|
||||
public class IndexCreationMappingEventListener implements ApplicationListener<MappingContextEvent<Neo4jPersistentEntity<?>, Neo4jPersistentProperty>>, InitializingBean {
|
||||
private Neo4jTemplate template;
|
||||
|
||||
private Queue<Neo4jPersistentEntity> initialEntities=new ConcurrentLinkedQueue<Neo4jPersistentEntity>();
|
||||
private boolean isInitialized=false;
|
||||
public IndexCreationMappingEventListener(Neo4jTemplate template) {
|
||||
this.template = template;
|
||||
}
|
||||
@@ -37,8 +42,16 @@ public class IndexCreationMappingEventListener implements ApplicationListener<Ma
|
||||
@Override
|
||||
public void onApplicationEvent(MappingContextEvent<Neo4jPersistentEntity<?>, Neo4jPersistentProperty> event) {
|
||||
if (!(event.getSource() instanceof Neo4jPersistentEntity)) return;
|
||||
|
||||
final Neo4jPersistentEntity entity = event.getPersistentEntity();
|
||||
if (!isInitialized) {
|
||||
initialEntities.add(entity);
|
||||
}
|
||||
else {
|
||||
ensureEntityIndexes(entity);
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureEntityIndexes(Neo4jPersistentEntity entity) {
|
||||
final Class entityType = entity.getType();
|
||||
template.getIndex(entityType, null, IndexType.SIMPLE);
|
||||
entity.doWithProperties(new PropertyHandler<Neo4jPersistentProperty>() {
|
||||
@@ -50,4 +63,13 @@ public class IndexCreationMappingEventListener implements ApplicationListener<Ma
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
isInitialized = true;
|
||||
for (Neo4jPersistentEntity entity : initialEntities) {
|
||||
ensureEntityIndexes(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.data.neo4j.support.mapping;
|
||||
import org.neo4j.graphdb.PropertyContainer;
|
||||
import org.springframework.data.mapping.context.AbstractMappingContext;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.neo4j.annotation.NodeEntity;
|
||||
import org.springframework.data.neo4j.annotation.RelationshipEntity;
|
||||
@@ -93,6 +94,36 @@ public class Neo4jMappingContext extends AbstractMappingContext<Neo4jPersistentE
|
||||
for (Neo4jPersistentEntityImpl<?> entity : getPersistentEntities()) {
|
||||
if (entity.matchesAlias(alias)) return entity;
|
||||
}
|
||||
return tryToResolveAliasAsEntityClassName(alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
try {
|
||||
super.afterPropertiesSet();
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private Neo4jPersistentEntity<?> tryToResolveAliasAsEntityClassName(Object alias) {
|
||||
if (alias instanceof Class) {
|
||||
try {
|
||||
return getPersistentEntity((Class)alias);
|
||||
} catch(MappingException me) {
|
||||
// ignores
|
||||
}
|
||||
}
|
||||
if (alias instanceof String && alias.toString().contains(".")) {
|
||||
try {
|
||||
return tryToResolveAliasAsEntityClassName(Class.forName(alias.toString()));
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
if (alias instanceof StoredEntityType) {
|
||||
return ((StoredEntityType)alias).getEntity();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,29 @@
|
||||
<xsd:complexType>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="beans:identifiedType">
|
||||
<xsd:attribute name="storeDirectory" type="xsd:string" />
|
||||
<xsd:attribute name="storeDirectory" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
default store-directory of the Neo4j database
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
|
||||
<xsd:attribute name="graphDatabaseService" type="graphDatabaseServiceRef" />
|
||||
<xsd:attribute name="entityManagerFactory" type="xsd:string" />
|
||||
<xsd:attribute name="base-package" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
base package for persistent entities.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="entityManagerFactory" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
entity manager factory bean reference for cross-store configuration
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
@@ -31,13 +31,17 @@ import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.GenericConverter;
|
||||
import org.springframework.data.neo4j.model.PersonRepository;
|
||||
import org.springframework.data.neo4j.support.Neo4jTemplate;
|
||||
import org.springframework.data.neo4j.support.mapping.Neo4jMappingContext;
|
||||
import org.springframework.data.neo4j.support.mapping.Neo4jPersistentEntityImpl;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
@@ -53,6 +57,8 @@ public class DataGraphNamespaceHandlerTest {
|
||||
Neo4jTemplate neo4jTemplate;
|
||||
@Autowired
|
||||
PlatformTransactionManager transactionManager;
|
||||
@Autowired
|
||||
Neo4jMappingContext mappingContext;
|
||||
@Autowired(required = false)
|
||||
PersonRepository personRepository;
|
||||
}
|
||||
@@ -96,6 +102,13 @@ public class DataGraphNamespaceHandlerTest {
|
||||
assertInjected("-code");
|
||||
}
|
||||
@Test
|
||||
public void injectionForBasePackageOfEntities() {
|
||||
Config config = assertInjected("-entities");
|
||||
Collection<Neo4jPersistentEntityImpl<?>> entities = config.mappingContext.getPersistentEntities();
|
||||
System.out.println(entities);
|
||||
assertTrue(entities.size() > 0);
|
||||
}
|
||||
@Test
|
||||
public void injectionForConversionService() {
|
||||
final Config config = assertInjected("-conversion");
|
||||
final ConversionService conversionService = config.neo4jTemplate.getConversionService();
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.data.neo4j.model;
|
||||
|
||||
import org.springframework.data.neo4j.annotation.GraphId;
|
||||
import org.springframework.data.neo4j.annotation.Indexed;
|
||||
import org.springframework.data.neo4j.annotation.NodeEntity;
|
||||
|
||||
@@ -25,6 +26,8 @@ import org.springframework.data.neo4j.annotation.NodeEntity;
|
||||
*/
|
||||
@NodeEntity
|
||||
public class Attribute<T> {
|
||||
private @GraphId Long id;
|
||||
|
||||
@Indexed
|
||||
T value;
|
||||
|
||||
|
||||
@@ -21,8 +21,9 @@ import org.springframework.data.neo4j.annotation.GraphId;
|
||||
import org.springframework.data.neo4j.annotation.NodeEntity;
|
||||
|
||||
@NodeEntity
|
||||
public abstract class Car {
|
||||
public class Car {
|
||||
@GraphId
|
||||
public
|
||||
Long id;
|
||||
public Car() {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.neo4j.repository;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.neo4j.graphdb.NotFoundException;
|
||||
import org.neo4j.graphdb.Transaction;
|
||||
import org.neo4j.kernel.impl.util.FileUtils;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.dao.DataRetrievalFailureException;
|
||||
import org.springframework.data.neo4j.model.Car;
|
||||
import org.springframework.data.neo4j.model.Volvo;
|
||||
import org.springframework.data.neo4j.support.Neo4jTemplate;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@Ignore
|
||||
public class ReadWriteTest {
|
||||
public static void main(String[] args) throws IOException {
|
||||
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:ReadWriteTest-context.xml");
|
||||
boolean delete = false;
|
||||
try {
|
||||
Neo4jTemplate template = ctx.getBean(Neo4jTemplate.class);
|
||||
Car car = findOne(template);
|
||||
if (car != null) {
|
||||
delete = true;
|
||||
assertEquals(Volvo.class, car.getClass());
|
||||
} else {
|
||||
Transaction tx = template.beginTx();
|
||||
Volvo volvo = template.save(new Volvo());
|
||||
assertEquals(1, volvo.id.intValue());
|
||||
tx.success();
|
||||
tx.finish();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
delete = true;
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
ctx.close();
|
||||
if (delete) {
|
||||
FileUtils.deleteRecursively(new File("target/read-write.db"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Car findOne(Neo4jTemplate template) {
|
||||
try {
|
||||
return template.findOne(1, Car.class);
|
||||
} catch (DataRetrievalFailureException nfe) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
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/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
|
||||
http://www.springframework.org/schema/data/neo4j http://www.springframework.org/schema/data/neo4j/spring-neo4j-2.0.xsd">
|
||||
<context:annotation-config/>
|
||||
<neo4j:config storeDirectory="target/read-write.db"/>
|
||||
<neo4j:repositories base-package="org.springframework.data.neo4j.repository"/>
|
||||
</beans>
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
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/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
|
||||
http://www.springframework.org/schema/data/neo4j http://www.springframework.org/schema/data/neo4j/spring-neo4j-2.0.xsd">
|
||||
|
||||
<context:annotation-config/>
|
||||
<neo4j:config storeDirectory="target/config-test" base-package="org.springframework.data.neo4j.model"/>
|
||||
<bean id="config" class="org.springframework.data.neo4j.config.DataGraphNamespaceHandlerTest$Config"/>
|
||||
|
||||
<neo4j:repositories base-package="org.springframework.data.neo4j.model"/>
|
||||
</beans>
|
||||
Reference in New Issue
Block a user