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-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/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/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/CassandraEntityClassScanner.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraEntityClassScanner.java
new file mode 100644
index 000000000..a32c21055
--- /dev/null
+++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraEntityClassScanner.java
@@ -0,0 +1,136 @@
+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;
+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 {
+
+ 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;
+
+ 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);
+ }
+
+ 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 extends Annotation> 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 extends Annotation>[] getEntityAnnotations() {
+ return new Class[] { Table.class, Persistent.class, PrimaryKeyClass.class };
+ }
+}
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 43e4ded92..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
@@ -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 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 736aa0922..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,18 +15,12 @@
*/
package org.springframework.data.cassandra.config.java;
-import java.util.HashSet;
-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;
@@ -34,12 +28,8 @@ 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.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.
@@ -54,7 +44,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}.
@@ -64,11 +53,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[] getEntityBasePackages() {
+ return new String[] { getClass().getPackage().getName() };
}
@Bean
@@ -77,15 +66,12 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC
CassandraDataSessionFactoryBean bean = new CassandraDataSessionFactoryBean();
bean.setCluster(cluster().getObject());
- bean.setConverter(converter());
+ bean.setConverter(cassandraConverter());
bean.setSchemaAction(getSchemaAction());
bean.setKeyspaceName(getKeyspaceName());
bean.setStartupScripts(getStartupScripts());
bean.setShutdownScripts(getShutdownScripts());
- bean.setEntityClassLoader(beanClassLoader);
- bean.setMapping(mapping);
-
return bean;
}
@@ -96,7 +82,7 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC
*/
@Bean
public CassandraAdminOperations cassandraTemplate() throws Exception {
- return new CassandraAdminTemplate(session().getObject(), converter());
+ return new CassandraAdminTemplate(session().getObject(), cassandraConverter());
}
/**
@@ -105,59 +91,21 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC
* @throws ClassNotFoundException
*/
@Bean
- public CassandraMappingContext cassandraMappingContext() throws ClassNotFoundException {
- DefaultCassandraMappingContext context = new DefaultCassandraMappingContext();
- context.setInitialEntitySet(getInitialEntitySet());
- return context;
+ public CassandraMappingContext cassandraMapping() throws ClassNotFoundException {
+
+ DefaultCassandraMappingContext bean = new DefaultCassandraMappingContext();
+ bean.setInitialEntitySet(CassandraEntityClassScanner.scan(getEntityBasePackages()));
+ bean.setBeanClassLoader(beanClassLoader);
+
+ return bean;
}
/**
* Return the {@link CassandraConverter} instance to convert Rows to Objects, Objects to BuiltStatements
- *
- * @throws ClassNotFoundException
*/
@Bean
- public CassandraConverter converter() throws ClassNotFoundException {
- MappingCassandraConverter converter = new MappingCassandraConverter(cassandraMappingContext());
- converter.setBeanClassLoader(beanClassLoader);
- return converter;
- }
-
- /**
- * Scans the mapping base package for entity classes annotated with {@link Table} or {@link Persistent}.
- *
- * @see #getEntityBasePackage()
- * @return Set<Class<?>> representing the annotated entity classes found.
- * @throws ClassNotFoundException
- */
- protected Set> getInitialEntitySet() throws ClassNotFoundException {
-
- String basePackage = getEntityBasePackage();
- Set> initialEntitySet = new HashSet>();
-
- 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;
- }
-
- 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 CassandraConverter cassandraConverter() throws Exception {
+ return new MappingCassandraConverter(cassandraMapping());
}
@Override
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/CassandraDataNamespaceHandler.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataNamespaceHandler.java
index fdd7fc80c..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,5 +36,7 @@ public class CassandraDataNamespaceHandler extends NamespaceHandlerSupport {
registerBeanDefinitionParser("cluster", new CassandraDataClusterParser());
registerBeanDefinitionParser("session", new CassandraDataSessionParser());
registerBeanDefinitionParser("template", new CassandraDataTemplateParser());
+ registerBeanDefinitionParser("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 ea2327801..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
@@ -1,20 +1,16 @@
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 static org.springframework.cassandra.config.xml.ParsingUtils.addRequiredPropertyValue;
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;
@@ -30,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) {
@@ -46,55 +50,11 @@ public class CassandraDataSessionParser extends CassandraSessionParser {
}
@Override
- protected void parseUnhandledElement(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
+ protected void setDefaultProperties(BeanDefinitionBuilder builder) {
- if ("mapping".equals(element.getLocalName())) {
- parseMapping(element, parserContext, builder);
- } else {
- super.parseUnhandledElement(element, parserContext, builder);
- }
- }
+ super.setDefaultProperties(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);
+ addRequiredPropertyValue(builder, "schemaAction", SchemaAction.NONE.name());
+ addRequiredPropertyReference(builder, "converter", DefaultDataBeanNames.CONVERTER);
}
}
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
new file mode 100644
index 000000000..1c4d482d6
--- /dev/null
+++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingContextParser.java
@@ -0,0 +1,87 @@
+package org.springframework.data.cassandra.config.xml;
+
+import java.util.HashSet;
+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.AbstractSingleBeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+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;
+import org.springframework.util.xml.DomUtils;
+import org.w3c.dom.Element;
+
+/**
+ * Spring Data Cassandra XML namespace parser for the <mapping> element.
+ *
+ * @author Matthew T. Adams
+ */
+public class CassandraMappingContextParser extends AbstractSingleBeanDefinitionParser {
+
+ @Override
+ protected Class> getBeanClass(Element element) {
+ return DefaultCassandraMappingContext.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.CONTEXT;
+ }
+
+ @Override
+ protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
+
+ CassandraMappingXmlBeanFactoryPostProcessorRegistrar.ensureRegistration(element, parserContext);
+
+ parseMapping(element, builder);
+ }
+
+ protected void parseMapping(Element element, BeanDefinitionBuilder builder) {
+
+ Set mappings = new HashSet();
+
+ for (Element entity : DomUtils.getChildElementsByTagName(element, "entity")) {
+
+ EntityMapping entityMapping = parseEntity(entity);
+
+ 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/CassandraMappingConverterParser.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingConverterParser.java
new file mode 100644
index 000000000..5dd2a6c81
--- /dev/null
+++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraMappingConverterParser.java
@@ -0,0 +1,45 @@
+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.AbstractSingleBeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.data.cassandra.config.DefaultDataBeanNames;
+import org.springframework.data.cassandra.convert.MappingCassandraConverter;
+import org.springframework.util.StringUtils;
+import org.w3c.dom.Element;
+
+/**
+ * Spring Data Cassandra XML namespace parser for the <converter> element.
+ *
+ * @author Matthew T. Adams
+ */
+public class CassandraMappingConverterParser extends AbstractSingleBeanDefinitionParser {
+
+ @Override
+ protected Class> getBeanClass(Element element) {
+ return MappingCassandraConverter.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) {
+
+ CassandraMappingXmlBeanFactoryPostProcessorRegistrar.ensureRegistration(element, parserContext);
+
+ String mappingRef = element.getAttribute("mapping-ref");
+ if (!StringUtils.hasText(mappingRef)) {
+ 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/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/CassandraMappingContext.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraMappingContext.java
index d468e4b0a..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;
@@ -59,22 +58,17 @@ public interface CassandraMappingContext extends
boolean usesTable(TableMetadata table);
/**
- * Returns the {@link CassandraPersistentEntity} for the given type. If it doesn't exist, this method throws
- * {@link IllegalArgumentException}.
+ * 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 Java type of the persistent entity.
- * @return The {@link CassandraPersistentEntity} describing the persistent Java type.
- * @throws IllegalArgumentException if the persistent entity is unknown
+ * @param type The class of the existing persistent entity.
+ * @return The existing persistent entity.
*/
- public CassandraPersistentEntity> getRequiredPersistentEntity(Class> type);
+ CassandraPersistentEntity> getExistingPersistentEntity(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
+ * Returns whether this {@link CassandraMappingContext} already contains a {@link CassandraPersistentEntity} for the
+ * given type.
*/
- public CassandraPersistentEntity> getRequiredPersistentEntity(TypeInformation> 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 e48f7ec7d..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
@@ -37,6 +37,8 @@ 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;
@@ -52,9 +54,14 @@ public class DefaultCassandraMappingContext extends
CassandraMappingContext, ApplicationContextAware {
protected ApplicationContext context;
+ protected Mapping mapping = new Mapping();
+ protected ClassLoader beanClassLoader;
+
+ // useful caches
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}.
@@ -63,6 +70,14 @@ public class DefaultCassandraMappingContext extends
setSimpleTypeHolder(new CassandraSimpleTypeHolder());
}
+ @Override
+ public void initialize() {
+
+ super.initialize();
+
+ processMappingOverrides();
+ }
+
@Override
public Collection> getPersistentEntities() {
return getPersistentEntities(false);
@@ -123,6 +138,8 @@ public class DefaultCassandraMappingContext extends
nonPrimaryKeyEntities.add(entity);
}
+ entitiesByType.put(entity.getType(), entity);
+
return entity;
}
@@ -184,28 +201,65 @@ public class DefaultCassandraMappingContext extends
return spec;
}
- @Override
- public CassandraPersistentEntity> getRequiredPersistentEntity(Class> type) {
+ public void setMapping(Mapping mapping) {
- CassandraPersistentEntity> entity = getPersistentEntity(type);
+ Assert.notNull(mapping);
- if (entity == null) {
- throw new IllegalArgumentException(String.format("no persistence metadata found for type [%s]", type.getName()));
+ this.mapping = mapping;
+ }
+
+ protected void processMappingOverrides() {
+
+ if (mapping == null) {
+ return;
}
- return entity;
+ for (EntityMapping entityMapping : mapping.getEntityMappings()) {
+
+ if (entityMapping == null) {
+ continue;
+ }
+
+ String entityClassName = entityMapping.getEntityClassName();
+ Class> entityClass;
+ try {
+ entityClass = ClassUtils.forName(entityClassName, 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;
}
@Override
- public CassandraPersistentEntity> getRequiredPersistentEntity(TypeInformation> type) {
+ public CassandraPersistentEntity> getExistingPersistentEntity(Class> type) {
- CassandraPersistentEntity> entity = getPersistentEntity(type);
-
- if (entity == null) {
- throw new IllegalArgumentException(String.format("no persistence metadata found for type [%s]",
- type.getActualType()));
+ CassandraPersistentEntity> entity = entitiesByType.get(type);
+ if (entity != null) {
+ return entity;
}
- 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/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..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
@@ -452,8 +452,6 @@ Arbitrary CQL script to be executed against the session's keyspace during bean d
]]>
-
@@ -482,7 +480,7 @@ The name of a Cassandra Keyspace. No default; for the system keyspace, use the
use="optional">
@@ -500,7 +498,7 @@ The schema action to perform; default is NONE.
@@ -515,7 +513,7 @@ The reference to a Cassandra session; default is "cassandra-session".
use="optional">
@@ -629,13 +627,6 @@ The replication factor for the data center.
-
-
-
-
-
-
-
+
@@ -696,4 +686,65 @@ 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..0980a8472 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[] getEntityBasePackages() {
+ return new String[] { Comment.class.getPackage().getName() };
}
}
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..11ab552b4
--- /dev/null
+++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/mappingcontext/MappingContextIntegrationTests.java
@@ -0,0 +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
+ 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/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;
+}
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..76715f958 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[] getEntityBasePackages() {
+ 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 7b8ca6c36..ee68c6eba 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
@@ -66,8 +66,8 @@ public class CassandraDataOperationsTest extends AbstractSpringDataEmbeddedCassa
}
@Override
- public String getEntityBasePackage() {
- return Book.class.getPackage().getName();
+ public String[] getEntityBasePackages() {
+ 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..1177ad40f 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,33 +1,34 @@
-
+
+
+
+
+
-
+
-
-
+
+
-
-
-
-
-
-
-
+
+
-
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..b434f4221 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/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 @@
+
+
+
+
+
+
+
+
+
+
+
+
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..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
@@ -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..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
@@ -1,6 +1,6 @@
-
+
-
-
-
-
-
+