diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/MappingCassandraConverter.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/MappingCassandraConverter.java index 79387b654..5afdf7a59 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/MappingCassandraConverter.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/MappingCassandraConverter.java @@ -275,7 +275,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter implem pkEntity.doWithProperties(new PropertyHandler() { public void doWithPersistentProperty(CassandraPersistentProperty pkProp) { - if (pkProp.isPartitioned()) { + if (pkProp.isPartitionKeyColumn()) { spec.partitionKeyColumn(pkProp.getColumnName(), pkProp.getDataType()); } else { spec.clusteredKeyColumn(pkProp.getColumnName(), pkProp.getDataType(), pkProp.getOrdering()); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentProperty.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentProperty.java index 18a8a971c..f3b4bd052 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentProperty.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentProperty.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Set; import org.springframework.cassandra.core.Ordering; +import org.springframework.cassandra.core.PrimaryKeyType; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.mapping.Association; import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty; @@ -51,10 +52,6 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP super(field, propertyDescriptor, owner, simpleTypeHolder); } - /** - * Also considers fields that has an Id annotation. - * - */ @Override public boolean isIdProperty() { @@ -62,48 +59,40 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP return true; } - return getField().isAnnotationPresent(Id.class); + return getField().isAnnotationPresent(PrimaryKey.class); } - /** - * Returns the true if the field composite primary key. - * - * @return - */ @Override public boolean isCompositePrimaryKey() { - Class fieldType = getField().getType(); - return fieldType.isAnnotationPresent(CompositePrimaryKey.class); + return getField().getType().isAnnotationPresent(CompositePrimaryKey.class); } - /** - * Returns the column name to be used to store the value of the property inside the Cassandra. - * - * @return - */ public String getColumnName() { + + // first check @Column annotation Column annotation = getField().getAnnotation(Column.class); - return annotation != null && StringUtils.hasText(annotation.value()) ? annotation.value() : field.getName(); + if (annotation != null && StringUtils.hasText(annotation.value())) { + return annotation.value(); + } + + // else check @KeyColumn annotation + PrimaryKeyColumn anno = getField().getAnnotation(PrimaryKeyColumn.class); + if (anno == null || !StringUtils.hasText(anno.value())) { + return field.getName(); + } + return anno.value(); } - /** - * Returns ordering for the column. Valid only for clustered columns. - * - * @return - */ public Ordering getOrdering() { - Order annotation = getField().getAnnotation(Order.class); - return annotation != null ? annotation.value() : null; + + PrimaryKeyColumn anno = getField().getAnnotation(PrimaryKeyColumn.class); + + return anno == null ? null : anno.ordering(); } - /** - * Returns the data type information if exists. - * - * @return - */ public DataType getDataType() { Qualify annotation = getField().getAnnotation(Qualify.class); - if (annotation != null && annotation.type() != null) { + if (annotation != null) { return qualifyAnnotatedType(annotation); } if (isMap()) { @@ -153,28 +142,30 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP } } - /** - * Returns true if the property has secondary index on this column. - * - * @return - */ public boolean isIndexed() { return getField().isAnnotationPresent(Indexed.class); } - /** - * Returns true if the property has Partitioned annotation on this column. - * - * @return - */ - public boolean isPartitioned() { - return getField().isAnnotationPresent(Partitioned.class); + public boolean isPartitionKeyColumn() { + + PrimaryKeyColumn anno = getField().getAnnotation(PrimaryKeyColumn.class); + + return anno != null && anno.type() == PrimaryKeyType.PARTITIONED; + } + + @Override + public boolean isClusterKeyColumn() { + + PrimaryKeyColumn anno = getField().getAnnotation(PrimaryKeyColumn.class); + + return anno != null && anno.type() == PrimaryKeyType.CLUSTERED; + } + + @Override + public boolean isPrimaryKeyColumn() { + return getField().isAnnotationPresent(PrimaryKeyColumn.class); } - /* - * (non-Javadoc) - * @see org.springframework.data.mapping.model.AbstractPersistentProperty#createAssociation() - */ @Override protected Association createAssociation() { return new Association(this, null); @@ -206,5 +197,4 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP + this.getName() + "' type is '" + this.getType() + "' in the entity " + this.getOwner().getName()); } } - } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CachingCassandraPersistentProperty.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CachingCassandraPersistentProperty.java index 3ab27429a..403e55ffb 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CachingCassandraPersistentProperty.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CachingCassandraPersistentProperty.java @@ -92,10 +92,10 @@ public class CachingCassandraPersistentProperty extends BasicCassandraPersistent * @see org.springframework.data.mongodb.core.mapping.BasicCassandraPersistentProperty#isPartitioned() */ @Override - public boolean isPartitioned() { + public boolean isPartitionKeyColumn() { if (this.isPartitioned == null) { - this.isPartitioned = super.isPartitioned(); + this.isPartitioned = super.isPartitionKeyColumn(); } return this.isPartitioned; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraPersistentProperty.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraPersistentProperty.java index 528446419..81a1f5e55 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraPersistentProperty.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraPersistentProperty.java @@ -24,49 +24,50 @@ import com.datastax.driver.core.DataType; * Cassandra specific {@link org.springframework.data.mapping.PersistentProperty} extension. * * @author Alex Shvid + * @author Matthew T. Adams */ public interface CassandraPersistentProperty extends PersistentProperty { /** - * Returns the true if the field composite primary key. - * - * @return + * Whether the property is a composite primary key. */ boolean isCompositePrimaryKey(); /** - * Returns the name of the field a property is persisted to. - * - * @return + * The name of the column to which a property is persisted. */ String getColumnName(); /** - * Returns ordering for the column. Valid only for clustered columns. - * - * @return + * The ordering for the column. Valid only for clustered columns. */ Ordering getOrdering(); /** - * Returns the data type. - * - * @return + * The column's data type. */ DataType getDataType(); /** - * Returns true if the property has secondary index on this column. - * - * @return + * Whether the property has secondary index on this column. */ boolean isIndexed(); /** - * Returns true if the property has Partitioned annotation. - * - * @return + * Whether the property is a partition key column. */ - boolean isPartitioned(); + boolean isPartitionKeyColumn(); + /** + * Whether the property is a cluster key column. + */ + boolean isClusterKeyColumn(); + + /** + * Whether the property is a partition key column or a cluster key column + * + * @see #isPartitionKeyColumn() + * @see #isClusterKeyColumn() + */ + boolean isPrimaryKeyColumn(); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraSimpleTypes.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraSimpleTypes.java index b03537275..0ed4739ea 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraSimpleTypes.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraSimpleTypes.java @@ -53,16 +53,22 @@ public class CassandraSimpleTypes { primitiveWrapperTypeMap.put(Short.class, short.class); Set> simpleTypes = new HashSet>(); + for (DataType dataType : DataType.allPrimitiveTypes()) { - simpleTypes.add(dataType.asJavaClass()); + Class javaClass = dataType.asJavaClass(); + simpleTypes.add(javaClass); + javaClassToDataType.put(javaClass, dataType); + Class primitiveJavaClass = primitiveWrapperTypeMap.get(javaClass); if (primitiveJavaClass != null) { javaClassToDataType.put(primitiveJavaClass, dataType); } + nameToDataType.put(dataType.getName(), dataType); } + javaClassToDataType.put(String.class, DataType.text()); CASSANDRA_SIMPLE_TYPES = Collections.unmodifiableSet(simpleTypes); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/Column.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/Column.java index 70d29e5b7..64ae3a1cd 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/Column.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/Column.java @@ -38,6 +38,7 @@ import java.lang.annotation.RetentionPolicy; * Annotation to define custom metadata for document fields. * * @author Alex Shvid + * @author Matthew T. Adams */ @Documented @Retention(RetentionPolicy.RUNTIME) @@ -45,9 +46,6 @@ public @interface Column { /** * The name of the column in the table. - * - * @return */ String value() default ""; - } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CompositePrimaryKey.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CompositePrimaryKey.java index 1189b8016..300b426a8 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CompositePrimaryKey.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CompositePrimaryKey.java @@ -31,11 +31,12 @@ import java.lang.annotation.Target; * * * @author Alex Shvid + * @deprecated This class is actually unnecessary and can be inferred by the existence of field(s) with + * {@link PrimaryKeyColumn} annotations on them. */ - @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE }) +@Deprecated public @interface CompositePrimaryKey { - } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/Order.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/Order.java deleted file mode 100644 index 11c212411..000000000 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/Order.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2010-2013 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.mapping; - -import org.springframework.cassandra.core.Ordering; - -/** - * Annotation to define custom order for clustered column. - * - * @author Alex Shvid - */ -public @interface Order { - - /** - * Ordering of the column in the table. - * - * @return - */ - Ordering value() default Ordering.ASCENDING; - -} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/Id.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/PrimaryKey.java similarity index 77% rename from spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/Id.java rename to spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/PrimaryKey.java index cf1722f8d..3cd4415c3 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/Id.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/PrimaryKey.java @@ -21,12 +21,14 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * Identifies primary key or ID in the Cassandra table. Same as @org.springframework.data.annotation.Id + * Identifies the primary key field of the entity, which may be of a basic type or of a type that represents a composite + * primary key class. This field corresponds to the PRIMARY KEY of the corresponding Cassandra table. * * @author Alex Shvid + * @author Matthew T. Adams */ @Retention(value = RetentionPolicy.RUNTIME) @Target(value = { ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE }) @org.springframework.data.annotation.Id -public @interface Id { +public @interface PrimaryKey { } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/Partitioned.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/PrimaryKeyColumn.java similarity index 50% rename from spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/Partitioned.java rename to spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/PrimaryKeyColumn.java index f4aeb23e6..b882d35ae 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/Partitioned.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/PrimaryKeyColumn.java @@ -20,14 +20,35 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.cassandra.core.Ordering; +import org.springframework.cassandra.core.PrimaryKeyType; + /** - * Identifies partition key in the Cassandra composite primary key class. Annotated column is the part of the Cassandra - * Partition Key (former Row Id). - * - * @author Alex Shvid + * Identifies the annotated field of a composite primary key class as a primary key field that is either a partition or + * cluster key field. */ @Retention(value = RetentionPolicy.RUNTIME) -@Target(value = { ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE }) -public @interface Partitioned { +@Target(value = { ElementType.FIELD, ElementType.METHOD }) +public @interface PrimaryKeyColumn { + /** + * The name of the column in the table. + */ + String value() default ""; + + /** + * The order of this column among all primary key columns. + */ + int ordinal(); + + /** + * The type of this key column. Default is {@link PrimaryKeyType#CLUSTERED}. + */ + PrimaryKeyType type() default PrimaryKeyType.CLUSTERED; + + /** + * The cluster ordering of this column if {@link #type()} is {@link PrimaryKeyType#CLUSTERED}, otherwise ignored. + * Default is {@link Ordering#ASCENDING}. + */ + Ordering ordering() default Ordering.ASCENDING; } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Book.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Book.java index bc0659205..e647f9da1 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Book.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Book.java @@ -15,7 +15,7 @@ */ package org.springframework.data.cassandra.test.integration.table; -import org.springframework.data.cassandra.mapping.Id; +import org.springframework.data.cassandra.mapping.PrimaryKey; import org.springframework.data.cassandra.mapping.Table; /** @@ -27,7 +27,7 @@ import org.springframework.data.cassandra.mapping.Table; @Table(name = "book") public class Book { - @Id + @PrimaryKey private String isbn; private String title; diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Comment.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Comment.java index b7d7b1632..f049833ca 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Comment.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Comment.java @@ -18,7 +18,7 @@ package org.springframework.data.cassandra.test.integration.table; import java.util.Date; import java.util.Set; -import org.springframework.data.cassandra.mapping.Id; +import org.springframework.data.cassandra.mapping.PrimaryKey; import org.springframework.data.cassandra.mapping.Qualify; import org.springframework.data.cassandra.mapping.Table; @@ -36,7 +36,7 @@ public class Comment { /* * Primary Key */ - @Id + @PrimaryKey private CommentPK pk; private String text; diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/CommentPK.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/CommentPK.java index 626481e44..d4ed31cbf 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/CommentPK.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/CommentPK.java @@ -1,5 +1,3 @@ -package org.springframework.data.cassandra.test.integration.table; - /* * Copyright 2010-2013 the original author or authors. * @@ -15,10 +13,13 @@ package org.springframework.data.cassandra.test.integration.table; * See the License for the specific language governing permissions and * limitations under the License. */ +package org.springframework.data.cassandra.test.integration.table; + import java.util.Date; +import org.springframework.cassandra.core.PrimaryKeyType; import org.springframework.data.cassandra.mapping.CompositePrimaryKey; -import org.springframework.data.cassandra.mapping.Partitioned; +import org.springframework.data.cassandra.mapping.PrimaryKeyColumn; import org.springframework.data.cassandra.mapping.Qualify; import com.datastax.driver.core.DataType; @@ -35,12 +36,13 @@ public class CommentPK { /* * Row ID */ - @Partitioned + @PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED) private String author; /* * Clustered Column */ + @PrimaryKeyColumn(ordinal = 1) @Qualify(type = DataType.Name.TIMESTAMP) private Date time; diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/LogEntry.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/LogEntry.java index e845fa5a1..d2650f536 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/LogEntry.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/LogEntry.java @@ -17,7 +17,7 @@ package org.springframework.data.cassandra.test.integration.table; import java.util.Date; -import org.springframework.data.cassandra.mapping.Id; +import org.springframework.data.cassandra.mapping.PrimaryKey; import org.springframework.data.cassandra.mapping.Table; /** @@ -32,7 +32,7 @@ public class LogEntry { /* * Primary Key */ - @Id + @PrimaryKey private Date logDate; private String hostname; diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/NotificationPK.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/NotificationPK.java index 22e892e3e..cf9664c55 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/NotificationPK.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/NotificationPK.java @@ -17,8 +17,9 @@ package org.springframework.data.cassandra.test.integration.table; import java.util.Date; +import org.springframework.cassandra.core.PrimaryKeyType; import org.springframework.data.cassandra.mapping.CompositePrimaryKey; -import org.springframework.data.cassandra.mapping.Partitioned; +import org.springframework.data.cassandra.mapping.PrimaryKeyColumn; import org.springframework.data.cassandra.mapping.Qualify; import com.datastax.driver.core.DataType; @@ -37,12 +38,13 @@ public class NotificationPK { /* * Row ID */ - @Partitioned + @PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED) private String username; /* * Clustered Column */ + @PrimaryKeyColumn(ordinal = 1) @Qualify(type = DataType.Name.TIMESTAMP) private Date time; diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/PostPK.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/PostPK.java index 80b19d0fc..b6f7e3630 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/PostPK.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/PostPK.java @@ -17,8 +17,9 @@ package org.springframework.data.cassandra.test.integration.table; import java.util.Date; +import org.springframework.cassandra.core.PrimaryKeyType; import org.springframework.data.cassandra.mapping.CompositePrimaryKey; -import org.springframework.data.cassandra.mapping.Partitioned; +import org.springframework.data.cassandra.mapping.PrimaryKeyColumn; /** * This is an example of dynamic table that creates each time new column with Post timestamp. @@ -36,12 +37,13 @@ public class PostPK { /* * Row ID */ - @Partitioned + @PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED) private String author; /* * Clustered Column */ + @PrimaryKeyColumn(ordinal = 1) private Date time; public String getAuthor() { diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/TimelinePK.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/TimelinePK.java index ab6fad8e7..8a54f2191 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/TimelinePK.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/TimelinePK.java @@ -17,8 +17,9 @@ package org.springframework.data.cassandra.test.integration.table; import java.util.Date; +import org.springframework.cassandra.core.PrimaryKeyType; import org.springframework.data.cassandra.mapping.CompositePrimaryKey; -import org.springframework.data.cassandra.mapping.Partitioned; +import org.springframework.data.cassandra.mapping.PrimaryKeyColumn; /** * This is an example of the users timeline dynamic table, where all columns are dynamically created by @ColumnId field @@ -36,12 +37,13 @@ public class TimelinePK { /* * Row ID */ - @Partitioned + @PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED) private String username; /* * Clustered Column */ + @PrimaryKeyColumn(ordinal = 1) private Date time; public String getUsername() {