Skip to content

Commit 9210308

Browse files
jxblummp911de
authored andcommitted
Fix test failures related to Joda Time and ThreeTenBackport type mappings.
Refactor and cleanup codebase. See #1170.
1 parent 967f674 commit 9210308

12 files changed

+191
-192
lines changed

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/AbstractCassandraConverter.java

-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616
package org.springframework.data.cassandra.core.convert;
1717

18-
1918
import java.util.Collections;
2019

2120
import org.springframework.beans.factory.InitializingBean;

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/CassandraConverter.java

+1
Original file line numberDiff line numberDiff line change
@@ -152,4 +152,5 @@ default Object convertToColumnType(Object value, TypeInformation<?> typeInformat
152152
* @param entity must not be {@literal null}.
153153
*/
154154
void write(Object source, Object sink, CassandraPersistentEntity<?> entity);
155+
155156
}

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/CassandraConverters.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,10 @@ public enum RowToDateConverter implements Converter<Row, Date> {
9292

9393
@Override
9494
public Date convert(Row row) {
95-
return Date.from(row.getInstant(0));
95+
96+
Instant instant = row.getInstant(0);
97+
98+
return instant != null ? Date.from(instant) : null;
9699
}
97100
}
98101

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/CassandraCustomConversions.java

+4-17
Original file line numberDiff line numberDiff line change
@@ -64,31 +64,18 @@ public CassandraCustomConversions(List<?> converters) {
6464

6565
/**
6666
* Cassandra-specific extension to {@link org.springframework.data.convert.CustomConversions.ConverterConfiguration}.
67-
* This extension avoids {@link Converter} registrations that enforce date mapping to {@link Date} from JSR-310, Joda
68-
* Time and ThreeTenBackport.
67+
* This extension avoids {@link Converter} registrations that enforce date mapping to {@link Date} from JSR-310.
6968
*/
7069
static class CassandraConverterConfiguration extends ConverterConfiguration {
7170

72-
public CassandraConverterConfiguration(StoreConversions storeConversions, List<?> userConverters) {
71+
CassandraConverterConfiguration(StoreConversions storeConversions, List<?> userConverters) {
7372
super(storeConversions, userConverters, getConverterFilter());
7473
}
7574

7675
static Predicate<ConvertiblePair> getConverterFilter() {
7776

78-
return convertiblePair -> {
79-
80-
if (sourceMatches(convertiblePair, "org.joda.time") || sourceMatches(convertiblePair, "org.threeten.bp")
81-
|| Jsr310Converters.supports(convertiblePair.getSourceType())
82-
&& Date.class.isAssignableFrom(convertiblePair.getTargetType())) {
83-
return false;
84-
}
85-
86-
return true;
87-
};
88-
}
89-
90-
private static boolean sourceMatches(ConvertiblePair convertiblePair, String packagePrefix) {
91-
return convertiblePair.getSourceType().getName().startsWith(packagePrefix);
77+
return convertiblePair -> !(Jsr310Converters.supports(convertiblePair.getSourceType())
78+
&& Date.class.isAssignableFrom(convertiblePair.getTargetType()));
9279
}
9380
}
9481
}

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/CassandraJsr310Converters.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ private CassandraJsr310Converters() {}
5555
converters.add(LocalTimeToMillisOfDayConverter.INSTANCE);
5656

5757
converters.add(DateToInstantConverter.INSTANCE);
58-
converters.add(LocalDateToInstantConverter.INSTANCE);
58+
converters.add(LocalDateTimeToInstantConverter.INSTANCE);
5959

6060
return converters;
6161
}
@@ -117,7 +117,7 @@ public Instant convert(Date source) {
117117
* @since 3.0
118118
*/
119119
@WritingConverter
120-
enum LocalDateToInstantConverter implements Converter<LocalDateTime, Instant> {
120+
enum LocalDateTimeToInstantConverter implements Converter<LocalDateTime, Instant> {
121121

122122
INSTANCE;
123123

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/DefaultColumnTypeResolver.java

+10-16
Original file line numberDiff line numberDiff line change
@@ -174,16 +174,11 @@ public CassandraColumnType resolve(TypeInformation<?> typeInformation) {
174174

175175
private CassandraColumnType resolve(TypeInformation<?> typeInformation, FrozenIndicator frozen) {
176176

177-
return getCustomWriteTarget(typeInformation).map(it -> {
178-
return createCassandraTypeDescriptor(tryResolve(it), ClassTypeInformation.from(it));
179-
}).orElseGet(() -> {
180-
181-
if (typeInformation.getType().isEnum()) {
182-
return ColumnType.create(String.class, DataTypes.TEXT);
183-
}
184-
185-
return createCassandraTypeDescriptor(typeInformation, frozen);
186-
});
177+
return getCustomWriteTarget(typeInformation)
178+
.map(it -> createCassandraTypeDescriptor(tryResolve(it), ClassTypeInformation.from(it)))
179+
.orElseGet(() -> typeInformation.getType().isEnum()
180+
? ColumnType.create(String.class, DataTypes.TEXT)
181+
: createCassandraTypeDescriptor(typeInformation, frozen));
187182
}
188183

189184
private Optional<Class<?>> getCustomWriteTarget(TypeInformation<?> typeInformation) {
@@ -203,9 +198,9 @@ private DataType tryResolve(Class<?> type) {
203198

204199
try {
205200
return getCodecRegistry().codecFor(type).getCqlType();
206-
} catch (CodecNotFoundException e) {
201+
} catch (CodecNotFoundException cause) {
207202
if (log.isDebugEnabled()) {
208-
log.debug(String.format("Cannot resolve Codec for %s", type.getName()), e);
203+
log.debug(String.format("Cannot resolve Codec for %s", type.getName()), cause);
209204
}
210205
return null;
211206
}
@@ -435,11 +430,10 @@ private CassandraColumnType createCassandraTypeDescriptor(TypeInformation<?> typ
435430
}
436431

437432
DataType dataType = tryResolve(typeInformation.getType());
438-
if (dataType == null) {
439-
return new UnresolvableCassandraType(typeInformation);
440-
}
441433

442-
return new DefaultCassandraColumnType(typeInformation, dataType);
434+
return dataType == null
435+
? new UnresolvableCassandraType(typeInformation)
436+
: new DefaultCassandraColumnType(typeInformation, dataType);
443437
}
444438

445439
private DataType getRequiredDataType(CassandraType annotation, int typeIndex) {

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverter.java

+49-47
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,19 @@
3737
import org.springframework.core.convert.ConversionService;
3838
import org.springframework.core.convert.support.DefaultConversionService;
3939
import org.springframework.dao.InvalidDataAccessApiUsageException;
40-
import org.springframework.data.cassandra.core.mapping.*;
40+
import org.springframework.data.cassandra.core.mapping.BasicCassandraPersistentEntity;
41+
import org.springframework.data.cassandra.core.mapping.BasicMapId;
42+
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
43+
import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity;
44+
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
45+
import org.springframework.data.cassandra.core.mapping.Column;
46+
import org.springframework.data.cassandra.core.mapping.Element;
47+
import org.springframework.data.cassandra.core.mapping.Embedded;
4148
import org.springframework.data.cassandra.core.mapping.Embedded.OnEmpty;
49+
import org.springframework.data.cassandra.core.mapping.EmbeddedEntityOperations;
50+
import org.springframework.data.cassandra.core.mapping.MapId;
51+
import org.springframework.data.cassandra.core.mapping.MapIdentifiable;
52+
import org.springframework.data.cassandra.core.mapping.UserTypeResolver;
4253
import org.springframework.data.convert.CustomConversions;
4354
import org.springframework.data.mapping.AccessOptions;
4455
import org.springframework.data.mapping.MappingException;
@@ -113,19 +124,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
113124
* Create a new {@link MappingCassandraConverter} with a {@link CassandraMappingContext}.
114125
*/
115126
public MappingCassandraConverter() {
116-
117-
super(newConversionService());
118-
119-
CassandraCustomConversions conversions = new CassandraCustomConversions(Collections.emptyList());
120-
121-
this.mappingContext = newDefaultMappingContext(conversions);
122-
this.codecRegistry = mappingContext.getCodecRegistry();
123-
this.spELContext = new SpELContext(RowReaderPropertyAccessor.INSTANCE);
124-
this.cassandraTypeResolver = new DefaultColumnTypeResolver(mappingContext,
125-
userTypeName -> getUserTypeResolver().resolveType(userTypeName), this::getCodecRegistry,
126-
this::getCustomConversions);
127-
this.setCustomConversions(conversions);
128-
this.embeddedEntityOperations = new EmbeddedEntityOperations(mappingContext);
127+
this(newDefaultMappingContext(new CassandraCustomConversions(Collections.emptyList())));
129128
}
130129

131130
/**
@@ -139,31 +138,42 @@ public MappingCassandraConverter(CassandraMappingContext mappingContext) {
139138

140139
Assert.notNull(mappingContext, "CassandraMappingContext must not be null");
141140

141+
UserTypeResolver userTypeResolver = userTypeName -> getUserTypeResolver().resolveType(userTypeName);
142+
142143
this.mappingContext = mappingContext;
143-
this.codecRegistry = mappingContext.getCodecRegistry();
144-
this.spELContext = new SpELContext(RowReaderPropertyAccessor.INSTANCE);
145-
this.cassandraTypeResolver = new DefaultColumnTypeResolver(mappingContext,
146-
userTypeName -> getUserTypeResolver().resolveType(userTypeName), this::getCodecRegistry,
147-
this::getCustomConversions);
144+
this.setCodecRegistry(mappingContext.getCodecRegistry());
148145
this.setCustomConversions(mappingContext.getCustomConversions());
146+
this.cassandraTypeResolver = new DefaultColumnTypeResolver(mappingContext, userTypeResolver,
147+
this::getCodecRegistry, this::getCustomConversions);
149148
this.embeddedEntityOperations = new EmbeddedEntityOperations(mappingContext);
149+
this.spELContext = new SpELContext(RowReaderPropertyAccessor.INSTANCE);
150150
}
151151

152152
/**
153-
* Creates a new {@link ConversionContext}.
153+
* Constructs a new instance of {@link ConversionContext} with various converters to convert different Cassandra
154+
* value types.
154155
*
155156
* @return the {@link ConversionContext}.
157+
* @see ConversionContext
156158
*/
157159
protected ConversionContext getConversionContext() {
158160

159-
return new ConversionContext(getCustomConversions(), this::doReadRow, this::doReadTupleValue, this::doReadUdtValue,
161+
return new ConversionContext(this::doReadRow, this::doReadTupleValue, this::doReadUdtValue,
160162
this::readCollectionOrArray, this::readMap, this::getPotentiallyConvertedSimpleRead);
161163
}
162164

163165
private static ConversionService newConversionService() {
164166
return new DefaultConversionService();
165167
}
166168

169+
/**
170+
* Constructs a new instance of a {@link MappingContext} for Cassandra.
171+
*
172+
* @param conversions {@link CassandraCustomConversions} object encapsulating complex type conversion logic.
173+
* @return a new {@link CassandraMappingContext}.
174+
* @see org.springframework.data.cassandra.core.mapping.CassandraMappingContext
175+
* @see org.springframework.data.mapping.context.MappingContext
176+
*/
167177
private static CassandraMappingContext newDefaultMappingContext(CassandraCustomConversions conversions) {
168178

169179
CassandraMappingContext mappingContext = new CassandraMappingContext();
@@ -174,6 +184,7 @@ private static CassandraMappingContext newDefaultMappingContext(CassandraCustomC
174184
return mappingContext;
175185
}
176186

187+
177188
/* (non-Javadoc)
178189
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
179190
*/
@@ -222,12 +233,7 @@ public void setCodecRegistry(CodecRegistry codecRegistry) {
222233
*/
223234
@Override
224235
public CodecRegistry getCodecRegistry() {
225-
226-
if (this.codecRegistry == null) {
227-
return mappingContext.getCodecRegistry();
228-
}
229-
230-
return this.codecRegistry;
236+
return this.codecRegistry != null ? this.codecRegistry : getMappingContext().getCodecRegistry();
231237
}
232238

233239
/**
@@ -249,12 +255,7 @@ public void setUserTypeResolver(UserTypeResolver userTypeResolver) {
249255
* @since 3.0
250256
*/
251257
public UserTypeResolver getUserTypeResolver() {
252-
253-
if (this.userTypeResolver == null) {
254-
return this.mappingContext.getUserTypeResolver();
255-
}
256-
257-
return userTypeResolver;
258+
return this.userTypeResolver != null ? this.userTypeResolver : getMappingContext().getUserTypeResolver();
258259
}
259260

260261
/* (non-Javadoc)
@@ -500,8 +501,8 @@ protected <S> S doReadEntity(ConversionContext context, CassandraValueProvider v
500501
return (S) getConversionService().convert(valueProvider.getSource(), rawType);
501502
}
502503

503-
CassandraPersistentEntity<S> entity = (CassandraPersistentEntity<S>) getMappingContext()
504-
.getPersistentEntity(typeHint);
504+
CassandraPersistentEntity<S> entity =
505+
(CassandraPersistentEntity<S>) getMappingContext().getPersistentEntity(typeHint);
505506

506507
if (entity == null) {
507508
throw new MappingException(
@@ -526,8 +527,8 @@ private static Class<?> getRawSourceType(CassandraValueProvider valueProvider) {
526527
return UdtValue.class;
527528
}
528529

529-
throw new InvalidDataAccessApiUsageException(
530-
"Unsupported source type: " + ClassUtils.getDescriptiveType(valueProvider.getSource()));
530+
throw new InvalidDataAccessApiUsageException(String.format("Unsupported source type: %s",
531+
ClassUtils.getDescriptiveType(valueProvider.getSource())));
531532
}
532533

533534
private <S> S doReadEntity(ConversionContext context, CassandraValueProvider valueProvider,
@@ -538,8 +539,8 @@ private <S> S doReadEntity(ConversionContext context, CassandraValueProvider val
538539

539540
if (persistenceConstructor != null && persistenceConstructor.hasParameters()) {
540541
SpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(valueProvider.getSource(), spELContext);
541-
ParameterValueProvider<CassandraPersistentProperty> parameterValueProvider = newParameterValueProvider(context,
542-
entity, valueProvider);
542+
ParameterValueProvider<CassandraPersistentProperty> parameterValueProvider =
543+
newParameterValueProvider(context, entity, valueProvider);
543544
provider = new ConverterAwareSpELExpressionParameterValueProvider(evaluator, getConversionService(),
544545
parameterValueProvider, context);
545546
} else {
@@ -881,10 +882,7 @@ public Object getId(Object object, CassandraPersistentEntity<?> entity) {
881882

882883
/**
883884
* Check custom conversions for type override or fall back to
884-
* {@link #determineTargetType(CassandraPersistentProperty)}
885-
*
886-
* @param property
887-
* @return
885+
* {@link ColumnTypeResolver#resolve(CassandraPersistentProperty)}.
888886
*/
889887
private Class<?> getTargetType(CassandraPersistentProperty property) {
890888
return getCustomConversions().getCustomWriteTarget(property.getType())
@@ -929,17 +927,20 @@ private Object getWriteValue(@Nullable Object value, ColumnType columnType) {
929927

930928
if (getCustomConversions().hasCustomWriteTarget(value.getClass(), requestedTargetType)) {
931929

932-
Class<?> resolvedTargetType = getCustomConversions().getCustomWriteTarget(value.getClass(), requestedTargetType)
930+
Class<?> resolvedTargetType = getCustomConversions()
931+
.getCustomWriteTarget(value.getClass(), requestedTargetType)
933932
.orElse(requestedTargetType);
934933

935934
return getConversionService().convert(value, resolvedTargetType);
936935
}
937936

938937
if (getCustomConversions().hasCustomWriteTarget(value.getClass())) {
939938

940-
Class<?> resolvedTargetType = getCustomConversions().getCustomWriteTarget(value.getClass())
941-
.orElseThrow(() -> new IllegalStateException(String
942-
.format("Unable to determined custom write target for value type [%s]", value.getClass().getName())));
939+
Class<?> resolvedTargetType = getCustomConversions()
940+
.getCustomWriteTarget(value.getClass())
941+
.orElseThrow(() -> new IllegalStateException(
942+
String.format("Unable to determined custom write target for value type [%s]",
943+
value.getClass().getName())));
943944

944945
return getConversionService().convert(value, resolvedTargetType);
945946
}
@@ -1123,6 +1124,7 @@ private Object getReadValue(ConversionContext context, CassandraValueProvider va
11231124
}
11241125

11251126
Object value = valueProvider.getPropertyValue(property);
1127+
11261128
return value == null ? null : context.convert(value, property.getTypeInformation());
11271129
}
11281130

0 commit comments

Comments
 (0)