This commit is contained in:
Matthew Adams
2013-12-11 15:55:06 -06:00
parent a50eb2f7ab
commit 68b624ec83
11 changed files with 170 additions and 72 deletions

View File

@@ -22,8 +22,8 @@ import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.data.convert.EntityInstantiators;
/**
* Base class for {@link CassandraConverter} implementations. Sets up a {@link GenericConversionService} and populates
* basic converters.
* Base class for {@link CassandraConverter} implementations. Sets up a {@link GenericConversionService} and
* populates basic converters.
*
* @author Alex Shvid
*/

View File

@@ -28,6 +28,6 @@ import org.springframework.data.convert.EntityConverter;
public interface CassandraConverter extends
EntityConverter<CassandraPersistentEntity<?>, CassandraPersistentProperty, Object, Object> {
// TODO: move this method to a more appropriate location
CreateTableSpecification getCreateTableSpecification(CassandraPersistentEntity<?> entity);
}

View File

@@ -20,7 +20,6 @@ import java.nio.ByteBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
import org.springframework.data.cassandra.util.CqlUtils;
import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
import org.springframework.data.mapping.model.PropertyValueProvider;
import org.springframework.data.mapping.model.SpELExpressionEvaluator;

View File

@@ -50,8 +50,8 @@ import com.datastax.driver.core.querybuilder.Update;
*
* @author Alex Shvid
*/
public class MappingCassandraConverter extends AbstractCassandraConverter implements ApplicationContextAware,
BeanClassLoaderAware {
public class MappingCassandraConverter extends AbstractCassandraConverter implements CassandraConverter,
ApplicationContextAware, BeanClassLoaderAware {
protected static final Logger log = LoggerFactory.getLogger(MappingCassandraConverter.class);
@@ -114,7 +114,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter implem
this.spELContext = new SpELContext(this.spELContext, applicationContext);
}
private <S extends Object> S readRowInternal(final CassandraPersistentEntity<S> entity, final Row row) {
protected <S extends Object> S readRowInternal(final CassandraPersistentEntity<S> entity, final Row row) {
final DefaultSpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(row, spELContext);
@@ -127,27 +127,40 @@ public class MappingCassandraConverter extends AbstractCassandraConverter implem
S instance = instantiator.createInstance(entity, parameterProvider);
final BeanWrapper<CassandraPersistentEntity<S>, S> wrapper = BeanWrapper.create(instance, conversionService);
final S result = wrapper.getBean();
S result = wrapper.getBean();
// Set properties not already set in the constructor
entity.doWithProperties(new PropertyHandler<CassandraPersistentProperty>() {
public void doWithPersistentProperty(CassandraPersistentProperty prop) {
boolean isConstructorProperty = entity.isConstructorArgument(prop);
boolean hasValueForProperty = row.getColumnDefinitions().contains(prop.getColumnName());
if (!hasValueForProperty || isConstructorProperty) {
return;
}
Object obj = propertyProvider.getPropertyValue(prop);
wrapper.setProperty(prop, obj, useFieldAccessOnly);
MappingCassandraConverter.this.handlePropertyRead(row, entity, prop, propertyProvider, wrapper);
}
});
return result;
}
protected void handlePropertyRead(final Row row, final CassandraPersistentEntity<?> entity,
final CassandraPersistentProperty prop,
final PropertyValueProvider<CassandraPersistentProperty> propertyProvider, final BeanWrapper<?, ?> wrapper) {
if (entity.isConstructorArgument(prop)) { // skip 'cause prop was set in ctor
return;
}
if (prop.isCompositePrimaryKey()) {
// TODO: handle composite primary key properties via recursion into this method
}
boolean hasValueForProperty = row.getColumnDefinitions().contains(prop.getColumnName());
if (!hasValueForProperty) {
return;
}
Object obj = propertyProvider.getPropertyValue(prop);
wrapper.setProperty(prop, obj, useFieldAccessOnly);
}
public void setUseFieldAccessOnly(boolean useFieldAccessOnly) {
this.useFieldAccessOnly = useFieldAccessOnly;
}

View File

@@ -25,7 +25,7 @@ import org.springframework.cassandra.core.PrimaryKeyType;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.mapping.Association;
import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.StringUtils;
@@ -48,7 +48,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
* @param simpleTypeHolder
*/
public BasicCassandraPersistentProperty(Field field, PropertyDescriptor propertyDescriptor,
CassandraPersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {
CassandraPersistentEntity<?> owner, CassandraSimpleTypeHolder simpleTypeHolder) {
super(field, propertyDescriptor, owner, simpleTypeHolder);
}
@@ -67,6 +67,24 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
return getField().getType().isAnnotationPresent(CompositePrimaryKey.class);
}
@Override
public Class<?> getCompositePrimaryKeyType() {
if (!isCompositePrimaryKey()) {
return null;
}
return getField().getType();
}
@Override
public CassandraPersistentEntity<?> getCompositePrimaryKeyEntity() {
if (!isCompositePrimaryKey()) {
return null;
}
return (CassandraPersistentEntity<?>) ClassTypeInformation.from(getCompositePrimaryKeyType());
}
public String getColumnName() {
// first check @Column annotation

View File

@@ -18,87 +18,136 @@ package org.springframework.data.cassandra.mapping;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.cassandra.core.Ordering;
import com.datastax.driver.core.DataType;
/**
* {@link CassandraPersistentProperty} caching access to {@link #isIdProperty()} and {@link #getColumnName()}.
* {@link BasicCassandraPersistentProperty} subclass that caches call results from the superclass.
*
* @author Alex Shvid
* @author Matthew T. Adams
*/
public class CachingCassandraPersistentProperty extends BasicCassandraPersistentProperty {
private Boolean isIdProperty;
private String columnName;
private Boolean isIndexed;
private Boolean isPartitioned;
private Boolean isCompositePrimaryKey;
private Boolean isPartitionKeyColumn;
private Boolean isClusterKeyColumn;
private Boolean isPrimaryKeyColumn;
private String columnName;
private Ordering ordering;
private boolean orderingCached = false;
private DataType dataType;
private Class<?> compositePrimaryKeyType;
private CassandraPersistentEntity<?> compositePrimaryKeyEntity;
/**
* Creates a new {@link CachingCassandraPersistentProperty}.
*
* @param field
* @param propertyDescriptor
* @param owner
* @param simpleTypeHolder
*/
public CachingCassandraPersistentProperty(Field field, PropertyDescriptor propertyDescriptor,
CassandraPersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {
CassandraPersistentEntity<?> owner, CassandraSimpleTypeHolder simpleTypeHolder) {
super(field, propertyDescriptor, owner, simpleTypeHolder);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.BasicCassandraPersistentProperty#isIdProperty()
*/
@Override
public CassandraPersistentEntity<?> getCompositePrimaryKeyEntity() {
if (compositePrimaryKeyEntity == null) {
compositePrimaryKeyEntity = super.getCompositePrimaryKeyEntity();
}
return compositePrimaryKeyEntity;
}
@Override
public Class<?> getCompositePrimaryKeyType() {
if (compositePrimaryKeyType == null) {
compositePrimaryKeyType = super.getCompositePrimaryKeyType();
}
return compositePrimaryKeyType;
}
@Override
public boolean isClusterKeyColumn() {
if (isClusterKeyColumn == null) {
isClusterKeyColumn = super.isClusterKeyColumn();
}
return isClusterKeyColumn;
}
@Override
public boolean isPrimaryKeyColumn() {
if (isPrimaryKeyColumn == null) {
isPrimaryKeyColumn = super.isPrimaryKeyColumn();
}
return isPrimaryKeyColumn;
}
@Override
public DataType getDataType() {
if (dataType == null) {
dataType = super.getDataType();
}
return dataType;
}
@Override
public Ordering getOrdering() {
if (!orderingCached) {
ordering = super.getOrdering();
orderingCached = true;
}
return ordering;
}
@Override
public boolean isCompositePrimaryKey() {
if (isCompositePrimaryKey == null) {
isCompositePrimaryKey = super.isCompositePrimaryKey();
}
return isCompositePrimaryKey;
}
@Override
public boolean isIdProperty() {
if (this.isIdProperty == null) {
this.isIdProperty = super.isIdProperty();
if (isIdProperty == null) {
isIdProperty = super.isIdProperty();
}
return this.isIdProperty;
return isIdProperty;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.BasicCassandraPersistentProperty#getFieldName()
*/
@Override
public String getColumnName() {
if (this.columnName == null) {
this.columnName = super.getColumnName();
if (columnName == null) {
columnName = super.getColumnName();
}
return this.columnName;
return columnName;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.BasicCassandraPersistentProperty#isIndexed()
*/
@Override
public boolean isIndexed() {
if (this.isIndexed == null) {
this.isIndexed = super.isIndexed();
if (isIndexed == null) {
isIndexed = super.isIndexed();
}
return this.isIndexed;
return isIndexed;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.BasicCassandraPersistentProperty#isPartitioned()
*/
@Override
public boolean isPartitionKeyColumn() {
if (this.isPartitioned == null) {
this.isPartitioned = super.isPartitionKeyColumn();
if (isPartitionKeyColumn == null) {
isPartitionKeyColumn = super.isPartitionKeyColumn();
}
return this.isPartitioned;
return isPartitionKeyColumn;
}
}

View File

@@ -27,13 +27,14 @@ import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.util.TypeInformation;
/**
* Default implementation of a {@link MappingContext} for Cassandra using {@link BasicCassandraPersistentEntity} and
* {@link BasicCassandraPersistentProperty} as primary abstractions.
* Default implementation of a {@link MappingContext} for Cassandra using {@link CassandraPersistentEntity} and
* {@link CassandraPersistentProperty} as primary abstractions.
*
* @author Alex Shvid
* @author Matthew T. Adams
*/
public class CassandraMappingContext extends
AbstractMappingContext<BasicCassandraPersistentEntity<?>, CassandraPersistentProperty> implements
AbstractMappingContext<CassandraPersistentEntity<?>, CassandraPersistentProperty> implements
ApplicationContextAware {
private ApplicationContext context;
@@ -47,12 +48,17 @@ public class CassandraMappingContext extends
@Override
public CassandraPersistentProperty createPersistentProperty(Field field, PropertyDescriptor descriptor,
BasicCassandraPersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {
CassandraPersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {
return createPersistentProperty(field, descriptor, owner, (CassandraSimpleTypeHolder) simpleTypeHolder);
}
public CassandraPersistentProperty createPersistentProperty(Field field, PropertyDescriptor descriptor,
CassandraPersistentEntity<?> owner, CassandraSimpleTypeHolder simpleTypeHolder) {
return new CachingCassandraPersistentProperty(field, descriptor, owner, simpleTypeHolder);
}
@Override
protected <T> BasicCassandraPersistentEntity<T> createPersistentEntity(TypeInformation<T> typeInformation) {
protected <T> CassandraPersistentEntity<T> createPersistentEntity(TypeInformation<T> typeInformation) {
BasicCassandraPersistentEntity<T> entity = new BasicCassandraPersistentEntity<T>(typeInformation);

View File

@@ -16,6 +16,7 @@
package org.springframework.data.cassandra.mapping;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.model.MutablePersistentEntity;
/**
* Cassandra specific {@link PersistentEntity} abstraction.
@@ -23,7 +24,7 @@ import org.springframework.data.mapping.PersistentEntity;
* @author Alex Shvid
* @author Matthew T. Adams
*/
public interface CassandraPersistentEntity<T> extends PersistentEntity<T, CassandraPersistentProperty> {
public interface CassandraPersistentEntity<T> extends MutablePersistentEntity<T, CassandraPersistentProperty> {
/**
* Returns the table name to which the entity shall be persisted.

View File

@@ -33,6 +33,18 @@ public interface CassandraPersistentProperty extends PersistentProperty<Cassandr
*/
boolean isCompositePrimaryKey();
/**
* Returns the type of the composite primary key class of this entity, or null if this class does not use a composite
* primary key.
*/
Class<?> getCompositePrimaryKeyType();
/**
* Returns a {@link CassandraPersistentEntity} representing the composite primary key class of this entity, or null if
* this class does not use a composite primary key.
*/
CassandraPersistentEntity<?> getCompositePrimaryKeyEntity();
/**
* The name of the column to which a property is persisted.
*/

View File

@@ -33,7 +33,7 @@ import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Update;
/**
* Utilties to convert Cassandra Annotated objects to Queries and CQL.
* Utilities to convert Cassandra Annotated objects to Queries and CQL.
*
* @author Alex Shvid
* @author David Webb

View File

@@ -28,9 +28,9 @@ import org.springframework.data.cassandra.mapping.BasicCassandraPersistentEntity
import org.springframework.data.cassandra.mapping.BasicCassandraPersistentProperty;
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
import org.springframework.data.cassandra.mapping.CassandraSimpleTypeHolder;
import org.springframework.data.cassandra.mapping.Column;
import org.springframework.data.cassandra.mapping.PrimaryKey;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.util.ReflectionUtils;
@@ -81,6 +81,6 @@ public class BasicCassandraPersistentPropertyIntegrationTests {
}
private CassandraPersistentProperty getPropertyFor(Field field) {
return new BasicCassandraPersistentProperty(field, null, entity, new SimpleTypeHolder());
return new BasicCassandraPersistentProperty(field, null, entity, new CassandraSimpleTypeHolder());
}
}