From 68b624ec835e00cd64aef7306a1225e8298089ca Mon Sep 17 00:00:00 2001 From: Matthew Adams Date: Wed, 11 Dec 2013 15:55:06 -0600 Subject: [PATCH] wip --- .../convert/AbstractCassandraConverter.java | 4 +- .../cassandra/convert/CassandraConverter.java | 2 +- .../CassandraPropertyValueProvider.java | 1 - .../convert/MappingCassandraConverter.java | 41 ++++-- .../BasicCassandraPersistentProperty.java | 22 ++- .../CachingCassandraPersistentProperty.java | 135 ++++++++++++------ .../mapping/CassandraMappingContext.java | 16 ++- .../mapping/CassandraPersistentEntity.java | 3 +- .../mapping/CassandraPersistentProperty.java | 12 ++ .../data/cassandra/util/CqlUtils.java | 2 +- ...draPersistentPropertyIntegrationTests.java | 4 +- 11 files changed, 170 insertions(+), 72 deletions(-) diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/AbstractCassandraConverter.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/AbstractCassandraConverter.java index 9f4195758..9943bcd87 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/AbstractCassandraConverter.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/AbstractCassandraConverter.java @@ -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 */ diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/CassandraConverter.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/CassandraConverter.java index 68f723ad6..ac07a2f98 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/CassandraConverter.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/CassandraConverter.java @@ -28,6 +28,6 @@ import org.springframework.data.convert.EntityConverter; public interface CassandraConverter extends EntityConverter, CassandraPersistentProperty, Object, Object> { + // TODO: move this method to a more appropriate location CreateTableSpecification getCreateTableSpecification(CassandraPersistentEntity entity); - } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/CassandraPropertyValueProvider.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/CassandraPropertyValueProvider.java index 109086254..4e7cea9c0 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/CassandraPropertyValueProvider.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/CassandraPropertyValueProvider.java @@ -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; 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 7284aeeb6..293bfe773 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 @@ -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 readRowInternal(final CassandraPersistentEntity entity, final Row row) { + protected S readRowInternal(final CassandraPersistentEntity 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, 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() { + 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 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; } 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 1617353fb..1ca9e6a9c 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 @@ -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 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 403e55ffb..0b4d05ed7 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 @@ -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; } - } 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 31029b5b4..dfe546e93 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 @@ -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, CassandraPersistentProperty> implements + AbstractMappingContext, 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 BasicCassandraPersistentEntity createPersistentEntity(TypeInformation typeInformation) { + protected CassandraPersistentEntity createPersistentEntity(TypeInformation typeInformation) { BasicCassandraPersistentEntity entity = new BasicCassandraPersistentEntity(typeInformation); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraPersistentEntity.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraPersistentEntity.java index 444f5e50d..12881fe95 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraPersistentEntity.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraPersistentEntity.java @@ -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 extends PersistentEntity { +public interface CassandraPersistentEntity extends MutablePersistentEntity { /** * Returns the table name to which the entity shall be persisted. 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 81a1f5e55..5b54b024c 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 @@ -33,6 +33,18 @@ public interface CassandraPersistentProperty extends PersistentProperty 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. */ diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/util/CqlUtils.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/util/CqlUtils.java index 1da50f119..a37380b85 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/util/CqlUtils.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/util/CqlUtils.java @@ -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 diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/mapping/BasicCassandraPersistentPropertyIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/mapping/BasicCassandraPersistentPropertyIntegrationTests.java index bcaede589..db6f31658 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/mapping/BasicCassandraPersistentPropertyIntegrationTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/mapping/BasicCassandraPersistentPropertyIntegrationTests.java @@ -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()); } }