DATACASS-523 - Polish.

This commit is contained in:
John Blum
2018-03-23 21:00:37 -07:00
parent dd718ae234
commit 48077f8b0e
36 changed files with 831 additions and 754 deletions

View File

@@ -16,6 +16,7 @@
package org.springframework.data.cassandra.config;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
import org.springframework.beans.factory.BeanClassLoaderAware;
@@ -64,9 +65,12 @@ public abstract class AbstractCassandraConfiguration extends AbstractClusterConf
protected Session getRequiredSession() {
CassandraSessionFactoryBean factoryBean = session();
Assert.state(factoryBean.getObject() != null, "Session factory not initialized");
return factoryBean.getObject();
Session session = factoryBean.getObject();
Assert.state(session != null, "Session factory not initialized");
return session;
}
/**
@@ -126,8 +130,8 @@ public abstract class AbstractCassandraConfiguration extends AbstractClusterConf
mappingCassandraConverter.setCustomConversions(customConversions());
return mappingCassandraConverter;
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e);
} catch (ClassNotFoundException cause) {
throw new IllegalStateException(cause);
}
}
@@ -146,9 +150,7 @@ public abstract class AbstractCassandraConfiguration extends AbstractClusterConf
CassandraMappingContext mappingContext = new CassandraMappingContext(
new SimpleUserTypeResolver(cluster, getKeyspaceName()), new SimpleTupleTypeFactory(cluster));
if (beanClassLoader != null) {
mappingContext.setBeanClassLoader(beanClassLoader);
}
Optional.ofNullable(this.beanClassLoader).ifPresent(mappingContext::setBeanClassLoader);
mappingContext.setInitialEntitySet(getInitialEntitySet());

View File

@@ -17,6 +17,8 @@ package org.springframework.data.cassandra.core.convert;
import java.util.Collections;
import lombok.NonNull;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.GenericConversionService;
@@ -64,6 +66,12 @@ public abstract class AbstractCassandraConverter implements CassandraConverter,
this.instantiators = instantiators;
}
@NonNull
@Override
public ConversionService getConversionService() {
return this.conversionService;
}
/**
* Registers the given custom conversions with the converter.
*/
@@ -76,7 +84,7 @@ public abstract class AbstractCassandraConverter implements CassandraConverter,
*/
@Override
public CustomConversions getCustomConversions() {
return conversions;
return this.conversions;
}
/* (non-Javadoc)
@@ -93,13 +101,10 @@ public abstract class AbstractCassandraConverter implements CassandraConverter,
*/
private void initializeConverters() {
ConversionService conversionService = getConversionService();
if (conversionService instanceof GenericConversionService) {
conversions.registerConvertersIn((GenericConversionService) conversionService);
getCustomConversions().registerConvertersIn((GenericConversionService) conversionService);
}
}
@Override
public ConversionService getConversionService() {
return conversionService;
}
}

View File

@@ -75,11 +75,10 @@ public class BasicCassandraRowValueProvider implements CassandraRowValueProvider
public <T> T getPropertyValue(CassandraPersistentProperty property) {
String spelExpression = property.getSpelExpression();
if (spelExpression != null) {
return evaluator.evaluate(spelExpression);
}
return (T) reader.get(property.getRequiredColumnName());
return spelExpression != null
? this.evaluator.evaluate(spelExpression)
: (T) this.reader.get(property.getRequiredColumnName());
}
/* (non-Javadoc)
@@ -87,7 +86,7 @@ public class BasicCassandraRowValueProvider implements CassandraRowValueProvider
*/
@Override
public Row getRow() {
return reader.getRow();
return this.reader.getRow();
}
/* (non-Javadoc)

View File

@@ -32,12 +32,12 @@ import com.datastax.driver.core.TupleValue;
*/
public class CassandraTupleValueProvider implements CassandraValueProvider {
private final TupleValue tupleValue;
private final CodecRegistry codecRegistry;
private final SpELExpressionEvaluator evaluator;
private final TupleValue tupleValue;
/**
* Create a new {@link CassandraTupleValueProvider} with the given {@link TupleValue} and
* {@link SpELExpressionEvaluator}.
@@ -58,14 +58,6 @@ public class CassandraTupleValueProvider implements CassandraValueProvider {
this.evaluator = evaluator;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.convert.CassandraValueProvider#hasProperty(org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty)
*/
@Override
public boolean hasProperty(CassandraPersistentProperty property) {
return tupleValue.getType().getComponentTypes().size() >= property.getRequiredOrdinal();
}
/* (non-Javadoc)
* @see org.springframework.data.mapping.model.PropertyValueProvider#getPropertyValue(org.springframework.data.mapping.PersistentProperty)
*/
@@ -74,6 +66,7 @@ public class CassandraTupleValueProvider implements CassandraValueProvider {
public <T> T getPropertyValue(CassandraPersistentProperty property) {
String spelExpression = property.getSpelExpression();
if (spelExpression != null) {
return evaluator.evaluate(spelExpression);
}
@@ -83,4 +76,12 @@ public class CassandraTupleValueProvider implements CassandraValueProvider {
return tupleValue.get(ordinal, codecRegistry.codecFor(elementType));
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.convert.CassandraValueProvider#hasProperty(org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty)
*/
@Override
public boolean hasProperty(CassandraPersistentProperty property) {
return this.tupleValue.getType().getComponentTypes().size() >= property.getRequiredOrdinal();
}
}

View File

@@ -71,6 +71,7 @@ public class CassandraUDTValueProvider implements CassandraValueProvider {
@Deprecated
public CassandraUDTValueProvider(UDTValue udtValue, CodecRegistry codecRegistry,
DefaultSpELExpressionEvaluator evaluator) {
this(udtValue, codecRegistry, (SpELExpressionEvaluator) evaluator);
}
@@ -82,14 +83,15 @@ public class CassandraUDTValueProvider implements CassandraValueProvider {
public <T> T getPropertyValue(CassandraPersistentProperty property) {
String spelExpression = property.getSpelExpression();
if (spelExpression != null) {
return evaluator.evaluate(spelExpression);
return this.evaluator.evaluate(spelExpression);
}
String name = property.getRequiredColumnName().toCql();
DataType fieldType = udtValue.getType().getFieldType(name);
DataType fieldType = this.udtValue.getType().getFieldType(name);
return udtValue.get(name, codecRegistry.codecFor(fieldType));
return this.udtValue.get(name, this.codecRegistry.codecFor(fieldType));
}
/* (non-Javadoc)
@@ -97,6 +99,6 @@ public class CassandraUDTValueProvider implements CassandraValueProvider {
*/
@Override
public boolean hasProperty(CassandraPersistentProperty property) {
return udtValue.getType().contains(property.getRequiredColumnName().toCql());
return this.udtValue.getType().contains(property.getRequiredColumnName().toCql());
}
}

View File

@@ -15,8 +15,6 @@
*/
package org.springframework.data.cassandra.core.convert;
import lombok.AllArgsConstructor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -25,13 +23,14 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.CollectionFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.cassandra.core.mapping.BasicCassandraPersistentEntity;
@@ -58,6 +57,9 @@ import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.datastax.driver.core.CodecRegistry;
import com.datastax.driver.core.DataType;
import com.datastax.driver.core.Row;
@@ -85,7 +87,7 @@ import com.datastax.driver.core.querybuilder.Update;
* @author John Blum
*/
public class MappingCassandraConverter extends AbstractCassandraConverter
implements CassandraConverter, ApplicationContextAware, BeanClassLoaderAware {
implements ApplicationContextAware, BeanClassLoaderAware {
private final Logger log = LoggerFactory.getLogger(getClass());
@@ -95,11 +97,24 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
private SpELContext spELContext;
private static ConversionService newConversionService() {
return new DefaultConversionService();
}
private static CassandraMappingContext newDefaultMappingContext() {
CassandraMappingContext mappingContext = new CassandraMappingContext();
mappingContext.setCustomConversions(new CassandraCustomConversions(Collections.emptyList()));
return mappingContext;
}
/**
* Create a new {@link MappingCassandraConverter} with a {@link CassandraMappingContext}.
*/
public MappingCassandraConverter() {
this(createMappingContext());
this(newDefaultMappingContext());
}
/**
@@ -109,7 +124,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
*/
public MappingCassandraConverter(CassandraMappingContext mappingContext) {
super(new DefaultConversionService());
super(newConversionService());
Assert.notNull(mappingContext, "CassandraMappingContext must not be null");
@@ -117,15 +132,6 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
this.spELContext = new SpELContext(RowReaderPropertyAccessor.INSTANCE);
}
private static CassandraMappingContext createMappingContext() {
CassandraMappingContext mappingContext = new CassandraMappingContext();
mappingContext.setCustomConversions(new CassandraCustomConversions(Collections.emptyList()));
return mappingContext;
}
/* (non-Javadoc)
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
@@ -142,6 +148,14 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
this.beanClassLoader = classLoader;
}
private TypeCodec<Object> getCodec(CassandraPersistentProperty property) {
return getCodecRegistry().codecFor(getMappingContext().getDataType(property));
}
private CodecRegistry getCodecRegistry() {
return CodecRegistry.DEFAULT_INSTANCE;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.convert.CassandraConverter#getMappingContext()
*/
@@ -151,7 +165,56 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
}
/**
* Read a {@link Row} into the requested target {@code type}.
* Create a new {@link ConvertingPropertyAccessor} for the given {@link Object source}
* and {@link CassandraPersistentEntity entity}.
*
* @param source {@link Object} containing the property values to access; must not be {@literal null}.
* @param entity {@link CassandraPersistentEntity} for the source; must not be {@literal null}.
* @return a new {@link ConvertingPropertyAccessor} for the given {@link Object source}
* and {@link CassandraPersistentEntity entity}.
* @see org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity
*/
private ConvertingPropertyAccessor newConvertingPropertyAccessor(Object source,
CassandraPersistentEntity<?> entity) {
PersistentPropertyAccessor propertyAccessor = source instanceof PersistentPropertyAccessor
? (PersistentPropertyAccessor) source : entity.getPropertyAccessor(source);
return new ConvertingPropertyAccessor(propertyAccessor, getConversionService());
}
private <S> PersistentEntityParameterValueProvider<CassandraPersistentProperty> newParameterValueProvider(
CassandraPersistentEntity<S> entity, CassandraValueProvider valueProvider) {
return new PersistentEntityParameterValueProvider<>(entity,
new MappingAndConvertingValueProvider(valueProvider), null);
}
@SuppressWarnings("unchecked")
private <T> Class<T> transformClassToBeanClassLoaderClass(Class<T> entity) {
try {
return (Class<T>) ClassUtils.forName(entity.getName(), this.beanClassLoader);
} catch (ClassNotFoundException | LinkageError ignore) {
return entity;
}
}
/* (non-Javadoc)
* @see org.springframework.data.convert.EntityReader#read(java.lang.Class, S)
*/
@Override
public <R> R read(Class<R> type, Object row) {
if (row instanceof Row) {
return readRow(type, (Row) row);
}
throw new MappingException(String.format("Unknown row object [%s]", ObjectUtils.nullSafeClassName(row)));
}
/**
* Read a {@link Row} into the requested target {@link Class type}.
*
* @param type must not be {@literal null}.
* @param row must not be {@literal null}.
@@ -178,69 +241,59 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
return getConversionService().convert(row, type);
}
CassandraPersistentEntity<R> persistentEntity = (CassandraPersistentEntity<R>) getMappingContext()
.getRequiredPersistentEntity(typeInfo);
CassandraPersistentEntity<R> persistentEntity =
(CassandraPersistentEntity<R>) getMappingContext().getRequiredPersistentEntity(typeInfo);
return readEntityFromRow(persistentEntity, row);
}
protected <S> S readEntityFromRow(CassandraPersistentEntity<S> entity, Row row) {
private <S> S readEntityFromRow(CassandraPersistentEntity<S> entity, Row row) {
return doRead(entity, row, expressionEvaluator -> new BasicCassandraRowValueProvider(row, expressionEvaluator));
}
protected <S> S readEntityFromUdt(CassandraPersistentEntity<S> entity, UDTValue udtValue) {
private <S> S readEntityFromTuple(CassandraPersistentEntity<S> entity, TupleValue tupleValue) {
return doRead(entity, tupleValue,
expressionEvaluator -> new CassandraTupleValueProvider(tupleValue, getCodecRegistry(), expressionEvaluator));
}
private <S> S readEntityFromUdt(CassandraPersistentEntity<S> entity, UDTValue udtValue) {
return doRead(entity, udtValue,
expressionEvaluator -> new CassandraUDTValueProvider(udtValue, getCodecRegistry(), expressionEvaluator));
}
protected <S> S readEntityFromTuple(CassandraPersistentEntity<S> entity, TupleValue tupleValue) {
return doRead(entity, tupleValue,
expressionEvaluator -> new CassandraTupleValueProvider(tupleValue, getCodecRegistry(), expressionEvaluator));
}
protected <S, V> S doRead(CassandraPersistentEntity<S> entity, V value,
private <S, V> S doRead(CassandraPersistentEntity<S> entity, V value,
Function<SpELExpressionEvaluator, CassandraValueProvider> valueProviderSupplier) {
DefaultSpELExpressionEvaluator expressionEvaluator = new DefaultSpELExpressionEvaluator(value, spELContext);
SpELExpressionEvaluator expressionEvaluator = new DefaultSpELExpressionEvaluator(value, this.spELContext);
CassandraValueProvider valueProvider = valueProviderSupplier.apply(expressionEvaluator);
PersistentEntityParameterValueProvider<CassandraPersistentProperty> parameterValueProvider = getParameterValueProvider(
entity, valueProvider);
PersistentEntityParameterValueProvider<CassandraPersistentProperty> parameterValueProvider =
newParameterValueProvider(entity, valueProvider);
EntityInstantiator instantiator = instantiators.getInstantiatorFor(entity);
EntityInstantiator instantiator = this.instantiators.getInstantiatorFor(entity);
S instance = instantiator.createInstance(entity, parameterValueProvider);
readProperties(entity, valueProvider, getConvertingAccessor(instance, entity));
readProperties(entity, valueProvider, newConvertingPropertyAccessor(instance, entity));
return instance;
}
private <S> PersistentEntityParameterValueProvider<CassandraPersistentProperty> getParameterValueProvider(
CassandraPersistentEntity<S> entity, CassandraValueProvider valueProvider) {
return new PersistentEntityParameterValueProvider<>(entity, new MappingAndConvertingValueProvider(valueProvider),
null);
}
protected void readPropertiesFromRow(CassandraPersistentEntity<?> entity, CassandraRowValueProvider row,
PersistentPropertyAccessor propertyAccessor) {
readProperties(entity, row, propertyAccessor);
}
protected void readProperties(CassandraPersistentEntity<?> entity, CassandraValueProvider valueProvider,
private void readProperties(CassandraPersistentEntity<?> entity, CassandraValueProvider valueProvider,
PersistentPropertyAccessor propertyAccessor) {
for (CassandraPersistentProperty property : entity) {
MappingCassandraConverter.this.readProperty(entity, property, valueProvider, propertyAccessor);
readProperty(entity, property, valueProvider, propertyAccessor);
}
}
protected void readProperty(CassandraPersistentEntity<?> entity, CassandraPersistentProperty property,
private void readProperty(CassandraPersistentEntity<?> entity, CassandraPersistentProperty property,
CassandraValueProvider valueProvider, PersistentPropertyAccessor propertyAccessor) {
// if true then skip; property was set in constructor
// if true then skip; property was set in the constructor
if (entity.isConstructorArgument(property)) {
return;
}
@@ -256,7 +309,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
}
// now recurse on using the key this time
readProperties(keyEntity, valueProvider, getConvertingAccessor(key, keyEntity));
readProperties(keyEntity, valueProvider, newConvertingPropertyAccessor(key, keyEntity));
// now that the key's properties have been populated, set the key property on the entity
propertyAccessor.setProperty(property, key);
@@ -271,24 +324,11 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
propertyAccessor.setProperty(property, getReadValue(valueProvider, property));
}
protected Object instantiatePrimaryKey(CassandraPersistentEntity<?> entity, CassandraPersistentProperty keyProperty,
private Object instantiatePrimaryKey(CassandraPersistentEntity<?> entity, CassandraPersistentProperty keyProperty,
CassandraValueProvider propertyProvider) {
return this.instantiators.getInstantiatorFor(entity).createInstance(entity,
getParameterValueProvider(entity, propertyProvider));
}
/* (non-Javadoc)
* @see org.springframework.data.convert.EntityReader#read(java.lang.Class, S)
*/
@Override
public <R> R read(Class<R> type, Object row) {
if (row instanceof Row) {
return readRow(type, (Row) row);
}
throw new MappingException("Unknown row object " + ObjectUtils.nullSafeClassName(row));
newParameterValueProvider(entity, propertyProvider));
}
/* (non-Javadoc)
@@ -324,16 +364,6 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
write(source, sink, entity);
}
@SuppressWarnings("unchecked")
private <T> Class<T> transformClassToBeanClassLoaderClass(Class<T> entity) {
try {
return (Class<T>) ClassUtils.forName(entity.getName(), this.beanClassLoader);
} catch (ClassNotFoundException | LinkageError ignore) {
return entity;
}
}
@Override
@SuppressWarnings("unchecked")
public void write(Object source, Object sink, CassandraPersistentEntity<?> entity) {
@@ -345,65 +375,21 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
}
if (sink instanceof Map) {
writeMapFromWrapper(getConvertingAccessor(source, entity), (Map<String, Object>) sink, entity);
writeMapFromWrapper(newConvertingPropertyAccessor(source, entity), (Map<String, Object>) sink, entity);
} else if (sink instanceof Insert) {
writeInsertFromObject(source, (Insert) sink, entity);
writeInsertFromWrapper(newConvertingPropertyAccessor(source, entity), (Insert) sink, entity);
} else if (sink instanceof Update) {
writeUpdateFromObject(source, (Update) sink, entity);
writeUpdateFromWrapper(newConvertingPropertyAccessor(source, entity), (Update) sink, entity);
} else if (sink instanceof Select.Where) {
writeSelectWhereFromObject(source, (Select.Where) sink, entity);
} else if (sink instanceof Delete.Where) {
writeDeleteWhereFromObject(source, (Delete.Where) sink, entity);
} else if (sink instanceof UDTValue) {
writeUDTValue(getConvertingAccessor(source, entity), (UDTValue) sink, entity);
} else if (sink instanceof TupleValue) {
writeTupleValue(getConvertingAccessor(source, entity), (TupleValue) sink, entity);
writeTupleValue(newConvertingPropertyAccessor(source, entity), (TupleValue) sink, entity);
} else if (sink instanceof UDTValue) {
writeUDTValue(newConvertingPropertyAccessor(source, entity), (UDTValue) sink, entity);
} else {
throw new MappingException("Unknown write target " + sink.getClass().getName());
}
}
private void writeInsertFromObject(Object object, Insert insert, CassandraPersistentEntity<?> entity) {
writeInsertFromWrapper(getConvertingAccessor(object, entity), insert, entity);
}
protected void writeInsertFromWrapper(ConvertingPropertyAccessor accessor, Insert insert,
CassandraPersistentEntity<?> entity) {
for (CassandraPersistentProperty property : entity) {
Object value = getWriteValue(property, accessor);
if (log.isDebugEnabled()) {
log.debug("doWithProperties Property.type {}, Property.value {}", property.getType().getName(), value);
}
if (property.isCompositePrimaryKey()) {
if (log.isDebugEnabled()) {
log.debug("Property is a compositeKey");
}
if (value == null) {
continue;
}
CassandraPersistentEntity<?> compositePrimaryKey = getMappingContext().getRequiredPersistentEntity(property);
writeInsertFromWrapper(getConvertingAccessor(value, compositePrimaryKey), insert, compositePrimaryKey);
continue;
}
if (value == null) {
continue;
}
if (log.isDebugEnabled()) {
log.debug("Adding insert.value [{}] - [{}]", property.getRequiredColumnName().toCql(), value);
}
insert.value(property.getRequiredColumnName().toCql(), value);
throw new MappingException(String.format("Unknown write target [%s]", ObjectUtils.nullSafeClassName(sink)));
}
}
@@ -430,7 +416,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
CassandraPersistentEntity<?> compositePrimaryKey = getMappingContext().getRequiredPersistentEntity(property);
writeMapFromWrapper(getConvertingAccessor(value, compositePrimaryKey), insert, compositePrimaryKey);
writeMapFromWrapper(newConvertingPropertyAccessor(value, compositePrimaryKey), insert, compositePrimaryKey);
continue;
}
@@ -443,16 +429,52 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
}
}
protected void writeUpdateFromObject(Object object, Update update, CassandraPersistentEntity<?> entity) {
writeUpdateFromWrapper(getConvertingAccessor(object, entity), update, entity);
}
protected void writeUpdateFromWrapper(ConvertingPropertyAccessor accessor, Update update,
private void writeInsertFromWrapper(ConvertingPropertyAccessor propertyAccessor, Insert insert,
CassandraPersistentEntity<?> entity) {
for (CassandraPersistentProperty property : entity) {
Object value = getWriteValue(property, accessor);
Object value = getWriteValue(property, propertyAccessor);
if (log.isDebugEnabled()) {
log.debug("doWithProperties Property.type {}, Property.value {}", property.getType().getName(), value);
}
if (property.isCompositePrimaryKey()) {
if (log.isDebugEnabled()) {
log.debug("Property is a compositeKey");
}
if (value == null) {
continue;
}
CassandraPersistentEntity<?> compositePrimaryKey = getMappingContext().getRequiredPersistentEntity(property);
writeInsertFromWrapper(newConvertingPropertyAccessor(value, compositePrimaryKey), insert, compositePrimaryKey);
continue;
}
if (value == null) {
continue;
}
if (log.isDebugEnabled()) {
log.debug("Adding insert.value [{}] - [{}]", property.getRequiredColumnName().toCql(), value);
}
insert.value(property.getRequiredColumnName().toCql(), value);
}
}
private void writeUpdateFromWrapper(ConvertingPropertyAccessor propertyAccessor, Update update,
CassandraPersistentEntity<?> entity) {
for (CassandraPersistentProperty property : entity) {
Object value = getWriteValue(property, propertyAccessor);
if (property.isCompositePrimaryKey()) {
@@ -462,7 +484,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
continue;
}
writeUpdateFromWrapper(getConvertingAccessor(value, compositePrimaryKey), update, compositePrimaryKey);
writeUpdateFromWrapper(newConvertingPropertyAccessor(value, compositePrimaryKey), update, compositePrimaryKey);
continue;
}
@@ -475,55 +497,36 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
}
}
protected void writeSelectWhereFromObject(Object object, Select.Where where, CassandraPersistentEntity<?> entity) {
/**
* Returns whether the property is part of the primary key.
*
* @param property {@link CassandraPersistentProperty} to evaluate.
* @return a boolean value indicating whether the given property is party of a primary key.
*/
private boolean isPrimaryKeyPart(CassandraPersistentProperty property) {
return property.isCompositePrimaryKey() || property.isPrimaryKeyColumn() || property.isIdProperty();
}
private void writeSelectWhereFromObject(Object object, Select.Where where, CassandraPersistentEntity<?> entity) {
getWhereClauses(object, entity).forEach(where::and);
}
protected void writeDeleteWhereFromObject(Object object, Delete.Where where, CassandraPersistentEntity<?> entity) {
private void writeDeleteWhereFromObject(Object object, Delete.Where where, CassandraPersistentEntity<?> entity) {
getWhereClauses(object, entity).forEach(where::and);
}
protected void writeUDTValue(ConvertingPropertyAccessor accessor, UDTValue udtValue,
CassandraPersistentEntity<?> entity) {
@Nullable
private Object extractId(Object source, CassandraPersistentEntity<?> entity) {
for (CassandraPersistentProperty property : entity) {
Object value = getWriteValue(property, accessor);
if (log.isDebugEnabled()) {
log.debug("writeUDTValueWhereFromObject Property.type {}, Property.value {}", property.getType().getName(),
value);
}
if (log.isDebugEnabled()) {
log.debug("Adding udt.value [{}] - [{}]", property.getRequiredColumnName().toCql(), value);
}
TypeCodec<Object> typeCodec = getCodecRegistry().codecFor(getMappingContext().getDataType(property));
udtValue.set(property.getRequiredColumnName().toCql(), value, typeCodec);
if (ClassUtils.isAssignableValue(entity.getType(), source)) {
return getId(source, entity);
} else if (source instanceof MapId) {
return source;
} else if (source instanceof MapIdentifiable) {
return ((MapIdentifiable) source).getMapId();
}
}
protected void writeTupleValue(ConvertingPropertyAccessor accessor, TupleValue tupleValue,
CassandraPersistentEntity<?> entity) {
for (CassandraPersistentProperty property : entity) {
Object value = getWriteValue(property, accessor);
if (log.isDebugEnabled()) {
log.debug("writeTupleValue Property.type {}, Property.value {}", property.getType().getName(), value);
}
if (log.isDebugEnabled()) {
log.debug("Adding tuple value [{}] - [{}]", property.getOrdinal(), value);
}
TypeCodec<Object> typeCodec = getCodecRegistry().codecFor(mappingContext.getDataType(property));
tupleValue.set(property.getRequiredOrdinal(), value, typeCodec);
}
return source;
}
private Collection<Clause> getWhereClauses(Object source, CassandraPersistentEntity<?> entity) {
@@ -544,64 +547,34 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
if (id instanceof MapId) {
CassandraPersistentEntity<?> whereEntity = compositeIdProperty != null
? getMappingContext().getRequiredPersistentEntity(compositeIdProperty)
: entity;
? getMappingContext().getRequiredPersistentEntity(compositeIdProperty)
: entity;
return getWhereClauses(MapId.class.cast(id), whereEntity);
}
if (idProperty == null) {
throw new InvalidDataAccessApiUsageException(
String.format("Cannot obtain where clauses for entity [%s] using [%s]", entity.getName(), source));
String.format("Cannot obtain where clauses for entity [%s] using [%s]", entity.getName(), source));
}
if (compositeIdProperty != null) {
if (!ClassUtils.isAssignableValue(compositeIdProperty.getType(), id)) {
throw new InvalidDataAccessApiUsageException(
String.format("Cannot use [%s] as composite Id for [%s]", id, entity.getName()));
String.format("Cannot use [%s] as composite Id for [%s]", id, entity.getName()));
}
CassandraPersistentEntity<?> compositePrimaryKey = getMappingContext()
.getRequiredPersistentEntity(compositeIdProperty);
CassandraPersistentEntity<?> compositePrimaryKey =
getMappingContext().getRequiredPersistentEntity(compositeIdProperty);
return getWhereClauses(getConvertingAccessor(id, compositePrimaryKey), compositePrimaryKey);
return getWhereClauses(newConvertingPropertyAccessor(id, compositePrimaryKey), compositePrimaryKey);
}
Class<?> targetType = getTargetType(idProperty);
return Collections.singleton(QueryBuilder.eq(idProperty.getRequiredColumnName().toCql(),
getPotentiallyConvertedSimpleValue(id, targetType)));
}
@Nullable
private Object extractId(Object source, CassandraPersistentEntity<?> entity) {
if (ClassUtils.isAssignableValue(entity.getType(), source)) {
return getId(source, entity);
} else if (source instanceof MapId) {
return source;
} else if (source instanceof MapIdentifiable) {
return ((MapIdentifiable) source).getMapId();
}
return source;
}
private Collection<Clause> getWhereClauses(ConvertingPropertyAccessor accessor, CassandraPersistentEntity<?> entity) {
Assert.isTrue(entity.isCompositePrimaryKey(),
String.format("Entity [%s] is not a composite primary key", entity.getName()));
Collection<Clause> clauses = new ArrayList<>();
for (CassandraPersistentProperty property : entity) {
TypeCodec<Object> codec = getCodec(property);
Object value = accessor.getProperty(property, codec.getJavaType().getRawType());
clauses.add(QueryBuilder.eq(property.getRequiredColumnName().toCql(), value));
}
return clauses;
getPotentiallyConvertedSimpleValue(id, targetType)));
}
private Collection<Clause> getWhereClauses(MapId id, CassandraPersistentEntity<?> entity) {
@@ -616,7 +589,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
if (persistentProperty == null) {
throw new IllegalArgumentException(String.format(
"MapId contains references [%s] that is an unknown property of [%s]", entry.getKey(), entity.getName()));
"MapId contains references [%s] that is an unknown property of [%s]", entry.getKey(), entity.getName()));
}
Object writeValue = getWriteValue(entry.getValue(), persistentProperty.getTypeInformation());
@@ -627,6 +600,65 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
return clauses;
}
private Collection<Clause> getWhereClauses(ConvertingPropertyAccessor accessor, CassandraPersistentEntity<?> entity) {
Assert.isTrue(entity.isCompositePrimaryKey(),
String.format("Entity [%s] is not a composite primary key", entity.getName()));
Collection<Clause> clauses = new ArrayList<>();
for (CassandraPersistentProperty property : entity) {
TypeCodec<Object> codec = getCodec(property);
Object value = accessor.getProperty(property, codec.getJavaType().getRawType());
clauses.add(QueryBuilder.eq(property.getRequiredColumnName().toCql(), value));
}
return clauses;
}
private void writeTupleValue(ConvertingPropertyAccessor propertyAccessor, TupleValue tupleValue,
CassandraPersistentEntity<?> entity) {
for (CassandraPersistentProperty property : entity) {
Object value = getWriteValue(property, propertyAccessor);
if (log.isDebugEnabled()) {
log.debug("writeTupleValue Property.type {}, Property.value {}", property.getType().getName(), value);
}
if (log.isDebugEnabled()) {
log.debug("Adding tuple value [{}] - [{}]", property.getOrdinal(), value);
}
TypeCodec<Object> typeCodec = getCodec(property);
tupleValue.set(property.getRequiredOrdinal(), value, typeCodec);
}
}
private void writeUDTValue(ConvertingPropertyAccessor propertyAccessor, UDTValue udtValue,
CassandraPersistentEntity<?> entity) {
for (CassandraPersistentProperty property : entity) {
Object value = getWriteValue(property, propertyAccessor);
if (log.isDebugEnabled()) {
log.debug("writeUDTValueWhereFromObject Property.type {}, Property.value {}", property.getType().getName(),
value);
}
if (log.isDebugEnabled()) {
log.debug("Adding udt.value [{}] - [{}]", property.getRequiredColumnName().toCql(), value);
}
TypeCodec<Object> typeCodec = getCodec(property);
udtValue.set(property.getRequiredColumnName().toCql(), value, typeCodec);
}
}
@Override
@SuppressWarnings("unchecked")
public Object getId(Object object, CassandraPersistentEntity<?> entity) {
@@ -634,10 +666,10 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
Assert.notNull(object, "Object instance must not be null");
Assert.notNull(entity, "CassandraPersistentEntity must not be null");
ConvertingPropertyAccessor propertyAccessor = getConvertingAccessor(object, entity);
ConvertingPropertyAccessor propertyAccessor = newConvertingPropertyAccessor(object, entity);
Assert.isTrue(entity.getType().isAssignableFrom(object.getClass()),
String.format("Given instance of type [%s] is not of compatible expected type [%s]",
String.format("Given instance of type [%s] is not compatible with expected type [%s]",
object.getClass().getName(), entity.getType().getName()));
if (object instanceof MapIdentifiable) {
@@ -668,32 +700,6 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
return id;
}
/**
* Create a new {@link ConvertingPropertyAccessor} for the given source and entity.
*
* @param source must not be {@literal null}.
* @param entity must not be {@literal null}.
* @return a new {@link ConvertingPropertyAccessor} for the given source and entity.
*/
private ConvertingPropertyAccessor getConvertingAccessor(Object source, CassandraPersistentEntity<?> entity) {
PersistentPropertyAccessor propertyAccessor = source instanceof PersistentPropertyAccessor
? (PersistentPropertyAccessor) source
: entity.getPropertyAccessor(source);
return new ConvertingPropertyAccessor(propertyAccessor, getConversionService());
}
/**
* Returns whether the property is part of the primary key.
*
* @param property {@link CassandraPersistentProperty} to evaluate.
* @return a boolean value indicating whether the given property is party of a primary key.
*/
private boolean isPrimaryKeyPart(CassandraPersistentProperty property) {
return (property.isCompositePrimaryKey() || property.isPrimaryKeyColumn() || property.isIdProperty());
}
private Class<?> getTargetType(CassandraPersistentProperty property) {
return getCustomConversions().getCustomWriteTarget(property.getType()).orElseGet(() -> {
@@ -702,8 +708,8 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
return getPropertyTargetType(property);
}
if (property.isCompositePrimaryKey() || getCustomConversions().isSimpleType(property.getType())
|| property.isCollectionLike()) {
if (property.isCompositePrimaryKey() || property.isCollectionLike()
|| getCustomConversions().isSimpleType(property.getType())) {
return property.getType();
}
@@ -721,7 +727,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
return property.getType();
}
TypeCodec<Object> codec = getCodecRegistry().codecFor(getMappingContext().getDataType(property));
TypeCodec<Object> codec = getCodecRegistry().codecFor(dataType);
return codec.getJavaType().getRawType();
}
@@ -731,13 +737,13 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
* {@link ConvertingPropertyAccessor} and perform optionally a conversion of collection element types.
*
* @param property the property.
* @param accessor the property accessor
* @param propertyAccessor the property accessor
* @return the return value, may be {@literal null}.
*/
@Nullable
@SuppressWarnings("unchecked")
private <T> T getWriteValue(CassandraPersistentProperty property, ConvertingPropertyAccessor accessor) {
return (T) getWriteValue(accessor.getProperty(property, (Class<T>) getTargetType(property)),
private <T> T getWriteValue(CassandraPersistentProperty property, ConvertingPropertyAccessor propertyAccessor) {
return (T) getWriteValue(propertyAccessor.getProperty(property, (Class<T>) getTargetType(property)),
property.getTypeInformation());
}
@@ -761,8 +767,9 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
if (getCustomConversions().hasCustomWriteTarget(value.getClass(), requestedTargetType)) {
Class<?> resolvedTargetType = getCustomConversions().getCustomWriteTarget(value.getClass(), requestedTargetType)
.orElse(requestedTargetType);
Class<?> resolvedTargetType =
getCustomConversions().getCustomWriteTarget(value.getClass(), requestedTargetType)
.orElse(requestedTargetType);
return getConversionService().convert(value, resolvedTargetType);
}
@@ -770,8 +777,9 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
if (getCustomConversions().hasCustomWriteTarget(value.getClass())) {
Class<?> resolvedTargetType = getCustomConversions().getCustomWriteTarget(value.getClass())
.orElseThrow(() -> new IllegalStateException(String
.format("Unable to determined custom write target for value type [%s]", value.getClass().getName())));
.orElseThrow(() -> new IllegalStateException(
String.format("Unable to determined custom write target for value type [%s]",
value.getClass().getName())));
return getConversionService().convert(value, resolvedTargetType);
}
@@ -797,6 +805,15 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
if (entity != null) {
if (entity.isTupleType()) {
TupleValue tupleValue = getMappingContext().getTupleType(entity).newValue();
write(value, tupleValue, entity);
return tupleValue;
}
if (entity.isUserDefinedType()) {
UDTValue udtValue = entity.getUserType().newValue();
@@ -805,15 +822,6 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
return udtValue;
}
if (entity.isTupleType()) {
TupleValue tupleValue = mappingContext.getTupleType(entity).newValue();
write(value, tupleValue, entity);
return tupleValue;
}
}
return value;
@@ -928,22 +936,22 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
* Retrieve the value to read for the given {@link CassandraPersistentProperty} from
* {@link BasicCassandraRowValueProvider} and perform optionally a conversion of collection element types.
*
* @param row the row.
* @param valueProvider the row.
* @param property the property.
* @return the return value, may be {@literal null}.
*/
@Nullable
@SuppressWarnings("unchecked")
protected Object getReadValue(CassandraValueProvider row, CassandraPersistentProperty property) {
private Object getReadValue(CassandraValueProvider valueProvider, CassandraPersistentProperty property) {
if (property.isCompositePrimaryKey()) {
CassandraPersistentEntity<?> keyEntity = getMappingContext().getRequiredPersistentEntity(property);
return instantiatePrimaryKey(keyEntity, property, row);
return instantiatePrimaryKey(keyEntity, property, valueProvider);
}
Object value = row.getPropertyValue(property);
Object value = valueProvider.getPropertyValue(property);
return value == null ? null : convertReadValue(value, property.getTypeInformation());
}
@@ -977,26 +985,26 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
return readMapInternal((Map<Object, Object>) value, typeInformation);
}
if (value instanceof UDTValue) {
BasicCassandraPersistentEntity<?> udtEntity = getMappingContext()
.getPersistentEntity(typeInformation.getRequiredActualType());
if (udtEntity != null && udtEntity.isUserDefinedType()) {
return readEntityFromUdt(udtEntity, (UDTValue) value);
}
}
if (value instanceof TupleValue) {
BasicCassandraPersistentEntity<?> tupleEntity = getMappingContext()
.getPersistentEntity(typeInformation.getRequiredActualType());
BasicCassandraPersistentEntity<?> tupleEntity =
getMappingContext().getPersistentEntity(typeInformation.getRequiredActualType());
if (tupleEntity != null) {
return readEntityFromTuple(tupleEntity, (TupleValue) value);
}
}
if (value instanceof UDTValue) {
BasicCassandraPersistentEntity<?> udtEntity =
getMappingContext().getPersistentEntity(typeInformation.getRequiredActualType());
if (udtEntity != null && udtEntity.isUserDefinedType()) {
return readEntityFromUdt(udtEntity, (UDTValue) value);
}
}
return getPotentiallyConvertedSimpleRead(value, typeInformation.getType());
}
@@ -1105,14 +1113,6 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
return Map.class.isAssignableFrom(mapType) ? mapType : Map.class;
}
private TypeCodec<Object> getCodec(CassandraPersistentProperty property) {
return getCodecRegistry().codecFor(mappingContext.getDataType(property));
}
private static CodecRegistry getCodecRegistry() {
return CodecRegistry.DEFAULT_INSTANCE;
}
/**
* {@link CassandraRowValueProvider} that delegates reads to {@link CassandraValueProvider} applying mapping and
* custom conversion from {@link MappingCassandraConverter}.

View File

@@ -118,8 +118,6 @@ public class QueryMapper {
Field field = createPropertyField(entity, criteriaDefinition.getColumnName());
Predicate predicate = criteriaDefinition.getPredicate();
field.getProperty().filter(CassandraPersistentProperty::isCompositePrimaryKey).ifPresent(it -> {
throw new IllegalArgumentException(
"Cannot use composite primary key directly. Reference a property of the composite primary key");
@@ -130,9 +128,13 @@ public class QueryMapper {
String.format("Cannot reference tuple value elements, property [%s]", field.getMappedKey()));
});
Predicate predicate = criteriaDefinition.getPredicate();
Object value = predicate.getValue();
TypeInformation<?> typeInformation = getTypeInformation(field, value);
Object mappedValue = value != null ? getConverter().convertToColumnType(value, typeInformation) : null;
Object mappedValue = value != null
? getConverter().convertToColumnType(value, getTypeInformation(field, value))
: null;
Predicate mappedPredicate = new Predicate(predicate.getOperator(), mappedValue);
@@ -164,11 +166,9 @@ public class QueryMapper {
Field field = createPropertyField(entity, column);
columns.getSelector(column).ifPresent(selector -> {
getCqlIdentifier(column, field).ifPresent(cqlIdentifier -> {
selectors.add(getMappedSelector(selector, cqlIdentifier));
});
});
columns.getSelector(column).ifPresent(selector ->
getCqlIdentifier(column, field).ifPresent(cqlIdentifier ->
selectors.add(getMappedSelector(selector, cqlIdentifier))));
}
if (columns.isEmpty()) {
@@ -208,6 +208,7 @@ public class QueryMapper {
FunctionCall functionCall = (FunctionCall) selector;
List<Object> mappedParameters = functionCall.getParameters().stream().map(obj -> {
if (obj instanceof Selector) {
return getMappedSelector((Selector) obj, cqlIdentifier);
}
@@ -254,11 +255,10 @@ public class QueryMapper {
field.getProperty().ifPresent(seen::add);
columns.getSelector(column) //
.filter(selector -> selector instanceof ColumnSelector) //
.ifPresent(columnSelector -> {
getCqlIdentifier(column, field).map(CqlIdentifier::toCql).ifPresent(columnNames::add);
});
columns.getSelector(column)
.filter(selector -> selector instanceof ColumnSelector)
.ifPresent(columnSelector ->
getCqlIdentifier(column, field).map(CqlIdentifier::toCql).ifPresent(columnNames::add));
}
if (columns.isEmpty()) {
@@ -308,12 +308,14 @@ public class QueryMapper {
try {
if (field.getProperty().isPresent()) {
return field.getProperty().map(cassandraPersistentProperty -> {
if (cassandraPersistentProperty.isCompositePrimaryKey()) {
throw new IllegalArgumentException(
"Cannot use composite primary key directly. Reference a property of the composite primary key");
}
return cassandraPersistentProperty.getRequiredColumnName();
});
}
@@ -324,13 +326,14 @@ public class QueryMapper {
return column.getCqlIdentifier();
} catch (IllegalStateException e) {
throw new IllegalArgumentException(e.getMessage(), e);
} catch (IllegalStateException cause) {
throw new IllegalArgumentException(cause.getMessage(), cause);
}
}
Field createPropertyField(CassandraPersistentEntity<?> entity, ColumnName key) {
return Optional.of(entity).<Field> map(e -> new MetadataBackedField(key, e, getMappingContext()))
Field createPropertyField(@Nullable CassandraPersistentEntity<?> entity, ColumnName key) {
return Optional.ofNullable(entity).<Field>map(e -> new MetadataBackedField(key, e, getMappingContext()))
.orElseGet(() -> new Field(key));
}
@@ -452,17 +455,17 @@ public class QueryMapper {
/**
* Returns the {@link PersistentPropertyPath} for the given {@code pathExpression}.
*
* @param pathExpression
* @return
* @param pathExpression {@link String} containing the path expression to evaluate
* @return the {@link PersistentPropertyPath} for the given {@code pathExpression}.
*/
private Optional<PersistentPropertyPath<CassandraPersistentProperty>> getPath(String pathExpression) {
try {
PropertyPath propertyPath = PropertyPath.from(pathExpression.replaceAll("\\.\\d", ""),
entity.getTypeInformation());
this.entity.getTypeInformation());
PersistentPropertyPath<CassandraPersistentProperty> persistentPropertyPath = mappingContext
.getPersistentPropertyPath(propertyPath);
PersistentPropertyPath<CassandraPersistentProperty> persistentPropertyPath =
this.mappingContext.getPersistentPropertyPath(propertyPath);
return Optional.of(persistentPropertyPath);
} catch (PropertyReferenceException e) {
@@ -485,7 +488,7 @@ public class QueryMapper {
*/
@Override
public Optional<CassandraPersistentProperty> getProperty() {
return optionalProperty;
return this.optionalProperty;
}
/*

View File

@@ -132,8 +132,8 @@ public class UpdateMapper extends QueryMapper {
Assert.state(op.getValue() != null,
() -> String.format("SetAtKeyOp for %s attempts to set null", field.getProperty()));
Optional<? extends TypeInformation<?>> typeInformation = field.getProperty()
.map(PersistentProperty::getTypeInformation);
Optional<? extends TypeInformation<?>> typeInformation =
field.getProperty().map(PersistentProperty::getTypeInformation);
Optional<TypeInformation<?>> keyType = typeInformation.map(TypeInformation::getComponentType);
Optional<TypeInformation<?>> valueType = typeInformation.map(TypeInformation::getMapValueType);
@@ -167,8 +167,8 @@ public class UpdateMapper extends QueryMapper {
if (collection.isEmpty()) {
DataType.Name dataType = field.getProperty().map(property -> getMappingContext().getDataType(property))
.map(DataType::getName).orElse(Name.LIST);
DataType.Name dataType = field.getProperty().map(property ->
getMappingContext().getDataType(property)).map(DataType::getName).orElse(Name.LIST);
if (dataType == Name.SET) {
return new SetOp(field.getMappedKey(), Collections.emptySet());

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.cassandra.core.mapping;
import static org.springframework.data.cassandra.core.cql.CqlIdentifier.*;
import static org.springframework.data.cassandra.core.cql.CqlIdentifier.of;
import java.util.Comparator;
import java.util.Optional;
@@ -51,16 +51,17 @@ import com.datastax.driver.core.UserType;
public class BasicCassandraPersistentEntity<T> extends BasicPersistentEntity<T, CassandraPersistentProperty>
implements CassandraPersistentEntity<T>, ApplicationContextAware {
private static final CassandraPersistentEntityMetadataVerifier DEFAULT_VERIFIER = new CompositeCassandraPersistentEntityMetadataVerifier();
private static final CassandraPersistentEntityMetadataVerifier DEFAULT_VERIFIER =
new CompositeCassandraPersistentEntityMetadataVerifier();
private Boolean forceQuote;
private CassandraPersistentEntityMetadataVerifier verifier = DEFAULT_VERIFIER;
private CqlIdentifier tableName;
private @Nullable StandardEvaluationContext spelContext;
private Optional<Boolean> forceQuote = Optional.empty();
private Optional<CqlIdentifier> tableName = Optional.empty();
/**
* Create a new {@link BasicCassandraPersistentEntity} given {@link TypeInformation}.
*
@@ -102,6 +103,7 @@ public class BasicCassandraPersistentEntity<T> extends BasicPersistentEntity<T,
setVerifier(verifier);
}
protected CqlIdentifier determineTableName() {
Table annotation = findAnnotation(Table.class);
@@ -119,11 +121,13 @@ public class BasicCassandraPersistentEntity<T> extends BasicPersistentEntity<T,
return of(getType().getSimpleName(), forceQuote);
}
String name = spelContext == null ? value : SpelUtils.evaluate(value, spelContext);
String name = Optional.ofNullable(this.spelContext)
.map(it -> SpelUtils.evaluate(value, it))
.orElse(value);
Assert.state(name != null, () -> String.format("Cannot determine default name for %s", this));
return of(name, forceQuote);
return CqlIdentifier.of(name, forceQuote);
}
/* (non-Javadoc)
@@ -158,9 +162,9 @@ public class BasicCassandraPersistentEntity<T> extends BasicPersistentEntity<T,
super.verify();
verifier.verify(this);
this.verifier.verify(this);
if (!tableName.isPresent()) {
if (this.tableName == null) {
setTableName(determineTableName());
}
}
@@ -185,9 +189,9 @@ public class BasicCassandraPersistentEntity<T> extends BasicPersistentEntity<T,
@Override
public void setForceQuote(boolean forceQuote) {
boolean changed = !this.forceQuote.isPresent() || this.forceQuote.filter(v -> v != forceQuote).isPresent();
boolean changed = !Boolean.valueOf(forceQuote).equals(this.forceQuote);
this.forceQuote = Optional.of(forceQuote);
this.forceQuote = forceQuote;
if (changed) {
setTableName(of(getTableName().getUnquoted(), forceQuote));
@@ -201,7 +205,8 @@ public class BasicCassandraPersistentEntity<T> extends BasicPersistentEntity<T,
public void setTableName(CqlIdentifier tableName) {
Assert.notNull(tableName, "CqlIdentifier must not be null");
this.tableName = Optional.of(tableName);
this.tableName = tableName;
}
/* (non-Javadoc)
@@ -209,7 +214,7 @@ public class BasicCassandraPersistentEntity<T> extends BasicPersistentEntity<T,
*/
@Override
public CqlIdentifier getTableName() {
return tableName.orElseGet(this::determineTableName);
return Optional.ofNullable(this.tableName).orElseGet(this::determineTableName);
}
/**
@@ -222,25 +227,9 @@ public class BasicCassandraPersistentEntity<T> extends BasicPersistentEntity<T,
/**
* @return the verifier.
*/
@SuppressWarnings("unused")
public CassandraPersistentEntityMetadataVerifier getVerifier() {
return verifier;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity#isUserDefinedType()
*/
@Override
public boolean isUserDefinedType() {
return false;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity#getUserType()
*/
@Override
@Nullable
public UserType getUserType() {
return null;
return this.verifier;
}
/* (non-Javadoc)
@@ -259,4 +248,21 @@ public class BasicCassandraPersistentEntity<T> extends BasicPersistentEntity<T,
public TupleType getTupleType() {
return null;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity#isUserDefinedType()
*/
@Override
public boolean isUserDefinedType() {
return false;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity#getUserType()
*/
@Override
@Nullable
public UserType getUserType() {
return null;
}
}

View File

@@ -15,8 +15,6 @@
*/
package org.springframework.data.cassandra.core.mapping;
import static org.springframework.data.cassandra.core.cql.CqlIdentifier.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedParameterizedType;
import java.lang.reflect.AnnotatedType;
@@ -66,19 +64,14 @@ import com.datastax.driver.core.UserType;
public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentProperty<CassandraPersistentProperty>
implements CassandraPersistentProperty, ApplicationContextAware {
private final @Nullable UserTypeResolver userTypeResolver;
// Indicates whether this property has been explicitly instructed to force quoted column names.
private Boolean forceQuote;
private @Nullable CqlIdentifier columnName;
private @Nullable StandardEvaluationContext spelContext;
/**
* Whether this property has been explicitly instructed to force quote column names.
*/
private Optional<Boolean> forceQuote = Optional.empty();
/**
* An unmodifiable list of this property's column names.
*/
private @Nullable CqlIdentifier columnName;
private final @Nullable UserTypeResolver userTypeResolver;
/**
* Create a new {@link BasicCassandraPersistentProperty}.
@@ -141,7 +134,8 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
this.columnName = determineColumnName();
}
Assert.state(this.columnName != null, () -> String.format("Cannot determine column name for %s", this));
Assert.state(this.columnName != null,
() -> String.format("Cannot determine column name for %s", this));
return this.columnName;
}
@@ -164,7 +158,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
PrimaryKeyColumn annotation = findAnnotation(PrimaryKeyColumn.class);
return (annotation != null ? annotation.ordering() : null);
return annotation != null ? annotation.ordering() : null;
}
/* (non-Javadoc)
@@ -178,7 +172,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
if (dataType == null) {
throw new InvalidDataAccessApiUsageException(String.format(
"Unknown type [%s] for property [%s] in entity [%s]; only primitive types and Collections or Maps of primitive types are allowed",
getType(), getName(), getOwner().getName()));
getType(), getName(), getOwner().getName()));
}
return dataType;
@@ -197,7 +191,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
List<TypeInformation<?>> args = getTypeInformation().getTypeArguments();
ensureTypeArguments(args.size(), 2);
assertTypeArguments(args.size(), 2);
return DataType.map(getDataTypeFor(args.get(0).getType()), getDataTypeFor(args.get(1).getType()));
}
@@ -206,7 +200,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
List<TypeInformation<?>> args = getTypeInformation().getTypeArguments();
ensureTypeArguments(args.size(), 1);
assertTypeArguments(args.size(), 1);
if (Set.class.isAssignableFrom(getType())) {
return DataType.set(getDataTypeFor(args.get(0).getType()));
@@ -226,21 +220,17 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
switch (type) {
case MAP:
ensureTypeArguments(annotation.typeArguments().length, 2);
assertTypeArguments(annotation.typeArguments().length, 2);
return DataType.map(CassandraSimpleTypeHolder.getDataTypeFor(annotation.typeArguments()[0]),
CassandraSimpleTypeHolder.getDataTypeFor(annotation.typeArguments()[1]));
case LIST:
ensureTypeArguments(annotation.typeArguments().length, 1);
if (annotation.typeArguments()[0] == Name.UDT) {
return DataType.list(getUserType(annotation));
}
return DataType.list(CassandraSimpleTypeHolder.getDataTypeFor(annotation.typeArguments()[0]));
assertTypeArguments(annotation.typeArguments().length, 1);
return annotation.typeArguments()[0] == Name.UDT ? DataType.list(getUserType(annotation))
: DataType.list(CassandraSimpleTypeHolder.getDataTypeFor(annotation.typeArguments()[0]));
case SET:
ensureTypeArguments(annotation.typeArguments().length, 1);
if (annotation.typeArguments()[0] == Name.UDT) {
return DataType.set(getUserType(annotation));
}
return DataType.set(CassandraSimpleTypeHolder.getDataTypeFor(annotation.typeArguments()[0]));
assertTypeArguments(annotation.typeArguments().length, 1);
return annotation.typeArguments()[0] == Name.UDT ? DataType.set(getUserType(annotation))
: DataType.set(CassandraSimpleTypeHolder.getDataTypeFor(annotation.typeArguments()[0]));
case UDT:
return getUserType(annotation);
default:
@@ -276,17 +266,18 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
if (dataType == null) {
throw new InvalidDataAccessApiUsageException(String.format(
"Only primitive types are allowed inside Collections for property [%1$s] of type ['%2$s'] in entity [%3$s]",
getName(), getType(), getOwner().getName()));
getName(), getType(), getOwner().getName()));
}
return dataType;
}
private void ensureTypeArguments(int args, int expected) {
private void assertTypeArguments(int args, int expected) {
if (args != expected) {
throw new InvalidDataAccessApiUsageException(
String.format("Expected [%1$s] typed arguments for property ['%2$s'] of type ['%3$s'] in entity [%4$s]",
expected, getName(), getType(), getOwner().getName()));
String.format("Expected [%1$s] type arguments for property ['%2$s'] of type ['%3$s'] in entity [%4$s]; actual was [%5$d]",
expected, getName(), getType(), getOwner().getName(), args));
}
}
@@ -295,26 +286,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
*/
@Override
public boolean isCompositePrimaryKey() {
return (AnnotatedElementUtils.findMergedAnnotation(getType(), PrimaryKeyClass.class) != null);
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty#isPrimaryKeyColumn()
*/
@Override
public boolean isPrimaryKeyColumn() {
return isAnnotationPresent(PrimaryKeyColumn.class);
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty#isPartitionKeyColumn()
*/
@Override
public boolean isPartitionKeyColumn() {
PrimaryKeyColumn annotation = findAnnotation(PrimaryKeyColumn.class);
return (annotation != null && PrimaryKeyType.PARTITIONED.equals(annotation.type()));
return AnnotatedElementUtils.findMergedAnnotation(getType(), PrimaryKeyClass.class) != null;
}
/* (non-Javadoc)
@@ -325,7 +297,26 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
PrimaryKeyColumn annotation = findAnnotation(PrimaryKeyColumn.class);
return (annotation != null && PrimaryKeyType.CLUSTERED.equals(annotation.type()));
return annotation != null && PrimaryKeyType.CLUSTERED.equals(annotation.type());
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty#isPartitionKeyColumn()
*/
@Override
public boolean isPartitionKeyColumn() {
PrimaryKeyColumn annotation = findAnnotation(PrimaryKeyColumn.class);
return annotation != null && PrimaryKeyType.PARTITIONED.equals(annotation.type());
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty#isPrimaryKeyColumn()
*/
@Override
public boolean isPrimaryKeyColumn() {
return isAnnotationPresent(PrimaryKeyColumn.class);
}
@Nullable
@@ -377,10 +368,10 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
String name = defaultName;
if (StringUtils.hasText(overriddenName)) {
name = (this.spelContext != null ? SpelUtils.evaluate(overriddenName, this.spelContext) : overriddenName);
name = this.spelContext != null ? SpelUtils.evaluate(overriddenName, this.spelContext) : overriddenName;
}
return name == null ? null : of(name, forceQuote);
return name != null ? CqlIdentifier.of(name, forceQuote) : null;
}
/* (non-Javadoc)
@@ -400,14 +391,12 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
@Override
public void setForceQuote(boolean forceQuote) {
boolean changed = !this.forceQuote.isPresent() || this.forceQuote.filter(v -> v != forceQuote).isPresent();
boolean changed = !Boolean.valueOf(forceQuote).equals(this.forceQuote);
this.forceQuote = Optional.of(forceQuote);
this.forceQuote = forceQuote;
if (changed) {
CqlIdentifier columnName = getRequiredColumnName();
setColumnName(of(columnName.getUnquoted(), forceQuote));
setColumnName(CqlIdentifier.of(getRequiredColumnName().getUnquoted(), forceQuote));
}
}
@@ -441,8 +430,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
@Override
public AnnotatedType findAnnotatedType(Class<? extends Annotation> annotationType) {
return Optionals
.toStream(Optional.ofNullable(getField()).map(Field::getAnnotatedType),
return Optionals.toStream(Optional.ofNullable(getField()).map(Field::getAnnotatedType),
Optional.ofNullable(getGetter()).map(Method::getAnnotatedReturnType),
Optional.ofNullable(getSetter()).map(it -> it.getParameters()[0].getAnnotatedType()))
.filter(it -> hasAnnotation(it, annotationType, getTypeInformation())).findFirst().orElse(null);

View File

@@ -54,14 +54,14 @@ public class BasicCassandraPersistentTupleEntity<T> extends BasicCassandraPersis
Assert.notNull(tupleTypeFactory, "TupleTypeFactory must not be null");
this.tupleType = Lazy.of(() -> tupleTypeFactory.create(getTupleFieldTypes()));
this.tupleType = Lazy.of(() -> tupleTypeFactory.create(getTupleFieldDataTypes()));
}
private List<DataType> getTupleFieldTypes() {
private List<DataType> getTupleFieldDataTypes() {
return StreamSupport.stream(spliterator(), false) //
.sorted(TuplePropertyComparator.INSTANCE) //
.map(CassandraPersistentProperty::getDataType) //
return StreamSupport.stream(spliterator(), false)
.sorted(TuplePropertyComparator.INSTANCE)
.map(CassandraPersistentProperty::getDataType)
.collect(Collectors.toList());
}
@@ -89,7 +89,7 @@ public class BasicCassandraPersistentTupleEntity<T> extends BasicCassandraPersis
*/
@Override
public TupleType getTupleType() {
return tupleType.get();
return this.tupleType.get();
}
/**
@@ -106,8 +106,8 @@ public class BasicCassandraPersistentTupleEntity<T> extends BasicCassandraPersis
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
*/
@Override
public int compare(CassandraPersistentProperty o1, CassandraPersistentProperty o2) {
return Integer.compare(o1.getRequiredOrdinal(), o2.getRequiredOrdinal());
public int compare(CassandraPersistentProperty propertyOne, CassandraPersistentProperty propertyTwo) {
return Integer.compare(propertyOne.getRequiredOrdinal(), propertyTwo.getRequiredOrdinal());
}
}
}

View File

@@ -42,6 +42,7 @@ public class BasicCassandraPersistentTupleProperty extends BasicCassandraPersist
*/
public BasicCassandraPersistentTupleProperty(Property property, CassandraPersistentEntity<?> owner,
SimpleTypeHolder simpleTypeHolder) {
this(property, owner, simpleTypeHolder, null);
}
@@ -72,16 +73,15 @@ public class BasicCassandraPersistentTupleProperty extends BasicCassandraPersist
try {
ordinal = getRequiredAnnotation(Element.class).value();
} catch (IllegalStateException e) {
} catch (IllegalStateException cause) {
throw new MappingException(
String.format("Missing @Element annotation in mapped tuple type for property [%s] in entity [%s]", getName(),
getOwner().getName()),
e);
String.format("Missing @Element annotation in mapped tuple type for property [%s] in entity [%s]",
getName(), getOwner().getName()), cause);
}
Assert.isTrue(ordinal >= 0,
String.format("Element ordinal must be greater or equal to zero for property [%s] in entity [%s]", getName(),
getOwner().getName()));
String.format("Element ordinal must be greater or equal to zero for property [%s] in entity [%s]",
getName(), getOwner().getName()));
return ordinal;
}
@@ -100,7 +100,15 @@ public class BasicCassandraPersistentTupleProperty extends BasicCassandraPersist
@Nullable
@Override
public Integer getOrdinal() {
return ordinal;
return this.ordinal;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty#isClusterKeyColumn()
*/
@Override
public boolean isClusterKeyColumn() {
return false;
}
/* (non-Javadoc)
@@ -111,14 +119,6 @@ public class BasicCassandraPersistentTupleProperty extends BasicCassandraPersist
return false;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty#isPrimaryKeyColumn()
*/
@Override
public boolean isPrimaryKeyColumn() {
return false;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty#isPartitionKeyColumn()
*/
@@ -128,10 +128,10 @@ public class BasicCassandraPersistentTupleProperty extends BasicCassandraPersist
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty#isClusterKeyColumn()
* @see org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty#isPrimaryKeyColumn()
*/
@Override
public boolean isClusterKeyColumn() {
public boolean isPrimaryKeyColumn() {
return false;
}

View File

@@ -15,10 +15,20 @@
*/
package org.springframework.data.cassandra.core.mapping;
import static org.springframework.data.cassandra.core.cql.keyspace.CreateTableSpecification.*;
import static org.springframework.data.cassandra.core.mapping.CassandraSimpleTypeHolder.*;
import static org.springframework.data.cassandra.core.cql.keyspace.CreateTableSpecification.createTable;
import static org.springframework.data.cassandra.core.mapping.CassandraSimpleTypeHolder.getDataTypeFor;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.StreamSupport;
@@ -67,19 +77,20 @@ public class CassandraMappingContext
private @Nullable ApplicationContext applicationContext;
private CassandraPersistentEntityMetadataVerifier verifier =
new CompositeCassandraPersistentEntityMetadataVerifier();
private @Nullable ClassLoader beanClassLoader;
private CassandraPersistentEntityMetadataVerifier verifier = new CompositeCassandraPersistentEntityMetadataVerifier();
private CustomConversions customConversions = new CustomConversions(
StoreConversions.of(CassandraSimpleTypeHolder.HOLDER), Collections.emptyList());
private CustomConversions customConversions =
new CustomConversions(StoreConversions.of(CassandraSimpleTypeHolder.HOLDER), Collections.emptyList());
private Mapping mapping = new Mapping();
private @Nullable UserTypeResolver userTypeResolver;
private TupleTypeFactory tupleTypeFactory = CodecRegistryTupleTypeFactory.DEFAULT;
private @Nullable UserTypeResolver userTypeResolver;
// caches
private final Map<CqlIdentifier, Set<CassandraPersistentEntity<?>>> entitySetsByTableName = new HashMap<>();
@@ -90,10 +101,6 @@ public class CassandraMappingContext
* Create a new {@link CassandraMappingContext}.
*/
public CassandraMappingContext() {
StoreConversions storeConversions = StoreConversions.of(CassandraSimpleTypeHolder.HOLDER);
setCustomConversions(new CustomConversions(storeConversions, Collections.emptyList()));
setSimpleTypeHolder(CassandraSimpleTypeHolder.HOLDER);
}
@@ -106,15 +113,8 @@ public class CassandraMappingContext
*/
public CassandraMappingContext(UserTypeResolver userTypeResolver, TupleTypeFactory tupleTypeFactory) {
Assert.notNull(userTypeResolver, "UserTypeResolver must not be null");
Assert.notNull(tupleTypeFactory, "TupleTypeFactory must not be null");
StoreConversions storeConversions = StoreConversions.of(CassandraSimpleTypeHolder.HOLDER);
setUserTypeResolver(userTypeResolver);
setTupleTypeFactory(tupleTypeFactory);
setCustomConversions(new CustomConversions(storeConversions, Collections.emptyList()));
setSimpleTypeHolder(CassandraSimpleTypeHolder.HOLDER);
}
@@ -123,7 +123,9 @@ public class CassandraMappingContext
*/
@Override
public void initialize() {
super.initialize();
processMappingOverrides();
}
@@ -158,6 +160,7 @@ public class CassandraMappingContext
}
private static void processMappingOverrides(CassandraPersistentEntity<?> entity, EntityMapping entityMapping) {
entityMapping.getPropertyMappings()
.forEach((key, propertyMapping) -> processMappingOverride(entity, propertyMapping));
}
@@ -233,6 +236,24 @@ public class CassandraMappingContext
return Collections.unmodifiableSet(this.userDefinedTypes);
}
/**
* Sets the {@link TupleTypeFactory}.
*
* @param tupleTypeFactory must not be {@literal null}.
* @since 2.1
*/
public void setTupleTypeFactory(TupleTypeFactory tupleTypeFactory) {
Assert.notNull(tupleTypeFactory, "TupleTypeFactory must not be null");
this.tupleTypeFactory = tupleTypeFactory;
}
@NonNull
protected TupleTypeFactory getTupleTypeFactory() {
return this.tupleTypeFactory;
}
/**
* Sets the {@link UserTypeResolver}.
*
@@ -246,17 +267,9 @@ public class CassandraMappingContext
this.userTypeResolver = userTypeResolver;
}
/**
* Sets the {@link TupleTypeFactory}.
*
* @param tupleTypeFactory must not be {@literal null}.
* @since 2.1
*/
public void setTupleTypeFactory(TupleTypeFactory tupleTypeFactory) {
Assert.notNull(tupleTypeFactory, "TupleTypeFactory must not be null");
this.tupleTypeFactory = tupleTypeFactory;
@Nullable
protected UserTypeResolver getUserTypeResolver() {
return this.userTypeResolver;
}
/**
@@ -291,8 +304,8 @@ public class CassandraMappingContext
}
// now do some caching of the entity
Set<CassandraPersistentEntity<?>> entities = this.entitySetsByTableName.computeIfAbsent(entity.getTableName(),
cqlIdentifier -> new HashSet<>());
Set<CassandraPersistentEntity<?>> entities =
this.entitySetsByTableName.computeIfAbsent(entity.getTableName(), cqlIdentifier -> new HashSet<>());
entities.add(entity);
@@ -320,33 +333,29 @@ public class CassandraMappingContext
@Override
protected <T> BasicCassandraPersistentEntity<T> createPersistentEntity(TypeInformation<T> typeInformation) {
BasicCassandraPersistentEntity<T> entity = Optional.ofNullable(resolveUserDefinedType(typeInformation))
.<BasicCassandraPersistentEntity<T>> map(resolvedUserDefinedType -> new CassandraUserTypePersistentEntity<>(
typeInformation, getVerifier(), resolveUserTypeResolver()))
.orElseGet(() -> {
boolean tuple = AnnotatedElementUtils.hasAnnotation(typeInformation.getType(), Tuple.class);
if (tuple) {
return new BasicCassandraPersistentTupleEntity<>(typeInformation, tupleTypeFactory);
}
return new BasicCassandraPersistentEntity<>(typeInformation, getVerifier());
});
BasicCassandraPersistentEntity<T> entity = isUserDefinedType(typeInformation)
? new CassandraUserTypePersistentEntity<>(typeInformation, getVerifier(), resolveUserTypeResolver())
: isTuple(typeInformation)
? new BasicCassandraPersistentTupleEntity<>(typeInformation, getTupleTypeFactory())
: new BasicCassandraPersistentEntity<>(typeInformation, getVerifier());
Optional.ofNullable(this.applicationContext).ifPresent(entity::setApplicationContext);
return entity;
}
@Nullable
private UserDefinedType resolveUserDefinedType(TypeInformation typeInformation) {
return AnnotatedElementUtils.findMergedAnnotation(typeInformation.getType(), UserDefinedType.class);
private boolean isTuple(TypeInformation<?> typeInformation) {
return AnnotatedElementUtils.hasAnnotation(typeInformation.getType(), Tuple.class);
}
private boolean isUserDefinedType(TypeInformation<?> typeInformation) {
return AnnotatedElementUtils.hasAnnotation(typeInformation.getType(), UserDefinedType.class);
}
@NonNull
private UserTypeResolver resolveUserTypeResolver() {
UserTypeResolver resolvedUserTypeResolver = this.userTypeResolver;
UserTypeResolver resolvedUserTypeResolver = getUserTypeResolver();
Assert.state(resolvedUserTypeResolver != null, "UserTypeResolver must not be null");
@@ -360,15 +369,9 @@ public class CassandraMappingContext
protected CassandraPersistentProperty createPersistentProperty(Property property,
BasicCassandraPersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {
BasicCassandraPersistentProperty persistentProperty;
if (owner.isTupleType()) {
persistentProperty = new BasicCassandraPersistentTupleProperty(property, owner, simpleTypeHolder,
this.userTypeResolver);
} else {
persistentProperty = new BasicCassandraPersistentProperty(property, owner, simpleTypeHolder,
this.userTypeResolver);
}
BasicCassandraPersistentProperty persistentProperty = owner.isTupleType()
? new BasicCassandraPersistentTupleProperty(property, owner, simpleTypeHolder, getUserTypeResolver())
: new BasicCassandraPersistentProperty(property, owner, simpleTypeHolder, getUserTypeResolver());
Optional.ofNullable(this.applicationContext).ifPresent(persistentProperty::setApplicationContext);
@@ -410,7 +413,9 @@ public class CassandraMappingContext
return getPersistentEntities().stream().flatMap(entity -> StreamSupport.stream(entity.spliterator(), false))
.flatMap(it -> Optionals.toStream(Optional.ofNullable(it.findAnnotation(CassandraType.class))))
.map(CassandraType::userTypeName).filter(StringUtils::hasText).map(CqlIdentifier::of)
.map(CassandraType::userTypeName)
.filter(StringUtils::hasText)
.map(CqlIdentifier::of)
.anyMatch(identifier::equals);
}
@@ -520,7 +525,8 @@ public class CassandraMappingContext
*/
public DataType getDataType(Class<?> type) {
return this.customConversions.getCustomWriteTarget(type).map(CassandraSimpleTypeHolder::getDataTypeFor)
return this.customConversions.getCustomWriteTarget(type)
.map(CassandraSimpleTypeHolder::getDataTypeFor)
.orElseGet(() -> getDataTypeFor(type));
}
@@ -555,10 +561,11 @@ public class CassandraMappingContext
if (annotation.type() == Name.TUPLE) {
DataType[] dataTypes = Arrays.stream(annotation.typeArguments()).map(CassandraSimpleTypeHolder::getDataTypeFor)
DataType[] dataTypes = Arrays.stream(annotation.typeArguments())
.map(CassandraSimpleTypeHolder::getDataTypeFor)
.toArray(DataType[]::new);
return tupleTypeFactory.create(dataTypes);
return getTupleTypeFactory().create(dataTypes);
}
if (annotation.type() == Name.UDT) {
@@ -633,11 +640,12 @@ public class CassandraMappingContext
private TupleType getTupleType(DataTypeProvider dataTypeProvider, CassandraPersistentEntity<?> persistentEntity) {
List<DataType> types = new ArrayList<>();
for (CassandraPersistentProperty persistentProperty : persistentEntity) {
types.add(getDataTypeWithUserTypeFactory(persistentProperty, dataTypeProvider));
}
return tupleTypeFactory.create(types);
return getTupleTypeFactory().create(types);
}
@SuppressWarnings("all")

View File

@@ -36,6 +36,13 @@ public interface CassandraPersistentEntity<T> extends PersistentEntity<T, Cassan
*/
boolean isCompositePrimaryKey();
/**
* Sets whether to enforce quoting when using the {@link #getTableName()} in CQL.
*
* @param forceQuote {@literal true} to enforce quoting; {@literal false} to disable enforced quoting usage.
*/
void setForceQuote(boolean forceQuote);
/**
* Returns the table name to which the entity shall be persisted.
*/
@@ -49,11 +56,19 @@ public interface CassandraPersistentEntity<T> extends PersistentEntity<T, Cassan
void setTableName(CqlIdentifier tableName);
/**
* Sets whether to enforce quoting when using the {@link #getTableName()} in CQL.
*
* @param forceQuote {@literal true} to enforce quoting; {@literal false} to disable enforced quoting usage.
* @return {@literal true} if the type is a mapped tuple type.
* @since 2.1
* @see Tuple
*/
void setForceQuote(boolean forceQuote);
boolean isTupleType();
/**
* @return the {@link TupleType} matching the data types from {@link BasicCassandraPersistentTupleProperty mapped
* tuple elements}.
* @since 2.1
*/
@Nullable
TupleType getTupleType();
/**
* @return {@literal true} if the type is a mapped user defined type.
@@ -70,18 +85,4 @@ public interface CassandraPersistentEntity<T> extends PersistentEntity<T, Cassan
@Nullable
UserType getUserType();
/**
* @return {@literal true} if the type is a mapped tuple type.
* @since 2.1
* @see Tuple
*/
boolean isTupleType();
/**
* @return the {@link TupleType} matching the data types from {@link BasicCassandraPersistentTupleProperty mapped
* tuple elements}.
* @since 2.1
*/
@Nullable
TupleType getTupleType();
}

View File

@@ -24,6 +24,7 @@ import org.springframework.data.cassandra.core.cql.CqlIdentifier;
import org.springframework.data.cassandra.core.cql.Ordering;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.datastax.driver.core.DataType;
@@ -39,6 +40,15 @@ import com.datastax.driver.core.DataType;
public interface CassandraPersistentProperty
extends PersistentProperty<CassandraPersistentProperty>, ApplicationContextAware {
/**
* If this property is mapped with a single column, set the column name to the given {@link CqlIdentifier}. If this
* property is not mapped by a single column, throws {@link IllegalStateException}. If the given column name is null,
* {@link IllegalArgumentException} is thrown.
*
* @param columnName must not be {@literal null}.
*/
void setColumnName(CqlIdentifier columnName);
/**
* The name of the single column to which the property is persisted.
*/
@@ -55,13 +65,30 @@ public interface CassandraPersistentProperty
CqlIdentifier columnName = getColumnName();
if (columnName == null) {
throw new IllegalStateException("No column name available for this persistent property");
}
Assert.state(columnName != null,
String.format("No column name available for this persistent property [%1$s.%2$s]",
getOwner().getName(), getName()));
return columnName;
}
/**
* The column's data type. Not valid for a composite primary key.
*
* @return the Cassandra {@link DataType}
* @throws InvalidDataAccessApiUsageException if the {@link DataType} cannot be resolved
* @see CassandraType
*/
DataType getDataType();
/**
* Whether to force-quote the column names of this property.
*
* @param forceQuote {@literal true} to enforce quoting.
* @see CassandraPersistentProperty#getColumnName()
*/
void setForceQuote(boolean forceQuote);
/**
* The name of the element ordinal to which the property is persisted when the owning type is a mapped tuple.
*/
@@ -78,9 +105,9 @@ public interface CassandraPersistentProperty
Integer ordinal = getOrdinal();
if (ordinal == null) {
throw new IllegalStateException("No ordinal available for this persistent property");
}
Assert.state(ordinal != null ,
String.format("No ordinal available for this persistent property [%1$s.%2$s]",
getOwner().getName(), getName()));
return ordinal;
}
@@ -93,19 +120,27 @@ public interface CassandraPersistentProperty
Ordering getPrimaryKeyOrdering();
/**
* The column's data type. Not valid for a composite primary key.
*
* @return the Cassandra {@link DataType}
* @throws InvalidDataAccessApiUsageException if the {@link DataType} cannot be resolved
* @see CassandraType
* Whether the property is a cluster key column.
*/
DataType getDataType();
boolean isClusterKeyColumn();
/**
* Whether the property is a composite primary key.
*/
boolean isCompositePrimaryKey();
/**
* Returns whether the property is a {@link java.util.Map}.
*
* @return a boolean indicating whether this property type is a {@link java.util.Map}.
*/
boolean isMapLike();
/**
* Whether the property is a partition key column.
*/
boolean isPartitionKeyColumn();
/**
* Whether the property is a partition key column or a cluster key column
*
@@ -114,40 +149,6 @@ public interface CassandraPersistentProperty
*/
boolean isPrimaryKeyColumn();
/**
* Whether the property is a partition key column.
*/
boolean isPartitionKeyColumn();
/**
* Whether the property is a cluster key column.
*/
boolean isClusterKeyColumn();
/**
* Whether to force-quote the column names of this property.
*
* @param forceQuote {@literal true} to enforce quoting.
* @see CassandraPersistentProperty#getColumnName()
*/
void setForceQuote(boolean forceQuote);
/**
* If this property is mapped with a single column, set the column name to the given {@link CqlIdentifier}. If this
* property is not mapped by a single column, throws {@link IllegalStateException}. If the given column name is null,
* {@link IllegalArgumentException} is thrown.
*
* @param columnName must not be {@literal null}.
*/
void setColumnName(CqlIdentifier columnName);
/**
* Returns whether the property is a {@link java.util.Map}.
*
* @return a boolean indicating whether this property type is a {@link java.util.Map}.
*/
boolean isMapLike();
/**
* Find an {@link AnnotatedType} by {@code annotationType} derived from the property type. Annotated type is looked up
* by introspecting property field/accessors. Collection/Map-like types are introspected for type annotations within
@@ -159,4 +160,5 @@ public interface CassandraPersistentProperty
*/
@Nullable
AnnotatedType findAnnotatedType(Class<? extends Annotation> annotationType);
}

View File

@@ -53,14 +53,15 @@ enum CassandraPersistentTupleMetadataVerifier implements CassandraPersistentEnti
}
if (!ordinals.add(tupleProperty.getOrdinal())) {
throw new MappingException(
String.format("Duplicate ordinal [%d] in entity [%s]", tupleProperty.getOrdinal(), entity.getName()));
throw new MappingException(String.format("Duplicate ordinal [%d] in entity [%s]",
tupleProperty.getOrdinal(), entity.getName()));
}
}
if (ordinals.isEmpty()) {
throw new MappingException(String.format(
"Mapped tuple contains no persistent elements annotated with @Element in entity [%s]", entity.getName()));
throw new MappingException(
String.format("Mapped tuple contains no persistent elements annotated with @Element in entity [%s]",
entity.getName()));
}
List<Integer> missingMappings = IntStream.range(0, ordinals.size()).boxed().collect(Collectors.toList());

View File

@@ -73,8 +73,8 @@ public class CassandraSimpleTypeHolder extends SimpleTypeHolder {
simpleTypes.add(Number.class);
simpleTypes.add(Row.class);
simpleTypes.add(UDTValue.class);
simpleTypes.add(TupleValue.class);
simpleTypes.add(UDTValue.class);
classToDataType = Collections.unmodifiableMap(classToDataType(codecRegistry, primitiveWrappers));
nameToDataType = Collections.unmodifiableMap(nameToDataType());

View File

@@ -39,10 +39,10 @@ public class CodecRegistryTupleTypeFactory implements TupleTypeFactory {
*/
public static final CodecRegistryTupleTypeFactory DEFAULT = new CodecRegistryTupleTypeFactory();
private final ProtocolVersion protocolVersion;
private final CodecRegistry codecRegistry;
private final ProtocolVersion protocolVersion;
/**
* Creates a new {@link CodecRegistryTupleTypeFactory} using newest protocol version and the default
* {@link CodecRegistry}.
@@ -66,19 +66,19 @@ public class CodecRegistryTupleTypeFactory implements TupleTypeFactory {
this.codecRegistry = codecRegistry;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.mapping.TupleTypeFactory#create(java.util.List)
*/
@Override
public TupleType create(List<DataType> types) {
return create(types.toArray(new DataType[0]));
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.mapping.TupleTypeFactory#create(com.datastax.driver.core.DataType[])
*/
@Override
public TupleType create(DataType... types) {
return TupleType.of(protocolVersion, codecRegistry, types);
return TupleType.of(this.protocolVersion, this.codecRegistry, types);
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.mapping.TupleTypeFactory#create(java.util.List)
*/
@Override
public TupleType create(List<DataType> types) {
return create(types.toArray(new DataType[types.size()]));
}
}

View File

@@ -51,6 +51,6 @@ public class SimpleTupleTypeFactory implements TupleTypeFactory {
*/
@Override
public TupleType create(List<DataType> types) {
return cluster.getMetadata().newTupleType(types);
return this.cluster.getMetadata().newTupleType(types);
}
}

View File

@@ -55,4 +55,5 @@ public interface TupleTypeFactory {
* @return the {@link TupleType} representing the given {@link DataType tuple element types}.
*/
TupleType create(List<DataType> types);
}

View File

@@ -58,8 +58,7 @@ public abstract class ColumnName {
*/
public static ColumnName from(String columnName) {
Assert.notNull(columnName, "Column name must not be null");
Assert.hasText(columnName, "Column name must not be empty");
Assert.hasText(columnName, "Column name must not be null or empty");
return new StringColumnName(columnName);
}
@@ -144,7 +143,7 @@ public abstract class ColumnName {
*/
@Override
public String toCql() {
return columnName;
return this.columnName;
}
/* (non-Javadoc)
@@ -152,7 +151,7 @@ public abstract class ColumnName {
*/
@Override
public String toString() {
return columnName;
return this.columnName;
}
}
@@ -182,7 +181,7 @@ public abstract class ColumnName {
*/
@Override
public Optional<CqlIdentifier> getCqlIdentifier() {
return Optional.of(cqlIdentifier);
return Optional.of(this.cqlIdentifier);
}
/* (non-Javadoc)
@@ -190,7 +189,7 @@ public abstract class ColumnName {
*/
@Override
public String toCql() {
return cqlIdentifier.toCql();
return this.cqlIdentifier.toCql();
}
/* (non-Javadoc)
@@ -198,7 +197,7 @@ public abstract class ColumnName {
*/
@Override
public String toString() {
return cqlIdentifier.toString();
return this.cqlIdentifier.toString();
}
}
}

View File

@@ -100,8 +100,15 @@ public interface CriteriaDefinition {
*/
enum Operators implements Operator {
EQ("="), GT(">"), GTE(">="), LT("<"), LTE("<="), CONTAINS("CONTAINS"), CONTAINS_KEY("CONTAINS KEY"), IN("IN"), LIKE(
"LIKE");
CONTAINS("CONTAINS"),
CONTAINS_KEY("CONTAINS KEY"),
EQ("="),
GT(">"),
GTE(">="),
LT("<"),
LTE("<="),
IN("IN"),
LIKE("LIKE");
private final String operator;

View File

@@ -15,24 +15,24 @@
*/
package org.springframework.data.cassandra.core.convert;
import static org.assertj.core.api.Assertions.*;
import static org.springframework.data.cassandra.test.util.RowMockUtil.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.data.cassandra.test.util.RowMockUtil.column;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.data.cassandra.core.mapping.BasicCassandraPersistentEntity;
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
import org.springframework.data.cassandra.core.mapping.Element;
import org.springframework.data.cassandra.core.mapping.Tuple;
import org.springframework.data.cassandra.test.util.RowMockUtil;
import com.datastax.driver.core.DataType;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.TupleValue;
import com.datastax.driver.core.querybuilder.Insert;
@@ -46,32 +46,36 @@ import com.datastax.driver.core.querybuilder.QueryBuilder;
@RunWith(MockitoJUnitRunner.Silent.class)
public class MappingCassandraConverterMappedTupleUnitTests {
@Rule public final ExpectedException expectedException = ExpectedException.none();
CassandraMappingContext mappingContext;
MappingCassandraConverter mappingCassandraConverter;
Row rowMock;
CassandraMappingContext mappingContext;
MappingCassandraConverter mappingCassandraConverter;
@Before
public void setUp() {
mappingContext = new CassandraMappingContext();
mappingCassandraConverter = new MappingCassandraConverter(mappingContext);
mappingCassandraConverter.afterPropertiesSet();
this.mappingContext = new CassandraMappingContext();
this.mappingCassandraConverter = new MappingCassandraConverter(mappingContext);
this.mappingCassandraConverter.afterPropertiesSet();
}
@Test // DATACASS-523
public void shouldReadMappedTupleValue() {
BasicCassandraPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(MappedTuple.class);
BasicCassandraPersistentEntity<?> entity = this.mappingContext.getRequiredPersistentEntity(MappedTuple.class);
TupleValue value = entity.getTupleType().newValue("hello", 1);
rowMock = RowMockUtil.newRowMock(column("tuple", value, entity.getTupleType()));
this.rowMock = RowMockUtil.newRowMock(
column("name", "Jon Doe", DataType.text()),
column("tuple", value, entity.getTupleType())
);
Person person = mappingCassandraConverter.read(Person.class, rowMock);
Person person = this.mappingCassandraConverter.read(Person.class, rowMock);
assertThat(person).isNotNull();
assertThat(person.getName()).isEqualTo("Jon Doe");
MappedTuple tuple = person.getTuple();
@@ -83,18 +87,19 @@ public class MappingCassandraConverterMappedTupleUnitTests {
public void shouldWriteMappedTuple() {
MappedTuple tuple = new MappedTuple("hello", 1);
Person person = new Person(tuple);
Person person = new Person("Jon Doe", tuple);
Insert insert = QueryBuilder.insertInto("table");
mappingCassandraConverter.write(person, insert);
this.mappingCassandraConverter.write(person, insert);
assertThat(insert.toString()).contains("VALUES (('hello',1))");
assertThat(insert.toString()).contains("VALUES ('Jon Doe',('hello',1))");
}
@Data
@AllArgsConstructor
private static class Person {
String name;
MappedTuple tuple;
}
@@ -102,9 +107,7 @@ public class MappingCassandraConverterMappedTupleUnitTests {
@Data
@AllArgsConstructor
private static class MappedTuple {
@Element(0) String name;
@Element(1) int position;
}
}

View File

@@ -20,6 +20,7 @@ import static org.assertj.core.api.Assertions.*;
import lombok.Data;
import java.util.Arrays;
import java.util.Collections;
import java.util.Currency;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -84,30 +85,30 @@ public class MappingCassandraConverterTupleIntegrationTests extends AbstractSpri
}
}
@Autowired Session session;
@Autowired MappingCassandraConverter converter;
@Autowired Session session;
@Before
public void setUp() {
if (initialized.compareAndSet(false, true)) {
session.execute("DROP TYPE IF EXISTS address;");
session.execute("DROP TABLE IF EXISTS person;");
this.session.execute("DROP TYPE IF EXISTS address;");
this.session.execute("DROP TABLE IF EXISTS person;");
CassandraMappingContext mappingContext = converter.getMappingContext();
CreateUserTypeSpecification createAddress = mappingContext
.getCreateUserTypeSpecificationFor(mappingContext.getRequiredPersistentEntity(AddressUserType.class));
session.execute(CreateUserTypeCqlGenerator.toCql(createAddress));
this.session.execute(CreateUserTypeCqlGenerator.toCql(createAddress));
CreateTableSpecification createPerson = mappingContext
.getCreateTableSpecificationFor(mappingContext.getRequiredPersistentEntity(Person.class));
session.execute(CreateTableCqlGenerator.toCql(createPerson));
this.session.execute(CreateTableCqlGenerator.toCql(createPerson));
} else {
session.execute("TRUNCATE person;");
this.session.execute("TRUNCATE person;");
}
}
@@ -115,35 +116,39 @@ public class MappingCassandraConverterTupleIntegrationTests extends AbstractSpri
public void shouldInsertRowWithComplexTuple() {
Person person = new Person();
person.setId("foo");
MappedTuple tuple = new MappedTuple();
AddressUserType userType = new AddressUserType();
userType.setZip("myzip");
MappedTuple tuple = new MappedTuple();
tuple.setAddressUserType(userType);
tuple.setCurrency(Arrays.asList(Currency.getInstance("EUR"), Currency.getInstance("USD")));
tuple.setName("bar");
person.setMappedTuple(tuple);
person.setMappedTuples(Arrays.asList(tuple));
person.setMappedTuples(Collections.singletonList(tuple));
Insert insert = QueryBuilder.insertInto("person");
converter.write(person, insert);
session.execute(insert);
this.converter.write(person, insert);
this.session.execute(insert);
}
@Test // DATACASS-523
public void shouldReadRowWithComplexTuple() {
session.execute("INSERT INTO person (id,mappedtuple,mappedtuples) VALUES (" + //
"'foo'," //
this.session.execute("INSERT INTO person (id,mappedtuple,mappedtuples) VALUES ("
+ "'foo'," //
+ "({zip:'myzip'},['EUR','USD'],'bar')," //
+ "[({zip:'myzip'},['EUR','USD'],'bar')]);\n");
ResultSet resultSet = session.execute("SELECT * FROM person;");
ResultSet resultSet = this.session.execute("SELECT * FROM person;");
Person person = converter.read(Person.class, resultSet.one());
Person person = this.converter.read(Person.class, resultSet.one());
assertThat(person.getMappedTuples()).hasSize(1);
assertThat(person.getMappedTuple()).isNotNull();

View File

@@ -15,11 +15,9 @@
*/
package org.springframework.data.cassandra.core.convert;
import static org.assertj.core.api.Assertions.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.*;
import lombok.AllArgsConstructor;
import static org.mockito.Mockito.when;
import java.util.Collection;
import java.util.Collections;
@@ -28,11 +26,14 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.data.annotation.Id;
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
@@ -70,14 +71,17 @@ import com.datastax.driver.core.UserType;
public class QueryMapperUnitTests {
CassandraMappingContext mappingContext = new CassandraMappingContext();
CassandraPersistentEntity<?> persistentEntity;
MappingCassandraConverter cassandraConverter;
QueryMapper queryMapper;
@Mock UserTypeResolver userTypeResolver;
UserType userType = UserTypeBuilder.forName("address").withField("street", DataType.varchar()).build();
@Mock UserTypeResolver userTypeResolver;
@Before
public void before() {
@@ -333,18 +337,22 @@ public class QueryMapperUnitTests {
Filter filter = Filter.from(Criteria.where("tuple").is(tuple));
Filter mappedObject = queryMapper.getMappedObject(filter, mappingContext.getRequiredPersistentEntity(Person.class));
Filter mappedObject = this.queryMapper.getMappedObject(filter,
this.mappingContext.getRequiredPersistentEntity(Person.class));
TupleValue tupleValue = this.mappingContext.getRequiredPersistentEntity(MappedTuple.class)
.getTupleType().newValue();
TupleValue tupleValue = mappingContext.getRequiredPersistentEntity(MappedTuple.class).getTupleType().newValue();
tupleValue.setString(0, "foo");
assertThat(mappedObject).contains(Criteria.where("tuple").is(tupleValue));
}
@Test(expected = IllegalArgumentException.class) // DATACASS-523
public void referencingTupleElementsInQueryShouldFail() {
queryMapper.getMappedObject(Filter.from(Criteria.where("tuple.zip").is("")),
mappingContext.getRequiredPersistentEntity(Person.class));
this.queryMapper.getMappedObject(Filter.from(Criteria.where("tuple.zip").is("123")),
this.mappingContext.getRequiredPersistentEntity(Person.class));
}
static class Person {
@@ -367,14 +375,12 @@ public class QueryMapperUnitTests {
@Tuple
@AllArgsConstructor
static class MappedTuple {
@Element(0) String zip;
}
@UserDefinedType
@AllArgsConstructor
static class Address {
String street;
}

View File

@@ -15,11 +15,8 @@
*/
package org.springframework.data.cassandra.core.convert;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.Currency;
@@ -27,11 +24,15 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.data.annotation.Id;
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
@@ -56,15 +57,19 @@ import com.datastax.driver.core.UserType;
public class UpdateMapperUnitTests {
CassandraMappingContext mappingContext = new CassandraMappingContext();
CassandraPersistentEntity<?> persistentEntity;
MappingCassandraConverter cassandraConverter;
UpdateMapper updateMapper;
@Mock UserTypeResolver userTypeResolver;
CassandraPersistentEntity<?> persistentEntity;
Currency currency = Currency.getInstance("EUR");
MappingCassandraConverter cassandraConverter;
UpdateMapper updateMapper;
UserType manufacturer = UserTypeBuilder.forName("manufacturer").withField("name", DataType.varchar()).build();
@Mock UserTypeResolver userTypeResolver;
@Before
public void before() {
@@ -226,7 +231,8 @@ public class UpdateMapperUnitTests {
@Test // DATACASS-523
public void shouldMapTuple() {
Update update = updateMapper.getMappedObject(Update.empty().set("tuple", new MappedTuple("foo")), persistentEntity);
Update update = this.updateMapper.getMappedObject(Update.empty().set("tuple", new MappedTuple("foo")),
this.persistentEntity);
assertThat(update.getUpdateOperations()).hasSize(1);
assertThat(update.toString()).isEqualTo("tuple = ('foo')");
@@ -234,7 +240,7 @@ public class UpdateMapperUnitTests {
@Test(expected = IllegalArgumentException.class) // DATACASS-523
public void referencingTupleElementsInQueryShouldFail() {
updateMapper.getMappedObject(Update.empty().set("tuple.zip", "bar"), persistentEntity);
this.updateMapper.getMappedObject(Update.empty().set("tuple.zip", "bar"), this.persistentEntity);
}
static class Person {

View File

@@ -15,9 +15,13 @@
*/
package org.springframework.data.cassandra.core.mapping;
import static org.assertj.core.api.Assertions.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -29,6 +33,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AliasFor;
@@ -51,17 +56,20 @@ public class BasicCassandraPersistentEntityUnitTests {
@Test
public void subclassInheritsAtDocumentAnnotation() {
BasicCassandraPersistentEntity<Notification> entity = new BasicCassandraPersistentEntity<>(
ClassTypeInformation.from(Notification.class));
BasicCassandraPersistentEntity<Notification> entity =
new BasicCassandraPersistentEntity<>(ClassTypeInformation.from(Notification.class));
assertThat(entity.getTableName().toCql()).isEqualTo("messages");
}
@Test
public void evaluatesSpELExpression() {
BasicCassandraPersistentEntity<Area> entity = new BasicCassandraPersistentEntity<>(
ClassTypeInformation.from(Area.class));
entity.setApplicationContext(context);
BasicCassandraPersistentEntity<Area> entity =
new BasicCassandraPersistentEntity<>(ClassTypeInformation.from(Area.class));
entity.setApplicationContext(this.context);
assertThat(entity.getTableName().toCql()).isEqualTo("a123");
}
@@ -71,8 +79,8 @@ public class BasicCassandraPersistentEntityUnitTests {
TableNameHolderThingy bean = new TableNameHolderThingy();
bean.tableName = "my_user_line";
when(context.getBean("tableNameHolderThingy")).thenReturn(bean);
when(context.containsBean("tableNameHolderThingy")).thenReturn(true);
when(this.context.getBean("tableNameHolderThingy")).thenReturn(bean);
when(this.context.containsBean("tableNameHolderThingy")).thenReturn(true);
BasicCassandraPersistentEntity<UserLine> entity = new BasicCassandraPersistentEntity<>(
ClassTypeInformation.from(UserLine.class));
@@ -84,32 +92,34 @@ public class BasicCassandraPersistentEntityUnitTests {
@Test
public void setForceQuoteCallsSetTableName() {
BasicCassandraPersistentEntity<Message> entitySpy = spy(
new BasicCassandraPersistentEntity<>(ClassTypeInformation.from(Message.class)));
BasicCassandraPersistentEntity<Message> entitySpy =
spy(new BasicCassandraPersistentEntity<>(ClassTypeInformation.from(Message.class)));
DirectFieldAccessor dfa = new DirectFieldAccessor(entitySpy);
DirectFieldAccessor directFieldAccessor = new DirectFieldAccessor(entitySpy);
entitySpy.setTableName(CqlIdentifier.of("Messages", false));
assertThat((Optional) dfa.getPropertyValue("forceQuote")).isNotPresent();
assertThat(directFieldAccessor.getPropertyValue("forceQuote")).isNull();
entitySpy.setForceQuote(true);
assertThat((Optional) dfa.getPropertyValue("forceQuote")).contains(true);
assertThat(directFieldAccessor.getPropertyValue("forceQuote")).isEqualTo(true);
verify(entitySpy, times(2)).setTableName(isA(CqlIdentifier.class));
}
@Test
public void setForceQuoteDoesNothing() {
BasicCassandraPersistentEntity<Message> entitySpy = spy(
new BasicCassandraPersistentEntity<>(ClassTypeInformation.from(Message.class)));
DirectFieldAccessor dfa = new DirectFieldAccessor(entitySpy);
dfa.setPropertyValue("forceQuote", Optional.of(true));
BasicCassandraPersistentEntity<Message> entitySpy =
spy(new BasicCassandraPersistentEntity<>(ClassTypeInformation.from(Message.class)));
DirectFieldAccessor directFieldAccessor = new DirectFieldAccessor(entitySpy);
directFieldAccessor.setPropertyValue("forceQuote", true);
entitySpy.setForceQuote(true);
assertThat((Optional) dfa.getPropertyValue("forceQuote")).contains(true);
assertThat(directFieldAccessor.getPropertyValue("forceQuote")).isEqualTo(true);
verify(entitySpy, never()).setTableName(isA(CqlIdentifier.class));
}
@@ -117,8 +127,8 @@ public class BasicCassandraPersistentEntityUnitTests {
@Test // DATACASS-172
public void isUserDefinedTypeShouldReturnFalse() {
BasicCassandraPersistentEntity<UserLine> entity = new BasicCassandraPersistentEntity<>(
ClassTypeInformation.from(UserLine.class));
BasicCassandraPersistentEntity<UserLine> entity =
new BasicCassandraPersistentEntity<>(ClassTypeInformation.from(UserLine.class));
assertThat(entity.isUserDefinedType()).isFalse();
}
@@ -126,8 +136,8 @@ public class BasicCassandraPersistentEntityUnitTests {
@Test // DATACASS-259
public void shouldConsiderComposedTableAnnotation() {
BasicCassandraPersistentEntity<TableWithComposedAnnotation> entity = new BasicCassandraPersistentEntity<>(
ClassTypeInformation.from(TableWithComposedAnnotation.class));
BasicCassandraPersistentEntity<TableWithComposedAnnotation> entity =
new BasicCassandraPersistentEntity<>(ClassTypeInformation.from(TableWithComposedAnnotation.class));
assertThat(entity.getTableName()).isEqualTo(CqlIdentifier.of("mytable", true));
}
@@ -135,8 +145,8 @@ public class BasicCassandraPersistentEntityUnitTests {
@Test // DATACASS-259
public void shouldConsiderComposedPrimaryKeyClassAnnotation() {
BasicCassandraPersistentEntity<PrimaryKeyClassWithComposedAnnotation> entity = new BasicCassandraPersistentEntity<>(
ClassTypeInformation.from(PrimaryKeyClassWithComposedAnnotation.class));
BasicCassandraPersistentEntity<PrimaryKeyClassWithComposedAnnotation> entity =
new BasicCassandraPersistentEntity<>(ClassTypeInformation.from(PrimaryKeyClassWithComposedAnnotation.class));
assertThat(entity.isCompositePrimaryKey()).isTrue();
}

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.cassandra.core.mapping;
import static org.assertj.core.api.Assertions.*;
import static org.assertj.core.api.Assertions.assertThat;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -24,6 +24,7 @@ import java.util.Date;
import java.util.UUID;
import org.junit.Test;
import org.springframework.core.annotation.AliasFor;
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
import org.springframework.data.mapping.model.Property;

View File

@@ -15,8 +15,11 @@
*/
package org.springframework.data.cassandra.core.mapping;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.anyList;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Arrays;
@@ -27,6 +30,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.data.annotation.Transient;
import org.springframework.data.mapping.MappingException;
@@ -49,13 +53,15 @@ public class BasicCassandraPersistentTupleEntityUnitTests {
@Before
public void before() {
mappingContext.setTupleTypeFactory(tupleTypeFactory);
this.mappingContext.setTupleTypeFactory(tupleTypeFactory);
}
@Test // DATACASS-523
public void shouldCreatePersistentTupleEntity() {
BasicCassandraPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(Address.class);
BasicCassandraPersistentEntity<?> entity = this.mappingContext.getRequiredPersistentEntity(Address.class);
assertThat(entity).isInstanceOf(BasicCassandraPersistentTupleEntity.class);
entity.verify();
}
@@ -65,12 +71,11 @@ public class BasicCassandraPersistentTupleEntityUnitTests {
List<String> propertyNames = new ArrayList<>();
BasicCassandraPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(Address.class);
BasicCassandraPersistentEntity<?> entity = this.mappingContext.getRequiredPersistentEntity(Address.class);
entity.verify();
entity.forEach(it -> {
propertyNames.add(it.getName());
});
entity.forEach(it -> propertyNames.add(it.getName()));
assertThat(propertyNames).containsSequence("street", "city", "sortOrder");
}
@@ -78,10 +83,11 @@ public class BasicCassandraPersistentTupleEntityUnitTests {
@Test // DATACASS-523
public void shouldCreateTupleType() {
when(tupleTypeFactory.create(anyList())).thenReturn(TupleType.of(ProtocolVersion.NEWEST_SUPPORTED,
when(this.tupleTypeFactory.create(anyList())).thenReturn(TupleType.of(ProtocolVersion.NEWEST_SUPPORTED,
CodecRegistry.DEFAULT_INSTANCE, DataType.text(), DataType.text(), DataType.cint()));
BasicCassandraPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(Address.class);
BasicCassandraPersistentEntity<?> entity = this.mappingContext.getRequiredPersistentEntity(Address.class);
entity.verify();
entity.getTupleType();
@@ -92,14 +98,14 @@ public class BasicCassandraPersistentTupleEntityUnitTests {
@Test // DATACASS-523
public void shouldReportDuplicateMappings() {
assertThatThrownBy(() -> mappingContext.getRequiredPersistentEntity(DuplicateElement.class))
assertThatThrownBy(() -> this.mappingContext.getRequiredPersistentEntity(DuplicateElement.class))
.isInstanceOf(MappingException.class).hasMessageContaining("Duplicate ordinal [0]");
}
@Test // DATACASS-523
public void shouldReportMissingOrdinalMappings() {
assertThatThrownBy(() -> mappingContext.getRequiredPersistentEntity(MissingElementOrdinals.class))
assertThatThrownBy(() -> this.mappingContext.getRequiredPersistentEntity(MissingElementOrdinals.class))
.isInstanceOf(MappingException.class).hasMessageContaining("Mapped tuple has no")
.hasMessageContaining("for ordinal(s): 0");
}
@@ -107,7 +113,7 @@ public class BasicCassandraPersistentTupleEntityUnitTests {
@Test // DATACASS-523
public void shouldReportNegativeOrdinalIndex() {
assertThatThrownBy(() -> mappingContext.getRequiredPersistentEntity(NegativeIndex.class))
assertThatThrownBy(() -> this.mappingContext.getRequiredPersistentEntity(NegativeIndex.class))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("Element ordinal must be greater or equal to zero for property [street] in entity");
}
@@ -115,7 +121,7 @@ public class BasicCassandraPersistentTupleEntityUnitTests {
@Test // DATACASS-523
public void shouldReportNoElements() {
assertThatThrownBy(() -> mappingContext.getRequiredPersistentEntity(NoElements.class))
assertThatThrownBy(() -> this.mappingContext.getRequiredPersistentEntity(NoElements.class))
.isInstanceOf(MappingException.class)
.hasMessageContaining("Mapped tuple contains no persistent elements annotated");
}
@@ -123,7 +129,7 @@ public class BasicCassandraPersistentTupleEntityUnitTests {
@Test // DATACASS-523
public void shouldReportMissingAnnotations() {
assertThatThrownBy(() -> mappingContext.getRequiredPersistentEntity(MissingAnnotation.class))
assertThatThrownBy(() -> this.mappingContext.getRequiredPersistentEntity(MissingAnnotation.class))
.isInstanceOf(MappingException.class)
.hasMessageContaining("Missing @Element annotation in mapped tuple type for property [street]");
}

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.cassandra.core.mapping;
import static org.assertj.core.api.Assertions.*;
import static org.assertj.core.api.Assertions.assertThat;
import java.lang.reflect.Field;
import java.util.Date;
@@ -24,6 +24,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.data.mapping.model.Property;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.util.ReflectionUtils;

View File

@@ -15,8 +15,10 @@
*/
package org.springframework.data.cassandra.core.mapping;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.Serializable;
import java.util.Collection;
@@ -27,6 +29,7 @@ import java.util.NoSuchElementException;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.convert.converter.Converter;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.annotation.Id;
@@ -475,13 +478,14 @@ public class CassandraMappingContextUnitTests {
@Test // DATACASS-523
public void shouldCreateMappedTupleType() {
CassandraPersistentEntity<?> persistentEntity = mappingContext.getRequiredPersistentEntity(MappedTuple.class);
CassandraPersistentEntity<?> persistentEntity =
this.mappingContext.getRequiredPersistentEntity(MappedTuple.class);
assertThat(persistentEntity).isInstanceOf(BasicCassandraPersistentTupleEntity.class);
assertThat(mappingContext.getUserDefinedTypeEntities()).isEmpty();
assertThat(mappingContext.getPersistentEntities()).hasSize(1);
assertThat(mappingContext.getTableEntities()).isEmpty();
assertThat(this.mappingContext.getUserDefinedTypeEntities()).isEmpty();
assertThat(this.mappingContext.getPersistentEntities()).hasSize(1);
assertThat(this.mappingContext.getTableEntities()).isEmpty();
}
@Test // DATACASS-172

View File

@@ -15,14 +15,18 @@
*/
package org.springframework.data.cassandra.core.mapping;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import static org.springframework.data.cassandra.core.mapping.CassandraPersistentPropertyComparator.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import static org.springframework.data.cassandra.core.mapping.CassandraPersistentPropertyComparator.INSTANCE;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
/**

View File

@@ -15,12 +15,9 @@
*/
package org.springframework.data.cassandra.core.mapping;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.util.ArrayList;
@@ -29,8 +26,13 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.annotation.Id;
import org.springframework.data.cassandra.core.convert.CassandraCustomConversions;

View File

@@ -15,7 +15,8 @@
*/
package org.springframework.data.cassandra.core.mapping;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Collections;
@@ -42,10 +43,10 @@ public class SimpleTupleTypeFactoryUnitTests {
@Test // DATACASS-523
public void shouldCreateTupleTypes() {
when(cluster.getMetadata()).thenReturn(metadata);
when(this.cluster.getMetadata()).thenReturn(this.metadata);
new SimpleTupleTypeFactory(cluster).create(DataType.varchar());
new SimpleTupleTypeFactory(this.cluster).create(DataType.varchar());
verify(metadata).newTupleType(Collections.singletonList(DataType.varchar()));
verify(this.metadata).newTupleType(Collections.singletonList(DataType.varchar()));
}
}

View File

@@ -17,7 +17,8 @@ package org.springframework.data.cassandra.test.util;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.Arrays;
@@ -41,46 +42,49 @@ public class RowMockUtil {
* @param columns
* @return
*/
public static Row newRowMock(final Column... columns) {
public static Row newRowMock(Column... columns) {
Assert.notNull(columns, "Columns must not be null");
Row rowMock = mock(Row.class);
ColumnDefinitions columnDefinitionsMock = mock(ColumnDefinitions.class);
Row mockRow = mock(Row.class);
when(rowMock.getColumnDefinitions()).thenReturn(columnDefinitionsMock);
ColumnDefinitions mockColumnDefinitions = mock(ColumnDefinitions.class);
when(columnDefinitionsMock.contains(anyString())).thenAnswer(invocation -> Arrays.stream(columns)
when(mockRow.getColumnDefinitions()).thenReturn(mockColumnDefinitions);
when(mockColumnDefinitions.contains(anyString())).thenAnswer(invocation -> Arrays.stream(columns)
.anyMatch(column -> column.name.equalsIgnoreCase((String) invocation.getArguments()[0])));
when(columnDefinitionsMock.getIndexOf(anyString())).thenAnswer(invocation -> {
when(mockColumnDefinitions.getIndexOf(anyString())).thenAnswer(invocation -> {
int counter = 0;
for (Column column : columns) {
if (column.name.equalsIgnoreCase((String) invocation.getArguments()[0])) {
return counter;
}
counter++;
}
return -1;
});
when(columnDefinitionsMock.getType(anyInt()))
when(mockColumnDefinitions.getType(anyInt()))
.thenAnswer(invocation -> columns[(Integer) invocation.getArguments()[0]].type);
when(rowMock.getObject(anyInt())).thenAnswer(invocation -> columns[(Integer) invocation.getArguments()[0]].value);
when(rowMock.getString(anyInt())).thenAnswer(invocation -> columns[(Integer) invocation.getArguments()[0]].value);
when(rowMock.getDate(anyInt())).thenAnswer(invocation -> columns[(Integer) invocation.getArguments()[0]].value);
when(rowMock.getBool(anyInt())).thenAnswer(invocation -> columns[(Integer) invocation.getArguments()[0]].value);
when(rowMock.getInet(anyInt())).thenAnswer(invocation -> columns[(Integer) invocation.getArguments()[0]].value);
when(rowMock.getTimestamp(anyInt()))
.thenAnswer(invocation -> columns[(Integer) invocation.getArguments()[0]].value);
when(rowMock.getUUID(anyInt())).thenAnswer(invocation -> columns[(Integer) invocation.getArguments()[0]].value);
when(rowMock.getTupleValue(anyInt()))
when(mockRow.getBool(anyInt())).thenAnswer(invocation -> columns[(Integer) invocation.getArguments()[0]].value);
when(mockRow.getDate(anyInt())).thenAnswer(invocation -> columns[(Integer) invocation.getArguments()[0]].value);
when(mockRow.getInet(anyInt())).thenAnswer(invocation -> columns[(Integer) invocation.getArguments()[0]].value);
when(mockRow.getObject(anyInt())).thenAnswer(invocation -> columns[(Integer) invocation.getArguments()[0]].value);
when(mockRow.getString(anyInt())).thenAnswer(invocation -> columns[(Integer) invocation.getArguments()[0]].value);
when(mockRow.getTimestamp(anyInt()))
.thenAnswer(invocation -> columns[(Integer) invocation.getArguments()[0]].value);
when(mockRow.getTupleValue(anyInt()))
.thenAnswer(invocation -> columns[(Integer) invocation.getArguments()[0]].value);
when(mockRow.getUUID(anyInt())).thenAnswer(invocation -> columns[(Integer) invocation.getArguments()[0]].value);
return rowMock;
return mockRow;
}
/**
@@ -111,5 +115,4 @@ public class RowMockUtil {
this.type = type;
}
}
}

View File

@@ -415,7 +415,7 @@ thus allowing the name to be different than the field name of the class.
Types are derived from the property declaration by default.
* `@UserDefinedType` - applied at the type level to specify a Cassandra User-defined Data Type (UDT).
Types are derived from the declaration by default.
* `@Tuple` - applied at the type level to use a type as mapped tuple.
* `@Tuple` - applied at the type level to use a type as a mapped tuple.
* `@Element` - applied at the field level to specify element/field ordinals within a mapped tuple.
Types are derived from the property declaration by default.