From f451050a15f81757ef83a468b45dd4a38c1fc46e Mon Sep 17 00:00:00 2001 From: Matthew Adams Date: Mon, 10 Feb 2014 18:02:47 -0600 Subject: [PATCH 01/13] DATACASS-91 - ready to test multiple base package entity scanning --- .../config/xml/DefaultBeanNames.java | 6 +- ...NamespaceCreatingXmlConfigTest-context.xml | 91 +++++++-------- .../config/xml/XmlConfigTest-context.xml | 15 ++- ...ataCassandraMappingContextFactoryBean.java | 46 ++++++++ ...sandraDataMappingConverterFactoryBean.java | 49 ++++++++ .../config/CassandraEntityClassScanner.java | 110 ++++++++++++++++++ .../config/DefaultDataBeanNames.java | 5 +- ...tractSpringDataCassandraConfiguration.java | 55 +++------ ...ndraDataCassandraMappingContextParser.java | 52 +++++++++ ...raDataMappingCassandraConverterParser.java | 62 ++++++++++ .../xml/CassandraDataNamespaceHandler.java | 2 + .../xml/CassandraDataSessionParser.java | 9 ++ .../DefaultCassandraMappingContext.java | 16 +++ ...andraRepositoryConfigurationExtension.java | 3 +- ...andra-1.0-trying-to-use-xml-extension.xsd} | 0 .../cassandra/config/spring-cassandra-1.0.xsd | 68 ++++++++++- ...tRepositoryJavaConfigIntegrationTests.java | 4 +- ...rRepositoryJavaConfigIntegrationTests.java | 4 +- .../template/CassandraDataOperationsTest.java | 13 +-- ...itoryXmlConfigIntegrationTests-context.xml | 11 +- .../CassandraNamespaceTests-context.xml | 25 ++-- ...itoryXmlConfigIntegrationTests-context.xml | 12 +- .../resources/spring-data-cassandra-basic.xml | 11 +- 23 files changed, 509 insertions(+), 160 deletions(-) create mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataCassandraMappingContextFactoryBean.java create mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataMappingConverterFactoryBean.java create mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraEntityClassScanner.java create mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataCassandraMappingContextParser.java create mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataMappingCassandraConverterParser.java rename spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/{ext-spring-cassandra-1.0.xsd => spring-cassandra-1.0-trying-to-use-xml-extension.xsd} (100%) diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/DefaultBeanNames.java b/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/DefaultBeanNames.java index c50dc5316..89b34678b 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/DefaultBeanNames.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/DefaultBeanNames.java @@ -22,7 +22,7 @@ package org.springframework.cassandra.config.xml; */ public interface DefaultBeanNames { - public static final String CLUSTER = "cassandra-cluster"; - public static final String SESSION = "cassandra-session"; - public static final String TEMPLATE = "cql-template"; + public static final String CLUSTER = "cassandraCluster"; + public static final String SESSION = "cassandraSession"; + public static final String TEMPLATE = "cqlTemplate"; } diff --git a/spring-cassandra/src/test/resources/org/springframework/cassandra/test/integration/config/xml/PropertyPlaceholderNamespaceCreatingXmlConfigTest-context.xml b/spring-cassandra/src/test/resources/org/springframework/cassandra/test/integration/config/xml/PropertyPlaceholderNamespaceCreatingXmlConfigTest-context.xml index 906a2a32f..8259eb66c 100644 --- a/spring-cassandra/src/test/resources/org/springframework/cassandra/test/integration/config/xml/PropertyPlaceholderNamespaceCreatingXmlConfigTest-context.xml +++ b/spring-cassandra/src/test/resources/org/springframework/cassandra/test/integration/config/xml/PropertyPlaceholderNamespaceCreatingXmlConfigTest-context.xml @@ -10,69 +10,66 @@ location="classpath:/org/springframework/cassandra/test/integration/config/xml/ppncxct.properties" /> - - + + - + - - - + + + - - - - - + - + + + + - + - + - - - + max-simultaneous-requests="${remote.max.requests}" core-connections="${remote.core.connections}" + max-connections="${remote.max.connections}" /> + + + - - + + - - + - + diff --git a/spring-cassandra/src/test/resources/org/springframework/cassandra/test/integration/config/xml/XmlConfigTest-context.xml b/spring-cassandra/src/test/resources/org/springframework/cassandra/test/integration/config/xml/XmlConfigTest-context.xml index 7f63c803a..c779fde4b 100644 --- a/spring-cassandra/src/test/resources/org/springframework/cassandra/test/integration/config/xml/XmlConfigTest-context.xml +++ b/spring-cassandra/src/test/resources/org/springframework/cassandra/test/integration/config/xml/XmlConfigTest-context.xml @@ -9,8 +9,8 @@ - + @@ -18,16 +18,15 @@ min-simultaneous-requests="25" max-simultaneous-requests="100" core-connections="1" max-connections="2" /> + connect-timeout-millis="5000" keep-alive="true" read-timeout-millis="60000" + reuse-address="true" so-linger="60" tcp-no-delay="true" + receive-buffer-size="65536" send-buffer-size="65536" /> - + - + diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataCassandraMappingContextFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataCassandraMappingContextFactoryBean.java new file mode 100644 index 000000000..3a087a06c --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataCassandraMappingContextFactoryBean.java @@ -0,0 +1,46 @@ +package org.springframework.data.cassandra.config; + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.data.cassandra.mapping.CassandraMappingContext; +import org.springframework.data.cassandra.mapping.DefaultCassandraMappingContext; + +public class CassandraDataCassandraMappingContextFactoryBean implements FactoryBean, + InitializingBean { + + protected Set basePackages = new HashSet(); + + @Override + public void afterPropertiesSet() throws Exception { + } + + @Override + public CassandraMappingContext getObject() throws Exception { + + DefaultCassandraMappingContext cmc = new DefaultCassandraMappingContext(); + cmc.setInitialEntitySet(new CassandraEntityClassScanner(basePackages).scanForEntityClasses()); + + return cmc; + } + + @Override + public Class getObjectType() { + return CassandraMappingContext.class; + } + + @Override + public boolean isSingleton() { + return true; + } + + public Set getBasePackages() { + return basePackages; + } + + public void setBasePackages(Set basePackages) { + this.basePackages = basePackages; + } +} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataMappingConverterFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataMappingConverterFactoryBean.java new file mode 100644 index 000000000..48fba014a --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataMappingConverterFactoryBean.java @@ -0,0 +1,49 @@ +package org.springframework.data.cassandra.config; + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.data.cassandra.convert.CassandraConverter; +import org.springframework.data.cassandra.convert.MappingCassandraConverter; +import org.springframework.data.cassandra.mapping.CassandraMappingContext; +import org.springframework.util.Assert; + +public class CassandraDataMappingConverterFactoryBean implements FactoryBean, InitializingBean { + + protected CassandraMappingContext mappingContext; + protected Set basePackages = new HashSet(); + + @Override + public void afterPropertiesSet() throws Exception { + Assert.notNull(mappingContext); + Assert.notNull(basePackages); + } + + @Override + public CassandraConverter getObject() throws Exception { + return new MappingCassandraConverter(mappingContext); + } + + @Override + public Class getObjectType() { + return CassandraConverter.class; + } + + @Override + public boolean isSingleton() { + return true; + } + + public CassandraMappingContext getMappingContext() { + return mappingContext; + } + + public void setMappingContext(CassandraMappingContext mappingContext) { + + Assert.notNull(mappingContext); + + this.mappingContext = mappingContext; + } +} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraEntityClassScanner.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraEntityClassScanner.java new file mode 100644 index 000000000..aeef0a590 --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraEntityClassScanner.java @@ -0,0 +1,110 @@ +package org.springframework.data.cassandra.config; + +import java.lang.annotation.Annotation; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.data.annotation.Persistent; +import org.springframework.data.cassandra.mapping.PrimaryKeyClass; +import org.springframework.data.cassandra.mapping.Table; +import org.springframework.util.ClassUtils; +import org.springframework.util.StringUtils; + +/** + * Scans packages for Cassandra entities. + * + * @author Matthew T. Adams + */ +public class CassandraEntityClassScanner { + + protected Set entityBasePackages = new HashSet(); + protected Set> entityBasePackageClasses = new HashSet>(); + protected ClassLoader beanClassLoader; + + public CassandraEntityClassScanner() { + } + + public CassandraEntityClassScanner(Collection entityBasePackages) { + this(entityBasePackages, null); + } + + public CassandraEntityClassScanner(Collection entityBasePackages, + Collection> entityBasePackageClasses) { + + setEntityBasePackages(entityBasePackages); + setEntityBasePackageClasses(entityBasePackageClasses); + } + + public Set getEntityBasePackages() { + return Collections.unmodifiableSet(entityBasePackages); + } + + public void setEntityBasePackages(Collection entityBasePackages) { + this.entityBasePackages = entityBasePackages == null ? new HashSet() : new HashSet( + entityBasePackages); + } + + public Set> getEntityBasePackageClasses() { + return Collections.unmodifiableSet(entityBasePackageClasses); + } + + public void setEntityBasePackageClasses(Collection> entityBasePackageClasses) { + this.entityBasePackageClasses = entityBasePackageClasses == null ? new HashSet>() : new HashSet>( + entityBasePackageClasses); + } + + public void setBeanClassLoader(ClassLoader beanClassLoader) { + this.beanClassLoader = beanClassLoader; + } + + /** + * Scans the mapping base package for entity classes annotated with {@link Table} or {@link Persistent}. + * + * @see #getEntityBasePackages() + * @return Set<Class<?>> representing the annotated entity classes found. + * @throws ClassNotFoundException + */ + public Set> scanForEntityClasses() throws ClassNotFoundException { + + Set> classes = new HashSet>(); + + for (String basePackage : getEntityBasePackages()) { + classes.addAll(scanBasePackageForEntities(basePackage)); + } + + for (Class basePackageClass : getEntityBasePackageClasses()) { + classes.addAll(scanBasePackageForEntities(basePackageClass.getPackage().getName())); + } + + return classes; + } + + protected Set> scanBasePackageForEntities(String basePackage) throws ClassNotFoundException { + + HashSet> classes = new HashSet>(); + + if (StringUtils.hasText(basePackage)) { + ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider( + false); + for (Class annoClass : getEntityAnnotations()) { + componentProvider.addIncludeFilter(new AnnotationTypeFilter(annoClass)); + } + + for (BeanDefinition candidate : componentProvider.findCandidateComponents(basePackage)) { + classes.add(ClassUtils.forName(candidate.getBeanClassName(), beanClassLoader)); + } + } + + return classes; + } + + @SuppressWarnings("unchecked") + public Class[] getEntityAnnotations() { + return new Class[] { Table.class, Persistent.class, PrimaryKeyClass.class }; + } +} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/DefaultDataBeanNames.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/DefaultDataBeanNames.java index 43e4ded92..4443e54d6 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/DefaultDataBeanNames.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/DefaultDataBeanNames.java @@ -4,6 +4,7 @@ import org.springframework.cassandra.config.xml.DefaultBeanNames; public interface DefaultDataBeanNames extends DefaultBeanNames { - public static final String DATA_TEMPLATE = "cassandra-template"; - public static final String CONVERTER = "cassandra-converter"; + public static final String DATA_TEMPLATE = "cassandraTemplate"; + public static final String CONVERTER = "cassandraConverter"; + public static final String MAPPING_CONTEXT = "cassandra-mapping"; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/java/AbstractSpringDataCassandraConfiguration.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/java/AbstractSpringDataCassandraConfiguration.java index 736aa0922..a86e13b5c 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/java/AbstractSpringDataCassandraConfiguration.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/java/AbstractSpringDataCassandraConfiguration.java @@ -15,18 +15,15 @@ */ package org.springframework.data.cassandra.config.java; -import java.util.HashSet; +import java.util.Arrays; import java.util.Set; import org.springframework.beans.factory.BeanClassLoaderAware; -import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.cassandra.config.java.AbstractClusterConfiguration; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.context.annotation.Configuration; -import org.springframework.core.type.filter.AnnotationTypeFilter; -import org.springframework.data.annotation.Persistent; import org.springframework.data.cassandra.config.CassandraDataSessionFactoryBean; +import org.springframework.data.cassandra.config.CassandraEntityClassScanner; import org.springframework.data.cassandra.config.SchemaAction; import org.springframework.data.cassandra.convert.CassandraConverter; import org.springframework.data.cassandra.convert.MappingCassandraConverter; @@ -35,11 +32,8 @@ import org.springframework.data.cassandra.core.CassandraAdminTemplate; import org.springframework.data.cassandra.mapping.CassandraMappingContext; import org.springframework.data.cassandra.mapping.DefaultCassandraMappingContext; import org.springframework.data.cassandra.mapping.Mapping; -import org.springframework.data.cassandra.mapping.PrimaryKeyClass; import org.springframework.data.cassandra.mapping.Table; import org.springframework.data.mapping.context.MappingContext; -import org.springframework.util.ClassUtils; -import org.springframework.util.StringUtils; /** * Base class for Spring Data Cassandra configuration using JavaConfig. @@ -64,11 +58,11 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC } /** - * The base package to scan for entities annotated with {@link Table} annotations. By default, returns the package - * name of {@literal this} (this.getClass().getPackage().getName()). + * The base packages to scan for entities annotated with {@link Table} annotations. By default, returns the package + * name of {@literal this} (this.getClass().getPackage().getName()). This method must never return null. */ - public String getEntityBasePackage() { - return getClass().getPackage().getName(); + public String[] getMappingBasePackages() { + return new String[] { getClass().getPackage().getName() }; } @Bean @@ -118,46 +112,27 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC */ @Bean public CassandraConverter converter() throws ClassNotFoundException { - MappingCassandraConverter converter = new MappingCassandraConverter(cassandraMappingContext()); - converter.setBeanClassLoader(beanClassLoader); - return converter; + return new MappingCassandraConverter(cassandraMappingContext()); } /** - * Scans the mapping base package for entity classes annotated with {@link Table} or {@link Persistent}. + * Scans the mapping base package for entity classes. * - * @see #getEntityBasePackage() + * @see #getMappingBasePackages() + * @see #getEntityScanner() * @return Set<Class<?>> representing the annotated entity classes found. * @throws ClassNotFoundException */ protected Set> getInitialEntitySet() throws ClassNotFoundException { - String basePackage = getEntityBasePackage(); - Set> initialEntitySet = new HashSet>(); + CassandraEntityClassScanner entityScanner = getEntityScanner(); + entityScanner.setEntityBasePackages(Arrays.asList(getMappingBasePackages())); - if (StringUtils.hasText(basePackage)) { - ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider( - false); - componentProvider.addIncludeFilter(new AnnotationTypeFilter(Table.class)); - componentProvider.addIncludeFilter(new AnnotationTypeFilter(Persistent.class)); - componentProvider.addIncludeFilter(new AnnotationTypeFilter(PrimaryKeyClass.class)); - - for (BeanDefinition candidate : componentProvider.findCandidateComponents(basePackage)) { - - Class clazz = ClassUtils.forName(candidate.getBeanClassName(), beanClassLoader); - initialEntitySet.add(clazz); - } - } - - processMappingOverrides(initialEntitySet); - - return initialEntitySet; + return entityScanner.scanForEntityClasses(); } - protected void processMappingOverrides(Set> entityTypes) { - - // TODO: search for external entity mapping info (xml/properties/yaml/etc) here & update this.mapping - // similar to JPA's or JDO's external metadata search algorithms + public CassandraEntityClassScanner getEntityScanner() { + return new CassandraEntityClassScanner(); } @Override diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataCassandraMappingContextParser.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataCassandraMappingContextParser.java new file mode 100644 index 000000000..fe696044c --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataCassandraMappingContextParser.java @@ -0,0 +1,52 @@ +package org.springframework.data.cassandra.config.xml; + +import java.util.Set; + +import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.data.cassandra.config.CassandraDataCassandraMappingContextFactoryBean; +import org.springframework.data.cassandra.config.DefaultDataBeanNames; +import org.springframework.util.StringUtils; +import org.w3c.dom.Element; + +/** + * Spring Data Cassandra XML namespace parser for the <mapping-context> element. + * + * @author Matthew T. Adams + */ +public class CassandraDataCassandraMappingContextParser extends AbstractSimpleBeanDefinitionParser { + + @Override + protected Class getBeanClass(Element element) { + return CassandraDataCassandraMappingContextFactoryBean.class; + } + + @Override + protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) + throws BeanDefinitionStoreException { + + String id = super.resolveId(element, definition, parserContext); + return StringUtils.hasText(id) ? id : DefaultDataBeanNames.MAPPING_CONTEXT; + } + + @Override + protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + super.doParse(element, parserContext, builder); + + parseBasePackagesAttribute(element, parserContext, builder); + } + + protected void parseBasePackagesAttribute(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + + String basePackages = element.getAttribute("base-packages"); + if (!StringUtils.hasText(basePackages)) { + return; + } + + Set basePackageSet = StringUtils.commaDelimitedListToSet(basePackages); + builder.addPropertyValue("basePackages", basePackageSet); + } +} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataMappingCassandraConverterParser.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataMappingCassandraConverterParser.java new file mode 100644 index 000000000..18eefc9c7 --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataMappingCassandraConverterParser.java @@ -0,0 +1,62 @@ +package org.springframework.data.cassandra.config.xml; + +import java.util.Set; + +import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.data.cassandra.config.CassandraDataMappingConverterFactoryBean; +import org.springframework.data.cassandra.config.DefaultDataBeanNames; +import org.springframework.util.StringUtils; +import org.w3c.dom.Element; + +/** + * Spring Data Cassandra XML namespace parser for the <mapping-converter> element. + * + * @author Matthew T. Adams + */ +public class CassandraDataMappingCassandraConverterParser extends AbstractSimpleBeanDefinitionParser { + + @Override + protected Class getBeanClass(Element element) { + return CassandraDataMappingConverterFactoryBean.class; + } + + @Override + protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) + throws BeanDefinitionStoreException { + + String id = super.resolveId(element, definition, parserContext); + return StringUtils.hasText(id) ? id : DefaultDataBeanNames.CONVERTER; + } + + @Override + protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + super.doParse(element, parserContext, builder); + + parseMappingContextAttribute(element, parserContext, builder); + parseBasePackagesAttribute(element, parserContext, builder); + } + + protected void parseMappingContextAttribute(Element element, ParserContext parserContext, + BeanDefinitionBuilder builder) { + + String mappingContextRef = element.getAttribute("mapping-context-ref"); + if (!StringUtils.hasText(mappingContextRef)) { + mappingContextRef = DefaultDataBeanNames.MAPPING_CONTEXT; + } + builder.addPropertyReference("mappingContext", mappingContextRef); + } + + protected void parseBasePackagesAttribute(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + + String basePackages = element.getAttribute("base-packages"); + if (!StringUtils.hasText(basePackages)) { + return; + } + + Set basePackageSet = StringUtils.commaDelimitedListToSet(basePackages); + } +} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataNamespaceHandler.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataNamespaceHandler.java index fdd7fc80c..349b87ce3 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataNamespaceHandler.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataNamespaceHandler.java @@ -36,5 +36,7 @@ public class CassandraDataNamespaceHandler extends NamespaceHandlerSupport { registerBeanDefinitionParser("cluster", new CassandraDataClusterParser()); registerBeanDefinitionParser("session", new CassandraDataSessionParser()); registerBeanDefinitionParser("template", new CassandraDataTemplateParser()); + registerBeanDefinitionParser("mapping-converter", new CassandraDataMappingCassandraConverterParser()); + registerBeanDefinitionParser("mapping-context", new CassandraDataCassandraMappingContextParser()); } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataSessionParser.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataSessionParser.java index ea2327801..fef2f1842 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataSessionParser.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataSessionParser.java @@ -45,6 +45,15 @@ public class CassandraDataSessionParser extends CassandraSessionParser { } } + @Override + protected void setDefaultProperties(BeanDefinitionBuilder builder) { + + super.setDefaultProperties(builder); + + addRequiredPropertyReference(builder, "converter", DefaultDataBeanNames.CONVERTER); + addRequiredPropertyReference(builder, "schemaAction", SchemaAction.NONE.name()); + } + @Override protected void parseUnhandledElement(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/DefaultCassandraMappingContext.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/DefaultCassandraMappingContext.java index e48f7ec7d..36ac828e4 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/DefaultCassandraMappingContext.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/DefaultCassandraMappingContext.java @@ -52,6 +52,8 @@ public class DefaultCassandraMappingContext extends CassandraMappingContext, ApplicationContextAware { protected ApplicationContext context; + + // useful caches protected Map>> entitySetsByTableName = new HashMap>>(); protected Set> nonPrimaryKeyEntities = new HashSet>(); protected Set> primaryKeyEntities = new HashSet>(); @@ -63,6 +65,20 @@ public class DefaultCassandraMappingContext extends setSimpleTypeHolder(new CassandraSimpleTypeHolder()); } + @Override + public void initialize() { + + super.initialize(); + + processMappingOverrides(); + } + + protected void processMappingOverrides() { + + // TODO: search for external entity mapping info (xml/properties/yaml/etc) here & update this.mapping + // similar to JPA's or JDO's external metadata search algorithms + } + @Override public Collection> getPersistentEntities() { return getPersistentEntities(false); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/config/CassandraRepositoryConfigurationExtension.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/config/CassandraRepositoryConfigurationExtension.java index 91b2fc35a..5821450f0 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/config/CassandraRepositoryConfigurationExtension.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/config/CassandraRepositoryConfigurationExtension.java @@ -18,6 +18,7 @@ package org.springframework.data.cassandra.repository.config; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.cassandra.config.xml.ParsingUtils; import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.data.cassandra.config.DefaultDataBeanNames; import org.springframework.data.cassandra.repository.support.CassandraRepositoryFactoryBean; import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource; import org.springframework.data.repository.config.RepositoryConfigurationExtension; @@ -52,7 +53,7 @@ public class CassandraRepositoryConfigurationExtension extends RepositoryConfigu Element element = config.getElement(); ParsingUtils.addOptionalPropertyReference(builder, "cassandraTemplate", element, CASSANDRA_TEMPLATE_REF, - "cassandra-template"); + DefaultDataBeanNames.TEMPLATE); } @Override diff --git a/spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/ext-spring-cassandra-1.0.xsd b/spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/spring-cassandra-1.0-trying-to-use-xml-extension.xsd similarity index 100% rename from spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/ext-spring-cassandra-1.0.xsd rename to spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/spring-cassandra-1.0-trying-to-use-xml-extension.xsd diff --git a/spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/spring-cassandra-1.0.xsd b/spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/spring-cassandra-1.0.xsd index bed6fd896..14d048be2 100644 --- a/spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/spring-cassandra-1.0.xsd +++ b/spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/spring-cassandra-1.0.xsd @@ -482,7 +482,7 @@ The name of a Cassandra Keyspace. No default; for the system keyspace, use the use="optional"> @@ -500,7 +500,7 @@ The schema action to perform; default is NONE. @@ -515,7 +515,7 @@ The reference to a Cassandra session; default is "cassandra-session". use="optional"> @@ -676,11 +676,10 @@ Table name override. - + @@ -696,4 +695,61 @@ The reference to a cassandraTemplate. Will default to 'cassandra-template'. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/composites/CommentRepositoryJavaConfigIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/composites/CommentRepositoryJavaConfigIntegrationTests.java index 4515b97af..99a396907 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/composites/CommentRepositoryJavaConfigIntegrationTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/composites/CommentRepositoryJavaConfigIntegrationTests.java @@ -69,8 +69,8 @@ public class CommentRepositoryJavaConfigIntegrationTests extends AbstractSpringD } @Override - public String getEntityBasePackage() { - return Comment.class.getPackage().getName(); + public String[] getMappingBasePackages() { + return new String[] { Comment.class.getPackage().getName() }; } } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/repository/UserRepositoryJavaConfigIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/repository/UserRepositoryJavaConfigIntegrationTests.java index 9ca1eac3e..1d6a180bf 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/repository/UserRepositoryJavaConfigIntegrationTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/repository/UserRepositoryJavaConfigIntegrationTests.java @@ -68,8 +68,8 @@ public class UserRepositoryJavaConfigIntegrationTests extends AbstractSpringData } @Override - public String getEntityBasePackage() { - return User.class.getPackage().getName(); + public String[] getMappingBasePackages() { + return new String[] { User.class.getPackage().getName() }; } } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/template/CassandraDataOperationsTest.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/template/CassandraDataOperationsTest.java index 047545bc8..6406ba08a 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/template/CassandraDataOperationsTest.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/template/CassandraDataOperationsTest.java @@ -16,7 +16,6 @@ package org.springframework.data.cassandra.test.integration.template; import static org.springframework.cassandra.core.keyspace.CreateKeyspaceSpecification.createKeyspace; -import static org.springframework.cassandra.core.keyspace.DropTableSpecification.dropTable; import java.io.IOException; import java.util.ArrayList; @@ -24,30 +23,22 @@ import java.util.Arrays; import java.util.List; import java.util.UUID; -import org.apache.commons.io.FileUtils; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cassandra.core.ConsistencyLevel; import org.springframework.cassandra.core.QueryOptions; import org.springframework.cassandra.core.RetryPolicy; import org.springframework.cassandra.core.keyspace.CreateKeyspaceSpecification; import org.springframework.context.annotation.Configuration; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; import org.springframework.data.cassandra.config.SchemaAction; -import org.springframework.data.cassandra.core.CassandraOperations; import org.springframework.data.cassandra.test.integration.simpletons.Book; import org.springframework.data.cassandra.test.integration.support.AbstractSpringDataEmbeddedCassandraIntegrationTest; import org.springframework.data.cassandra.test.integration.support.TestConfig; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import com.datastax.driver.core.TableMetadata; import com.datastax.driver.core.querybuilder.QueryBuilder; import com.datastax.driver.core.querybuilder.Select; @@ -75,8 +66,8 @@ public class CassandraDataOperationsTest extends AbstractSpringDataEmbeddedCassa } @Override - public String getEntityBasePackage() { - return Book.class.getPackage().getName(); + public String[] getMappingBasePackages() { + return new String[] { Book.class.getPackage().getName() }; } } diff --git a/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/composites/CommentRepositoryXmlConfigIntegrationTests-context.xml b/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/composites/CommentRepositoryXmlConfigIntegrationTests-context.xml index a181a4745..325c8e0c7 100644 --- a/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/composites/CommentRepositoryXmlConfigIntegrationTests-context.xml +++ b/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/composites/CommentRepositoryXmlConfigIntegrationTests-context.xml @@ -2,24 +2,23 @@ - - + - + diff --git a/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/config/CassandraNamespaceTests-context.xml b/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/config/CassandraNamespaceTests-context.xml index 5709113fc..a25253303 100644 --- a/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/config/CassandraNamespaceTests-context.xml +++ b/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/config/CassandraNamespaceTests-context.xml @@ -11,9 +11,8 @@ - + @@ -27,21 +26,13 @@ durable-writes="true" /> - - + + + - - - - + - - - - + diff --git a/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/repository/UserRepositoryXmlConfigIntegrationTests-context.xml b/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/repository/UserRepositoryXmlConfigIntegrationTests-context.xml index a80188b22..973c3c938 100644 --- a/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/repository/UserRepositoryXmlConfigIntegrationTests-context.xml +++ b/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/repository/UserRepositoryXmlConfigIntegrationTests-context.xml @@ -1,7 +1,8 @@ - - + - + diff --git a/spring-data-cassandra/src/test/resources/spring-data-cassandra-basic.xml b/spring-data-cassandra/src/test/resources/spring-data-cassandra-basic.xml index 7c6868246..39c99629f 100644 --- a/spring-data-cassandra/src/test/resources/spring-data-cassandra-basic.xml +++ b/spring-data-cassandra/src/test/resources/spring-data-cassandra-basic.xml @@ -10,15 +10,10 @@ - + - - - + - + From 30787eac5ac4ed5d07fb770be2d862e11a301e7b Mon Sep 17 00:00:00 2001 From: john-mcpeek Date: Mon, 10 Feb 2014 20:52:58 -0500 Subject: [PATCH 02/13] Added CqlIdentifier. Put in the basics pieces. --- .../cassandra/core/CqlIdentifier.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 spring-cassandra/src/main/java/org/springframework/cassandra/core/CqlIdentifier.java diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/core/CqlIdentifier.java b/spring-cassandra/src/main/java/org/springframework/cassandra/core/CqlIdentifier.java new file mode 100644 index 000000000..6f11f5792 --- /dev/null +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/core/CqlIdentifier.java @@ -0,0 +1,44 @@ +package org.springframework.cassandra.core; + +public class CqlIdentifier { + private String identifier; + private boolean quoted; + + public CqlIdentifier(String identifier) { + this(identifier, false); + } + + public CqlIdentifier(String identifier, boolean forceQuoting) { + } + + public String toCql() { + return identifier; + } + + public StringBuilder toCql(StringBuilder sb) { + return sb.append(toCql()); + } + + @Override + public String toString() { + return toCql(); + } + + public String getIdentifier() { + return toCql(); + } + + public boolean isQuoted() { + return quoted; + } + + public static CqlIdentifier cqlId(String identifier) { + CqlIdentifier id = new CqlIdentifier(identifier); + return id; + } + + public static CqlIdentifier quotedCqlId(String identifier) { + CqlIdentifier id = new CqlIdentifier(identifier, true); + return id; + } +} From e3a131007c423b36fafe286da6bb933a8d917d9c Mon Sep 17 00:00:00 2001 From: Matthew Adams Date: Mon, 10 Feb 2014 23:14:30 -0600 Subject: [PATCH 03/13] DATACASS-91 - now scanning packages via XML & Java config --- ...ataCassandraMappingContextFactoryBean.java | 46 ------------ .../CassandraDataSessionFactoryBean.java | 56 -------------- .../CassandraMappingContextFactoryBean.java | 73 +++++++++++++++++++ ...CassandraMappingConverterFactoryBean.java} | 2 +- .../config/DefaultDataBeanNames.java | 2 +- ...tractSpringDataCassandraConfiguration.java | 36 ++++----- .../xml/CassandraDataNamespaceHandler.java | 4 +- .../xml/CassandraDataSessionParser.java | 66 +---------------- ...ava => CassandraMappingContextParser.java} | 56 +++++++++++++- ...a => CassandraMappingConverterParser.java} | 23 ++---- .../DefaultCassandraMappingContext.java | 70 ++++++++++++++++-- .../cassandra/config/spring-cassandra-1.0.xsd | 21 ++---- ...itoryXmlConfigIntegrationTests-context.xml | 30 ++++---- .../CassandraNamespaceTests-context.xml | 2 +- ...itoryXmlConfigIntegrationTests-context.xml | 30 ++++---- .../resources/spring-data-cassandra-basic.xml | 8 +- 16 files changed, 266 insertions(+), 259 deletions(-) delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataCassandraMappingContextFactoryBean.java create mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingContextFactoryBean.java rename spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/{CassandraDataMappingConverterFactoryBean.java => CassandraMappingConverterFactoryBean.java} (91%) rename spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/{CassandraDataCassandraMappingContextParser.java => CassandraMappingContextParser.java} (50%) rename spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/{CassandraDataMappingCassandraConverterParser.java => CassandraMappingConverterParser.java} (68%) diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataCassandraMappingContextFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataCassandraMappingContextFactoryBean.java deleted file mode 100644 index 3a087a06c..000000000 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataCassandraMappingContextFactoryBean.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.springframework.data.cassandra.config; - -import java.util.HashSet; -import java.util.Set; - -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.data.cassandra.mapping.CassandraMappingContext; -import org.springframework.data.cassandra.mapping.DefaultCassandraMappingContext; - -public class CassandraDataCassandraMappingContextFactoryBean implements FactoryBean, - InitializingBean { - - protected Set basePackages = new HashSet(); - - @Override - public void afterPropertiesSet() throws Exception { - } - - @Override - public CassandraMappingContext getObject() throws Exception { - - DefaultCassandraMappingContext cmc = new DefaultCassandraMappingContext(); - cmc.setInitialEntitySet(new CassandraEntityClassScanner(basePackages).scanForEntityClasses()); - - return cmc; - } - - @Override - public Class getObjectType() { - return CassandraMappingContext.class; - } - - @Override - public boolean isSingleton() { - return true; - } - - public Set getBasePackages() { - return basePackages; - } - - public void setBasePackages(Set basePackages) { - this.basePackages = basePackages; - } -} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataSessionFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataSessionFactoryBean.java index 436b66b68..69bc1be26 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataSessionFactoryBean.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataSessionFactoryBean.java @@ -7,10 +7,7 @@ import org.springframework.data.cassandra.convert.CassandraConverter; import org.springframework.data.cassandra.core.CassandraAdminTemplate; import org.springframework.data.cassandra.mapping.CassandraMappingContext; import org.springframework.data.cassandra.mapping.CassandraPersistentEntity; -import org.springframework.data.cassandra.mapping.EntityMapping; -import org.springframework.data.cassandra.mapping.Mapping; import org.springframework.util.Assert; -import org.springframework.util.StringUtils; import com.datastax.driver.core.KeyspaceMetadata; import com.datastax.driver.core.Metadata; @@ -22,8 +19,6 @@ public class CassandraDataSessionFactoryBean extends CassandraSessionFactoryBean protected CassandraAdminTemplate admin; protected CassandraConverter converter; protected CassandraMappingContext mappingContext; - protected Mapping mapping; - protected ClassLoader entityClassLoader = getClass().getClassLoader(); @Override public void afterPropertiesSet() throws Exception { @@ -34,42 +29,9 @@ public class CassandraDataSessionFactoryBean extends CassandraSessionFactoryBean admin = new CassandraAdminTemplate(session, converter); - mapping = mapping == null ? new Mapping() : mapping; - - processMappingOverrides(); performSchemaAction(); } - protected void processMappingOverrides() throws ClassNotFoundException { - - if (mapping == null) { - return; - } - - for (EntityMapping entityMapping : mapping.getEntityMappings()) { - - if (entityMapping == null) { - continue; - } - - String entityClassName = entityMapping.getEntityClassName(); - Class entityClass = Class.forName(entityClassName, false, entityClassLoader); - - CassandraPersistentEntity entity = mappingContext.getPersistentEntity(entityClass); - - if (entity == null) { - throw new IllegalStateException(String.format("unknown persistent entity class name [%s]", entityClassName)); - } - - String tableName = entityMapping.getTableName(); - if (!StringUtils.hasText(tableName)) { - continue; - } - - entity.setTableName(tableName); - } - } - protected void performSchemaAction() { boolean dropTables = false; @@ -138,22 +100,4 @@ public class CassandraDataSessionFactoryBean extends CassandraSessionFactoryBean this.converter = converter; this.mappingContext = converter.getMappingContext(); } - - public Mapping getMapping() { - return mapping; - } - - public void setMapping(Mapping mapping) { - Assert.notNull(mapping); - this.mapping = mapping; - } - - public ClassLoader getEntityClassLoader() { - return entityClassLoader; - } - - public void setEntityClassLoader(ClassLoader entityClassLoader) { - Assert.notNull(entityClassLoader); - this.entityClassLoader = entityClassLoader; - } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingContextFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingContextFactoryBean.java new file mode 100644 index 000000000..2489a7ad9 --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingContextFactoryBean.java @@ -0,0 +1,73 @@ +package org.springframework.data.cassandra.config; + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.data.cassandra.mapping.CassandraMappingContext; +import org.springframework.data.cassandra.mapping.DefaultCassandraMappingContext; +import org.springframework.data.cassandra.mapping.Mapping; +import org.springframework.util.Assert; + +public class CassandraMappingContextFactoryBean implements FactoryBean, InitializingBean { + + protected Set basePackages = new HashSet(); + protected Mapping mapping; + protected ClassLoader entityClassLoader; + + @Override + public void afterPropertiesSet() throws Exception { + mapping = mapping == null ? new Mapping() : mapping; + } + + @Override + public CassandraMappingContext getObject() throws Exception { + + DefaultCassandraMappingContext mappingContext = new DefaultCassandraMappingContext(); + mappingContext.setInitialEntitySet(new CassandraEntityClassScanner(basePackages).scanForEntityClasses()); + mappingContext.setMapping(mapping); + mappingContext.setBeanClassLoader(entityClassLoader); + + mappingContext.initialize(); // this is necessary here + + return mappingContext; + } + + @Override + public Class getObjectType() { + return CassandraMappingContext.class; + } + + @Override + public boolean isSingleton() { + return true; + } + + public Set getBasePackages() { + return basePackages; + } + + public void setBasePackages(Set basePackages) { + this.basePackages = basePackages == null ? new HashSet() : new HashSet(basePackages); + } + + public Mapping getMapping() { + return mapping; + } + + public void setMapping(Mapping mapping) { + + Assert.notNull(mapping); + + this.mapping = mapping; + } + + public ClassLoader getEntityClassLoader() { + return entityClassLoader; + } + + public void setEntityClassLoader(ClassLoader entityClassLoader) { + this.entityClassLoader = entityClassLoader; + } +} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataMappingConverterFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingConverterFactoryBean.java similarity index 91% rename from spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataMappingConverterFactoryBean.java rename to spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingConverterFactoryBean.java index 48fba014a..e6e3353f5 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataMappingConverterFactoryBean.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingConverterFactoryBean.java @@ -10,7 +10,7 @@ import org.springframework.data.cassandra.convert.MappingCassandraConverter; import org.springframework.data.cassandra.mapping.CassandraMappingContext; import org.springframework.util.Assert; -public class CassandraDataMappingConverterFactoryBean implements FactoryBean, InitializingBean { +public class CassandraMappingConverterFactoryBean implements FactoryBean, InitializingBean { protected CassandraMappingContext mappingContext; protected Set basePackages = new HashSet(); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/DefaultDataBeanNames.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/DefaultDataBeanNames.java index 4443e54d6..c91114d88 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/DefaultDataBeanNames.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/DefaultDataBeanNames.java @@ -6,5 +6,5 @@ public interface DefaultDataBeanNames extends DefaultBeanNames { public static final String DATA_TEMPLATE = "cassandraTemplate"; public static final String CONVERTER = "cassandraConverter"; - public static final String MAPPING_CONTEXT = "cassandra-mapping"; + public static final String MAPPING_CONTEXT = "cassandraMapping"; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/java/AbstractSpringDataCassandraConfiguration.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/java/AbstractSpringDataCassandraConfiguration.java index a86e13b5c..992da0ac6 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/java/AbstractSpringDataCassandraConfiguration.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/java/AbstractSpringDataCassandraConfiguration.java @@ -16,6 +16,7 @@ package org.springframework.data.cassandra.config.java; import java.util.Arrays; +import java.util.HashSet; import java.util.Set; import org.springframework.beans.factory.BeanClassLoaderAware; @@ -24,14 +25,12 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.cassandra.config.CassandraDataSessionFactoryBean; import org.springframework.data.cassandra.config.CassandraEntityClassScanner; +import org.springframework.data.cassandra.config.CassandraMappingContextFactoryBean; +import org.springframework.data.cassandra.config.CassandraMappingConverterFactoryBean; import org.springframework.data.cassandra.config.SchemaAction; import org.springframework.data.cassandra.convert.CassandraConverter; -import org.springframework.data.cassandra.convert.MappingCassandraConverter; import org.springframework.data.cassandra.core.CassandraAdminOperations; import org.springframework.data.cassandra.core.CassandraAdminTemplate; -import org.springframework.data.cassandra.mapping.CassandraMappingContext; -import org.springframework.data.cassandra.mapping.DefaultCassandraMappingContext; -import org.springframework.data.cassandra.mapping.Mapping; import org.springframework.data.cassandra.mapping.Table; import org.springframework.data.mapping.context.MappingContext; @@ -48,7 +47,6 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC protected abstract String getKeyspaceName(); protected ClassLoader beanClassLoader; - protected Mapping mapping = new Mapping(); /** * The {@link SchemaAction} to perform. Defaults to {@link SchemaAction#NONE}. @@ -71,15 +69,12 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC CassandraDataSessionFactoryBean bean = new CassandraDataSessionFactoryBean(); bean.setCluster(cluster().getObject()); - bean.setConverter(converter()); + bean.setConverter(converter().getObject()); bean.setSchemaAction(getSchemaAction()); bean.setKeyspaceName(getKeyspaceName()); bean.setStartupScripts(getStartupScripts()); bean.setShutdownScripts(getShutdownScripts()); - bean.setEntityClassLoader(beanClassLoader); - bean.setMapping(mapping); - return bean; } @@ -90,7 +85,7 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC */ @Bean public CassandraAdminOperations cassandraTemplate() throws Exception { - return new CassandraAdminTemplate(session().getObject(), converter()); + return new CassandraAdminTemplate(session().getObject(), converter().getObject()); } /** @@ -99,20 +94,25 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC * @throws ClassNotFoundException */ @Bean - public CassandraMappingContext cassandraMappingContext() throws ClassNotFoundException { - DefaultCassandraMappingContext context = new DefaultCassandraMappingContext(); - context.setInitialEntitySet(getInitialEntitySet()); - return context; + public CassandraMappingContextFactoryBean cassandraMapping() throws ClassNotFoundException { + + CassandraMappingContextFactoryBean bean = new CassandraMappingContextFactoryBean(); + bean.setBasePackages(new HashSet(Arrays.asList(getMappingBasePackages()))); + bean.setEntityClassLoader(beanClassLoader); + + return bean; } /** * Return the {@link CassandraConverter} instance to convert Rows to Objects, Objects to BuiltStatements - * - * @throws ClassNotFoundException */ @Bean - public CassandraConverter converter() throws ClassNotFoundException { - return new MappingCassandraConverter(cassandraMappingContext()); + public CassandraMappingConverterFactoryBean converter() throws Exception { + + CassandraMappingConverterFactoryBean bean = new CassandraMappingConverterFactoryBean(); + bean.setMappingContext(cassandraMapping().getObject()); + + return bean; } /** diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataNamespaceHandler.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataNamespaceHandler.java index 349b87ce3..8dc3ac7b2 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataNamespaceHandler.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataNamespaceHandler.java @@ -36,7 +36,7 @@ public class CassandraDataNamespaceHandler extends NamespaceHandlerSupport { registerBeanDefinitionParser("cluster", new CassandraDataClusterParser()); registerBeanDefinitionParser("session", new CassandraDataSessionParser()); registerBeanDefinitionParser("template", new CassandraDataTemplateParser()); - registerBeanDefinitionParser("mapping-converter", new CassandraDataMappingCassandraConverterParser()); - registerBeanDefinitionParser("mapping-context", new CassandraDataCassandraMappingContextParser()); + registerBeanDefinitionParser("mapping-converter", new CassandraMappingConverterParser()); + registerBeanDefinitionParser("mapping", new CassandraMappingContextParser()); } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataSessionParser.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataSessionParser.java index fef2f1842..e850bb07b 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataSessionParser.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataSessionParser.java @@ -1,20 +1,15 @@ package org.springframework.data.cassandra.config.xml; -import static org.springframework.cassandra.config.xml.ParsingUtils.*; - -import java.util.HashSet; -import java.util.Set; +import static org.springframework.cassandra.config.xml.ParsingUtils.addOptionalPropertyReference; +import static org.springframework.cassandra.config.xml.ParsingUtils.addOptionalPropertyValue; +import static org.springframework.cassandra.config.xml.ParsingUtils.addRequiredPropertyReference; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.cassandra.config.xml.CassandraSessionParser; -import org.springframework.data.cassandra.config.DefaultDataBeanNames; import org.springframework.data.cassandra.config.CassandraDataSessionFactoryBean; +import org.springframework.data.cassandra.config.DefaultDataBeanNames; import org.springframework.data.cassandra.config.SchemaAction; -import org.springframework.data.cassandra.mapping.EntityMapping; -import org.springframework.data.cassandra.mapping.Mapping; -import org.springframework.util.StringUtils; -import org.springframework.util.xml.DomUtils; import org.w3c.dom.Attr; import org.w3c.dom.Element; @@ -53,57 +48,4 @@ public class CassandraDataSessionParser extends CassandraSessionParser { addRequiredPropertyReference(builder, "converter", DefaultDataBeanNames.CONVERTER); addRequiredPropertyReference(builder, "schemaAction", SchemaAction.NONE.name()); } - - @Override - protected void parseUnhandledElement(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { - - if ("mapping".equals(element.getLocalName())) { - parseMapping(element, parserContext, builder); - } else { - super.parseUnhandledElement(element, parserContext, builder); - } - } - - protected void parseMapping(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { - - // TODO: parse attributes here, if there ever are any - - Set mappings = new HashSet(); - - for (Element child : DomUtils.getChildElementsByTagName(element, "entity")) { - - EntityMapping entityMapping = parseEntity(child); - - if (entityMapping != null) { - mappings.add(entityMapping); - } - } - - Mapping mapping = new Mapping(); - mapping.setEntityMappings(mappings); - - builder.addPropertyValue("mapping", mapping); - } - - protected EntityMapping parseEntity(Element entity) { - - String className = entity.getAttribute("class"); - if (!StringUtils.hasText(className)) { - throw new IllegalStateException("class attribute must not be empty"); - } - - Element table = DomUtils.getChildElementByTagName(entity, "table"); - if (table == null) { - return null; - } - - String tableName = table.getAttribute("name"); - if (!StringUtils.hasText(tableName)) { - tableName = null; - } - - // TODO: parse future entity mappings here, like table options - - return new EntityMapping(className, tableName); - } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataCassandraMappingContextParser.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingContextParser.java similarity index 50% rename from spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataCassandraMappingContextParser.java rename to spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingContextParser.java index fe696044c..ee3991c39 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataCassandraMappingContextParser.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingContextParser.java @@ -1,5 +1,6 @@ package org.springframework.data.cassandra.config.xml; +import java.util.HashSet; import java.util.Set; import org.springframework.beans.factory.BeanDefinitionStoreException; @@ -7,21 +8,24 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.data.cassandra.config.CassandraDataCassandraMappingContextFactoryBean; +import org.springframework.data.cassandra.config.CassandraMappingContextFactoryBean; import org.springframework.data.cassandra.config.DefaultDataBeanNames; +import org.springframework.data.cassandra.mapping.EntityMapping; +import org.springframework.data.cassandra.mapping.Mapping; import org.springframework.util.StringUtils; +import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; /** - * Spring Data Cassandra XML namespace parser for the <mapping-context> element. + * Spring Data Cassandra XML namespace parser for the <mapping> element. * * @author Matthew T. Adams */ -public class CassandraDataCassandraMappingContextParser extends AbstractSimpleBeanDefinitionParser { +public class CassandraMappingContextParser extends AbstractSimpleBeanDefinitionParser { @Override protected Class getBeanClass(Element element) { - return CassandraDataCassandraMappingContextFactoryBean.class; + return CassandraMappingContextFactoryBean.class; } @Override @@ -37,6 +41,7 @@ public class CassandraDataCassandraMappingContextParser extends AbstractSimpleBe super.doParse(element, parserContext, builder); parseBasePackagesAttribute(element, parserContext, builder); + parseMapping(element, parserContext, builder); } protected void parseBasePackagesAttribute(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { @@ -49,4 +54,47 @@ public class CassandraDataCassandraMappingContextParser extends AbstractSimpleBe Set basePackageSet = StringUtils.commaDelimitedListToSet(basePackages); builder.addPropertyValue("basePackages", basePackageSet); } + + protected void parseMapping(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + + // TODO: parse **attributes** here, if there ever are any + + Set mappings = new HashSet(); + + for (Element child : DomUtils.getChildElementsByTagName(element, "entity")) { + + EntityMapping entityMapping = parseEntity(child); + + if (entityMapping != null) { + mappings.add(entityMapping); + } + } + + Mapping mapping = new Mapping(); + mapping.setEntityMappings(mappings); + + builder.addPropertyValue("mapping", mapping); + } + + protected EntityMapping parseEntity(Element entity) { + + String className = entity.getAttribute("class"); + if (!StringUtils.hasText(className)) { + throw new IllegalStateException("class attribute must not be empty"); + } + + Element table = DomUtils.getChildElementByTagName(entity, "table"); + if (table == null) { + return null; + } + + String tableName = table.getAttribute("name"); + if (!StringUtils.hasText(tableName)) { + tableName = null; + } + + // TODO: parse future entity mappings here, like table options + + return new EntityMapping(className, tableName); + } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataMappingCassandraConverterParser.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingConverterParser.java similarity index 68% rename from spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataMappingCassandraConverterParser.java rename to spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingConverterParser.java index 18eefc9c7..6a830f119 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataMappingCassandraConverterParser.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingConverterParser.java @@ -1,13 +1,11 @@ package org.springframework.data.cassandra.config.xml; -import java.util.Set; - import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.data.cassandra.config.CassandraDataMappingConverterFactoryBean; +import org.springframework.data.cassandra.config.CassandraMappingConverterFactoryBean; import org.springframework.data.cassandra.config.DefaultDataBeanNames; import org.springframework.util.StringUtils; import org.w3c.dom.Element; @@ -17,11 +15,11 @@ import org.w3c.dom.Element; * * @author Matthew T. Adams */ -public class CassandraDataMappingCassandraConverterParser extends AbstractSimpleBeanDefinitionParser { +public class CassandraMappingConverterParser extends AbstractSimpleBeanDefinitionParser { @Override protected Class getBeanClass(Element element) { - return CassandraDataMappingConverterFactoryBean.class; + return CassandraMappingConverterFactoryBean.class; } @Override @@ -34,29 +32,20 @@ public class CassandraDataMappingCassandraConverterParser extends AbstractSimple @Override protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + super.doParse(element, parserContext, builder); parseMappingContextAttribute(element, parserContext, builder); - parseBasePackagesAttribute(element, parserContext, builder); } protected void parseMappingContextAttribute(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { - String mappingContextRef = element.getAttribute("mapping-context-ref"); + String mappingContextRef = element.getAttribute("mapping-ref"); if (!StringUtils.hasText(mappingContextRef)) { mappingContextRef = DefaultDataBeanNames.MAPPING_CONTEXT; } + builder.addPropertyReference("mappingContext", mappingContextRef); } - - protected void parseBasePackagesAttribute(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { - - String basePackages = element.getAttribute("base-packages"); - if (!StringUtils.hasText(basePackages)) { - return; - } - - Set basePackageSet = StringUtils.commaDelimitedListToSet(basePackages); - } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/DefaultCassandraMappingContext.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/DefaultCassandraMappingContext.java index 36ac828e4..02417f1fd 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/DefaultCassandraMappingContext.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/DefaultCassandraMappingContext.java @@ -37,6 +37,7 @@ import org.springframework.data.mapping.model.MappingException; import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.util.TypeInformation; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; import com.datastax.driver.core.TableMetadata; @@ -52,6 +53,9 @@ public class DefaultCassandraMappingContext extends CassandraMappingContext, ApplicationContextAware { protected ApplicationContext context; + protected Mapping mapping = new Mapping(); + protected ClassLoader beanClassLoader; + protected boolean initialized; // useful caches protected Map>> entitySetsByTableName = new HashMap>>(); @@ -65,18 +69,27 @@ public class DefaultCassandraMappingContext extends setSimpleTypeHolder(new CassandraSimpleTypeHolder()); } + @Override + public void afterPropertiesSet() { + if (initialized) { + return; + } + + super.afterPropertiesSet(); + } + @Override public void initialize() { + if (initialized) { + return; + } + super.initialize(); processMappingOverrides(); - } - protected void processMappingOverrides() { - - // TODO: search for external entity mapping info (xml/properties/yaml/etc) here & update this.mapping - // similar to JPA's or JDO's external metadata search algorithms + initialized = true; } @Override @@ -224,4 +237,51 @@ public class DefaultCassandraMappingContext extends return entity; } + + public void setMapping(Mapping mapping) { + + Assert.notNull(mapping); + + this.mapping = mapping; + } + + protected void processMappingOverrides() { + + if (mapping == null) { + return; + } + + for (EntityMapping entityMapping : mapping.getEntityMappings()) { + + if (entityMapping == null) { + continue; + } + + String entityClassName = entityMapping.getEntityClassName(); + Class entityClass; + try { + entityClass = Class.forName(entityClassName, false, beanClassLoader == null ? getClass().getClassLoader() + : beanClassLoader); + } catch (ClassNotFoundException e) { + throw new IllegalStateException(String.format("unknown persistent entity name [%s]", entityClassName), e); + } + + CassandraPersistentEntity entity = getPersistentEntity(entityClass); + + if (entity == null) { + throw new IllegalStateException(String.format("unknown persistent entity class name [%s]", entityClassName)); + } + + String tableName = entityMapping.getTableName(); + if (!StringUtils.hasText(tableName)) { + continue; + } + + entity.setTableName(tableName); + } + } + + public void setBeanClassLoader(ClassLoader beanClassLoader) { + this.beanClassLoader = beanClassLoader; + } } diff --git a/spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/spring-cassandra-1.0.xsd b/spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/spring-cassandra-1.0.xsd index 14d048be2..1f784ee6c 100644 --- a/spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/spring-cassandra-1.0.xsd +++ b/spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/spring-cassandra-1.0.xsd @@ -452,8 +452,6 @@ Arbitrary CQL script to be executed against the session's keyspace during bean d ]]> - @@ -629,13 +627,6 @@ The replication factor for the data center. - - - - - - - + + + + @@ -729,12 +724,12 @@ Defines a CassandraConverter for getting rich mapping functionality. - diff --git a/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/composites/CommentRepositoryXmlConfigIntegrationTests-context.xml b/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/composites/CommentRepositoryXmlConfigIntegrationTests-context.xml index 325c8e0c7..8f3c5e1ca 100644 --- a/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/composites/CommentRepositoryXmlConfigIntegrationTests-context.xml +++ b/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/composites/CommentRepositoryXmlConfigIntegrationTests-context.xml @@ -1,6 +1,6 @@ - - + + + + + + + - - + + - - - - - - - + - diff --git a/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/config/CassandraNamespaceTests-context.xml b/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/config/CassandraNamespaceTests-context.xml index a25253303..5b0e5d619 100644 --- a/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/config/CassandraNamespaceTests-context.xml +++ b/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/config/CassandraNamespaceTests-context.xml @@ -27,7 +27,7 @@ - + - - + + + + + + + - - + + - - - - - - - + - diff --git a/spring-data-cassandra/src/test/resources/spring-data-cassandra-basic.xml b/spring-data-cassandra/src/test/resources/spring-data-cassandra-basic.xml index 39c99629f..15653c53d 100644 --- a/spring-data-cassandra/src/test/resources/spring-data-cassandra-basic.xml +++ b/spring-data-cassandra/src/test/resources/spring-data-cassandra-basic.xml @@ -1,6 +1,6 @@ - + - - - + From e71c446a3f0408b77a5ca9bf624611e2c5ef846b Mon Sep 17 00:00:00 2001 From: Matthew Adams Date: Mon, 10 Feb 2014 23:17:48 -0600 Subject: [PATCH 04/13] DATACASS-91 - renamed Java config @Bean converter() to cassandraConverter() in order to match DefaultDataBeanNames --- .../java/AbstractSpringDataCassandraConfiguration.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/java/AbstractSpringDataCassandraConfiguration.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/java/AbstractSpringDataCassandraConfiguration.java index 992da0ac6..5d1e35dc8 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/java/AbstractSpringDataCassandraConfiguration.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/java/AbstractSpringDataCassandraConfiguration.java @@ -69,7 +69,7 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC CassandraDataSessionFactoryBean bean = new CassandraDataSessionFactoryBean(); bean.setCluster(cluster().getObject()); - bean.setConverter(converter().getObject()); + bean.setConverter(cassandraConverter().getObject()); bean.setSchemaAction(getSchemaAction()); bean.setKeyspaceName(getKeyspaceName()); bean.setStartupScripts(getStartupScripts()); @@ -85,7 +85,7 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC */ @Bean public CassandraAdminOperations cassandraTemplate() throws Exception { - return new CassandraAdminTemplate(session().getObject(), converter().getObject()); + return new CassandraAdminTemplate(session().getObject(), cassandraConverter().getObject()); } /** @@ -107,7 +107,7 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC * Return the {@link CassandraConverter} instance to convert Rows to Objects, Objects to BuiltStatements */ @Bean - public CassandraMappingConverterFactoryBean converter() throws Exception { + public CassandraMappingConverterFactoryBean cassandraConverter() throws Exception { CassandraMappingConverterFactoryBean bean = new CassandraMappingConverterFactoryBean(); bean.setMappingContext(cassandraMapping().getObject()); From 7b8cd2ab60dea2dc67beceb60628330a5d80c7bd Mon Sep 17 00:00:00 2001 From: Matthew Adams Date: Tue, 11 Feb 2014 09:17:04 -0600 Subject: [PATCH 05/13] DATACASS-91 - aligning terminology --- .../CassandraMappingContextFactoryBean.java | 24 +++++++++---------- ...tractSpringDataCassandraConfiguration.java | 10 ++++---- .../xml/CassandraMappingContextParser.java | 4 ++-- .../DefaultCassandraMappingContext.java | 4 ++-- .../cassandra/config/spring-cassandra-1.0.xsd | 2 +- ...tRepositoryJavaConfigIntegrationTests.java | 2 +- ...rRepositoryJavaConfigIntegrationTests.java | 2 +- .../template/CassandraDataOperationsTest.java | 2 +- ...itoryXmlConfigIntegrationTests-context.xml | 2 +- ...itoryXmlConfigIntegrationTests-context.xml | 2 +- 10 files changed, 27 insertions(+), 27 deletions(-) diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingContextFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingContextFactoryBean.java index 2489a7ad9..5fc72ddf0 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingContextFactoryBean.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingContextFactoryBean.java @@ -12,9 +12,9 @@ import org.springframework.util.Assert; public class CassandraMappingContextFactoryBean implements FactoryBean, InitializingBean { - protected Set basePackages = new HashSet(); + protected Set entityBasePackages = new HashSet(); protected Mapping mapping; - protected ClassLoader entityClassLoader; + protected ClassLoader beanClassLoader; @Override public void afterPropertiesSet() throws Exception { @@ -25,9 +25,9 @@ public class CassandraMappingContextFactoryBean implements FactoryBean getBasePackages() { - return basePackages; + public Set getEntityBasePackages() { + return entityBasePackages; } - public void setBasePackages(Set basePackages) { - this.basePackages = basePackages == null ? new HashSet() : new HashSet(basePackages); + public void setEntityBasePackages(Set basePackages) { + this.entityBasePackages = basePackages == null ? new HashSet() : new HashSet(basePackages); } public Mapping getMapping() { @@ -63,11 +63,11 @@ public class CassandraMappingContextFactoryBean implements FactoryBeanthis.getClass().getPackage().getName()). This method must never return null. */ - public String[] getMappingBasePackages() { + public String[] getEntityBasePackages() { return new String[] { getClass().getPackage().getName() }; } @@ -97,8 +97,8 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC public CassandraMappingContextFactoryBean cassandraMapping() throws ClassNotFoundException { CassandraMappingContextFactoryBean bean = new CassandraMappingContextFactoryBean(); - bean.setBasePackages(new HashSet(Arrays.asList(getMappingBasePackages()))); - bean.setEntityClassLoader(beanClassLoader); + bean.setEntityBasePackages(new HashSet(Arrays.asList(getEntityBasePackages()))); + bean.setBeanClassLoader(beanClassLoader); return bean; } @@ -118,7 +118,7 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC /** * Scans the mapping base package for entity classes. * - * @see #getMappingBasePackages() + * @see #getEntityBasePackages() * @see #getEntityScanner() * @return Set<Class<?>> representing the annotated entity classes found. * @throws ClassNotFoundException @@ -126,7 +126,7 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC protected Set> getInitialEntitySet() throws ClassNotFoundException { CassandraEntityClassScanner entityScanner = getEntityScanner(); - entityScanner.setEntityBasePackages(Arrays.asList(getMappingBasePackages())); + entityScanner.setEntityBasePackages(Arrays.asList(getEntityBasePackages())); return entityScanner.scanForEntityClasses(); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingContextParser.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingContextParser.java index ee3991c39..a7e0cf95e 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingContextParser.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingContextParser.java @@ -46,13 +46,13 @@ public class CassandraMappingContextParser extends AbstractSimpleBeanDefinitionP protected void parseBasePackagesAttribute(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { - String basePackages = element.getAttribute("base-packages"); + String basePackages = element.getAttribute("entity-base-packages"); if (!StringUtils.hasText(basePackages)) { return; } Set basePackageSet = StringUtils.commaDelimitedListToSet(basePackages); - builder.addPropertyValue("basePackages", basePackageSet); + builder.addPropertyValue("entityBasePackages", basePackageSet); } protected void parseMapping(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/DefaultCassandraMappingContext.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/DefaultCassandraMappingContext.java index 02417f1fd..b3bb25d5d 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/DefaultCassandraMappingContext.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/DefaultCassandraMappingContext.java @@ -37,6 +37,7 @@ import org.springframework.data.mapping.model.MappingException; import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.util.TypeInformation; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import com.datastax.driver.core.TableMetadata; @@ -260,8 +261,7 @@ public class DefaultCassandraMappingContext extends String entityClassName = entityMapping.getEntityClassName(); Class entityClass; try { - entityClass = Class.forName(entityClassName, false, beanClassLoader == null ? getClass().getClassLoader() - : beanClassLoader); + entityClass = ClassUtils.forName(entityClassName, beanClassLoader); } catch (ClassNotFoundException e) { throw new IllegalStateException(String.format("unknown persistent entity name [%s]", entityClassName), e); } diff --git a/spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/spring-cassandra-1.0.xsd b/spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/spring-cassandra-1.0.xsd index 1f784ee6c..40e8a3b54 100644 --- a/spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/spring-cassandra-1.0.xsd +++ b/spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/spring-cassandra-1.0.xsd @@ -702,7 +702,7 @@ Defines a CassandraMappingContext for holding rich entity mapping information. - + entity-base-packages="org.springframework.data.cassandra.test.integration.composites"> diff --git a/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/repository/UserRepositoryXmlConfigIntegrationTests-context.xml b/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/repository/UserRepositoryXmlConfigIntegrationTests-context.xml index 656c0a620..418d3d343 100644 --- a/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/repository/UserRepositoryXmlConfigIntegrationTests-context.xml +++ b/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/repository/UserRepositoryXmlConfigIntegrationTests-context.xml @@ -13,7 +13,7 @@ + entity-base-packages="org.springframework.data.cassandra.test.integration.repository"> From 0f121597f21c09db4ba78192dbfae7456be2ae79 Mon Sep 17 00:00:00 2001 From: Matthew Adams Date: Tue, 11 Feb 2014 09:33:25 -0600 Subject: [PATCH 06/13] DATACASS-91 - renamed mapping-converter XML element to converter --- .../cassandra/config/xml/CassandraDataNamespaceHandler.java | 2 +- .../cassandra/config/xml/CassandraMappingConverterParser.java | 2 +- .../data/cassandra/config/spring-cassandra-1.0.xsd | 2 +- .../test/integration/config/CassandraNamespaceTests-context.xml | 2 +- .../src/test/resources/spring-data-cassandra-basic.xml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataNamespaceHandler.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataNamespaceHandler.java index 8dc3ac7b2..d432cd458 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataNamespaceHandler.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataNamespaceHandler.java @@ -36,7 +36,7 @@ public class CassandraDataNamespaceHandler extends NamespaceHandlerSupport { registerBeanDefinitionParser("cluster", new CassandraDataClusterParser()); registerBeanDefinitionParser("session", new CassandraDataSessionParser()); registerBeanDefinitionParser("template", new CassandraDataTemplateParser()); - registerBeanDefinitionParser("mapping-converter", new CassandraMappingConverterParser()); + registerBeanDefinitionParser("converter", new CassandraMappingConverterParser()); registerBeanDefinitionParser("mapping", new CassandraMappingContextParser()); } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingConverterParser.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingConverterParser.java index 6a830f119..2ee61c67b 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingConverterParser.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingConverterParser.java @@ -11,7 +11,7 @@ import org.springframework.util.StringUtils; import org.w3c.dom.Element; /** - * Spring Data Cassandra XML namespace parser for the <mapping-converter> element. + * Spring Data Cassandra XML namespace parser for the <converter> element. * * @author Matthew T. Adams */ diff --git a/spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/spring-cassandra-1.0.xsd b/spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/spring-cassandra-1.0.xsd index 40e8a3b54..ee2d195ee 100644 --- a/spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/spring-cassandra-1.0.xsd +++ b/spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/spring-cassandra-1.0.xsd @@ -713,7 +713,7 @@ The comma-delimited base packages in which to scan for entities and their mappin - + - + diff --git a/spring-data-cassandra/src/test/resources/spring-data-cassandra-basic.xml b/spring-data-cassandra/src/test/resources/spring-data-cassandra-basic.xml index 15653c53d..3d736d478 100644 --- a/spring-data-cassandra/src/test/resources/spring-data-cassandra-basic.xml +++ b/spring-data-cassandra/src/test/resources/spring-data-cassandra-basic.xml @@ -10,7 +10,7 @@ - + From 24be302c039da5b0c471b44e3d40ba1dd8db7f8e Mon Sep 17 00:00:00 2001 From: Matthew Adams Date: Tue, 11 Feb 2014 11:05:38 -0600 Subject: [PATCH 07/13] DATACASS-91 - improved XML parsing & Java config --- .../config/xml/CassandraSessionParser.java | 4 +- .../config/xml/CassandraTemplateParser.java | 6 +- .../config/CassandraEntityClassScanner.java | 26 +++++++ .../CassandraMappingContextFactoryBean.java | 73 ------------------- .../CassandraMappingConverterFactoryBean.java | 49 ------------- ...tractSpringDataCassandraConfiguration.java | 47 +++--------- .../xml/CassandraMappingContextParser.java | 34 +++------ .../xml/CassandraMappingConverterParser.java | 26 +++---- .../DefaultCassandraMappingContext.java | 16 ---- .../resources/spring-data-cassandra-basic.xml | 2 +- 10 files changed, 60 insertions(+), 223 deletions(-) delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingContextFactoryBean.java delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingConverterFactoryBean.java diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/CassandraSessionParser.java b/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/CassandraSessionParser.java index 344308e42..184fdc0d3 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/CassandraSessionParser.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/CassandraSessionParser.java @@ -22,7 +22,7 @@ import static org.springframework.cassandra.config.xml.ParsingUtils.addRequiredP import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.cassandra.config.CassandraSessionFactoryBean; import org.springframework.util.StringUtils; @@ -37,7 +37,7 @@ import org.w3c.dom.NamedNodeMap; * @author David Webb * @author Matthew T. Adams */ -public class CassandraSessionParser extends AbstractSimpleBeanDefinitionParser { +public class CassandraSessionParser extends AbstractSingleBeanDefinitionParser { @Override protected Class getBeanClass(Element element) { diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/CassandraTemplateParser.java b/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/CassandraTemplateParser.java index 871bd0bbe..03f370e7a 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/CassandraTemplateParser.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/CassandraTemplateParser.java @@ -15,12 +15,12 @@ */ package org.springframework.cassandra.config.xml; -import static org.springframework.cassandra.config.xml.ParsingUtils.*; +import static org.springframework.cassandra.config.xml.ParsingUtils.addOptionalPropertyReference; import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.cassandra.config.CassandraTemplateFactoryBean; import org.springframework.util.StringUtils; @@ -32,7 +32,7 @@ import org.w3c.dom.Element; * @author David Webb * @author Matthew T. Adams */ -public class CassandraTemplateParser extends AbstractSimpleBeanDefinitionParser { +public class CassandraTemplateParser extends AbstractSingleBeanDefinitionParser { @Override protected Class getBeanClass(Element element) { diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraEntityClassScanner.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraEntityClassScanner.java index aeef0a590..a32c21055 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraEntityClassScanner.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraEntityClassScanner.java @@ -1,6 +1,7 @@ package org.springframework.data.cassandra.config; import java.lang.annotation.Annotation; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -22,6 +23,23 @@ import org.springframework.util.StringUtils; */ public class CassandraEntityClassScanner { + public static Set> scan(String... entityBasePackages) throws ClassNotFoundException { + return new CassandraEntityClassScanner(entityBasePackages).scanForEntityClasses(); + } + + public static Set> scan(Class... entityBasePackageClasses) throws ClassNotFoundException { + return new CassandraEntityClassScanner(entityBasePackageClasses).scanForEntityClasses(); + } + + public static Set> scan(Collection entityBasePackages) throws ClassNotFoundException { + return new CassandraEntityClassScanner(entityBasePackages).scanForEntityClasses(); + } + + public static Set> scan(Collection entityBasePackages, Collection> entityBasePackageClasses) + throws ClassNotFoundException { + return new CassandraEntityClassScanner(entityBasePackages, entityBasePackageClasses).scanForEntityClasses(); + } + protected Set entityBasePackages = new HashSet(); protected Set> entityBasePackageClasses = new HashSet>(); protected ClassLoader beanClassLoader; @@ -29,6 +47,14 @@ public class CassandraEntityClassScanner { public CassandraEntityClassScanner() { } + public CassandraEntityClassScanner(Class... entityBasePackageClasses) { + this(null, Arrays.asList(entityBasePackageClasses)); + } + + public CassandraEntityClassScanner(String... entityBasePackages) { + this(Arrays.asList(entityBasePackages)); + } + public CassandraEntityClassScanner(Collection entityBasePackages) { this(entityBasePackages, null); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingContextFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingContextFactoryBean.java deleted file mode 100644 index 5fc72ddf0..000000000 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingContextFactoryBean.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.springframework.data.cassandra.config; - -import java.util.HashSet; -import java.util.Set; - -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.data.cassandra.mapping.CassandraMappingContext; -import org.springframework.data.cassandra.mapping.DefaultCassandraMappingContext; -import org.springframework.data.cassandra.mapping.Mapping; -import org.springframework.util.Assert; - -public class CassandraMappingContextFactoryBean implements FactoryBean, InitializingBean { - - protected Set entityBasePackages = new HashSet(); - protected Mapping mapping; - protected ClassLoader beanClassLoader; - - @Override - public void afterPropertiesSet() throws Exception { - mapping = mapping == null ? new Mapping() : mapping; - } - - @Override - public CassandraMappingContext getObject() throws Exception { - - DefaultCassandraMappingContext mappingContext = new DefaultCassandraMappingContext(); - mappingContext.setInitialEntitySet(new CassandraEntityClassScanner(entityBasePackages).scanForEntityClasses()); - mappingContext.setMapping(mapping); - mappingContext.setBeanClassLoader(beanClassLoader); - - mappingContext.initialize(); // this is necessary here - - return mappingContext; - } - - @Override - public Class getObjectType() { - return CassandraMappingContext.class; - } - - @Override - public boolean isSingleton() { - return true; - } - - public Set getEntityBasePackages() { - return entityBasePackages; - } - - public void setEntityBasePackages(Set basePackages) { - this.entityBasePackages = basePackages == null ? new HashSet() : new HashSet(basePackages); - } - - public Mapping getMapping() { - return mapping; - } - - public void setMapping(Mapping mapping) { - - Assert.notNull(mapping); - - this.mapping = mapping; - } - - public ClassLoader getBeanClassLoader() { - return beanClassLoader; - } - - public void setBeanClassLoader(ClassLoader entityClassLoader) { - this.beanClassLoader = entityClassLoader; - } -} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingConverterFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingConverterFactoryBean.java deleted file mode 100644 index e6e3353f5..000000000 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingConverterFactoryBean.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.springframework.data.cassandra.config; - -import java.util.HashSet; -import java.util.Set; - -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.data.cassandra.convert.CassandraConverter; -import org.springframework.data.cassandra.convert.MappingCassandraConverter; -import org.springframework.data.cassandra.mapping.CassandraMappingContext; -import org.springframework.util.Assert; - -public class CassandraMappingConverterFactoryBean implements FactoryBean, InitializingBean { - - protected CassandraMappingContext mappingContext; - protected Set basePackages = new HashSet(); - - @Override - public void afterPropertiesSet() throws Exception { - Assert.notNull(mappingContext); - Assert.notNull(basePackages); - } - - @Override - public CassandraConverter getObject() throws Exception { - return new MappingCassandraConverter(mappingContext); - } - - @Override - public Class getObjectType() { - return CassandraConverter.class; - } - - @Override - public boolean isSingleton() { - return true; - } - - public CassandraMappingContext getMappingContext() { - return mappingContext; - } - - public void setMappingContext(CassandraMappingContext mappingContext) { - - Assert.notNull(mappingContext); - - this.mappingContext = mappingContext; - } -} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/java/AbstractSpringDataCassandraConfiguration.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/java/AbstractSpringDataCassandraConfiguration.java index 2408b305a..601235749 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/java/AbstractSpringDataCassandraConfiguration.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/java/AbstractSpringDataCassandraConfiguration.java @@ -15,22 +15,19 @@ */ package org.springframework.data.cassandra.config.java; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.cassandra.config.java.AbstractClusterConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.cassandra.config.CassandraDataSessionFactoryBean; import org.springframework.data.cassandra.config.CassandraEntityClassScanner; -import org.springframework.data.cassandra.config.CassandraMappingContextFactoryBean; -import org.springframework.data.cassandra.config.CassandraMappingConverterFactoryBean; import org.springframework.data.cassandra.config.SchemaAction; import org.springframework.data.cassandra.convert.CassandraConverter; +import org.springframework.data.cassandra.convert.MappingCassandraConverter; import org.springframework.data.cassandra.core.CassandraAdminOperations; import org.springframework.data.cassandra.core.CassandraAdminTemplate; +import org.springframework.data.cassandra.mapping.CassandraMappingContext; +import org.springframework.data.cassandra.mapping.DefaultCassandraMappingContext; import org.springframework.data.cassandra.mapping.Table; import org.springframework.data.mapping.context.MappingContext; @@ -69,7 +66,7 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC CassandraDataSessionFactoryBean bean = new CassandraDataSessionFactoryBean(); bean.setCluster(cluster().getObject()); - bean.setConverter(cassandraConverter().getObject()); + bean.setConverter(cassandraConverter()); bean.setSchemaAction(getSchemaAction()); bean.setKeyspaceName(getKeyspaceName()); bean.setStartupScripts(getStartupScripts()); @@ -85,7 +82,7 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC */ @Bean public CassandraAdminOperations cassandraTemplate() throws Exception { - return new CassandraAdminTemplate(session().getObject(), cassandraConverter().getObject()); + return new CassandraAdminTemplate(session().getObject(), cassandraConverter()); } /** @@ -94,10 +91,10 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC * @throws ClassNotFoundException */ @Bean - public CassandraMappingContextFactoryBean cassandraMapping() throws ClassNotFoundException { + public CassandraMappingContext cassandraMapping() throws ClassNotFoundException { - CassandraMappingContextFactoryBean bean = new CassandraMappingContextFactoryBean(); - bean.setEntityBasePackages(new HashSet(Arrays.asList(getEntityBasePackages()))); + DefaultCassandraMappingContext bean = new DefaultCassandraMappingContext(); + bean.setInitialEntitySet(CassandraEntityClassScanner.scan(getEntityBasePackages())); bean.setBeanClassLoader(beanClassLoader); return bean; @@ -107,32 +104,8 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC * Return the {@link CassandraConverter} instance to convert Rows to Objects, Objects to BuiltStatements */ @Bean - public CassandraMappingConverterFactoryBean cassandraConverter() throws Exception { - - CassandraMappingConverterFactoryBean bean = new CassandraMappingConverterFactoryBean(); - bean.setMappingContext(cassandraMapping().getObject()); - - return bean; - } - - /** - * Scans the mapping base package for entity classes. - * - * @see #getEntityBasePackages() - * @see #getEntityScanner() - * @return Set<Class<?>> representing the annotated entity classes found. - * @throws ClassNotFoundException - */ - protected Set> getInitialEntitySet() throws ClassNotFoundException { - - CassandraEntityClassScanner entityScanner = getEntityScanner(); - entityScanner.setEntityBasePackages(Arrays.asList(getEntityBasePackages())); - - return entityScanner.scanForEntityClasses(); - } - - public CassandraEntityClassScanner getEntityScanner() { - return new CassandraEntityClassScanner(); + public CassandraConverter cassandraConverter() throws Exception { + return new MappingCassandraConverter(cassandraMapping()); } @Override diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingContextParser.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingContextParser.java index a7e0cf95e..6565af3ee 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingContextParser.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingContextParser.java @@ -6,10 +6,10 @@ import java.util.Set; import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.data.cassandra.config.CassandraMappingContextFactoryBean; import org.springframework.data.cassandra.config.DefaultDataBeanNames; +import org.springframework.data.cassandra.mapping.DefaultCassandraMappingContext; import org.springframework.data.cassandra.mapping.EntityMapping; import org.springframework.data.cassandra.mapping.Mapping; import org.springframework.util.StringUtils; @@ -21,11 +21,11 @@ import org.w3c.dom.Element; * * @author Matthew T. Adams */ -public class CassandraMappingContextParser extends AbstractSimpleBeanDefinitionParser { +public class CassandraMappingContextParser extends AbstractSingleBeanDefinitionParser { @Override protected Class getBeanClass(Element element) { - return CassandraMappingContextFactoryBean.class; + return DefaultCassandraMappingContext.class; } @Override @@ -37,33 +37,17 @@ public class CassandraMappingContextParser extends AbstractSimpleBeanDefinitionP } @Override - protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { - super.doParse(element, parserContext, builder); - - parseBasePackagesAttribute(element, parserContext, builder); - parseMapping(element, parserContext, builder); + protected void doParse(Element element, BeanDefinitionBuilder builder) { + parseMapping(element, builder); } - protected void parseBasePackagesAttribute(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { - - String basePackages = element.getAttribute("entity-base-packages"); - if (!StringUtils.hasText(basePackages)) { - return; - } - - Set basePackageSet = StringUtils.commaDelimitedListToSet(basePackages); - builder.addPropertyValue("entityBasePackages", basePackageSet); - } - - protected void parseMapping(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { - - // TODO: parse **attributes** here, if there ever are any + protected void parseMapping(Element element, BeanDefinitionBuilder builder) { Set mappings = new HashSet(); - for (Element child : DomUtils.getChildElementsByTagName(element, "entity")) { + for (Element entity : DomUtils.getChildElementsByTagName(element, "entity")) { - EntityMapping entityMapping = parseEntity(child); + EntityMapping entityMapping = parseEntity(entity); if (entityMapping != null) { mappings.add(entityMapping); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingConverterParser.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingConverterParser.java index 2ee61c67b..8f75493f9 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingConverterParser.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingConverterParser.java @@ -3,10 +3,10 @@ package org.springframework.data.cassandra.config.xml; import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.data.cassandra.config.CassandraMappingConverterFactoryBean; import org.springframework.data.cassandra.config.DefaultDataBeanNames; +import org.springframework.data.cassandra.convert.MappingCassandraConverter; import org.springframework.util.StringUtils; import org.w3c.dom.Element; @@ -15,11 +15,11 @@ import org.w3c.dom.Element; * * @author Matthew T. Adams */ -public class CassandraMappingConverterParser extends AbstractSimpleBeanDefinitionParser { +public class CassandraMappingConverterParser extends AbstractSingleBeanDefinitionParser { @Override protected Class getBeanClass(Element element) { - return CassandraMappingConverterFactoryBean.class; + return MappingCassandraConverter.class; } @Override @@ -31,21 +31,13 @@ public class CassandraMappingConverterParser extends AbstractSimpleBeanDefinitio } @Override - protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + protected void doParse(Element element, BeanDefinitionBuilder builder) { - super.doParse(element, parserContext, builder); - - parseMappingContextAttribute(element, parserContext, builder); - } - - protected void parseMappingContextAttribute(Element element, ParserContext parserContext, - BeanDefinitionBuilder builder) { - - String mappingContextRef = element.getAttribute("mapping-ref"); - if (!StringUtils.hasText(mappingContextRef)) { - mappingContextRef = DefaultDataBeanNames.MAPPING_CONTEXT; + String mappingRef = element.getAttribute("mapping-ref"); + if (!StringUtils.hasText(mappingRef)) { + mappingRef = DefaultDataBeanNames.MAPPING_CONTEXT; } - builder.addPropertyReference("mappingContext", mappingContextRef); + builder.addConstructorArgReference(mappingRef); } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/DefaultCassandraMappingContext.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/DefaultCassandraMappingContext.java index b3bb25d5d..7971580c4 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/DefaultCassandraMappingContext.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/DefaultCassandraMappingContext.java @@ -56,7 +56,6 @@ public class DefaultCassandraMappingContext extends protected ApplicationContext context; protected Mapping mapping = new Mapping(); protected ClassLoader beanClassLoader; - protected boolean initialized; // useful caches protected Map>> entitySetsByTableName = new HashMap>>(); @@ -70,27 +69,12 @@ public class DefaultCassandraMappingContext extends setSimpleTypeHolder(new CassandraSimpleTypeHolder()); } - @Override - public void afterPropertiesSet() { - if (initialized) { - return; - } - - super.afterPropertiesSet(); - } - @Override public void initialize() { - if (initialized) { - return; - } - super.initialize(); processMappingOverrides(); - - initialized = true; } @Override diff --git a/spring-data-cassandra/src/test/resources/spring-data-cassandra-basic.xml b/spring-data-cassandra/src/test/resources/spring-data-cassandra-basic.xml index 3d736d478..b5ac038be 100644 --- a/spring-data-cassandra/src/test/resources/spring-data-cassandra-basic.xml +++ b/spring-data-cassandra/src/test/resources/spring-data-cassandra-basic.xml @@ -10,7 +10,7 @@ - + From a031ff77fe199b49e6ee4af4a37c64a4e6f5c5c4 Mon Sep 17 00:00:00 2001 From: Matthew Adams Date: Tue, 11 Feb 2014 13:13:10 -0600 Subject: [PATCH 08/13] DATACASS-91 - added test that searches multiple packages --- .../cassandra/core/CassandraTemplate.java | 10 ++-- .../BasicCassandraPersistentEntity.java | 1 - .../mapping/CassandraMappingContext.java | 20 -------- .../DefaultCassandraMappingContext.java | 25 ---------- .../MappingContextIntegrationTests.java | 28 +++++++++++ .../MultipackageScanningIntegrationTests.java | 47 +++++++++++++++++++ .../integration/multipackagescanning/Top.java | 11 +++++ .../multipackagescanning/first/First.java | 11 +++++ .../multipackagescanning/second/Second.java | 11 +++++ .../multipackagescanning/third/Third.java | 11 +++++ 10 files changed, 124 insertions(+), 51 deletions(-) create mode 100644 spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/mappingcontext/MappingContextIntegrationTests.java create mode 100644 spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/multipackagescanning/MultipackageScanningIntegrationTests.java create mode 100644 spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/multipackagescanning/Top.java create mode 100644 spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/multipackagescanning/first/First.java create mode 100644 spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/multipackagescanning/second/Second.java create mode 100644 spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/multipackagescanning/third/Third.java diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java index 189719802..f000371d7 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java @@ -123,7 +123,7 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation Assert.notNull(type); Assert.notNull(id); - CassandraPersistentEntity entity = mappingContext.getRequiredPersistentEntity(type); + CassandraPersistentEntity entity = mappingContext.getPersistentEntity(type); Select select = QueryBuilder.select().countAll().from(entity.getTableName()); appendIdCriteria(select.where(), entity, id); @@ -152,9 +152,9 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation Assert.notNull(type); Assert.notNull(id); - CassandraPersistentEntity entity = mappingContext.getRequiredPersistentEntity(type); + CassandraPersistentEntity entity = mappingContext.getPersistentEntity(type); - Delete delete = QueryBuilder.delete().all().from(entity.getTableName()); + Delete delete = QueryBuilder.delete().from(entity.getTableName()); appendIdCriteria(delete.where(), entity, id); execute(delete.getQueryString()); @@ -192,7 +192,7 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation @Override public String getTableName(Class type) { - return mappingContext.getRequiredPersistentEntity(type).getTableName(); + return mappingContext.getPersistentEntity(type).getTableName(); } @Override @@ -252,7 +252,7 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation @Override public List selectBySimpleIds(Class type, Iterable ids) { - CassandraPersistentEntity entity = mappingContext.getRequiredPersistentEntity(type); + CassandraPersistentEntity entity = mappingContext.getPersistentEntity(type); if (entity.getIdProperty().isCompositePrimaryKey()) { throw new IllegalArgumentException(String.format( diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentEntity.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentEntity.java index a1b52dd25..863e8f838 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentEntity.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentEntity.java @@ -27,7 +27,6 @@ import org.springframework.context.expression.BeanFactoryResolver; import org.springframework.data.cassandra.util.CassandraNamingUtils; import org.springframework.data.mapping.Association; import org.springframework.data.mapping.AssociationHandler; -import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PropertyHandler; import org.springframework.data.mapping.model.BasicPersistentEntity; import org.springframework.data.util.TypeInformation; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraMappingContext.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraMappingContext.java index d468e4b0a..9d712931d 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraMappingContext.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraMappingContext.java @@ -57,24 +57,4 @@ public interface CassandraMappingContext extends * @param table May not be null. */ boolean usesTable(TableMetadata table); - - /** - * Returns the {@link CassandraPersistentEntity} for the given type. If it doesn't exist, this method throws - * {@link IllegalArgumentException}. - * - * @param type The Java type of the persistent entity. - * @return The {@link CassandraPersistentEntity} describing the persistent Java type. - * @throws IllegalArgumentException if the persistent entity is unknown - */ - public CassandraPersistentEntity getRequiredPersistentEntity(Class type); - - /** - * Returns the {@link CassandraPersistentEntity} for the given type. If it doesn't exist, this method throws - * {@link IllegalArgumentException}. - * - * @param type The {@link TypeInformation} of the persistent entity. - * @return The {@link CassandraPersistentEntity} describing the persistent Java type. - * @throws IllegalArgumentException if the persistent entity is unknown - */ - public CassandraPersistentEntity getRequiredPersistentEntity(TypeInformation type); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/DefaultCassandraMappingContext.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/DefaultCassandraMappingContext.java index 7971580c4..8f860b505 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/DefaultCassandraMappingContext.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/DefaultCassandraMappingContext.java @@ -198,31 +198,6 @@ public class DefaultCassandraMappingContext extends return spec; } - @Override - public CassandraPersistentEntity getRequiredPersistentEntity(Class type) { - - CassandraPersistentEntity entity = getPersistentEntity(type); - - if (entity == null) { - throw new IllegalArgumentException(String.format("no persistence metadata found for type [%s]", type.getName())); - } - - return entity; - } - - @Override - public CassandraPersistentEntity getRequiredPersistentEntity(TypeInformation type) { - - CassandraPersistentEntity entity = getPersistentEntity(type); - - if (entity == null) { - throw new IllegalArgumentException(String.format("no persistence metadata found for type [%s]", - type.getActualType())); - } - - return entity; - } - public void setMapping(Mapping mapping) { Assert.notNull(mapping); diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/mappingcontext/MappingContextIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/mappingcontext/MappingContextIntegrationTests.java new file mode 100644 index 000000000..95a372c9f --- /dev/null +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/mappingcontext/MappingContextIntegrationTests.java @@ -0,0 +1,28 @@ +package org.springframework.data.cassandra.test.integration.mappingcontext; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; +import org.springframework.data.cassandra.mapping.CassandraPersistentEntity; +import org.springframework.data.cassandra.mapping.DefaultCassandraMappingContext; + +public class MappingContextIntegrationTests { + + public static class Transient { + } + + @Test + // TODO: (expected = MappingException.class) + public void testGetPersistentEntityOfTransientType() { + + // TODO: when entity verification is added (DATACASS-85), this should throw a MappingException + + DefaultCassandraMappingContext ctx = new DefaultCassandraMappingContext(); + CassandraPersistentEntity entity = ctx.getPersistentEntity(Transient.class); + + // TODO: remove following lines after DATACASS-85 + assertNotNull(entity); + assertEquals(Transient.class.getSimpleName().toLowerCase(), entity.getTableName()); + } +} diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/multipackagescanning/MultipackageScanningIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/multipackagescanning/MultipackageScanningIntegrationTests.java new file mode 100644 index 000000000..ee5fd8014 --- /dev/null +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/multipackagescanning/MultipackageScanningIntegrationTests.java @@ -0,0 +1,47 @@ +package org.springframework.data.cassandra.test.integration.multipackagescanning; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Collection; +import java.util.HashSet; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.data.cassandra.config.CassandraEntityClassScanner; +import org.springframework.data.cassandra.mapping.CassandraPersistentEntity; +import org.springframework.data.cassandra.mapping.DefaultCassandraMappingContext; +import org.springframework.data.cassandra.test.integration.multipackagescanning.first.First; +import org.springframework.data.cassandra.test.integration.multipackagescanning.second.Second; +import org.springframework.data.cassandra.test.integration.multipackagescanning.third.Third; + +public class MultipackageScanningIntegrationTests { + + DefaultCassandraMappingContext mapping; + String pkg = getClass().getPackage().getName(); + + @Before + public void before() throws ClassNotFoundException { + + mapping = new DefaultCassandraMappingContext(); + mapping.setInitialEntitySet(CassandraEntityClassScanner.scan(pkg + ".first", pkg + ".second")); + + mapping.initialize(); + } + + @Test + public void test() { + + Collection> entities = mapping.getPersistentEntities(); + + Collection> types = new HashSet>(entities.size()); + for (CassandraPersistentEntity entity : entities) { + types.add(entity.getType()); + } + + assertTrue(types.contains(First.class)); + assertTrue(types.contains(Second.class)); + assertFalse(types.contains(Third.class)); + assertFalse(types.contains(Top.class)); + } +} diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/multipackagescanning/Top.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/multipackagescanning/Top.java new file mode 100644 index 000000000..2d4bcfea4 --- /dev/null +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/multipackagescanning/Top.java @@ -0,0 +1,11 @@ +package org.springframework.data.cassandra.test.integration.multipackagescanning; + +import org.springframework.data.cassandra.mapping.PrimaryKey; +import org.springframework.data.cassandra.mapping.Table; + +@Table +public class Top { + + @PrimaryKey + String key; +} diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/multipackagescanning/first/First.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/multipackagescanning/first/First.java new file mode 100644 index 000000000..ac937b8ef --- /dev/null +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/multipackagescanning/first/First.java @@ -0,0 +1,11 @@ +package org.springframework.data.cassandra.test.integration.multipackagescanning.first; + +import org.springframework.data.cassandra.mapping.PrimaryKey; +import org.springframework.data.cassandra.mapping.Table; + +@Table +public class First { + + @PrimaryKey + String key; +} diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/multipackagescanning/second/Second.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/multipackagescanning/second/Second.java new file mode 100644 index 000000000..7e3478ba4 --- /dev/null +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/multipackagescanning/second/Second.java @@ -0,0 +1,11 @@ +package org.springframework.data.cassandra.test.integration.multipackagescanning.second; + +import org.springframework.data.cassandra.mapping.PrimaryKey; +import org.springframework.data.cassandra.mapping.Table; + +@Table +public class Second { + + @PrimaryKey + String key; +} diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/multipackagescanning/third/Third.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/multipackagescanning/third/Third.java new file mode 100644 index 000000000..39ccbdda0 --- /dev/null +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/multipackagescanning/third/Third.java @@ -0,0 +1,11 @@ +package org.springframework.data.cassandra.test.integration.multipackagescanning.third; + +import org.springframework.data.cassandra.mapping.PrimaryKey; +import org.springframework.data.cassandra.mapping.Table; + +@Table +public class Third { + + @PrimaryKey + String key; +} From 3dd7e532ef8b79b412348ba6ce4208d25600e490 Mon Sep 17 00:00:00 2001 From: john-mcpeek Date: Tue, 11 Feb 2014 22:09:25 -0500 Subject: [PATCH 09/13] Moved identifier logic to CqlIdentifer. Updated all the classes that used the checkIdentifier() method to have a CqlIdentifer. Also update those classes for getName() and such. --- .../cassandra/core/CqlIdentifier.java | 69 ++++++++++++++++++- .../cassandra/core/cql/CqlStringUtils.java | 57 +-------------- .../keyspace/ColumnChangeSpecification.java | 12 ++-- .../core/keyspace/ColumnSpecification.java | 22 +++--- .../keyspace/CreateIndexSpecification.java | 13 ++-- .../core/keyspace/IndexNameSpecification.java | 12 ++-- .../keyspace/KeyspaceActionSpecification.java | 20 +++--- .../core/keyspace/TableNameSpecification.java | 12 ++-- .../test/unit/core/cql/CqlIdentifierTest.java | 20 ++++++ .../unit/core/cql/CqlStringUtilsTest.java | 13 ---- .../AlterTableCqlGeneratorTests.java | 1 + .../BasicCassandraPersistentEntity.java | 1 - ...andraPersistentEntityIntegrationTests.java | 2 - .../template/CassandraDataOperationsTest.java | 9 --- 14 files changed, 129 insertions(+), 134 deletions(-) create mode 100644 spring-cassandra/src/test/java/org/springframework/cassandra/test/unit/core/cql/CqlIdentifierTest.java diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/core/CqlIdentifier.java b/spring-cassandra/src/main/java/org/springframework/cassandra/core/CqlIdentifier.java index 6f11f5792..3b3b17e97 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/core/CqlIdentifier.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/core/CqlIdentifier.java @@ -1,6 +1,15 @@ package org.springframework.cassandra.core; +import java.util.regex.Pattern; + +import org.springframework.cassandra.core.cql.CqlStringUtils; + public class CqlIdentifier { + public static final String UNQUOTED_IDENTIFIER_REGEX = "[a-zA-Z_][a-zA-Z0-9_]*"; + public static final Pattern UNQUOTED_IDENTIFIER_PATTERN = Pattern.compile(UNQUOTED_IDENTIFIER_REGEX); + public static final String QUOTED_IDENTIFIER_REGEX = "[a-zA-Z_]([a-zA-Z0-9_]|\"{2}+)*"; + public static final Pattern QUOTED_IDENTIFIER_PATTERN = Pattern.compile(QUOTED_IDENTIFIER_REGEX); + private String identifier; private boolean quoted; @@ -8,11 +17,29 @@ public class CqlIdentifier { this(identifier, false); } + /** + * Renders the given string as a legal Cassandra identifier. + *
    + *
  • If the given identifier is a legal quoted identifier or forceQuote is true, it is set encased in double quotes. + *
  • + *
  • If the given identifier is a legal unquoted identifier, it is set unchanged.
  • + *
  • If the given identifier is illegal, an {@link IllegalArgumentException} is thrown.
  • + *
+ */ public CqlIdentifier(String identifier, boolean forceQuoting) { + if (isUnquotedIdentifier(identifier) && forceQuoting == false) { + this.identifier = identifier; + } else if (isQuotedIdentifier(identifier)) { + this.identifier = identifier; + quoted = true; + } else { + throw new IllegalArgumentException("[" + identifier + "] is not a valid CQL quoted or unquoted identifier"); + } } public String toCql() { - return identifier; + String id = quoted ? CqlStringUtils.doubleQuote(identifier) : identifier; + return id; } public StringBuilder toCql(StringBuilder sb) { @@ -41,4 +68,44 @@ public class CqlIdentifier { CqlIdentifier id = new CqlIdentifier(identifier, true); return id; } + + public static boolean isIdentifier(CharSequence chars) { + return isUnquotedIdentifier(chars) || isQuotedIdentifier(chars); + } + + public static boolean isUnquotedIdentifier(CharSequence chars) { + return UNQUOTED_IDENTIFIER_PATTERN.matcher(chars).matches(); + } + + public static boolean isQuotedIdentifier(CharSequence chars) { + return QUOTED_IDENTIFIER_PATTERN.matcher(chars).matches(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((identifier == null) ? 0 : identifier.hashCode()); + result = prime * result + (quoted ? 1231 : 1237); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + CqlIdentifier other = (CqlIdentifier) obj; + if (identifier == null) { + if (other.identifier != null) + return false; + } else if (!identifier.equals(other.identifier)) + return false; + if (quoted != other.quoted) + return false; + return true; + } } diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/CqlStringUtils.java b/spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/CqlStringUtils.java index 61180cc7f..73d0c70e3 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/CqlStringUtils.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/CqlStringUtils.java @@ -23,7 +23,7 @@ public class CqlStringUtils { protected static final String SINGLE_QUOTE = "\'"; protected static final String DOUBLE_SINGLE_QUOTE = "\'\'"; - protected static final String DOUBLE_QUOTE = "\""; + public static final String DOUBLE_QUOTE = "\""; protected static final String DOUBLE_DOUBLE_QUOTE = "\"\""; protected static final String EMPTY_STRING = ""; protected static final String TYPE_PARAMETER_PREFIX = "<"; @@ -36,61 +36,6 @@ public class CqlStringUtils { public static final String UNESCAPED_DOUBLE_QUOTE_REGEX = "TODO"; public static final Pattern UNESCAPED_DOUBLE_QUOTE_PATTERN = Pattern.compile(UNESCAPED_DOUBLE_QUOTE_REGEX); - public static final String UNQUOTED_IDENTIFIER_REGEX = "[a-zA-Z_][a-zA-Z0-9_]*"; - public static final Pattern UNQUOTED_IDENTIFIER_PATTERN = Pattern.compile(UNQUOTED_IDENTIFIER_REGEX); - - public static boolean isUnquotedIdentifier(CharSequence chars) { - return UNQUOTED_IDENTIFIER_PATTERN.matcher(chars).matches(); - } - - public static void checkUnquotedIdentifier(CharSequence chars) { - if (!CqlStringUtils.isUnquotedIdentifier(chars)) { - throw new IllegalArgumentException("[" + chars + "] is not a valid CQL identifier"); - } - } - - public static final String QUOTED_IDENTIFIER_REGEX = "[a-zA-Z_]([a-zA-Z0-9_]|\"{2}+)*"; - public static final Pattern QUOTED_IDENTIFIER_PATTERN = Pattern.compile(QUOTED_IDENTIFIER_REGEX); - - public static boolean isQuotedIdentifier(CharSequence chars) { - return QUOTED_IDENTIFIER_PATTERN.matcher(chars).matches(); - } - - public static void checkQuotedIdentifier(CharSequence chars) { - if (!CqlStringUtils.isQuotedIdentifier(chars)) { - throw new IllegalArgumentException("[" + chars + "] is not a valid CQL quoted identifier"); - } - } - - public static boolean isIdentifier(CharSequence chars) { - return isUnquotedIdentifier(chars) || isQuotedIdentifier(chars); - } - - public static void checkIdentifier(CharSequence chars) { - if (!CqlStringUtils.isIdentifier(chars)) { - throw new IllegalArgumentException("[" + chars + "] is not a valid CQL quoted or unquoted identifier"); - } - } - - /** - * Renders the given string as a legal Cassandra identifier. - *
    - *
  • If the given identifier is a legal unquoted identifier, it is returned unchanged.
  • - *
  • If the given identifier is a legal quoted identifier, it is returned encased in double quotes.
  • - *
  • If the given identifier is illegal, an {@link IllegalArgumentException} is thrown.
  • - *
- */ - public static String identifize(String candidate) { - - checkIdentifier(candidate); - - if (isUnquotedIdentifier(candidate)) { - return candidate; - } - // else it must be quoted - return doubleQuote(candidate); - } - /** * Renders the given string as a legal Cassandra string column or table option value, by escaping single quotes and * encasing the result in single quotes. Given null, returns null. diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/ColumnChangeSpecification.java b/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/ColumnChangeSpecification.java index 6cea473f8..665a52797 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/ColumnChangeSpecification.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/ColumnChangeSpecification.java @@ -15,8 +15,7 @@ */ package org.springframework.cassandra.core.keyspace; -import static org.springframework.cassandra.core.cql.CqlStringUtils.checkIdentifier; -import static org.springframework.cassandra.core.cql.CqlStringUtils.identifize; +import org.springframework.cassandra.core.CqlIdentifier; /** * Base class for column change specifications. @@ -25,22 +24,21 @@ import static org.springframework.cassandra.core.cql.CqlStringUtils.identifize; */ public abstract class ColumnChangeSpecification { - private String name; + private CqlIdentifier identifier; public ColumnChangeSpecification(String name) { setName(name); } private void setName(String name) { - checkIdentifier(name); - this.name = name; + identifier = new CqlIdentifier(name); } public String getName() { - return name; + return identifier.getIdentifier(); } public String getNameAsIdentifier() { - return identifize(name); + return identifier.toCql(); } } diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/ColumnSpecification.java b/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/ColumnSpecification.java index 9c2d0ba03..aa6e491e0 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/ColumnSpecification.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/ColumnSpecification.java @@ -15,15 +15,14 @@ */ package org.springframework.cassandra.core.keyspace; -import static org.springframework.cassandra.core.cql.CqlStringUtils.checkIdentifier; -import static org.springframework.cassandra.core.cql.CqlStringUtils.identifize; -import static org.springframework.cassandra.core.cql.CqlStringUtils.noNull; -import static org.springframework.cassandra.core.PrimaryKeyType.PARTITIONED; -import static org.springframework.cassandra.core.PrimaryKeyType.CLUSTERED; import static org.springframework.cassandra.core.Ordering.ASCENDING; +import static org.springframework.cassandra.core.PrimaryKeyType.CLUSTERED; +import static org.springframework.cassandra.core.PrimaryKeyType.PARTITIONED; +import static org.springframework.cassandra.core.cql.CqlStringUtils.noNull; -import org.springframework.cassandra.core.PrimaryKeyType; +import org.springframework.cassandra.core.CqlIdentifier; import org.springframework.cassandra.core.Ordering; +import org.springframework.cassandra.core.PrimaryKeyType; import com.datastax.driver.core.DataType; @@ -45,7 +44,7 @@ public class ColumnSpecification { */ public static final Ordering DEFAULT_ORDERING = ASCENDING; - private String name; + private CqlIdentifier identifier; private DataType type; // TODO: determining if we should be coupling this to Datastax Java Driver type? private PrimaryKeyType keyType; private Ordering ordering; @@ -56,8 +55,7 @@ public class ColumnSpecification { * @return this */ public ColumnSpecification name(String name) { - checkIdentifier(name); - this.name = name; + identifier = new CqlIdentifier(name); return this; } @@ -148,11 +146,11 @@ public class ColumnSpecification { } public String getName() { - return name; + return identifier.getIdentifier(); } public String getNameAsIdentifier() { - return identifize(name); + return identifier.toCql(); } public DataType getType() { @@ -172,7 +170,7 @@ public class ColumnSpecification { } public StringBuilder toCql(StringBuilder cql) { - return (cql = noNull(cql)).append(name).append(" ").append(type); + return (cql = noNull(cql)).append(identifier).append(" ").append(type); } @Override diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/CreateIndexSpecification.java b/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/CreateIndexSpecification.java index 1f9f89d46..bd782b1f3 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/CreateIndexSpecification.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/CreateIndexSpecification.java @@ -15,9 +15,7 @@ */ package org.springframework.cassandra.core.keyspace; -import static org.springframework.cassandra.core.cql.CqlStringUtils.checkIdentifier; -import static org.springframework.cassandra.core.cql.CqlStringUtils.identifize; - +import org.springframework.cassandra.core.CqlIdentifier; import org.springframework.util.StringUtils; /** @@ -31,7 +29,7 @@ public class CreateIndexSpecification extends IndexNameSpecification /** * The name of the index. */ - private String name; + private CqlIdentifier identifier; /** * Sets the index name. @@ -38,17 +37,16 @@ public abstract class IndexNameSpecification */ @SuppressWarnings("unchecked") public T name(String name) { - checkIdentifier(name); - this.name = name; + identifier = new CqlIdentifier(name); return (T) this; } public String getName() { - return name; + return identifier.getIdentifier(); } public String getNameAsIdentifier() { - return identifize(name); + return identifier.toCql(); } } diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/KeyspaceActionSpecification.java b/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/KeyspaceActionSpecification.java index cddc2115d..83c6db79e 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/KeyspaceActionSpecification.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/KeyspaceActionSpecification.java @@ -1,7 +1,6 @@ package org.springframework.cassandra.core.keyspace; -import static org.springframework.cassandra.core.cql.CqlStringUtils.checkIdentifier; -import static org.springframework.cassandra.core.cql.CqlStringUtils.identifize; +import org.springframework.cassandra.core.CqlIdentifier; /** * Abstract builder class to support the construction of keyspace specifications. @@ -13,9 +12,9 @@ import static org.springframework.cassandra.core.cql.CqlStringUtils.identifize; public abstract class KeyspaceActionSpecification> { /** - * The name of the table. + * The name of the keyspace. */ - private String name; + private CqlIdentifier identifier; /** * Sets the keyspace name. @@ -24,17 +23,16 @@ public abstract class KeyspaceActionSpecification thatSpec = (KeyspaceActionSpecification) that; - return this.name.equals(thatSpec.name) && this.getClass().equals(that.getClass()); + return this.identifier.equals(thatSpec.identifier) && this.getClass().equals(that.getClass()); } @Override public int hashCode() { - return this.name.hashCode() ^ this.getClass().hashCode(); + return this.identifier.hashCode() ^ this.getClass().hashCode(); } } diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/TableNameSpecification.java b/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/TableNameSpecification.java index f99addd15..f66eb8e91 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/TableNameSpecification.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/TableNameSpecification.java @@ -15,8 +15,7 @@ */ package org.springframework.cassandra.core.keyspace; -import static org.springframework.cassandra.core.cql.CqlStringUtils.checkIdentifier; -import static org.springframework.cassandra.core.cql.CqlStringUtils.identifize; +import org.springframework.cassandra.core.CqlIdentifier; /** * Abstract builder class to support the construction of table specifications. @@ -29,7 +28,7 @@ public abstract class TableNameSpecification /** * The name of the table. */ - private String name; + private CqlIdentifier identifier; /** * Sets the table name. @@ -38,16 +37,15 @@ public abstract class TableNameSpecification */ @SuppressWarnings("unchecked") public T name(String name) { - checkIdentifier(name); - this.name = name; + identifier = new CqlIdentifier(name); return (T) this; } public String getName() { - return name; + return identifier.getIdentifier(); } public String getNameAsIdentifier() { - return identifize(name); + return identifier.toCql(); } } diff --git a/spring-cassandra/src/test/java/org/springframework/cassandra/test/unit/core/cql/CqlIdentifierTest.java b/spring-cassandra/src/test/java/org/springframework/cassandra/test/unit/core/cql/CqlIdentifierTest.java new file mode 100644 index 000000000..8b404ec5e --- /dev/null +++ b/spring-cassandra/src/test/java/org/springframework/cassandra/test/unit/core/cql/CqlIdentifierTest.java @@ -0,0 +1,20 @@ +package org.springframework.cassandra.test.unit.core.cql; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.springframework.cassandra.core.CqlIdentifier.isQuotedIdentifier; +import static org.springframework.cassandra.core.CqlIdentifier.isUnquotedIdentifier; + +import org.junit.Test; + +public class CqlIdentifierTest { + + @Test + public void testIsQuotedIdentifier() throws Exception { + assertFalse(isQuotedIdentifier("my\"id")); + assertTrue(isQuotedIdentifier("my\"\"id")); + assertFalse(isUnquotedIdentifier("my\"id")); + assertTrue(isUnquotedIdentifier("myid")); + } + +} diff --git a/spring-cassandra/src/test/java/org/springframework/cassandra/test/unit/core/cql/CqlStringUtilsTest.java b/spring-cassandra/src/test/java/org/springframework/cassandra/test/unit/core/cql/CqlStringUtilsTest.java index e54d7b29b..9da6874a5 100644 --- a/spring-cassandra/src/test/java/org/springframework/cassandra/test/unit/core/cql/CqlStringUtilsTest.java +++ b/spring-cassandra/src/test/java/org/springframework/cassandra/test/unit/core/cql/CqlStringUtilsTest.java @@ -1,18 +1,5 @@ package org.springframework.cassandra.test.unit.core.cql; -import static org.junit.Assert.*; -import static org.springframework.cassandra.core.cql.CqlStringUtils.isQuotedIdentifier; -import static org.springframework.cassandra.core.cql.CqlStringUtils.isUnquotedIdentifier; - -import org.junit.Test; public class CqlStringUtilsTest { - - @Test - public void testIsQuotedIdentifier() throws Exception { - assertFalse(isQuotedIdentifier("my\"id")); - assertTrue(isQuotedIdentifier("my\"\"id")); - assertFalse(isUnquotedIdentifier("my\"id")); - assertTrue(isUnquotedIdentifier("myid")); - } } diff --git a/spring-cassandra/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/AlterTableCqlGeneratorTests.java b/spring-cassandra/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/AlterTableCqlGeneratorTests.java index e281fdaa7..e1b3fe86e 100644 --- a/spring-cassandra/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/AlterTableCqlGeneratorTests.java +++ b/spring-cassandra/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/AlterTableCqlGeneratorTests.java @@ -26,6 +26,7 @@ public class AlterTableCqlGeneratorTests { * Asserts that the preamble is first & correctly formatted in the given CQL string. */ public static void assertPreamble(String tableName, String cql) { + System.out.println("cql: " + cql); assertTrue(cql.startsWith("ALTER TABLE " + tableName + " ")); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentEntity.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentEntity.java index a1b52dd25..863e8f838 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentEntity.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentEntity.java @@ -27,7 +27,6 @@ import org.springframework.context.expression.BeanFactoryResolver; import org.springframework.data.cassandra.util.CassandraNamingUtils; import org.springframework.data.mapping.Association; import org.springframework.data.mapping.AssociationHandler; -import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PropertyHandler; import org.springframework.data.mapping.model.BasicPersistentEntity; import org.springframework.data.util.TypeInformation; diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/mapping/BasicCassandraPersistentEntityIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/mapping/BasicCassandraPersistentEntityIntegrationTests.java index 306351a00..a59e06da6 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/mapping/BasicCassandraPersistentEntityIntegrationTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/mapping/BasicCassandraPersistentEntityIntegrationTests.java @@ -19,8 +19,6 @@ import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.when; -import org.cassandraunit.utils.EmbeddedCassandraServerHelper; -import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/template/CassandraDataOperationsTest.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/template/CassandraDataOperationsTest.java index 047545bc8..7b8ca6c36 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/template/CassandraDataOperationsTest.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/template/CassandraDataOperationsTest.java @@ -16,7 +16,6 @@ package org.springframework.data.cassandra.test.integration.template; import static org.springframework.cassandra.core.keyspace.CreateKeyspaceSpecification.createKeyspace; -import static org.springframework.cassandra.core.keyspace.DropTableSpecification.dropTable; import java.io.IOException; import java.util.ArrayList; @@ -24,30 +23,22 @@ import java.util.Arrays; import java.util.List; import java.util.UUID; -import org.apache.commons.io.FileUtils; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cassandra.core.ConsistencyLevel; import org.springframework.cassandra.core.QueryOptions; import org.springframework.cassandra.core.RetryPolicy; import org.springframework.cassandra.core.keyspace.CreateKeyspaceSpecification; import org.springframework.context.annotation.Configuration; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; import org.springframework.data.cassandra.config.SchemaAction; -import org.springframework.data.cassandra.core.CassandraOperations; import org.springframework.data.cassandra.test.integration.simpletons.Book; import org.springframework.data.cassandra.test.integration.support.AbstractSpringDataEmbeddedCassandraIntegrationTest; import org.springframework.data.cassandra.test.integration.support.TestConfig; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import com.datastax.driver.core.TableMetadata; import com.datastax.driver.core.querybuilder.QueryBuilder; import com.datastax.driver.core.querybuilder.Select; From 5449d0c2769107889e5478b93b2e4f6d40df967f Mon Sep 17 00:00:00 2001 From: john-mcpeek Date: Tue, 11 Feb 2014 22:38:22 -0500 Subject: [PATCH 10/13] The getIdentifier() (now getName()) method was calling toCql(), now it just returns the internal variable. Changed the member variable from identifier to name. This makes if match the way it is used in the code. --- .../cassandra/core/CqlIdentifier.java | 28 +++++++++---------- .../keyspace/ColumnChangeSpecification.java | 2 +- .../core/keyspace/ColumnSpecification.java | 2 +- .../keyspace/CreateIndexSpecification.java | 2 +- .../core/keyspace/IndexNameSpecification.java | 2 +- .../keyspace/KeyspaceActionSpecification.java | 2 +- .../core/keyspace/TableNameSpecification.java | 2 +- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/core/CqlIdentifier.java b/spring-cassandra/src/main/java/org/springframework/cassandra/core/CqlIdentifier.java index 3b3b17e97..5a0cb22d4 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/core/CqlIdentifier.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/core/CqlIdentifier.java @@ -10,7 +10,7 @@ public class CqlIdentifier { public static final String QUOTED_IDENTIFIER_REGEX = "[a-zA-Z_]([a-zA-Z0-9_]|\"{2}+)*"; public static final Pattern QUOTED_IDENTIFIER_PATTERN = Pattern.compile(QUOTED_IDENTIFIER_REGEX); - private String identifier; + private String name; private boolean quoted; public CqlIdentifier(String identifier) { @@ -26,19 +26,19 @@ public class CqlIdentifier { *
  • If the given identifier is illegal, an {@link IllegalArgumentException} is thrown.
  • * */ - public CqlIdentifier(String identifier, boolean forceQuoting) { - if (isUnquotedIdentifier(identifier) && forceQuoting == false) { - this.identifier = identifier; - } else if (isQuotedIdentifier(identifier)) { - this.identifier = identifier; + public CqlIdentifier(String name, boolean forceQuoting) { + if (isUnquotedIdentifier(name) && forceQuoting == false) { + this.name = name; + } else if (isQuotedIdentifier(name)) { + this.name = name; quoted = true; } else { - throw new IllegalArgumentException("[" + identifier + "] is not a valid CQL quoted or unquoted identifier"); + throw new IllegalArgumentException("[" + name + "] is not a valid CQL quoted or unquoted identifier"); } } public String toCql() { - String id = quoted ? CqlStringUtils.doubleQuote(identifier) : identifier; + String id = quoted ? CqlStringUtils.doubleQuote(name) : name; return id; } @@ -51,8 +51,8 @@ public class CqlIdentifier { return toCql(); } - public String getIdentifier() { - return toCql(); + public String getName() { + return name; } public boolean isQuoted() { @@ -85,7 +85,7 @@ public class CqlIdentifier { public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + ((identifier == null) ? 0 : identifier.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + (quoted ? 1231 : 1237); return result; } @@ -99,10 +99,10 @@ public class CqlIdentifier { if (getClass() != obj.getClass()) return false; CqlIdentifier other = (CqlIdentifier) obj; - if (identifier == null) { - if (other.identifier != null) + if (name == null) { + if (other.name != null) return false; - } else if (!identifier.equals(other.identifier)) + } else if (!name.equals(other.name)) return false; if (quoted != other.quoted) return false; diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/ColumnChangeSpecification.java b/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/ColumnChangeSpecification.java index 665a52797..0cdc23ee1 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/ColumnChangeSpecification.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/ColumnChangeSpecification.java @@ -35,7 +35,7 @@ public abstract class ColumnChangeSpecification { } public String getName() { - return identifier.getIdentifier(); + return identifier.getName(); } public String getNameAsIdentifier() { diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/ColumnSpecification.java b/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/ColumnSpecification.java index aa6e491e0..ca8a2eec3 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/ColumnSpecification.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/ColumnSpecification.java @@ -146,7 +146,7 @@ public class ColumnSpecification { } public String getName() { - return identifier.getIdentifier(); + return identifier.getName(); } public String getNameAsIdentifier() { diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/CreateIndexSpecification.java b/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/CreateIndexSpecification.java index bd782b1f3..5744e5c1a 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/CreateIndexSpecification.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/CreateIndexSpecification.java @@ -92,7 +92,7 @@ public class CreateIndexSpecification extends IndexNameSpecification } public String getName() { - return identifier.getIdentifier(); + return identifier.getName(); } public String getNameAsIdentifier() { diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/KeyspaceActionSpecification.java b/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/KeyspaceActionSpecification.java index 83c6db79e..f8fd83af7 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/KeyspaceActionSpecification.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/core/keyspace/KeyspaceActionSpecification.java @@ -28,7 +28,7 @@ public abstract class KeyspaceActionSpecification } public String getName() { - return identifier.getIdentifier(); + return identifier.getName(); } public String getNameAsIdentifier() { From 863b7d87917060e8dd323512a2fcc1dcd9eb7ae0 Mon Sep 17 00:00:00 2001 From: john-mcpeek Date: Wed, 12 Feb 2014 08:10:37 -0500 Subject: [PATCH 11/13] Added class level comment. --- .../org/springframework/cassandra/core/CqlIdentifier.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/core/CqlIdentifier.java b/spring-cassandra/src/main/java/org/springframework/cassandra/core/CqlIdentifier.java index 5a0cb22d4..9371948ab 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/core/CqlIdentifier.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/core/CqlIdentifier.java @@ -4,6 +4,12 @@ import java.util.regex.Pattern; import org.springframework.cassandra.core.cql.CqlStringUtils; +/** + * This encapsulates the logic for CQL identifiers. + * + * @author John McPeek + * + */ public class CqlIdentifier { public static final String UNQUOTED_IDENTIFIER_REGEX = "[a-zA-Z_][a-zA-Z0-9_]*"; public static final Pattern UNQUOTED_IDENTIFIER_PATTERN = Pattern.compile(UNQUOTED_IDENTIFIER_REGEX); From eb68f6f5558fd6be5acf464ae383249aab6225b4 Mon Sep 17 00:00:00 2001 From: Matthew Adams Date: Wed, 12 Feb 2014 18:32:08 -0600 Subject: [PATCH 12/13] DATACASS-91 - now defaulting mapping context, converter, & template if not defined in XML --- .../config/BeanDefinitionBuilderArgument.java | 65 ++++++ .../cassandra/config/BeanDefinitionUtils.java | 144 ++++++++++++++ ...sandraMappingBeanFactoryPostProcessor.java | 188 ++++++++++++++++++ .../config/DefaultDataBeanNames.java | 2 +- .../xml/CassandraDataClusterParser.java | 11 + .../xml/CassandraDataSessionParser.java | 11 +- .../xml/CassandraDataTemplateParser.java | 3 + .../xml/CassandraMappingContextParser.java | 7 +- .../xml/CassandraMappingConverterParser.java | 6 +- ...gXmlBeanFactoryPostProcessorRegistrar.java | 44 ++++ .../mapping/CassandraMappingContext.java | 16 +- .../DefaultCassandraMappingContext.java | 19 ++ .../MappingContextIntegrationTests.java | 30 ++- ...soluteMinimumXmlConfigIntegrationTest.java | 28 +++ .../minimal/config/entities/AbsMin.java | 12 ++ .../config/entities/AbsMinRepository.java | 6 + ...inimumXmlConfigIntegrationTest-context.xml | 22 ++ 17 files changed, 605 insertions(+), 9 deletions(-) create mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/BeanDefinitionBuilderArgument.java create mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/BeanDefinitionUtils.java create mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingBeanFactoryPostProcessor.java create mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingXmlBeanFactoryPostProcessorRegistrar.java create mode 100644 spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/minimal/config/AbsoluteMinimumXmlConfigIntegrationTest.java create mode 100644 spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/minimal/config/entities/AbsMin.java create mode 100644 spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/minimal/config/entities/AbsMinRepository.java create mode 100644 spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/minimal/config/AbsoluteMinimumXmlConfigIntegrationTest-context.xml diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/BeanDefinitionBuilderArgument.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/BeanDefinitionBuilderArgument.java new file mode 100644 index 000000000..fa72ff549 --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/BeanDefinitionBuilderArgument.java @@ -0,0 +1,65 @@ +package org.springframework.data.cassandra.config; + +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.util.StringUtils; + +/** + * Parameter used in conjunction with: + *

    + * {@link BeanDefinitionBuilder#addConstructorArgReference(String)}, + * {@link BeanDefinitionBuilder#addConstructorArgValue(Object)}, + * {@link BeanDefinitionBuilder#addPropertyReference(String, String)}, and + * {@link BeanDefinitionBuilder#addPropertyValue(String, Object)}. + *

    + * Easy and succinct to create if methods {@link #ref(CharSequence)} or {@link #val(Object)} are used and imported + * statically. + * + * @see BeanDefinitionBuilderArgument#ref(CharSequence) + * @see BeanDefinitionBuilderArgument#val(Object) + */ +public class BeanDefinitionBuilderArgument { + + /** + * Returns a {@link BeanDefinitionBuilderArgument} with {@link #reference} equal to true. Convenient if + * imported statically. + * + * @param value The name of the bean reference. + */ + public static BeanDefinitionBuilderArgument ref(CharSequence value) { + return new BeanDefinitionBuilderArgument(true, value); + } + + /** + * Returns a {@link BeanDefinitionBuilderArgument} with {@link #reference} equal to false. Convenient if + * imported statically. + * + * @param value The constructor argument's value. + */ + public static BeanDefinitionBuilderArgument val(Object value) { + return new BeanDefinitionBuilderArgument(false, value); + } + + protected boolean reference; + protected Object value; + + protected BeanDefinitionBuilderArgument(boolean reference, Object value) { + this.reference = reference; + if (this.reference && (value == null || !(value instanceof CharSequence))) { + throw new IllegalArgumentException(String.format( + "reference argument must have value of type CharSequence, not [%s]", value == null ? "null" : value + .getClass().getName())); + } + if (!StringUtils.hasText((CharSequence) value)) { + throw new IllegalArgumentException("given CharSequence has no text"); + } + this.value = value; + } + + public boolean isReference() { + return reference; + } + + public Object getValue() { + return value; + } +} \ No newline at end of file diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/BeanDefinitionUtils.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/BeanDefinitionUtils.java new file mode 100644 index 000000000..666c5beb5 --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/BeanDefinitionUtils.java @@ -0,0 +1,144 @@ +package org.springframework.data.cassandra.config; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryUtils; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.util.StringUtils; + +public class BeanDefinitionUtils { + + /** + * Returns a {@link BeanDefinitionBuilder} iff no {@link BeanDefinition} of the required type is found in the given + * {@link ListableBeanFactory}, otherwise returns null, indicating that at least one existed. + * + * @param factory The {@link ListableBeanFactory} in which to look for the {@link BeanDefinition}, including + * ancestors. + * @param requiredType The {@link BeanDefinition}'s required type. + * @param instantiableType The instantiable type for the {@link BeanDefinitionBuilder}. + * @param constructorArgs Any {@link BeanDefinitionBuilderArgument}s required by the instantiableType's constructor. + * @return A {@link BeanDefinitionBuilder} iff no {@link BeanDefinition} of the required type is found, otherwise + * null. + * @see BeanDefinitionUtils#createBeanDefinitionBuilderIfNoBeanDefinitionOfTypeExists(ListableBeanFactory, Class, + * Class, BeanDefinitionBuilderArgument...) + * @see BeanDefinitionBuilderArgument#ref(Object) + * @see BeanDefinitionBuilderArgument#val(Object) + */ + public static BeanDefinitionBuilder createBeanDefinitionBuilderIfNoBeanDefinitionOfTypeExists( + ListableBeanFactory factory, Class requiredType, Class instantiableType, + BeanDefinitionBuilderArgument... constructorArgs) { + + String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(factory, requiredType, true, false); + if (names.length > 0) { + return null; + } + + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(instantiableType); + if (constructorArgs == null) { + return builder; + } + + for (BeanDefinitionBuilderArgument arg : constructorArgs) { + if (arg.reference) { + builder.addConstructorArgReference(arg.value.toString()); + } else { + builder.addConstructorArgValue(arg.value); + } + } + + return builder; + } + + /** + * Returns the single {@link BeanDefinitionHolder} with the given type, or null of none were found and + * required was false, otherwise throws {@link IllegalArgumentException}. + * + * @param registry The {@link BeanDefinitionRegistry}, often the very same instance as the factor + * parameter. + * @param factory The {@link ListableBeanFactory}, often the very same instance as the registry + * parameter. + * @param type The required {@link BeanDefinition}'s type. + * @param includeNonSingletons Whether to include beans with scope other than singleton + * @param allowEagerInit Whether to allow eager initialization of beans. + * @param required Whether to allow the return of null if none were found. + * @return The {@link BeanDefinitionHolder} or null if none found, depending on the value of required. + * @throws IllegalArgumentException If multiple were found. + * @see BeanFactoryUtils#beanNamesForTypeIncludingAncestors(ListableBeanFactory, Class, boolean, boolean) + */ + public static BeanDefinitionHolder getSingleBeanDefinitionOfType(BeanDefinitionRegistry registry, + ListableBeanFactory factory, Class type, boolean includeNonSingletons, boolean allowEagerInit, boolean required) { + + BeanDefinitionHolder[] definitions = getBeanDefinitionsOfType(registry, factory, type, includeNonSingletons, + allowEagerInit); + + if (definitions.length == 1) { + return definitions[0]; + } + + if (definitions.length == 0 && !required) { + return null; + } + + String[] names = new String[definitions.length]; + for (int i = 0; i < names.length; i++) { + names[i] = definitions[i].getBeanName(); + } + + throw new IllegalStateException(String.format("expected one bean definition of type [%s], but found %d: %s", + type.getName(), definitions.length, StringUtils.arrayToCommaDelimitedString(names))); + } + + /** + * Returns all {@link BeanDefinitionHolder}s with the given type. + * + * @param registry The {@link BeanDefinitionRegistry}, often the very same instance as the factor + * parameter. + * @param factory The {@link ListableBeanFactory}, often the very same instance as the registry + * parameter. + * @param type The required {@link BeanDefinition}'s type. + * @param includeNonSingletons Whether to include beans with scope other than singleton + * @param allowEagerInit Whether to allow eager initialization of beans. + * @param required Whether to allow the return of null if none were found. + * @return The {@link BeanDefinitionHolder}s -- never returns null. + * @see BeanFactoryUtils#beanNamesForTypeIncludingAncestors(ListableBeanFactory, Class, boolean, boolean) + */ + public static BeanDefinitionHolder[] getBeanDefinitionsOfType(BeanDefinitionRegistry registry, + ListableBeanFactory factory, Class type, boolean includeNonSingletons, boolean allowEagerInit) { + + String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(factory, type, includeNonSingletons, + allowEagerInit); + + if (names.length == 0) { + return new BeanDefinitionHolder[] {}; + } + + BeanDefinitionHolder[] array = new BeanDefinitionHolder[names.length]; + + for (int i = 0; i < names.length; i++) { + + String name = names[i]; + BeanDefinition beanDefinition = null; + + while (beanDefinition == null) { + try { + beanDefinition = registry.getBeanDefinition(name); + } catch (NoSuchBeanDefinitionException x) { + if (FactoryBean.class.isAssignableFrom(type)) { // try unmangled BeanFactory-prefixed name + name = name.substring(BeanFactory.FACTORY_BEAN_PREFIX.length()); + } else { + throw x; + } + } + } + + array[i] = new BeanDefinitionHolder(beanDefinition, name); + } + + return array; + } +} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingBeanFactoryPostProcessor.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingBeanFactoryPostProcessor.java new file mode 100644 index 000000000..7b12fbb3e --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingBeanFactoryPostProcessor.java @@ -0,0 +1,188 @@ +package org.springframework.data.cassandra.config; + +import static org.springframework.data.cassandra.config.BeanDefinitionUtils.getBeanDefinitionsOfType; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; +import org.springframework.data.cassandra.convert.CassandraConverter; +import org.springframework.data.cassandra.convert.MappingCassandraConverter; +import org.springframework.data.cassandra.core.CassandraOperations; +import org.springframework.data.cassandra.core.CassandraTemplate; +import org.springframework.data.cassandra.mapping.CassandraMappingContext; +import org.springframework.data.cassandra.mapping.DefaultCassandraMappingContext; +import org.springframework.util.StringUtils; + +import com.datastax.driver.core.Session; + +/** + * {@link BeanDefinitionRegistryPostProcessor} that does its best to register any missing Spring Data Cassandra beans + * that can be defaulted. Specifically, it attempts to create default bean definitions for the following required + * interface types via their default implementation types: + *

      + *
    • {@link CassandraOperations} via {@link CassandraTemplate}
    • + *
    • {@link CassandraMappingContext} via {@link DefaultCassandraMappingContext}
    • + *
    • {@link CassandraConverter} via {@link MappingCassandraConverter}
    • + *
    + *

    + * If there are multiple definitions for any type that another type depends on, an {@link IllegalStateException} is + * thrown. For example, if there are two definitions for type {@link CassandraMappingContext} present and no definition + * for type {@link CassandraConverter}, then it's impossible to know which {@link CassandraMappingContext} is to be used + * when creating a default definition for the {@link CassandraConverter}. + *

    + * If a single definition of a required type is present, then it is used. For example, if there is already a + * {@link CassandraMappingContext} definition present, then it will be used in the + * {@link DefaultCassandraMappingContext} bean definition. + *

    + * It requires that a single {@link Session} or {@link CassandraDataSessionFactoryBean} definition be present. As + * described above, multiple {@link Session} definitions, multiple {@link CassandraDataSessionFactoryBean} definitions, + * or both a {@link Session} and {@link CassandraDataSessionFactoryBean} will cause an {@link IllegalStateException} to + * be thrown. + * + * @author Matthew T. Adams + */ +public class CassandraMappingBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor { + + /** + * Does nothing. + */ + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + } + + /** + * Ensures that {@link BeanDefinition}s for a {@link CassandraMappingContext} and a {@link CassandraConverter} exist. + */ + @Override + public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { + + if (!(registry instanceof ListableBeanFactory)) { + return; + } + ListableBeanFactory factory = (ListableBeanFactory) registry; + + registerMissingDefaultableBeanDefinitions(registry, factory); + } + + protected void registerMissingDefaultableBeanDefinitions(BeanDefinitionRegistry registry, ListableBeanFactory factory) { + + // see if any template definitions exist, which requires a converter, which requires a mapping context + BeanDefinitionHolder[] templateBeans = getBeanDefinitionsOfType(registry, factory, CassandraOperations.class, true, + false); + + if (templateBeans.length >= 1) { + return; + } + + // need a session & converter for the default template + + // see if an actual Session definition exists + String sessionBeanName = findSessionBeanName(registry, factory); + + // see if any converter bean definitions exist, which requires a mapping context + BeanDefinitionHolder[] converterBeans = getBeanDefinitionsOfType(registry, factory, + MappingCassandraConverter.class, true, false); + + if (converterBeans.length == 1) { + + registerDefaultTemplate(registry, sessionBeanName, converterBeans[0].getBeanName()); + return; + } else if (converterBeans.length > 1) { + // then throw, because we need to create a default converter, but we wouldn't know which mapping context to use + throw new IllegalStateException(String.format( + "found %d beans of type [%s] - can't disambiguate for creation of [%s]", converterBeans.length, + CassandraConverter.class.getName(), CassandraTemplate.class.getName())); + } + + // see if any mapping context bean definitions exist + BeanDefinitionHolder[] contextBeans = getBeanDefinitionsOfType(registry, factory, CassandraMappingContext.class, + true, false); + + if (contextBeans.length > 1) { + // then throw, because we need to create a default converter, but we wouldn't know which mapping context to use + throw new IllegalStateException(String.format( + "found %d beans of type [%s] - can't disambiguate for creation of [%s]", contextBeans.length, + CassandraMappingContext.class.getName(), MappingCassandraConverter.class.getName())); + } + + // create the mapping context if necessary + BeanDefinitionHolder contextBean = contextBeans.length == 1 ? contextBeans[0] : null; + if (contextBean == null) { + contextBean = regsiterDefaultContext(registry); + } + + // create the default converter & template bean definitions + BeanDefinitionHolder converter = registerDefaultConverter(registry, contextBean.getBeanName()); + registerDefaultTemplate(registry, sessionBeanName, converter.getBeanName()); + } + + public String findSessionBeanName(BeanDefinitionRegistry registry, ListableBeanFactory factory) { + + // first, search for any session and session factory beans + BeanDefinitionHolder[] sessionBeans = getBeanDefinitionsOfType(registry, factory, Session.class, true, false); + BeanDefinitionHolder[] sessionFactoryBeans = getBeanDefinitionsOfType(registry, factory, + CassandraDataSessionFactoryBean.class, true, false); + + int sessionCount = sessionBeans.length; + int sessionFactoryCount = sessionFactoryBeans.length; + int totalCount = sessionCount + sessionFactoryCount; + + if (totalCount == 0 || totalCount > 1) { // can't create default template -- none or multiple + throw createSessionException(totalCount, Session.class, CassandraDataSessionFactoryBean.class); + } + + if (sessionCount == 1) { + return sessionBeans[0].getBeanName(); + } + // else it must be the one session factory bean + return sessionFactoryBeans[0].getBeanName(); + } + + protected IllegalStateException createSessionException(int beanDefinitionCount, Class... types) { + + return new IllegalStateException(String.format("found %d beans of type%s [%s] - %s for creation of default [%s]", + beanDefinitionCount, beanDefinitionCount == 1 ? "" : "s", StringUtils.arrayToCommaDelimitedString(types), + beanDefinitionCount == 0 ? "need exactly one" : "can't disambiguate", CassandraTemplate.class.getName())); + } + + protected BeanDefinitionHolder regsiterDefaultContext(BeanDefinitionRegistry registry) { + + BeanDefinitionHolder contextBean = new BeanDefinitionHolder(BeanDefinitionBuilder.genericBeanDefinition( + DefaultCassandraMappingContext.class).getBeanDefinition(), DefaultDataBeanNames.CONTEXT); + + registry.registerBeanDefinition(contextBean.getBeanName(), contextBean.getBeanDefinition()); + + return contextBean; + } + + public BeanDefinitionHolder registerDefaultConverter(BeanDefinitionRegistry registry, String contextBeanName) { + + BeanDefinitionBuilder converterBeanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition( + MappingCassandraConverter.class).addConstructorArgReference(contextBeanName); + BeanDefinitionHolder beanDefinition = new BeanDefinitionHolder(converterBeanDefinitionBuilder.getBeanDefinition(), + DefaultDataBeanNames.CONVERTER); + + registry.registerBeanDefinition(beanDefinition.getBeanName(), beanDefinition.getBeanDefinition()); + + return beanDefinition; + } + + public BeanDefinitionHolder registerDefaultTemplate(BeanDefinitionRegistry registry, String sessionBeanName, + String converterBeanName) { + + BeanDefinitionBuilder templateBeanDefinitionBuilder = BeanDefinitionBuilder + .genericBeanDefinition(CassandraTemplate.class).addConstructorArgReference(sessionBeanName) + .addConstructorArgReference(converterBeanName); + BeanDefinition beanDefinition = templateBeanDefinitionBuilder.getBeanDefinition(); + + BeanDefinitionHolder template = new BeanDefinitionHolder(beanDefinition, DefaultDataBeanNames.TEMPLATE); + registry.registerBeanDefinition(template.getBeanName(), template.getBeanDefinition()); + + return template; + } +} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/DefaultDataBeanNames.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/DefaultDataBeanNames.java index c91114d88..959c0623b 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/DefaultDataBeanNames.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/DefaultDataBeanNames.java @@ -6,5 +6,5 @@ public interface DefaultDataBeanNames extends DefaultBeanNames { public static final String DATA_TEMPLATE = "cassandraTemplate"; public static final String CONVERTER = "cassandraConverter"; - public static final String MAPPING_CONTEXT = "cassandraMapping"; + public static final String CONTEXT = "cassandraMapping"; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataClusterParser.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataClusterParser.java index e2d3dc43f..856057ed1 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataClusterParser.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataClusterParser.java @@ -1,6 +1,9 @@ package org.springframework.data.cassandra.config.xml; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.xml.ParserContext; import org.springframework.cassandra.config.xml.CassandraClusterParser; +import org.w3c.dom.Element; /** * Spring Data Cassandra XML namespace parser for the <cluster> element. @@ -8,4 +11,12 @@ import org.springframework.cassandra.config.xml.CassandraClusterParser; * @author Matthew T. Adams */ public class CassandraDataClusterParser extends CassandraClusterParser { + + @Override + protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { + + CassandraMappingXmlBeanFactoryPostProcessorRegistrar.ensureRegistration(element, parserContext); + + return super.parseInternal(element, parserContext); + } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataSessionParser.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataSessionParser.java index e850bb07b..8e80f39ce 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataSessionParser.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataSessionParser.java @@ -3,6 +3,7 @@ package org.springframework.data.cassandra.config.xml; import static org.springframework.cassandra.config.xml.ParsingUtils.addOptionalPropertyReference; import static org.springframework.cassandra.config.xml.ParsingUtils.addOptionalPropertyValue; import static org.springframework.cassandra.config.xml.ParsingUtils.addRequiredPropertyReference; +import static org.springframework.cassandra.config.xml.ParsingUtils.addRequiredPropertyValue; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.ParserContext; @@ -25,6 +26,14 @@ public class CassandraDataSessionParser extends CassandraSessionParser { return CassandraDataSessionFactoryBean.class; } + @Override + protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + + super.doParse(element, parserContext, builder); + + CassandraMappingXmlBeanFactoryPostProcessorRegistrar.ensureRegistration(element, parserContext); + } + @Override protected void parseUnhandledSessionElementAttribute(Attr attribute, ParserContext parserContext, BeanDefinitionBuilder builder) { @@ -45,7 +54,7 @@ public class CassandraDataSessionParser extends CassandraSessionParser { super.setDefaultProperties(builder); + addRequiredPropertyValue(builder, "schemaAction", SchemaAction.NONE.name()); addRequiredPropertyReference(builder, "converter", DefaultDataBeanNames.CONVERTER); - addRequiredPropertyReference(builder, "schemaAction", SchemaAction.NONE.name()); } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataTemplateParser.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataTemplateParser.java index 13251df72..893086ec1 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataTemplateParser.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataTemplateParser.java @@ -32,6 +32,9 @@ public class CassandraDataTemplateParser extends CassandraTemplateParser { @Override protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + + CassandraMappingXmlBeanFactoryPostProcessorRegistrar.ensureRegistration(element, parserContext); + super.doParse(element, parserContext, builder); parseConverterAttribute(element, parserContext, builder); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingContextParser.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingContextParser.java index 6565af3ee..1c4d482d6 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingContextParser.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingContextParser.java @@ -33,11 +33,14 @@ public class CassandraMappingContextParser extends AbstractSingleBeanDefinitionP throws BeanDefinitionStoreException { String id = super.resolveId(element, definition, parserContext); - return StringUtils.hasText(id) ? id : DefaultDataBeanNames.MAPPING_CONTEXT; + return StringUtils.hasText(id) ? id : DefaultDataBeanNames.CONTEXT; } @Override - protected void doParse(Element element, BeanDefinitionBuilder builder) { + protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + + CassandraMappingXmlBeanFactoryPostProcessorRegistrar.ensureRegistration(element, parserContext); + parseMapping(element, builder); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingConverterParser.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingConverterParser.java index 8f75493f9..5dd2a6c81 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingConverterParser.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingConverterParser.java @@ -31,11 +31,13 @@ public class CassandraMappingConverterParser extends AbstractSingleBeanDefinitio } @Override - protected void doParse(Element element, BeanDefinitionBuilder builder) { + protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + + CassandraMappingXmlBeanFactoryPostProcessorRegistrar.ensureRegistration(element, parserContext); String mappingRef = element.getAttribute("mapping-ref"); if (!StringUtils.hasText(mappingRef)) { - mappingRef = DefaultDataBeanNames.MAPPING_CONTEXT; + mappingRef = DefaultDataBeanNames.CONTEXT; } builder.addConstructorArgReference(mappingRef); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingXmlBeanFactoryPostProcessorRegistrar.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingXmlBeanFactoryPostProcessorRegistrar.java new file mode 100644 index 000000000..b7499c34e --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingXmlBeanFactoryPostProcessorRegistrar.java @@ -0,0 +1,44 @@ +package org.springframework.data.cassandra.config.xml; + +import org.springframework.beans.factory.BeanFactoryUtils; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.data.cassandra.config.CassandraMappingBeanFactoryPostProcessor; +import org.springframework.data.config.BeanComponentDefinitionBuilder; +import org.w3c.dom.Element; + +/** + * Ensures that a {@link CassandraMappingBeanFactoryPostProcessor} is registered. + * + * @author Matthew T. Adams + */ +public class CassandraMappingXmlBeanFactoryPostProcessorRegistrar { + + /** + * Ensures that a {@link CassandraMappingBeanFactoryPostProcessor} is registered. This method is a no-op if one is + * already registered. + */ + public static void ensureRegistration(Element element, ParserContext parserContext) { + + BeanDefinitionRegistry registry = parserContext.getRegistry(); + if (!(registry instanceof GenericApplicationContext)) { + return; + } + ConfigurableListableBeanFactory factory = ((GenericApplicationContext) registry).getBeanFactory(); + + String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(factory, + CassandraMappingBeanFactoryPostProcessor.class, true, false); + if (names.length > 0) { + return; + } + + BeanComponentDefinitionBuilder componentBuilder = new BeanComponentDefinitionBuilder(element, parserContext); + BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder + .genericBeanDefinition(CassandraMappingBeanFactoryPostProcessor.class); + + parserContext.registerBeanComponent(componentBuilder.getComponent(definitionBuilder)); + } +} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraMappingContext.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraMappingContext.java index 9d712931d..06bf6fe15 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraMappingContext.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraMappingContext.java @@ -4,7 +4,6 @@ import java.util.Collection; import org.springframework.cassandra.core.keyspace.CreateTableSpecification; import org.springframework.data.mapping.context.MappingContext; -import org.springframework.data.util.TypeInformation; import com.datastax.driver.core.TableMetadata; @@ -57,4 +56,19 @@ public interface CassandraMappingContext extends * @param table May not be null. */ boolean usesTable(TableMetadata table); + + /** + * Returns the existing {@link CassandraPersistentEntity} for the given {@link Class}. If it is not yet known to this + * {@link CassandraMappingContext}, an {@link IllegalArgumentException} is thrown. + * + * @param type The class of the existing persistent entity. + * @return The existing persistent entity. + */ + CassandraPersistentEntity getExistingPersistentEntity(Class type); + + /** + * Returns whether this {@link CassandraMappingContext} already contains a {@link CassandraPersistentEntity} for the + * given type. + */ + boolean contains(Class type); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/DefaultCassandraMappingContext.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/DefaultCassandraMappingContext.java index 8f860b505..ff7747400 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/DefaultCassandraMappingContext.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/DefaultCassandraMappingContext.java @@ -61,6 +61,7 @@ public class DefaultCassandraMappingContext extends protected Map>> entitySetsByTableName = new HashMap>>(); protected Set> nonPrimaryKeyEntities = new HashSet>(); protected Set> primaryKeyEntities = new HashSet>(); + protected Map, CassandraPersistentEntity> entitiesByType = new HashMap, CassandraPersistentEntity>(); /** * Creates a new {@link DefaultCassandraMappingContext}. @@ -137,6 +138,8 @@ public class DefaultCassandraMappingContext extends nonPrimaryKeyEntities.add(entity); } + entitiesByType.put(entity.getType(), entity); + return entity; } @@ -243,4 +246,20 @@ public class DefaultCassandraMappingContext extends public void setBeanClassLoader(ClassLoader beanClassLoader) { this.beanClassLoader = beanClassLoader; } + + @Override + public CassandraPersistentEntity getExistingPersistentEntity(Class type) { + + CassandraPersistentEntity entity = entitiesByType.get(type); + if (entity != null) { + return entity; + } + + throw new IllegalArgumentException(String.format("unknown persistent type [%s]", type.getName())); + } + + @Override + public boolean contains(Class type) { + return entitiesByType.containsKey(type); + } } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/mappingcontext/MappingContextIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/mappingcontext/MappingContextIntegrationTests.java index 95a372c9f..11ab552b4 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/mappingcontext/MappingContextIntegrationTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/mappingcontext/MappingContextIntegrationTests.java @@ -1,28 +1,54 @@ package org.springframework.data.cassandra.test.integration.mappingcontext; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import org.junit.Test; import org.springframework.data.cassandra.mapping.CassandraPersistentEntity; import org.springframework.data.cassandra.mapping.DefaultCassandraMappingContext; +import org.springframework.data.cassandra.mapping.PrimaryKey; +import org.springframework.data.cassandra.mapping.Table; public class MappingContextIntegrationTests { public static class Transient { } + @Table + public static class X { + @PrimaryKey + String key; + } + + @Table + public static class Y { + @PrimaryKey + String key; + } + + DefaultCassandraMappingContext ctx = new DefaultCassandraMappingContext(); + @Test // TODO: (expected = MappingException.class) public void testGetPersistentEntityOfTransientType() { // TODO: when entity verification is added (DATACASS-85), this should throw a MappingException - - DefaultCassandraMappingContext ctx = new DefaultCassandraMappingContext(); CassandraPersistentEntity entity = ctx.getPersistentEntity(Transient.class); // TODO: remove following lines after DATACASS-85 assertNotNull(entity); assertEquals(Transient.class.getSimpleName().toLowerCase(), entity.getTableName()); } + + @Test + public void testGetExistingPersistentEntityHappyPath() { + + ctx.getPersistentEntity(X.class); + + assertTrue(ctx.contains(X.class)); + assertNotNull(ctx.getExistingPersistentEntity(X.class)); + assertFalse(ctx.contains(Y.class)); + } } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/minimal/config/AbsoluteMinimumXmlConfigIntegrationTest.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/minimal/config/AbsoluteMinimumXmlConfigIntegrationTest.java new file mode 100644 index 000000000..eef313a63 --- /dev/null +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/minimal/config/AbsoluteMinimumXmlConfigIntegrationTest.java @@ -0,0 +1,28 @@ +package org.springframework.data.cassandra.test.integration.minimal.config; + +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.cassandra.mapping.CassandraMappingContext; +import org.springframework.data.cassandra.test.integration.minimal.config.entities.AbsMin; +import org.springframework.data.cassandra.test.integration.support.AbstractSpringDataEmbeddedCassandraIntegrationTest; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +public class AbsoluteMinimumXmlConfigIntegrationTest extends AbstractSpringDataEmbeddedCassandraIntegrationTest { + + @Autowired + CassandraMappingContext context; + + @Test + public void test() { + + assertNotNull(context); + + context.getPersistentEntity(AbsMin.class); + } +} diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/minimal/config/entities/AbsMin.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/minimal/config/entities/AbsMin.java new file mode 100644 index 000000000..cd49629c3 --- /dev/null +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/minimal/config/entities/AbsMin.java @@ -0,0 +1,12 @@ +package org.springframework.data.cassandra.test.integration.minimal.config.entities; + +import org.springframework.data.cassandra.mapping.PrimaryKey; +import org.springframework.data.cassandra.mapping.Table; + +@Table +public class AbsMin { + + @PrimaryKey + String key; + +} diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/minimal/config/entities/AbsMinRepository.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/minimal/config/entities/AbsMinRepository.java new file mode 100644 index 000000000..ffcb0fc2f --- /dev/null +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/minimal/config/entities/AbsMinRepository.java @@ -0,0 +1,6 @@ +package org.springframework.data.cassandra.test.integration.minimal.config.entities; + +import org.springframework.data.cassandra.repository.CassandraRepository; + +public interface AbsMinRepository extends CassandraRepository { +} diff --git a/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/minimal/config/AbsoluteMinimumXmlConfigIntegrationTest-context.xml b/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/minimal/config/AbsoluteMinimumXmlConfigIntegrationTest-context.xml new file mode 100644 index 000000000..7e2bc7eaa --- /dev/null +++ b/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/minimal/config/AbsoluteMinimumXmlConfigIntegrationTest-context.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + From d3a9d597b519d84a4e2b6cea224431b1777ecbab Mon Sep 17 00:00:00 2001 From: Matthew Adams Date: Wed, 12 Feb 2014 19:17:29 -0600 Subject: [PATCH 13/13] updated readme --- README.md | 91 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 78 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index d09c3699d..daba9a4f7 100644 --- a/README.md +++ b/README.md @@ -2,16 +2,19 @@ ## Quick Start -To begin working with ``spring-cassandra`` and ``spring-data-cassandra`` add the Spring Maven Repository to your ``pom.xml``. +To begin working with ``spring-cassandra`` or ``spring-data-cassandra``, add the Spring Maven Snapshot Repository to your ``pom.xml``. spring-libs-snapshot http://repo.spring.io/libs-snapshot + + true + -Then include the latest and greatest JAR into your project dependencies. +### CQL Only (spring-cassandra) -**CQL Only** +*Maven Coordinates* org.springframework.data @@ -19,7 +22,41 @@ Then include the latest and greatest JAR into your project dependencies. 1.0.0.BUILD-SNAPSHOT -**CQL and Object Mapping** +*Minimal Spring XML Configuration* + + + + + +*Minimal Spring JavaConfig* + + @Configuration + public class MyConfig extends AbstractSessionConfiguration { + + @Override + public String getKeyspaceName() { + return "sensors"; + } + + @Bean + public CqlOperations cqlTemplate() { + return new CqlTemplate(session.getObject()); + } + } + +*Application Class* + + public class SensorService { + + @Autowired + CqlOperations template; + + // ... + } + +### CQL and Object Mapping (spring-data-cassandra) + +*Maven Coordinates* org.springframework.data @@ -27,10 +64,39 @@ Then include the latest and greatest JAR into your project dependencies. 1.0.0.BUILD-SNAPSHOT +*Minimal Spring XML Configuration* + + + + + +*Minimal Spring JavaConfig* + + @Configuration + @EnableCassandraRepositories(basePackage = "org.example.domain") + public class MyConfig extends AbstractSpringDataCassandraConfiguration { + + @Override + public String getKeyspaceName() { + return "foobar"; + } + } + +*Application Class* + + public class SensorService { + + @Autowired + SensorRepository repo; + + // ... + } + + ## Release Preview The goal of this release preview is to publish the pieces of spring-data-cassandra as they become available -so that user's of the module can start to familiarize themselves with the components, and ultimately to provide +so that users of the module can start to familiarize themselves with the components, and ultimately to provide the development team feedback. We hope this iterative approach produces the most usable and developer friendly ``spring-data-cassandra`` repository. @@ -72,9 +138,9 @@ create more than one ``CqlTemplate`` (one per session, one session per keyspace) Here are some considerations when designing your application for use with ``spring-cassandra``. -* When creating a template, wire in a single ``Session`` per keyspace. _Remember, ``Session`` is threadsafe, so only use one session per keyspace!_ -* Cassandra's ``Session`` object is thread-safe, so you only need one per application & keyspace. -* Do not issue ``USE `` commands on your session; instead, _configure_ the keyspace name you intend to use. +* When creating a template, wire in a single ``Session`` per keyspace. +* ``Session`` is threadsafe, so only use one per keyspace per application context! +* __Do not issue__ ``USE `` __commands__ on your session; instead, _configure_ the keyspace name you intend to use. * The DataStax Java Driver handles all failover and retry logic for you. Become familiar with the [Driver Documentation](http://www.datastax.com/documentation/developer/java-driver/1.0/webhelp/index.html), which will help you configure your ``Cluster``. * If you are using a Cassandra ``Cluster`` spanning multiple data centers, please be insure to include hosts from all data centers in your contact points. @@ -84,7 +150,7 @@ We have included a variety of overloaded ``ingest()`` methods in ``CqlTemplate`` ### What's Next (early Q1 - 2014): Spring _Data_ Cassandra -The next round of work to do is to complete module ``spring-data-cassandra``, while taking feedback from the community's use of module ``spring-cassandra``. +The next round of work to do is to complete module ``spring-data-cassandra``, while taking feedback from the community's use of module ``spring-cassandra``. We are already well on our way to completion. #### Cassandra Repository @@ -101,7 +167,7 @@ This is another Spring template class to help you with all of your keyspace and #### Official Reference Guide -Once we have all the inner workings of the ``CassandraRepository`` interface completed, we will publish a full Reference Guide on using all of the features in ``spring-data-cassandra``. +Once we have all the inner workings of the ``CassandraRepository`` interface completed, we will publish a full reference guide on using all of the features in ``spring-data-cassandra``. ## CqlTemplate Examples @@ -163,9 +229,8 @@ following artifacts (or more recent versions thereof): * Datastax Java Driver 1.x * JDK 1.6+ -The GA release is expected as part of the as-yet unnamed fourth Spring -Data Release Train "D", following Spring Data Release Train -[Codd](https://github.com/spring-projects/spring-data-commons/wiki/Release-Train-Codd). +The GA release is expected as part of the Spring +Data release train [Dijkstra](https://github.com/spring-projects/spring-data-commons/wiki/Release-Train-Dijkstra). ## Cassandra 2.x