wip
This commit is contained in:
@@ -34,6 +34,7 @@ import org.springframework.util.StringUtils;
|
||||
* table name.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
* @author Matthew T. Adams
|
||||
*/
|
||||
public class BasicCassandraPersistentEntity<T> extends BasicPersistentEntity<T, CassandraPersistentProperty> implements
|
||||
CassandraPersistentEntity<T>, ApplicationContextAware {
|
||||
@@ -44,7 +45,7 @@ public class BasicCassandraPersistentEntity<T> extends BasicPersistentEntity<T,
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicCassandraPersistentEntity} with the given {@link TypeInformation}. Will default the table
|
||||
* name to the entities simple type name.
|
||||
* name to the entity's simple type name.
|
||||
*
|
||||
* @param typeInformation
|
||||
*/
|
||||
@@ -56,14 +57,10 @@ public class BasicCassandraPersistentEntity<T> extends BasicPersistentEntity<T,
|
||||
this.context = new StandardEvaluationContext();
|
||||
|
||||
Class<?> rawType = typeInformation.getType();
|
||||
String fallback = CassandraNamingUtils.getPreferredTableName(rawType);
|
||||
Table anno = rawType.getAnnotation(Table.class);
|
||||
|
||||
if (rawType.isAnnotationPresent(Table.class)) {
|
||||
Table d = rawType.getAnnotation(Table.class);
|
||||
this.table = StringUtils.hasText(d.name()) ? d.name() : fallback;
|
||||
} else {
|
||||
this.table = fallback;
|
||||
}
|
||||
this.table = anno != null && StringUtils.hasText(anno.name()) ? anno.name() : CassandraNamingUtils
|
||||
.getPreferredTableName(rawType);
|
||||
}
|
||||
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
|
||||
@@ -59,7 +59,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
|
||||
return true;
|
||||
}
|
||||
|
||||
return getField().isAnnotationPresent(PrimaryKey.class);
|
||||
return isAnnotationPresent(PrimaryKey.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -70,85 +70,105 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
|
||||
public String getColumnName() {
|
||||
|
||||
// first check @Column annotation
|
||||
Column annotation = getField().getAnnotation(Column.class);
|
||||
if (annotation != null && StringUtils.hasText(annotation.value())) {
|
||||
return annotation.value();
|
||||
Column column = findAnnotation(Column.class);
|
||||
if (column != null && StringUtils.hasText(column.value())) {
|
||||
return column.value();
|
||||
}
|
||||
|
||||
// else check @KeyColumn annotation
|
||||
PrimaryKeyColumn anno = getField().getAnnotation(PrimaryKeyColumn.class);
|
||||
if (anno == null || !StringUtils.hasText(anno.value())) {
|
||||
return field.getName();
|
||||
PrimaryKeyColumn pk = findAnnotation(PrimaryKeyColumn.class);
|
||||
if (pk != null && StringUtils.hasText(pk.value())) {
|
||||
return pk.value();
|
||||
}
|
||||
return anno.value();
|
||||
|
||||
// else default
|
||||
return field.getName().toLowerCase();
|
||||
}
|
||||
|
||||
public Ordering getOrdering() {
|
||||
|
||||
PrimaryKeyColumn anno = getField().getAnnotation(PrimaryKeyColumn.class);
|
||||
PrimaryKeyColumn anno = findAnnotation(PrimaryKeyColumn.class);
|
||||
|
||||
return anno == null ? null : anno.ordering();
|
||||
}
|
||||
|
||||
public DataType getDataType() {
|
||||
CassandraType annotation = getField().getAnnotation(CassandraType.class);
|
||||
|
||||
CassandraType annotation = findAnnotation(CassandraType.class);
|
||||
if (annotation != null) {
|
||||
return qualifyAnnotatedType(annotation);
|
||||
return getDataTypeFor(annotation);
|
||||
}
|
||||
|
||||
if (isMap()) {
|
||||
|
||||
List<TypeInformation<?>> args = getTypeInformation().getTypeArguments();
|
||||
ensureTypeArguments(args.size(), 2);
|
||||
return DataType.map(autodetectPrimitiveType(args.get(0).getType()),
|
||||
autodetectPrimitiveType(args.get(1).getType()));
|
||||
|
||||
return DataType.map(getDataTypeFor(args.get(0).getType()), getDataTypeFor(args.get(1).getType()));
|
||||
}
|
||||
|
||||
if (isCollectionLike()) {
|
||||
|
||||
List<TypeInformation<?>> args = getTypeInformation().getTypeArguments();
|
||||
ensureTypeArguments(args.size(), 1);
|
||||
|
||||
if (Set.class.isAssignableFrom(getType())) {
|
||||
return DataType.set(autodetectPrimitiveType(args.get(0).getType()));
|
||||
} else if (List.class.isAssignableFrom(getType())) {
|
||||
return DataType.list(autodetectPrimitiveType(args.get(0).getType()));
|
||||
return DataType.set(getDataTypeFor(args.get(0).getType()));
|
||||
}
|
||||
if (List.class.isAssignableFrom(getType())) {
|
||||
return DataType.list(getDataTypeFor(args.get(0).getType()));
|
||||
}
|
||||
}
|
||||
DataType dataType = CassandraSimpleTypeHolder.getDataTypeFor(this.getType());
|
||||
|
||||
DataType dataType = CassandraSimpleTypeHolder.getDataTypeFor(getType());
|
||||
if (dataType == null) {
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
"only primitive types and Set,List,Map collections are allowed, unknown type for property '" + this.getName()
|
||||
+ "' type is '" + this.getType() + "' in the entity " + this.getOwner().getName());
|
||||
String
|
||||
.format(
|
||||
"unknown type for property [%s], type [%s] in entity [%s]; only primitive types and collections or maps of primitive types are allowed",
|
||||
getName(), getType(), getOwner().getName()));
|
||||
}
|
||||
return dataType;
|
||||
}
|
||||
|
||||
private DataType qualifyAnnotatedType(CassandraType annotation) {
|
||||
private DataType getDataTypeFor(CassandraType annotation) {
|
||||
|
||||
DataType.Name type = annotation.type();
|
||||
|
||||
if (type.isCollection()) {
|
||||
switch (type) {
|
||||
|
||||
case MAP:
|
||||
ensureTypeArguments(annotation.typeArguments().length, 2);
|
||||
return DataType.map(resolvePrimitiveType(annotation.typeArguments()[0]),
|
||||
resolvePrimitiveType(annotation.typeArguments()[1]));
|
||||
return DataType.map(getDataTypeFor(annotation.typeArguments()[0]),
|
||||
getDataTypeFor(annotation.typeArguments()[1]));
|
||||
|
||||
case LIST:
|
||||
ensureTypeArguments(annotation.typeArguments().length, 1);
|
||||
return DataType.list(resolvePrimitiveType(annotation.typeArguments()[0]));
|
||||
return DataType.list(getDataTypeFor(annotation.typeArguments()[0]));
|
||||
|
||||
case SET:
|
||||
ensureTypeArguments(annotation.typeArguments().length, 1);
|
||||
return DataType.set(resolvePrimitiveType(annotation.typeArguments()[0]));
|
||||
return DataType.set(getDataTypeFor(annotation.typeArguments()[0]));
|
||||
|
||||
default:
|
||||
throw new InvalidDataAccessApiUsageException("unknown collection DataType for property '" + this.getName()
|
||||
+ "' type is '" + this.getType() + "' in the entity " + this.getOwner().getName());
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
String.format("unknown multivalued DataType [%s] for property [%s] in entity [%s]", type, getType(),
|
||||
getOwner().getName()));
|
||||
}
|
||||
} else {
|
||||
|
||||
return CassandraSimpleTypeHolder.getDataTypeFor(type);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isIndexed() {
|
||||
return getField().isAnnotationPresent(Indexed.class);
|
||||
return isAnnotationPresent(Indexed.class);
|
||||
}
|
||||
|
||||
public boolean isPartitionKeyColumn() {
|
||||
|
||||
PrimaryKeyColumn anno = getField().getAnnotation(PrimaryKeyColumn.class);
|
||||
PrimaryKeyColumn anno = findAnnotation(PrimaryKeyColumn.class);
|
||||
|
||||
return anno != null && anno.type() == PrimaryKeyType.PARTITIONED;
|
||||
}
|
||||
@@ -156,14 +176,14 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
|
||||
@Override
|
||||
public boolean isClusterKeyColumn() {
|
||||
|
||||
PrimaryKeyColumn anno = getField().getAnnotation(PrimaryKeyColumn.class);
|
||||
PrimaryKeyColumn anno = findAnnotation(PrimaryKeyColumn.class);
|
||||
|
||||
return anno != null && anno.type() == PrimaryKeyType.CLUSTERED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrimaryKeyColumn() {
|
||||
return getField().isAnnotationPresent(PrimaryKeyColumn.class);
|
||||
return isAnnotationPresent(PrimaryKeyColumn.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -171,7 +191,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
|
||||
return new Association<CassandraPersistentProperty>(this, null);
|
||||
}
|
||||
|
||||
DataType resolvePrimitiveType(DataType.Name typeName) {
|
||||
protected DataType getDataTypeFor(DataType.Name typeName) {
|
||||
DataType dataType = CassandraSimpleTypeHolder.getDataTypeFor(typeName);
|
||||
if (dataType == null) {
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
@@ -181,7 +201,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
|
||||
return dataType;
|
||||
}
|
||||
|
||||
DataType autodetectPrimitiveType(Class<?> javaType) {
|
||||
protected DataType getDataTypeFor(Class<?> javaType) {
|
||||
DataType dataType = CassandraSimpleTypeHolder.getDataTypeFor(javaType);
|
||||
if (dataType == null) {
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
@@ -191,7 +211,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
|
||||
return dataType;
|
||||
}
|
||||
|
||||
void ensureTypeArguments(int args, int expected) {
|
||||
protected void ensureTypeArguments(int args, int expected) {
|
||||
if (args != expected) {
|
||||
throw new InvalidDataAccessApiUsageException("expected " + expected + " of typed arguments for the property '"
|
||||
+ this.getName() + "' type is '" + this.getType() + "' in the entity " + this.getOwner().getName());
|
||||
|
||||
@@ -45,20 +45,12 @@ public class CassandraMappingContext extends
|
||||
setSimpleTypeHolder(new CassandraSimpleTypeHolder());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.AbstractMappingContext#createPersistentProperty(java.lang.reflect.Field, java.beans.PropertyDescriptor, org.springframework.data.mapping.MutablePersistentEntity, org.springframework.data.mapping.SimpleTypeHolder)
|
||||
*/
|
||||
@Override
|
||||
public CassandraPersistentProperty createPersistentProperty(Field field, PropertyDescriptor descriptor,
|
||||
BasicCassandraPersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {
|
||||
return new CachingCassandraPersistentProperty(field, descriptor, owner, simpleTypeHolder);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.BasicMappingContext#createPersistentEntity(org.springframework.data.util.TypeInformation, org.springframework.data.mapping.model.MappingContext)
|
||||
*/
|
||||
@Override
|
||||
protected <T> BasicCassandraPersistentEntity<T> createPersistentEntity(TypeInformation<T> typeInformation) {
|
||||
|
||||
@@ -71,10 +63,6 @@ public class CassandraMappingContext extends
|
||||
return entity;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
|
||||
*/
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.context = applicationContext;
|
||||
|
||||
@@ -31,8 +31,19 @@ import com.datastax.driver.core.DataType;
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CassandraType {
|
||||
|
||||
/**
|
||||
* The {@link DataType}.{@link Name} of the property.
|
||||
*/
|
||||
DataType.Name type();
|
||||
|
||||
/**
|
||||
* If the property is collection-like, then this attribute holds a single {@link DataType}.{@link Name}, representing
|
||||
* the element type of the collection.
|
||||
* <p/>
|
||||
* If the property is map, then this attribute holds exactly two {@link DataType}.{@link Name}s: the first is the key
|
||||
* type, and the second is the value type.
|
||||
* <p/>
|
||||
* If the property is neither collection-like or a map, then this attribute is ignored.
|
||||
*/
|
||||
DataType.Name[] typeArguments() default {};
|
||||
|
||||
}
|
||||
|
||||
@@ -31,8 +31,10 @@
|
||||
package org.springframework.data.cassandra.mapping;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation to define custom metadata for document fields.
|
||||
@@ -42,6 +44,7 @@ import java.lang.annotation.RetentionPolicy;
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value = { ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
public @interface Column {
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,21 +22,13 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Defines composite primary key class in the Cassandra table that contains several fields. Example:
|
||||
*
|
||||
* @CompositePrimaryKey class AccountPK { String account; String region; }
|
||||
*
|
||||
* @Table class Account {
|
||||
* @Id AccountPK pk; }
|
||||
*
|
||||
* Defines composite primary key class in the Cassandra table that contains several fields.
|
||||
*
|
||||
* @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.
|
||||
* @author Matthew T. Adams
|
||||
*/
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE })
|
||||
@Deprecated
|
||||
public @interface CompositePrimaryKey {
|
||||
}
|
||||
|
||||
@@ -21,15 +21,14 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Identifies a secondary index in the table. Usually it is a field with common dublicate values for the hole table.
|
||||
* such as city, place, educationType, state flags ant etc.
|
||||
* Identifies a secondary index in the table. Usually it is a field with common duplicate values within the table.
|
||||
*
|
||||
* Using unique fields is not common and has overhead, such as email, username and etc.
|
||||
* Using unique fields is not recommended.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
* @author Matthew T. Adams
|
||||
*/
|
||||
@Retention(value = RetentionPolicy.RUNTIME)
|
||||
@Target(value = { ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
public @interface Indexed {
|
||||
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import 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 <code>PRIMARY KEY</code> of the corresponding Cassandra table.
|
||||
@@ -29,6 +31,6 @@ import java.lang.annotation.Target;
|
||||
*/
|
||||
@Retention(value = RetentionPolicy.RUNTIME)
|
||||
@Target(value = { ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@org.springframework.data.annotation.Id
|
||||
@Id
|
||||
public @interface PrimaryKey {
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.cassandra.core.PrimaryKeyType;
|
||||
* cluster key field.
|
||||
*/
|
||||
@Retention(value = RetentionPolicy.RUNTIME)
|
||||
@Target(value = { ElementType.FIELD, ElementType.METHOD })
|
||||
@Target(value = { ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
public @interface PrimaryKeyColumn {
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user