DATACASS-487 - Polish.
This commit is contained in:
@@ -19,6 +19,7 @@ import java.util.List;
|
||||
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.CodecRegistry;
|
||||
import com.datastax.driver.core.ColumnDefinitions;
|
||||
@@ -51,50 +52,83 @@ public class ColumnReader {
|
||||
* Returns the row's column value.
|
||||
*/
|
||||
@Nullable
|
||||
public Object get(CqlIdentifier name) {
|
||||
return get(name.toCql());
|
||||
public Object get(CqlIdentifier columnName) {
|
||||
return get(columnName.toCql());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the row's column value.
|
||||
*/
|
||||
@Nullable
|
||||
public Object get(String name) {
|
||||
return get(getColumnIndex(name));
|
||||
public Object get(String columnName) {
|
||||
return get(getColumnIndex(columnName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read data from a Column using the {@code index}.
|
||||
* Read data from Column at the given {@code index}.
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
* @param columnIndex {@link Integer#TYPE index} of the Column.
|
||||
* @return the value of the Column in at index in the Row, or {@literal null} if the Column contains no value.
|
||||
*/
|
||||
@Nullable
|
||||
public Object get(int index) {
|
||||
public Object get(int columnIndex) {
|
||||
|
||||
if (row.isNull(index)) {
|
||||
if (row.isNull(columnIndex)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
DataType type = columns.getType(index);
|
||||
DataType type = columns.getType(columnIndex);
|
||||
|
||||
if (type.isCollection()) {
|
||||
return getCollection(index, type);
|
||||
return getCollection(columnIndex, type);
|
||||
}
|
||||
|
||||
if (Name.TUPLE.equals(type.getName())) {
|
||||
return row.getTupleValue(index);
|
||||
return row.getTupleValue(columnIndex);
|
||||
}
|
||||
|
||||
if (Name.UDT.equals(type.getName())) {
|
||||
return row.getUDTValue(index);
|
||||
return row.getUDTValue(columnIndex);
|
||||
}
|
||||
|
||||
return row.getObject(index);
|
||||
return row.getObject(columnIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the row's column value as an instance of the given type.
|
||||
*
|
||||
* @throws ClassCastException if the value cannot be converted to the requested type.
|
||||
*/
|
||||
@Nullable
|
||||
public <T> T get(CqlIdentifier columnName, Class<T> requestedType) {
|
||||
return get(columnName.toCql(), requestedType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the row's column value as an instance of the given type.
|
||||
*
|
||||
* @throws ClassCastException if the value cannot be converted to the requested type.
|
||||
*/
|
||||
@Nullable
|
||||
public <T> T get(String columnName, Class<T> requestedType) {
|
||||
return get(getColumnIndex(columnName), requestedType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the row's column value as an instance of the given type.
|
||||
*
|
||||
* @throws ClassCastException if the value cannot be converted to the requested type.
|
||||
*/
|
||||
@Nullable
|
||||
public <T> T get(int columnIndex, Class<T> requestedType) {
|
||||
|
||||
Object value = get(columnIndex);
|
||||
|
||||
return requestedType.cast(value);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Object getCollection(int i, DataType type) {
|
||||
private Object getCollection(int index, DataType type) {
|
||||
|
||||
List<DataType> collectionTypes = type.getTypeArguments();
|
||||
|
||||
@@ -102,71 +136,36 @@ public class ColumnReader {
|
||||
if (collectionTypes.size() == 1) {
|
||||
|
||||
DataType valueType = collectionTypes.get(0);
|
||||
|
||||
TypeCodec<Object> typeCodec = codecRegistry.codecFor(valueType);
|
||||
|
||||
if (type.equals(DataType.list(valueType))) {
|
||||
return row.getList(i, typeCodec.getJavaType().getRawType());
|
||||
return row.getList(index, typeCodec.getJavaType().getRawType());
|
||||
}
|
||||
|
||||
if (type.equals(DataType.set(valueType))) {
|
||||
return row.getSet(i, typeCodec.getJavaType().getRawType());
|
||||
return row.getSet(index, typeCodec.getJavaType().getRawType());
|
||||
}
|
||||
}
|
||||
|
||||
// Map
|
||||
if (type.getName() == Name.MAP) {
|
||||
return row.getObject(i);
|
||||
return row.getObject(index);
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Unknown Collection type encountered. Valid collections are Set, List and Map.");
|
||||
throw new IllegalStateException("Unknown Collection type encountered; valid collections are List, Set and Map.");
|
||||
}
|
||||
|
||||
private int getColumnIndex(String columnName) {
|
||||
|
||||
int index = columns.getIndexOf(columnName);
|
||||
|
||||
Assert.isTrue(index > -1, String.format("Column [%s] does not exist in table", columnName));
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
public Row getRow() {
|
||||
return row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the row's column value as an instance of the given type.
|
||||
*
|
||||
* @throws ClassCastException if the value cannot be converted to the requested type.
|
||||
*/
|
||||
@Nullable
|
||||
public <T> T get(CqlIdentifier name, Class<T> requestedType) {
|
||||
return get(getColumnIndex(name.toCql()), requestedType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the row's column value as an instance of the given type.
|
||||
*
|
||||
* @throws ClassCastException if the value cannot be converted to the requested type.
|
||||
*/
|
||||
@Nullable
|
||||
public <T> T get(String name, Class<T> requestedType) {
|
||||
return get(columns.getIndexOf(name), requestedType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the row's column value as an instance of the given type.
|
||||
*
|
||||
* @throws ClassCastException if the value cannot be converted to the requested type.
|
||||
*/
|
||||
@Nullable
|
||||
public <T> T get(int i, Class<T> requestedType) {
|
||||
|
||||
Object o = get(i);
|
||||
|
||||
if (o == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return requestedType.cast(o);
|
||||
}
|
||||
|
||||
private int getColumnIndex(String name) {
|
||||
|
||||
int indexOf = columns.getIndexOf(name);
|
||||
if (indexOf == -1) {
|
||||
throw new IllegalArgumentException("Column does not exist in Cassandra table: " + name);
|
||||
}
|
||||
return indexOf;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -24,8 +22,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
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;
|
||||
@@ -56,6 +54,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;
|
||||
@@ -116,6 +117,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
private static CassandraMappingContext createMappingContext() {
|
||||
|
||||
CassandraMappingContext mappingContext = new CassandraMappingContext();
|
||||
|
||||
mappingContext.setCustomConversions(new CassandraCustomConversions(Collections.emptyList()));
|
||||
|
||||
return mappingContext;
|
||||
@@ -142,7 +144,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
*/
|
||||
@Override
|
||||
public CassandraMappingContext getMappingContext() {
|
||||
return mappingContext;
|
||||
return this.mappingContext;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,8 +175,8 @@ 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);
|
||||
}
|
||||
@@ -185,10 +187,11 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
|
||||
BasicCassandraRowValueProvider rowValueProvider = new BasicCassandraRowValueProvider(row, expressionEvaluator);
|
||||
|
||||
PersistentEntityParameterValueProvider<CassandraPersistentProperty> parameterValueProvider = new PersistentEntityParameterValueProvider<>(
|
||||
entity, new MappingAndConvertingValueProvider(rowValueProvider), null);
|
||||
PersistentEntityParameterValueProvider<CassandraPersistentProperty> parameterValueProvider =
|
||||
getParameterValueProvider(entity, rowValueProvider);
|
||||
|
||||
EntityInstantiator instantiator = instantiators.getInstantiatorFor(entity);
|
||||
|
||||
S instance = instantiator.createInstance(entity, parameterValueProvider);
|
||||
|
||||
readPropertiesFromRow(entity, rowValueProvider, getConvertingAccessor(instance, entity));
|
||||
@@ -200,13 +203,14 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
|
||||
DefaultSpELExpressionEvaluator expressionEvaluator = new DefaultSpELExpressionEvaluator(udtValue, spELContext);
|
||||
|
||||
CassandraUDTValueProvider valueProvider = new CassandraUDTValueProvider(udtValue, CodecRegistry.DEFAULT_INSTANCE,
|
||||
expressionEvaluator);
|
||||
CassandraUDTValueProvider valueProvider =
|
||||
new CassandraUDTValueProvider(udtValue, CodecRegistry.DEFAULT_INSTANCE, expressionEvaluator);
|
||||
|
||||
PersistentEntityParameterValueProvider<CassandraPersistentProperty> parameterValueProvider = getParameterValueProvider(
|
||||
entity, valueProvider);
|
||||
PersistentEntityParameterValueProvider<CassandraPersistentProperty> parameterValueProvider =
|
||||
getParameterValueProvider(entity, valueProvider);
|
||||
|
||||
EntityInstantiator instantiator = instantiators.getInstantiatorFor(entity);
|
||||
|
||||
S instance = instantiator.createInstance(entity, parameterValueProvider);
|
||||
|
||||
readProperties(entity, valueProvider, getConvertingAccessor(instance, entity));
|
||||
@@ -216,8 +220,9 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
|
||||
private <S> PersistentEntityParameterValueProvider<CassandraPersistentProperty> getParameterValueProvider(
|
||||
CassandraPersistentEntity<S> entity, CassandraValueProvider valueProvider) {
|
||||
return new PersistentEntityParameterValueProvider<>(entity, new MappingAndConvertingValueProvider(valueProvider),
|
||||
null);
|
||||
|
||||
return new PersistentEntityParameterValueProvider<>(entity,
|
||||
new MappingAndConvertingValueProvider(valueProvider), null);
|
||||
}
|
||||
|
||||
protected void readPropertiesFromRow(CassandraPersistentEntity<?> entity, CassandraRowValueProvider row,
|
||||
@@ -244,7 +249,8 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
|
||||
if (property.isCompositePrimaryKey()) {
|
||||
|
||||
CassandraPersistentEntity<?> keyEntity = mappingContext.getRequiredPersistentEntity(property);
|
||||
CassandraPersistentEntity<?> keyEntity = getMappingContext().getRequiredPersistentEntity(property);
|
||||
|
||||
Object key = propertyAccessor.getProperty(property);
|
||||
|
||||
if (key == null) {
|
||||
@@ -270,7 +276,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
protected Object instantiatePrimaryKey(CassandraPersistentEntity<?> entity, CassandraPersistentProperty keyProperty,
|
||||
CassandraValueProvider propertyProvider) {
|
||||
|
||||
return instantiators.getInstantiatorFor(entity).createInstance(entity,
|
||||
return this.instantiators.getInstantiatorFor(entity).createInstance(entity,
|
||||
getParameterValueProvider(entity, propertyProvider));
|
||||
}
|
||||
|
||||
@@ -314,6 +320,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
Assert.notNull(source, "Value must not be null");
|
||||
|
||||
Class<?> beanClassLoaderClass = transformClassToBeanClassLoaderClass(source.getClass());
|
||||
|
||||
CassandraPersistentEntity<?> entity = getMappingContext().getRequiredPersistentEntity(beanClassLoaderClass);
|
||||
|
||||
write(source, sink, entity);
|
||||
@@ -321,9 +328,11 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> Class<T> transformClassToBeanClassLoaderClass(Class<T> entity) {
|
||||
|
||||
try {
|
||||
return (Class<T>) ClassUtils.forName(entity.getName(), beanClassLoader);
|
||||
} catch (ClassNotFoundException | LinkageError e) {
|
||||
return (Class<T>) ClassUtils.forName(entity.getName(), this.beanClassLoader);
|
||||
}
|
||||
catch (ClassNotFoundException | LinkageError ignore) {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
@@ -359,6 +368,47 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
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.getColumnName().toCql(), value);
|
||||
}
|
||||
|
||||
insert.value(property.getColumnName().toCql(), value);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeMapFromWrapper(ConvertingPropertyAccessor accessor, Map<String, Object> insert,
|
||||
CassandraPersistentEntity<?> entity) {
|
||||
|
||||
@@ -380,7 +430,9 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
continue;
|
||||
}
|
||||
|
||||
CassandraPersistentEntity<?> compositePrimaryKey = mappingContext.getRequiredPersistentEntity(property);
|
||||
CassandraPersistentEntity<?> compositePrimaryKey =
|
||||
getMappingContext().getRequiredPersistentEntity(property);
|
||||
|
||||
writeMapFromWrapper(getConvertingAccessor(value, compositePrimaryKey), insert, compositePrimaryKey);
|
||||
|
||||
continue;
|
||||
@@ -394,59 +446,21 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeInsertFromWrapper(final ConvertingPropertyAccessor accessor, final Insert insert,
|
||||
protected void writeUpdateFromObject(Object object, Update update, CassandraPersistentEntity<?> entity) {
|
||||
writeUpdateFromWrapper(getConvertingAccessor(object, entity), update, entity);
|
||||
}
|
||||
|
||||
protected void writeUpdateFromWrapper(ConvertingPropertyAccessor accessor, Update update,
|
||||
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 = mappingContext.getRequiredPersistentEntity(property);
|
||||
writeInsertFromWrapper(getConvertingAccessor(value, compositePrimaryKey), insert, compositePrimaryKey);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Adding insert.value [{}] - [{}]", property.getColumnName().toCql(), value);
|
||||
}
|
||||
|
||||
insert.value(property.getColumnName().toCql(), value);
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeUpdateFromObject(final Object object, final Update update, CassandraPersistentEntity<?> entity) {
|
||||
writeUpdateFromWrapper(getConvertingAccessor(object, entity), update, entity);
|
||||
}
|
||||
|
||||
protected void writeUpdateFromWrapper(final ConvertingPropertyAccessor accessor, final Update update,
|
||||
final CassandraPersistentEntity<?> entity) {
|
||||
|
||||
for (CassandraPersistentProperty property : entity) {
|
||||
|
||||
Object value = getWriteValue(property, accessor);
|
||||
|
||||
if (property.isCompositePrimaryKey()) {
|
||||
|
||||
CassandraPersistentEntity<?> compositePrimaryKey = mappingContext.getRequiredPersistentEntity(property);
|
||||
CassandraPersistentEntity<?> compositePrimaryKey =
|
||||
getMappingContext().getRequiredPersistentEntity(property);
|
||||
|
||||
if (value == null) {
|
||||
continue;
|
||||
@@ -481,8 +495,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
Object value = getWriteValue(property, accessor);
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("writeUDTValueWhereFromObject Property.type {}, Property.value {}", property.getType().getName(),
|
||||
value);
|
||||
log.debug("writeUDTValueWhereFromObject Property.type {}, Property.value {}", property.getType().getName(), value);
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
@@ -513,7 +526,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
if (id instanceof MapId) {
|
||||
|
||||
CassandraPersistentEntity<?> whereEntity = compositeIdProperty != null
|
||||
? mappingContext.getRequiredPersistentEntity(compositeIdProperty)
|
||||
? getMappingContext().getRequiredPersistentEntity(compositeIdProperty)
|
||||
: entity;
|
||||
|
||||
return getWhereClauses(MapId.class.cast(id), whereEntity);
|
||||
@@ -531,8 +544,8 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
String.format("Cannot use [%s] as composite Id for [%s]", id, entity.getName()));
|
||||
}
|
||||
|
||||
CassandraPersistentEntity<?> compositePrimaryKey = mappingContext
|
||||
.getRequiredPersistentEntity(compositeIdProperty);
|
||||
CassandraPersistentEntity<?> compositePrimaryKey =
|
||||
getMappingContext().getRequiredPersistentEntity(compositeIdProperty);
|
||||
|
||||
return getWhereClauses(getConvertingAccessor(id, compositePrimaryKey), compositePrimaryKey);
|
||||
}
|
||||
@@ -557,7 +570,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
return source;
|
||||
}
|
||||
|
||||
private Collection<Clause> getWhereClauses(final ConvertingPropertyAccessor accessor,
|
||||
private Collection<Clause> getWhereClauses(ConvertingPropertyAccessor accessor,
|
||||
CassandraPersistentEntity<?> entity) {
|
||||
|
||||
Assert.isTrue(entity.isCompositePrimaryKey(),
|
||||
@@ -586,7 +599,8 @@ 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());
|
||||
@@ -647,9 +661,9 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
*/
|
||||
private ConvertingPropertyAccessor getConvertingAccessor(Object source, CassandraPersistentEntity<?> entity) {
|
||||
|
||||
PersistentPropertyAccessor propertyAccessor = (source instanceof PersistentPropertyAccessor
|
||||
PersistentPropertyAccessor propertyAccessor = source instanceof PersistentPropertyAccessor
|
||||
? (PersistentPropertyAccessor) source
|
||||
: entity.getPropertyAccessor(source));
|
||||
: entity.getPropertyAccessor(source);
|
||||
|
||||
return new ConvertingPropertyAccessor(propertyAccessor, getConversionService());
|
||||
}
|
||||
@@ -730,12 +744,23 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
Class<?> requestedTargetType = typeInformation != null ? typeInformation.getType() : Object.class;
|
||||
|
||||
if (getCustomConversions().hasCustomWriteTarget(value.getClass(), requestedTargetType)) {
|
||||
return getConversionService().convert(value, getCustomConversions()
|
||||
.getCustomWriteTarget(value.getClass(), requestedTargetType).orElse(requestedTargetType));
|
||||
|
||||
Class<?> resolvedTargetType = getCustomConversions()
|
||||
.getCustomWriteTarget(value.getClass(), requestedTargetType)
|
||||
.orElse(requestedTargetType);
|
||||
|
||||
return getConversionService().convert(value, resolvedTargetType);
|
||||
}
|
||||
|
||||
if (getCustomConversions().hasCustomWriteTarget(value.getClass())) {
|
||||
return getConversionService().convert(value, getCustomConversions().getCustomWriteTarget(value.getClass()).get());
|
||||
|
||||
Class<?> resolvedTargetType = getCustomConversions()
|
||||
.getCustomWriteTarget(value.getClass())
|
||||
.orElseThrow(() -> new IllegalStateException(
|
||||
String.format("Unable to determined custom write target for value type [%s]",
|
||||
value.getClass().getName())));
|
||||
|
||||
return getConversionService().convert(value, resolvedTargetType);
|
||||
}
|
||||
|
||||
if (getCustomConversions().isSimpleType(value.getClass())) {
|
||||
@@ -743,7 +768,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
}
|
||||
|
||||
TypeInformation<?> type = typeInformation != null ? typeInformation
|
||||
: ClassTypeInformation.from((Class) value.getClass());
|
||||
: ClassTypeInformation.from((Class) value.getClass());
|
||||
|
||||
if (value instanceof Collection) {
|
||||
return writeCollectionInternal((Collection<Object>) value, type);
|
||||
@@ -754,6 +779,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
}
|
||||
|
||||
TypeInformation<?> actualType = type.getRequiredActualType();
|
||||
|
||||
BasicCassandraPersistentEntity<?> entity = getMappingContext().getPersistentEntity(actualType.getType());
|
||||
|
||||
if (entity != null && entity.isUserDefinedType()) {
|
||||
@@ -771,6 +797,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
private Object writeCollectionInternal(Collection<Object> source, TypeInformation<?> type) {
|
||||
|
||||
Collection<Object> converted = CollectionFactory.createCollection(getCollectionType(type), source.size());
|
||||
|
||||
TypeInformation<?> actualType = type.getRequiredActualType();
|
||||
|
||||
for (Object element : source) {
|
||||
@@ -788,9 +815,8 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
TypeInformation<?> valueType = type.getRequiredMapValueType();
|
||||
|
||||
for (Entry<Object, Object> entry : source.entrySet()) {
|
||||
|
||||
Object key = convertToColumnType(entry.getKey(), keyType);
|
||||
converted.put(key, convertToColumnType(entry.getValue(), valueType));
|
||||
converted.put(convertToColumnType(entry.getKey(), keyType),
|
||||
convertToColumnType(entry.getValue(), valueType));
|
||||
}
|
||||
|
||||
return converted;
|
||||
@@ -888,20 +914,18 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
|
||||
if (property.isCompositePrimaryKey()) {
|
||||
|
||||
CassandraPersistentEntity<?> keyEntity = mappingContext.getRequiredPersistentEntity(property);
|
||||
CassandraPersistentEntity<?> keyEntity = getMappingContext().getRequiredPersistentEntity(property);
|
||||
|
||||
return instantiatePrimaryKey(keyEntity, property, row);
|
||||
}
|
||||
|
||||
Object value = row.getPropertyValue(property);
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return convertReadValue(value, property.getTypeInformation());
|
||||
return value == null ? null : convertReadValue(value, property.getTypeInformation());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
private Object convertReadValue(Object value, TypeInformation<?> typeInformation) {
|
||||
|
||||
if (getCustomConversions().hasCustomWriteTarget(typeInformation.getRequiredActualType().getType())
|
||||
@@ -911,7 +935,8 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
|
||||
Collection<Object> original = (Collection<Object>) value;
|
||||
|
||||
Collection<Object> converted = CollectionFactory.createCollection(typeInformation.getType(), original.size());
|
||||
Collection<Object> converted =
|
||||
CollectionFactory.createCollection(typeInformation.getType(), original.size());
|
||||
|
||||
for (Object element : original) {
|
||||
converted.add(getConversionService().convert(element, typeInformation.getRequiredActualType().getType()));
|
||||
@@ -929,8 +954,8 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
return readMapInternal((Map<Object, Object>) value, typeInformation);
|
||||
}
|
||||
|
||||
BasicCassandraPersistentEntity<?> persistentEntity = getMappingContext()
|
||||
.getPersistentEntity(typeInformation.getRequiredActualType());
|
||||
BasicCassandraPersistentEntity<?> persistentEntity =
|
||||
getMappingContext().getPersistentEntity(typeInformation.getRequiredActualType());
|
||||
|
||||
if (persistentEntity != null && persistentEntity.isUserDefinedType() && value instanceof UDTValue) {
|
||||
return readEntityFromUdt(persistentEntity, (UDTValue) value);
|
||||
@@ -942,84 +967,102 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
/**
|
||||
* Reads the given {@link Collection} into a collection of the given {@link TypeInformation}.
|
||||
*
|
||||
* @param sourceValue must not be {@literal null}.
|
||||
* @param source must not be {@literal null}.
|
||||
* @param targetType must not be {@literal null}.
|
||||
* @return the converted {@link Collection} or array, will never be {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private Object readCollectionOrArrayInternal(Collection<?> sourceValue, TypeInformation<?> targetType) {
|
||||
private Object readCollectionOrArrayInternal(Collection<?> source, TypeInformation<?> targetType) {
|
||||
|
||||
Assert.notNull(targetType, "Target type must not be null!");
|
||||
Assert.notNull(targetType, "Target type must not be null");
|
||||
|
||||
Class<?> collectionType = targetType.getType();
|
||||
Class<?> collectionType = resolveCollectionType(targetType);
|
||||
Class<?> elementType = resolveElementType(targetType);
|
||||
|
||||
TypeInformation<?> componentType = targetType.getComponentType();
|
||||
Class<?> rawComponentType = componentType != null ? componentType.getType() : List.class;
|
||||
Collection<Object> collection = targetType.getType().isArray() ? new ArrayList<>()
|
||||
: CollectionFactory.createCollection(collectionType, elementType, source.size());
|
||||
|
||||
collectionType = Collection.class.isAssignableFrom(collectionType) ? collectionType : List.class;
|
||||
Collection<Object> items = targetType.getType().isArray() ? new ArrayList<>()
|
||||
: CollectionFactory.createCollection(collectionType, rawComponentType, sourceValue.size());
|
||||
|
||||
if (sourceValue.isEmpty()) {
|
||||
return getPotentiallyConvertedSimpleRead(items, collectionType);
|
||||
if (source.isEmpty()) {
|
||||
return getPotentiallyConvertedSimpleRead(collection, collectionType);
|
||||
}
|
||||
|
||||
BasicCassandraPersistentEntity<?> entity = getMappingContext().getPersistentEntity(rawComponentType);
|
||||
BasicCassandraPersistentEntity<?> entity = getMappingContext().getPersistentEntity(elementType);
|
||||
|
||||
if (entity != null && entity.isUserDefinedType()) {
|
||||
|
||||
for (Object udtValue : sourceValue) {
|
||||
items.add(readEntityFromUdt(entity, (UDTValue) udtValue));
|
||||
for (Object udtValue : source) {
|
||||
collection.add(readEntityFromUdt(entity, (UDTValue) udtValue));
|
||||
}
|
||||
|
||||
} else {
|
||||
for (Object item : sourceValue) {
|
||||
items.add(getPotentiallyConvertedSimpleRead(item, rawComponentType));
|
||||
for (Object element : source) {
|
||||
collection.add(getPotentiallyConvertedSimpleRead(element, elementType));
|
||||
}
|
||||
}
|
||||
|
||||
return getPotentiallyConvertedSimpleRead(items, targetType.getType());
|
||||
return getPotentiallyConvertedSimpleRead(collection, targetType.getType());
|
||||
}
|
||||
|
||||
private Class<?> resolveCollectionType(TypeInformation typeInformation) {
|
||||
|
||||
Class<?> collectionType = typeInformation.getType();
|
||||
|
||||
return Collection.class.isAssignableFrom(collectionType) ? collectionType : List.class;
|
||||
}
|
||||
|
||||
private Class<?> resolveElementType(TypeInformation typeInformation) {
|
||||
|
||||
TypeInformation<?> componentType = typeInformation.getComponentType();
|
||||
|
||||
return componentType != null ? componentType.getType() : Object.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the given {@link Map} into a map of the given {@link TypeInformation}.
|
||||
*
|
||||
* @param sourceValue must not be {@literal null}.
|
||||
* @param source must not be {@literal null}.
|
||||
* @param targetType must not be {@literal null}.
|
||||
* @return the converted {@link Collection} or array, will never be {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private Object readMapInternal(Map<Object, Object> sourceValue, TypeInformation<?> targetType) {
|
||||
private Object readMapInternal(Map<Object, Object> source, TypeInformation<?> targetType) {
|
||||
|
||||
Assert.notNull(targetType, "Target type must not be null!");
|
||||
Assert.notNull(targetType, "Target type must not be null");
|
||||
|
||||
TypeInformation<?> keyType = targetType.getComponentType();
|
||||
TypeInformation<?> valueType = targetType.getMapValueType();
|
||||
|
||||
Class<?> rawKeyType = keyType != null ? keyType.getType() : null;
|
||||
Map<Object, Object> map = CollectionFactory.createMap(targetType.getType(), rawKeyType, sourceValue.size());
|
||||
|
||||
if (sourceValue.isEmpty()) {
|
||||
Map<Object, Object> map = CollectionFactory.createMap(resolveMapType(targetType), rawKeyType, source.size());
|
||||
|
||||
if (source.isEmpty()) {
|
||||
return map;
|
||||
}
|
||||
|
||||
for (Entry<Object, Object> entry : sourceValue.entrySet()) {
|
||||
for (Entry<Object, Object> entry : source.entrySet()) {
|
||||
|
||||
Object key = entry.getKey();
|
||||
|
||||
if (rawKeyType != null && !rawKeyType.isAssignableFrom(key.getClass())) {
|
||||
if (key != null && rawKeyType != null && !rawKeyType.isAssignableFrom(key.getClass())) {
|
||||
key = convertReadValue(key, keyType);
|
||||
}
|
||||
|
||||
Object value = entry.getValue();
|
||||
|
||||
map.put(key, convertReadValue(value, valueType));
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
private Class<?> resolveMapType(TypeInformation<?> typeInformation) {
|
||||
|
||||
Class<?> mapType = typeInformation.getType();
|
||||
|
||||
return Map.class.isAssignableFrom(mapType) ? mapType : Map.class;
|
||||
}
|
||||
|
||||
private TypeCodec<Object> getCodec(CassandraPersistentProperty property) {
|
||||
return CodecRegistry.DEFAULT_INSTANCE.codecFor(mappingContext.getDataType(property));
|
||||
}
|
||||
@@ -1041,7 +1084,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
*/
|
||||
@Override
|
||||
public boolean hasProperty(CassandraPersistentProperty property) {
|
||||
return parent.hasProperty(property);
|
||||
return this.parent.hasProperty(property);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -1051,7 +1094,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getPropertyValue(CassandraPersistentProperty property) {
|
||||
return (T) getReadValue(parent, property);
|
||||
return (T) getReadValue(this.parent, property);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,8 +127,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);
|
||||
@@ -162,8 +162,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());
|
||||
|
||||
@@ -45,7 +45,6 @@ import org.springframework.data.cassandra.core.mapping.UserTypeUtil.FrozenLitera
|
||||
import org.springframework.data.convert.CustomConversions;
|
||||
import org.springframework.data.convert.CustomConversions.StoreConversions;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
import org.springframework.data.mapping.context.AbstractMappingContext;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.Property;
|
||||
@@ -78,32 +77,34 @@ public class CassandraMappingContext
|
||||
extends AbstractMappingContext<BasicCassandraPersistentEntity<?>, CassandraPersistentProperty>
|
||||
implements ApplicationContextAware, BeanClassLoaderAware {
|
||||
|
||||
private CassandraPersistentEntityMetadataVerifier verifier = new CompositeCassandraPersistentEntityMetadataVerifier();
|
||||
private @Nullable ApplicationContext applicationContext;
|
||||
|
||||
private CustomConversions customConversions = new CustomConversions(
|
||||
StoreConversions.of(CassandraSimpleTypeHolder.HOLDER), Collections.emptyList());
|
||||
private @Nullable ClassLoader beanClassLoader;
|
||||
|
||||
private CassandraPersistentEntityMetadataVerifier verifier =
|
||||
new CompositeCassandraPersistentEntityMetadataVerifier();
|
||||
|
||||
private CustomConversions customConversions =
|
||||
new CustomConversions(StoreConversions.of(CassandraSimpleTypeHolder.HOLDER), Collections.emptyList());
|
||||
|
||||
private Mapping mapping = new Mapping();
|
||||
|
||||
private @Nullable UserTypeResolver userTypeResolver;
|
||||
|
||||
private @Nullable ApplicationContext applicationContext;
|
||||
|
||||
private @Nullable ClassLoader beanClassLoader;
|
||||
|
||||
// caches
|
||||
private final Map<CqlIdentifier, Set<CassandraPersistentEntity<?>>> entitySetsByTableName = new HashMap<>();
|
||||
private final Set<BasicCassandraPersistentEntity<?>> userDefinedTypes = new HashSet<>();
|
||||
|
||||
private final Set<BasicCassandraPersistentEntity<?>> tableEntities = new HashSet<>();
|
||||
private final Set<BasicCassandraPersistentEntity<?>> userDefinedTypes = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Create a new {@link CassandraMappingContext}.
|
||||
*/
|
||||
public CassandraMappingContext() {
|
||||
|
||||
setCustomConversions(new CustomConversions(
|
||||
StoreConversions.of(CassandraSimpleTypeHolder.HOLDER), Collections.emptyList()));
|
||||
StoreConversions storeConversions = StoreConversions.of(CassandraSimpleTypeHolder.HOLDER);
|
||||
|
||||
setCustomConversions(new CustomConversions(storeConversions, Collections.emptyList()));
|
||||
setSimpleTypeHolder(CassandraSimpleTypeHolder.HOLDER);
|
||||
}
|
||||
|
||||
@@ -143,7 +144,7 @@ public class CassandraMappingContext
|
||||
}
|
||||
catch (ClassNotFoundException cause) {
|
||||
throw new IllegalStateException(
|
||||
String.format("Unknown persistent entity name [%s]", entityClassName), cause);
|
||||
String.format("Unknown persistent entity type name [%s]", entityClassName), cause);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,13 +464,11 @@ public class CassandraMappingContext
|
||||
|
||||
CreateUserTypeSpecification specification = CreateUserTypeSpecification.createType(entity.getTableName());
|
||||
|
||||
entity.doWithProperties((PropertyHandler<CassandraPersistentProperty>) property -> {
|
||||
|
||||
// Use frozen literal to not resolve types from Cassandra.
|
||||
// At this stage, they might be not created yet.
|
||||
for (CassandraPersistentProperty property : entity) {
|
||||
// Use frozen literal to not resolve types from Cassandra; At this stage, they might be not created yet.
|
||||
specification.field(property.getColumnName(),
|
||||
getDataTypeWithUserTypeFactory(property, DataTypeProvider.FrozenLiteral));
|
||||
});
|
||||
getDataTypeWithUserTypeFactory(property, DataTypeProvider.FrozenLiteral));
|
||||
}
|
||||
|
||||
if (specification.getFields().isEmpty()) {
|
||||
throw new MappingException(String.format("No fields in user type [%s]", entity.getType()));
|
||||
@@ -491,16 +490,8 @@ public class CassandraMappingContext
|
||||
public DataType getDataType(Class<?> type) {
|
||||
|
||||
return this.customConversions.getCustomWriteTarget(type)
|
||||
.map(CassandraSimpleTypeHolder::getDataTypeFor)
|
||||
.orElseGet(() -> getDataTypeFor(type));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private DataType getDataType(@NonNull Class<?> type, DataTypeProvider dataTypeProvider) {
|
||||
|
||||
BasicCassandraPersistentEntity<?> entity = getPersistentEntity(type);
|
||||
|
||||
return entity != null && entity.isUserDefinedType() ? dataTypeProvider.getDataType(entity) : getDataType(type);
|
||||
.map(CassandraSimpleTypeHolder::getDataTypeFor)
|
||||
.orElseGet(() -> getDataTypeFor(type));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -556,10 +547,11 @@ public class CassandraMappingContext
|
||||
return getDataTypeWithUserTypeFactory(property.getTypeInformation(), dataTypeProvider, property::getDataType);
|
||||
}
|
||||
|
||||
private DataType getDataTypeWithUserTypeFactory(TypeInformation<?> typeInformation, DataTypeProvider dataTypeProvider,
|
||||
Supplier<DataType> fallback) {
|
||||
private DataType getDataTypeWithUserTypeFactory(TypeInformation<?> typeInformation,
|
||||
DataTypeProvider dataTypeProvider, Supplier<DataType> fallback) {
|
||||
|
||||
BasicCassandraPersistentEntity<?> persistentEntity = getPersistentEntity(typeInformation.getRequiredActualType());
|
||||
BasicCassandraPersistentEntity<?> persistentEntity =
|
||||
getPersistentEntity(typeInformation.getRequiredActualType());
|
||||
|
||||
if (persistentEntity != null && persistentEntity.isUserDefinedType()) {
|
||||
|
||||
@@ -570,17 +562,16 @@ public class CassandraMappingContext
|
||||
}
|
||||
}
|
||||
|
||||
Optional<DataType> customWriteTarget = customConversions.getCustomWriteTarget(typeInformation.getType())
|
||||
Optional<DataType> customWriteTarget = this.customConversions
|
||||
.getCustomWriteTarget(typeInformation.getType())
|
||||
.map(CassandraSimpleTypeHolder::getDataTypeFor);
|
||||
|
||||
DataType dataType = customWriteTarget.orElseGet(() -> {
|
||||
|
||||
return customConversions.getCustomWriteTarget(typeInformation.getRequiredActualType().getType()) //
|
||||
.filter(it -> !typeInformation.isMap()) //
|
||||
DataType dataType = customWriteTarget.orElseGet(() ->
|
||||
this.customConversions.getCustomWriteTarget(typeInformation.getRequiredActualType().getType())
|
||||
.filter(it -> !typeInformation.isMap())
|
||||
.map(it -> {
|
||||
|
||||
if (typeInformation.isCollectionLike()) {
|
||||
|
||||
if (List.class.isAssignableFrom(typeInformation.getType())) {
|
||||
return DataType.list(getDataTypeFor(it));
|
||||
}
|
||||
@@ -591,16 +582,14 @@ public class CassandraMappingContext
|
||||
}
|
||||
|
||||
return getDataTypeFor(it);
|
||||
}).orElse(null);
|
||||
});
|
||||
|
||||
if (dataType != null) {
|
||||
return dataType;
|
||||
}
|
||||
}).orElse(null));
|
||||
|
||||
return typeInformation.isMap() ? getMapDataType(typeInformation, dataTypeProvider) : fallback.get();
|
||||
return dataType != null ? dataType
|
||||
: typeInformation.isMap() ? getMapDataType(typeInformation, dataTypeProvider) : fallback.get();
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private DataType getMapDataType(TypeInformation<?> typeInformation, DataTypeProvider dataTypeProvider) {
|
||||
|
||||
TypeInformation<?> keyTypeInformation = typeInformation.getComponentType();
|
||||
@@ -609,16 +598,18 @@ public class CassandraMappingContext
|
||||
DataType keyType = getDataTypeWithUserTypeFactory(keyTypeInformation, dataTypeProvider, () -> {
|
||||
|
||||
DataType type = getDataTypeFor(keyTypeInformation.getType());
|
||||
|
||||
if (type != null) {
|
||||
return type;
|
||||
}
|
||||
|
||||
throw new MappingException("Cannot resolve key type for " + typeInformation + ".");
|
||||
throw new MappingException(String.format("Cannot resolve key type for [%s]", typeInformation));
|
||||
});
|
||||
|
||||
DataType valueType = getDataTypeWithUserTypeFactory(valueTypeInformation, dataTypeProvider, () -> {
|
||||
|
||||
DataType type = getDataTypeFor(valueTypeInformation.getType());
|
||||
|
||||
if (type != null) {
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -90,21 +90,6 @@ public class CassandraSimpleTypeHolder extends SimpleTypeHolder {
|
||||
super(CASSANDRA_SIMPLE_TYPES, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the map between {@link Name} and {@link DataType}.
|
||||
*/
|
||||
private static Map<Name, DataType> nameToDataType() {
|
||||
|
||||
Map<Name, DataType> nameToDataType = new HashMap<>(16);
|
||||
|
||||
DataType.allPrimitiveTypes().forEach(dataType -> nameToDataType.put(dataType.getName(), dataType));
|
||||
|
||||
nameToDataType.put(Name.VARCHAR, DataType.varchar());
|
||||
nameToDataType.put(Name.TEXT, DataType.text());
|
||||
|
||||
return nameToDataType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the map between {@link Class} and {@link DataType}.
|
||||
* @param codecRegistry the Cassandra codec registry.
|
||||
@@ -139,6 +124,21 @@ public class CassandraSimpleTypeHolder extends SimpleTypeHolder {
|
||||
return classToDataType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the map between {@link Name} and {@link DataType}.
|
||||
*/
|
||||
private static Map<Name, DataType> nameToDataType() {
|
||||
|
||||
Map<Name, DataType> nameToDataType = new HashMap<>(16);
|
||||
|
||||
DataType.allPrimitiveTypes().forEach(dataType -> nameToDataType.put(dataType.getName(), dataType));
|
||||
|
||||
nameToDataType.put(Name.VARCHAR, DataType.varchar());
|
||||
nameToDataType.put(Name.TEXT, DataType.text());
|
||||
|
||||
return nameToDataType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Set} containing all Cassandra primitive types.
|
||||
*
|
||||
@@ -147,29 +147,32 @@ public class CassandraSimpleTypeHolder extends SimpleTypeHolder {
|
||||
*/
|
||||
private static Set<Class<?>> getCassandraPrimitiveTypes(CodecRegistry codecRegistry) {
|
||||
|
||||
return DataType.allPrimitiveTypes().stream().map(codecRegistry::codecFor).map(TypeCodec::getJavaType)
|
||||
.map(TypeToken::getRawType).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link DataType} for a {@link DataType.Name}.
|
||||
*
|
||||
* @param name must not be {@literal null}.
|
||||
* @return the {@link DataType} for {@link DataType.Name}.
|
||||
*/
|
||||
public static DataType getDataTypeFor(DataType.Name name) {
|
||||
return nameToDataType.get(name);
|
||||
return DataType.allPrimitiveTypes().stream()
|
||||
.map(codecRegistry::codecFor)
|
||||
.map(TypeCodec::getJavaType)
|
||||
.map(TypeToken::getRawType)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default {@link DataType} for a {@link Class}. This method resolves only simple types to a Cassandra
|
||||
* {@link DataType}. Other types are resolved to {@literal null}.
|
||||
*
|
||||
* @param javaClass must not be {@literal null}.
|
||||
* @param javaType must not be {@literal null}.
|
||||
* @return the {@link DataType} for {@code javaClass} if resolvable, otherwise {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
public static DataType getDataTypeFor(Class<?> javaClass) {
|
||||
return (javaClass.isEnum() ? DataType.varchar() : classToDataType.get(javaClass));
|
||||
public static DataType getDataTypeFor(Class<?> javaType) {
|
||||
return javaType.isEnum() ? DataType.varchar() : classToDataType.get(javaType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link DataType} for a {@link DataType.Name}.
|
||||
*
|
||||
* @param dataTypeName must not be {@literal null}.
|
||||
* @return the {@link DataType} for {@link DataType.Name}.
|
||||
*/
|
||||
public static DataType getDataTypeFor(DataType.Name dataTypeName) {
|
||||
return nameToDataType.get(dataTypeName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,14 +15,16 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.core.convert;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.BDDMockito.*;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.mockito.BDDMockito.when;
|
||||
|
||||
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.cassandra.core.cql.CqlIdentifier;
|
||||
|
||||
import com.datastax.driver.core.ColumnDefinitions;
|
||||
@@ -52,7 +54,7 @@ public class ColumnReaderUnitTests {
|
||||
underTest = new ColumnReader(row);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void throwsIllegalArgumentExceptionIfColumnDoesNotExistByName() {
|
||||
|
||||
when(columnDefinitions.getIndexOf(NON_EXISTENT_COLUMN)).thenReturn(-1);
|
||||
@@ -60,34 +62,47 @@ public class ColumnReaderUnitTests {
|
||||
try {
|
||||
underTest.get(NON_EXISTENT_COLUMN);
|
||||
fail("Expected illegal argument exception");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage()).isEqualTo("Column does not exist in Cassandra table: " + NON_EXISTENT_COLUMN);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("Column [%s] does not exist in table", NON_EXISTENT_COLUMN);
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void throwsIllegalArgumentExceptionIfColumnDoesNotExistByCqlIdentifier() {
|
||||
|
||||
when(columnDefinitions.getIndexOf(NON_EXISTENT_COLUMN)).thenReturn(-1);
|
||||
|
||||
try {
|
||||
underTest.get(CqlIdentifier.of(NON_EXISTENT_COLUMN));
|
||||
fail("Expected illegal argument exception");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage()).isEqualTo("Column does not exist in Cassandra table: " + NON_EXISTENT_COLUMN);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("Column [%s] does not exist in table", NON_EXISTENT_COLUMN);
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void throwsIllegalArgumentExceptionIfColumnDoesNotExistByCqlIdentifierAndType() {
|
||||
|
||||
when(columnDefinitions.getIndexOf(NON_EXISTENT_COLUMN)).thenReturn(-1);
|
||||
|
||||
try {
|
||||
underTest.get(CqlIdentifier.of(NON_EXISTENT_COLUMN), String.class);
|
||||
fail("Expected illegal argument exception");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage()).isEqualTo("Column does not exist in Cassandra table: " + NON_EXISTENT_COLUMN);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("Column [%s] does not exist in table", NON_EXISTENT_COLUMN);
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,11 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.core.convert;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -28,9 +24,14 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
@@ -399,11 +400,11 @@ public class MappingCassandraConverterUDTIntegrationTests extends AbstractSpring
|
||||
@Test // DATACASS-487
|
||||
public void shouldReadUdtInMap() {
|
||||
|
||||
session.execute("INSERT INTO supplier (id,acceptedCurrencies) VALUES ('1',"
|
||||
+ "{{name:'a good one'}:[{currency:'EUR'},{currency:'USD'}]});");
|
||||
this.session.execute("INSERT INTO supplier (id, acceptedCurrencies)"
|
||||
+ " VALUES ('1', {{name:'a good one'}:[{currency:'EUR'},{currency:'USD'}]});");
|
||||
|
||||
ResultSet resultSet = session.execute("SELECT * FROM supplier");
|
||||
Supplier supplier = converter.read(Supplier.class, resultSet.one());
|
||||
ResultSet resultSet = this.session.execute("SELECT * FROM supplier");
|
||||
Supplier supplier = this.converter.read(Supplier.class, resultSet.one());
|
||||
|
||||
assertThat(supplier.getAcceptedCurrencies()).isNotEmpty();
|
||||
|
||||
|
||||
@@ -15,12 +15,9 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.core.convert;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.springframework.data.cassandra.test.util.RowMockUtil.*;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.data.cassandra.test.util.RowMockUtil.column;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -28,6 +25,9 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
@@ -35,6 +35,7 @@ import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
|
||||
import org.springframework.data.cassandra.core.mapping.UserDefinedType;
|
||||
@@ -55,7 +56,6 @@ import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.Silent.class) // there are some unused stubbings in RowMockUtil but they're used in other
|
||||
// tests
|
||||
public class MappingCassandraConverterUDTUnitTests {
|
||||
|
||||
@Rule public final ExpectedException expectedException = ExpectedException.none();
|
||||
@@ -90,16 +90,17 @@ public class MappingCassandraConverterUDTUnitTests {
|
||||
UDTValue value2 = currency.newValue().setString("currency", "USD");
|
||||
|
||||
Map<UDTValue, List<UDTValue>> map = new HashMap<>();
|
||||
|
||||
map.put(key, Arrays.asList(value1, value2));
|
||||
|
||||
rowMock = RowMockUtil
|
||||
.newRowMock(column("acceptedCurrencies", map, DataType.map(manufacturer, DataType.list(currency))));
|
||||
rowMock = RowMockUtil.newRowMock(column("acceptedCurrencies", map, DataType.map(manufacturer, DataType.list(currency))));
|
||||
|
||||
Supplier supplier = mappingCassandraConverter.read(Supplier.class, rowMock);
|
||||
|
||||
assertThat(supplier.getAcceptedCurrencies()).isNotEmpty();
|
||||
|
||||
List<Currency> currencies = supplier.getAcceptedCurrencies().get(new Manufacturer("a good one"));
|
||||
|
||||
assertThat(currencies).contains(new Currency("EUR"), new Currency("USD"));
|
||||
}
|
||||
|
||||
@@ -110,7 +111,9 @@ public class MappingCassandraConverterUDTUnitTests {
|
||||
Arrays.asList(new Currency("EUR"), new Currency("USD")));
|
||||
|
||||
Supplier supplier = new Supplier(currencies);
|
||||
|
||||
Insert insert = QueryBuilder.insertInto("table");
|
||||
|
||||
mappingCassandraConverter.write(supplier, insert);
|
||||
|
||||
assertThat(insert.toString()).contains("VALUES ({{name:'a good one'}:[{currency:'EUR'},{currency:'USD'}]}");
|
||||
|
||||
@@ -15,14 +15,10 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.core.convert;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.junit.Assume.*;
|
||||
import static org.springframework.data.cassandra.core.mapping.BasicMapId.*;
|
||||
import static org.springframework.data.cassandra.test.util.RowMockUtil.*;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Value;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
import static org.springframework.data.cassandra.core.mapping.BasicMapId.id;
|
||||
import static org.springframework.data.cassandra.test.util.RowMockUtil.column;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
@@ -33,12 +29,26 @@ import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Value;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.core.SpringVersion;
|
||||
import org.springframework.core.convert.ConverterNotFoundException;
|
||||
import org.springframework.data.cassandra.core.cql.PrimaryKeyType;
|
||||
@@ -95,10 +105,10 @@ public class MappingCassandraConverterUnitTests {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
mappingContext = new CassandraMappingContext();
|
||||
this.mappingContext = new CassandraMappingContext();
|
||||
|
||||
mappingCassandraConverter = new MappingCassandraConverter(mappingContext);
|
||||
mappingCassandraConverter.afterPropertiesSet();
|
||||
this.mappingCassandraConverter = new MappingCassandraConverter(mappingContext);
|
||||
this.mappingCassandraConverter.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@Test // DATACASS-260
|
||||
@@ -907,15 +917,18 @@ public class MappingCassandraConverterUnitTests {
|
||||
|
||||
LocalDate date1 = LocalDate.fromYearMonthDay(2018, 1, 1);
|
||||
LocalDate date2 = LocalDate.fromYearMonthDay(2019, 1, 1);
|
||||
|
||||
Map<String, List<LocalDate>> times = Collections.singletonMap("Europe/Paris", Arrays.asList(date1, date2));
|
||||
|
||||
rowMock = RowMockUtil.newRowMock(
|
||||
RowMockUtil.column("times", times, DataType.map(DataType.varchar(), DataType.list(DataType.date()))));
|
||||
|
||||
TypeWithConvertedMap converted = mappingCassandraConverter.read(TypeWithConvertedMap.class, rowMock);
|
||||
TypeWithConvertedMap converted = this.mappingCassandraConverter.read(TypeWithConvertedMap.class, rowMock);
|
||||
|
||||
assertThat(converted.times).containsKeys(ZoneId.of("Europe/Paris"));
|
||||
|
||||
List<java.time.LocalDate> convertedTimes = converted.times.get(ZoneId.of("Europe/Paris"));
|
||||
|
||||
assertThat(convertedTimes).hasSize(2).hasOnlyElementsOfType(java.time.LocalDate.class);
|
||||
}
|
||||
|
||||
@@ -926,13 +939,15 @@ public class MappingCassandraConverterUnitTests {
|
||||
java.time.LocalDate date2 = java.time.LocalDate.of(2019, 1, 1);
|
||||
|
||||
TypeWithConvertedMap typeWithConvertedMap = new TypeWithConvertedMap();
|
||||
|
||||
typeWithConvertedMap.times = Collections.singletonMap(ZoneId.of("Europe/Paris"), Arrays.asList(date1, date2));
|
||||
|
||||
Insert insert = QueryBuilder.insertInto("table");
|
||||
|
||||
mappingCassandraConverter.write(typeWithConvertedMap, insert);
|
||||
this.mappingCassandraConverter.write(typeWithConvertedMap, insert);
|
||||
|
||||
List<Object> values = getValues(insert);
|
||||
|
||||
assertThat(values).hasSize(1);
|
||||
assertThat(values.get(0)).isInstanceOf(Map.class);
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -348,5 +349,4 @@ public class QueryMapperUnitTests {
|
||||
enum State {
|
||||
Active, Inactive;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -96,6 +97,7 @@ public class UpdateMapperUnitTests {
|
||||
public void shouldReplaceUdtMap() {
|
||||
|
||||
Manufacturer manufacturer = new Manufacturer("foobar");
|
||||
|
||||
Map<Manufacturer, Currency> map = Collections.singletonMap(manufacturer, currency);
|
||||
|
||||
Update update = updateMapper.getMappedObject(Update.empty().set("manufacturers", map), persistentEntity);
|
||||
@@ -126,6 +128,7 @@ public class UpdateMapperUnitTests {
|
||||
public void shouldCreateSetAtUdtKeyUpdate() {
|
||||
|
||||
Manufacturer manufacturer = new Manufacturer("foobar");
|
||||
|
||||
Update update = updateMapper.getMappedObject(Update.empty().set("manufacturers").atKey(manufacturer).to(currency),
|
||||
persistentEntity);
|
||||
|
||||
@@ -146,6 +149,7 @@ public class UpdateMapperUnitTests {
|
||||
public void shouldAddUdtToMap() {
|
||||
|
||||
Manufacturer manufacturer = new Manufacturer("foobar");
|
||||
|
||||
Update update = updateMapper.getMappedObject(Update.empty().addTo("manufacturers").entry(manufacturer, currency),
|
||||
persistentEntity);
|
||||
|
||||
|
||||
@@ -250,16 +250,19 @@ public class CassandraMappingContextUnitTests {
|
||||
public void shouldCreateTableForMappedAndConvertedColumn() {
|
||||
|
||||
UserType mappedudt = UserTypeBuilder.forName("mappedudt").withField("foo", DataType.ascii()).build();
|
||||
mappingContext.setUserTypeResolver(typeName -> mappedudt);
|
||||
mappingContext.setCustomConversions(
|
||||
new CassandraCustomConversions(Collections.singletonList(HumanToStringConverter.INSTANCE)));
|
||||
|
||||
CassandraPersistentEntity<?> persistentEntity = mappingContext
|
||||
.getRequiredPersistentEntity(WithMapOfMixedTypes.class);
|
||||
this.mappingContext.setUserTypeResolver(typeName -> mappedudt);
|
||||
this.mappingContext.setCustomConversions(new CassandraCustomConversions(
|
||||
Collections.singletonList(HumanToStringConverter.INSTANCE)));
|
||||
|
||||
CreateTableSpecification tableSpecification = mappingContext.getCreateTableSpecificationFor(persistentEntity);
|
||||
CassandraPersistentEntity<?> persistentEntity =
|
||||
this.mappingContext.getRequiredPersistentEntity(WithMapOfMixedTypes.class);
|
||||
|
||||
CreateTableSpecification tableSpecification =
|
||||
this.mappingContext.getCreateTableSpecificationFor(persistentEntity);
|
||||
|
||||
assertThat(tableSpecification.getColumns()).hasSize(2);
|
||||
|
||||
ColumnSpecification column = tableSpecification.getColumns().get(1);
|
||||
|
||||
assertThat(column.getType().toString()).isEqualTo("map<frozen<mappedudt>, list<text>>");
|
||||
|
||||
Reference in New Issue
Block a user