diff --git a/pom.xml b/pom.xml
index 50a87ddc8..1f6ae9734 100644
--- a/pom.xml
+++ b/pom.xml
@@ -124,6 +124,20 @@
true
+
+ joda-time
+ joda-time
+ ${jodatime}
+ true
+
+
+
+ org.threeten
+ threetenbp
+ ${threetenbp}
+ true
+
+
org.apache.cassandra
@@ -177,13 +191,6 @@
test
-
- joda-time
- joda-time
- ${jodatime}
- test
-
-
org.apache.commons
commons-lang3
diff --git a/spring-cql/template.mf b/spring-cql/template.mf
index a61324370..2c2bb8c07 100644
--- a/spring-cql/template.mf
+++ b/spring-cql/template.mf
@@ -5,6 +5,12 @@ Bundle-ManifestVersion: 2
Import-Package:
sun.reflect;version="0";resolution:=optional
Import-Template:
+ com.datastax.driver.core.*;resolution:="optional";version="[0.1.0, 1.0.0)",
+ com.google.common.*;resolution:="optional";version="[11.0.0, 20.0.0)",
+ javax.xml.transform.*;resolution:="optional";version="0",
+ org.aopalliance.*;version="[1.0.0, 2.0.0)";resolution:=optional,
+ org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
+ org.codehaus.jackson.*;resolution:="optional";version="[1.6, 2.0.0)",
org.springframework.beans.*;version="[3.1.0, 4.0.0)",
org.springframework.cache.*;version="[3.1.0, 4.0.0)",
org.springframework.context.*;version="[3.1.0, 4.0.0)",
@@ -16,15 +22,6 @@ Import-Template:
org.springframework.transaction.support.*;version="[3.1.0, 4.0.0)",
org.springframework.data.*;version="[1.5.0, 2.0.0)",
org.springframework.expression.*;version="[3.1.0, 4.0.0)",
- org.aopalliance.*;version="[1.0.0, 2.0.0)";resolution:=optional,
- org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
- org.w3c.dom.*;version="0",
- javax.xml.transform.*;resolution:="optional";version="0",
- com.datastax.driver.core.*;resolution:="optional";version="[0.1.0, 1.0.0)",
- org.apache.cassandra.db.marshal.*;version="[1.2.0, 1.3.0)",
+ org.springframework.cassandra.*;version="[1.0.0,2.0.0)",
org.slf4j.*;version="[1.5.0, 1.8.0)",
- org.idevlab.rjc.*;resolution:="optional";version="[0.6.4, 0.6.4]",
- org.apache.commons.pool.impl.*;resolution:="optional";version="[1.0.0, 3.0.0)",
- org.codehaus.jackson.*;resolution:="optional";version="[1.6, 2.0.0)",
- org.apache.commons.beanutils.*;resolution:="optional";version=1.8.5,
- com.google.common.*;resolution:="optional";version="[11.0.0, 20.0.0)"
\ No newline at end of file
+ org.w3c.dom.*;version="0"
diff --git a/spring-data-cassandra/pom.xml b/spring-data-cassandra/pom.xml
index 7c17a6ec6..40fa902fa 100644
--- a/spring-data-cassandra/pom.xml
+++ b/spring-data-cassandra/pom.xml
@@ -59,6 +59,18 @@
true
+
+ joda-time
+ joda-time
+ true
+
+
+
+ org.threeten
+ threetenbp
+ true
+
+
javax.enterprise
@@ -110,12 +122,6 @@
test
-
- joda-time
- joda-time
- test
-
-
commons-io
commons-io
diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/java/AbstractCassandraConfiguration.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/java/AbstractCassandraConfiguration.java
index f13d79713..b0efd5edf 100644
--- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/java/AbstractCassandraConfiguration.java
+++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/java/AbstractCassandraConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2014 the original author or authors
+ * Copyright 2013-2016 the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,14 +15,18 @@
*/
package org.springframework.data.cassandra.config.java;
+import java.util.Collections;
+
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.core.convert.converter.Converter;
import org.springframework.data.cassandra.config.CassandraEntityClassScanner;
import org.springframework.data.cassandra.config.CassandraSessionFactoryBean;
import org.springframework.data.cassandra.config.SchemaAction;
import org.springframework.data.cassandra.convert.CassandraConverter;
+import org.springframework.data.cassandra.convert.CustomConversions;
import org.springframework.data.cassandra.convert.MappingCassandraConverter;
import org.springframework.data.cassandra.core.CassandraAdminOperations;
import org.springframework.data.cassandra.core.CassandraAdminTemplate;
@@ -37,6 +41,7 @@ import org.springframework.data.mapping.context.MappingContext;
* @author Alex Shvid
* @author Matthew T. Adams
* @author John Blum
+ * @author Mark Paluch
*/
@Configuration
public abstract class AbstractCassandraConfiguration extends AbstractClusterConfiguration
@@ -72,15 +77,44 @@ public abstract class AbstractCassandraConfiguration extends AbstractClusterConf
mappingContext.setBeanClassLoader(beanClassLoader);
mappingContext.setInitialEntitySet(CassandraEntityClassScanner.scan(getEntityBasePackages()));
+ CustomConversions customConversions = customConversions();
+
+ mappingContext.setCustomConversions(customConversions);
+ mappingContext.setSimpleTypeHolder(customConversions.getSimpleTypeHolder());
+
return mappingContext;
}
/**
- * Return the {@link CassandraConverter} instance to convert Rows to Objects, Objects to BuiltStatements
+ * Register custom {@link Converter}s in a {@link CustomConversions} object if required. These
+ * {@link CustomConversions} will be registered with the {@link #cassandraConverter()} and {@link #cassandraMapping()}
+ * . Returns an empty {@link CustomConversions} instance by default.
+ *
+ * @return must not be {@literal null}.
+ * @since 1.5
+ */
+ @Bean
+ public CustomConversions customConversions() {
+ return new CustomConversions(Collections.emptyList());
+ }
+
+ /**
+ * Creates a {@link CassandraConverter} using the configured {@link #cassandraMapping()}. Will get
+ * {@link #customConversions()} applied.
+ *
+ * @see #customConversions()
+ * @see #cassandraMapping()
+ * @return
+ * @throws Exception
*/
@Bean
public CassandraConverter cassandraConverter() throws Exception {
- return new MappingCassandraConverter(cassandraMapping());
+
+ MappingCassandraConverter mappingCassandraConverter = new MappingCassandraConverter(cassandraMapping());
+
+ mappingCassandraConverter.setCustomConversions(customConversions());
+
+ return mappingCassandraConverter;
}
/**
@@ -99,19 +133,22 @@ public abstract class AbstractCassandraConfiguration extends AbstractClusterConf
}
/**
- * 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.
+ * 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[] getEntityBasePackages() {
return new String[] { getClass().getPackage().getName() };
}
+ /**
+ * Return the name of the keyspace to connect to.
+ *
+ * @return must not be {@literal null}.
+ */
protected abstract String getKeyspaceName();
/**
- * The {@link SchemaAction} to perform at startup. Defaults to {@link SchemaAction#NONE}.
+ * The {@link SchemaAction} to perform at startup. Defaults to {@link SchemaAction#NONE}.
*/
public SchemaAction getSchemaAction() {
return SchemaAction.NONE;
diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/CassandraJodaTimeConverters.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/CassandraJodaTimeConverters.java
new file mode 100644
index 000000000..b7adec039
--- /dev/null
+++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/CassandraJodaTimeConverters.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.cassandra.convert;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.joda.time.DateMidnight;
+import org.joda.time.LocalDate;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.util.ClassUtils;
+
+/**
+ * Helper class to register JSR-310 specific {@link Converter} implementations to convert between Cassandra types in
+ * case the library is present on the classpath.
+ *
+ * @author Mark Paluch
+ * @since 1.5
+ */
+@SuppressWarnings("deprecation")
+public abstract class CassandraJodaTimeConverters {
+
+ private static final boolean JODA_TIME_IS_PRESENT = ClassUtils.isPresent("org.joda.time.LocalDate", null);
+
+ private CassandraJodaTimeConverters() {}
+
+ /**
+ * Returns the converters to be registered. Will only return converters in case JodaTime is present on the class path.
+ *
+ * @return
+ */
+ public static Collection> getConvertersToRegister() {
+
+ if (!JODA_TIME_IS_PRESENT) {
+ return Collections.emptySet();
+ }
+
+ List> converters = new ArrayList>();
+ converters.add(CassandraLocalDateToLocalDateConverter.INSTANCE);
+ converters.add(LocalDateToCassandraLocalDateConverter.INSTANCE);
+
+ converters.add(CassandraLocalDateToDateMidnightConverter.INSTANCE);
+ converters.add(DateMidnightToCassandraLocalDateConverter.INSTANCE);
+
+ return converters;
+ }
+
+ /**
+ * Simple singleton to convert {@link com.datastax.driver.core.LocalDate}s to their {@link LocalDate} representation.
+ *
+ * @author Mark Paluch
+ */
+ public static enum CassandraLocalDateToLocalDateConverter
+ implements Converter {
+
+ INSTANCE;
+
+ @Override
+ public LocalDate convert(com.datastax.driver.core.LocalDate source) {
+ return new LocalDate(source.getYear(), source.getMonth(), source.getDay());
+ }
+ }
+
+ /**
+ * Simple singleton to convert {@link LocalDate}s to their {@link com.datastax.driver.core.LocalDate} representation.
+ *
+ * @author Mark Paluch
+ */
+ public static enum LocalDateToCassandraLocalDateConverter
+ implements Converter {
+
+ INSTANCE;
+
+ @Override
+ public com.datastax.driver.core.LocalDate convert(LocalDate source) {
+ return com.datastax.driver.core.LocalDate.fromYearMonthDay(source.getYear(), source.getMonthOfYear(),
+ source.getDayOfMonth());
+ }
+ }
+
+ /**
+ * Simple singleton to convert {@link com.datastax.driver.core.LocalDate}s to their {@link DateMidnight}
+ * representation.
+ *
+ * @author Mark Paluch
+ */
+ public static enum CassandraLocalDateToDateMidnightConverter
+ implements Converter {
+
+ INSTANCE;
+
+ @Override
+ public DateMidnight convert(com.datastax.driver.core.LocalDate source) {
+ return new DateMidnight(source.getYear(), source.getMonth(), source.getDay());
+ }
+ }
+
+ /**
+ * Simple singleton to convert {@link DateMidnight}s to their {@link com.datastax.driver.core.LocalDate}
+ * representation.
+ *
+ * @author Mark Paluch
+ */
+ public static enum DateMidnightToCassandraLocalDateConverter
+ implements Converter {
+
+ INSTANCE;
+
+ @Override
+ public com.datastax.driver.core.LocalDate convert(DateMidnight source) {
+ return com.datastax.driver.core.LocalDate.fromYearMonthDay(source.getYear(), source.getMonthOfYear(),
+ source.getDayOfMonth());
+ }
+ }
+}
diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/CassandraJsr310Converters.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/CassandraJsr310Converters.java
new file mode 100644
index 000000000..aa31617f6
--- /dev/null
+++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/CassandraJsr310Converters.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.cassandra.convert;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.data.convert.Jsr310Converters;
+import org.springframework.util.ClassUtils;
+
+/**
+ * Helper class to register JodaTime specific {@link Converter} implementations in case the library is present on the
+ * classpath.
+ *
+ * @author Mark Paluch
+ * @since 1.5
+ */
+@SuppressWarnings("Since15")
+public abstract class CassandraJsr310Converters {
+
+ private static final boolean JAVA_8_IS_PRESENT = ClassUtils.isPresent("java.time.LocalDateTime",
+ Jsr310Converters.class.getClassLoader());
+
+ private CassandraJsr310Converters() {}
+
+ /**
+ * Returns the converters to be registered. Will only return converters in case we're running on Java 8.
+ *
+ * @return
+ */
+ public static Collection> getConvertersToRegister() {
+
+ if (!JAVA_8_IS_PRESENT) {
+ return Collections.emptySet();
+ }
+
+ List> converters = new ArrayList>();
+ converters.add(CassandraLocalDateToLocalDateConverter.INSTANCE);
+ converters.add(LocalDateToCassandraLocalDateConverter.INSTANCE);
+
+ return converters;
+ }
+
+ /**
+ * Simple singleton to convert {@link com.datastax.driver.core.LocalDate}s to their {@link LocalDate} representation.
+ *
+ * @author Mark Paluch
+ */
+ public static enum CassandraLocalDateToLocalDateConverter
+ implements Converter {
+
+ INSTANCE;
+
+ @Override
+ public LocalDate convert(com.datastax.driver.core.LocalDate source) {
+ return LocalDate.of(source.getYear(), source.getMonth(), source.getDay());
+ }
+ }
+
+ /**
+ * Simple singleton to convert {@link LocalDate}s to their {@link com.datastax.driver.core.LocalDate} representation.
+ *
+ * @author Mark Paluch
+ */
+ public static enum LocalDateToCassandraLocalDateConverter
+ implements Converter {
+
+ INSTANCE;
+
+ @Override
+ public com.datastax.driver.core.LocalDate convert(LocalDate source) {
+ return com.datastax.driver.core.LocalDate.fromYearMonthDay(source.getYear(), source.getMonthValue(),
+ source.getDayOfMonth());
+ }
+ }
+}
diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/CassandraThreeTenBackPortConverters.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/CassandraThreeTenBackPortConverters.java
new file mode 100644
index 000000000..ad78fa5e5
--- /dev/null
+++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/CassandraThreeTenBackPortConverters.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.cassandra.convert;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.data.convert.ThreeTenBackPortConverters;
+import org.springframework.util.ClassUtils;
+import org.threeten.bp.Instant;
+import org.threeten.bp.LocalDate;
+import org.threeten.bp.LocalDateTime;
+import org.threeten.bp.ZoneId;
+
+/**
+ * Helper class to register {@link Converter} implementations for the ThreeTen Backport project in case it's present on
+ * the classpath.
+ *
+ * @author Mark Paluch
+ * @see http://www.threeten.org/threetenbp
+ * @since 1.5
+ */
+public abstract class CassandraThreeTenBackPortConverters {
+
+ private static final boolean THREE_TEN_BACK_PORT_IS_PRESENT = ClassUtils.isPresent("org.threeten.bp.LocalDateTime",
+ ThreeTenBackPortConverters.class.getClassLoader());
+
+ private CassandraThreeTenBackPortConverters() {}
+
+ /**
+ * Returns the converters to be registered. Will only return converters in case ThreeTen Backport is on the class
+ * path.
+ *
+ * @return
+ */
+ public static Collection> getConvertersToRegister() {
+
+ if (!THREE_TEN_BACK_PORT_IS_PRESENT) {
+ return Collections.emptySet();
+ }
+
+ List> converters = new ArrayList>();
+ converters.add(CassandraLocalDateToLocalDateConverter.INSTANCE);
+ converters.add(LocalDateToCassandraLocalDateConverter.INSTANCE);
+
+ return converters;
+ }
+
+ /**
+ * Simple singleton to convert {@link com.datastax.driver.core.LocalDate}s to their {@link LocalDate} representation.
+ *
+ * @author Mark Paluch
+ */
+ public static enum CassandraLocalDateToLocalDateConverter
+ implements Converter {
+
+ INSTANCE;
+
+ @Override
+ public LocalDate convert(com.datastax.driver.core.LocalDate source) {
+ return LocalDate.of(source.getYear(), source.getMonth(), source.getDay());
+ }
+ }
+
+ /**
+ * Simple singleton to convert {@link LocalDate}s to their {@link com.datastax.driver.core.LocalDate} representation.
+ *
+ * @author Mark Paluch
+ */
+ public static enum LocalDateToCassandraLocalDateConverter
+ implements Converter {
+
+ INSTANCE;
+
+ @Override
+ public com.datastax.driver.core.LocalDate convert(LocalDate source) {
+ return com.datastax.driver.core.LocalDate.fromYearMonthDay(source.getYear(), source.getMonthValue(),
+ source.getDayOfMonth());
+ }
+ }
+}
diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/CustomConversions.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/CustomConversions.java
index f5a893acc..414998163 100644
--- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/CustomConversions.java
+++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/CustomConversions.java
@@ -35,7 +35,10 @@ import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.core.convert.converter.GenericConverter.ConvertiblePair;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.data.cassandra.mapping.CassandraSimpleTypeHolder;
+import org.springframework.data.convert.JodaTimeConverters;
+import org.springframework.data.convert.Jsr310Converters;
import org.springframework.data.convert.ReadingConverter;
+import org.springframework.data.convert.ThreeTenBackPortConverters;
import org.springframework.data.convert.WritingConverter;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.util.CacheValue;
@@ -59,7 +62,7 @@ public class CustomConversions {
private final Set readingPairs;
private final Set writingPairs;
private final Set> customSimpleTypes;
- private final SimpleTypeHolder simpleTypeHolder;
+ private final CassandraSimpleTypeHolder simpleTypeHolder;
private final List