DATACASS-523 - Polish.
This commit is contained in:
@@ -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());
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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}.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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()]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,4 +55,5 @@ public interface TupleTypeFactory {
|
||||
* @return the {@link TupleType} representing the given {@link DataType tuple element types}.
|
||||
*/
|
||||
TupleType create(List<DataType> types);
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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]");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user