Skip to content

Commit 66dfce1

Browse files
committed
Refine table and column name generation.
We revised the table and column name generation by unifying the generation code into CqlIdentifierGenerator. We also properly distinguish between generated names that are generated and those provided by the application (i.e. through annotations). Closes #1263
1 parent 43405cb commit 66dfce1

File tree

10 files changed

+215
-135
lines changed

10 files changed

+215
-135
lines changed

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentEntity.java

+16-29
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,17 @@
1515
*/
1616
package org.springframework.data.cassandra.core.mapping;
1717

18+
import java.lang.annotation.Annotation;
1819
import java.util.Comparator;
1920
import java.util.Optional;
21+
import java.util.function.BiFunction;
2022

2123
import org.springframework.beans.BeansException;
2224
import org.springframework.context.ApplicationContext;
2325
import org.springframework.context.ApplicationContextAware;
2426
import org.springframework.context.expression.BeanFactoryAccessor;
2527
import org.springframework.context.expression.BeanFactoryResolver;
26-
import org.springframework.data.cassandra.util.SpelUtils;
28+
import org.springframework.core.annotation.AnnotationUtils;
2729
import org.springframework.data.mapping.Association;
2830
import org.springframework.data.mapping.AssociationHandler;
2931
import org.springframework.data.mapping.MappingException;
@@ -32,7 +34,6 @@
3234
import org.springframework.expression.spel.support.StandardEvaluationContext;
3335
import org.springframework.lang.Nullable;
3436
import org.springframework.util.Assert;
35-
import org.springframework.util.StringUtils;
3637

3738
import com.datastax.oss.driver.api.core.CqlIdentifier;
3839

@@ -49,14 +50,14 @@ public class BasicCassandraPersistentEntity<T> extends BasicPersistentEntity<T,
4950

5051
private static final CassandraPersistentEntityMetadataVerifier DEFAULT_VERIFIER = new CompositeCassandraPersistentEntityMetadataVerifier();
5152

53+
private final CqlIdentifierGenerator namingAccessor = new CqlIdentifierGenerator();
54+
5255
private Boolean forceQuote;
5356

5457
private CassandraPersistentEntityMetadataVerifier verifier = DEFAULT_VERIFIER;
5558

5659
private CqlIdentifier tableName;
5760

58-
private NamingStrategy namingStrategy = NamingStrategy.INSTANCE;
59-
6061
private @Nullable StandardEvaluationContext spelContext;
6162

6263
/**
@@ -101,27 +102,20 @@ protected BasicCassandraPersistentEntity(TypeInformation<T> typeInformation,
101102
}
102103

103104
protected CqlIdentifier determineTableName() {
104-
105-
Table annotation = findAnnotation(Table.class);
106-
107-
if (annotation != null) {
108-
return determineName(annotation.value(), annotation.forceQuote());
109-
}
110-
111-
return IdentifierFactory.create(getNamingStrategy().getTableName(this), false);
105+
return determineTableName(NamingStrategy::getTableName, findAnnotation(Table.class));
112106
}
113107

114-
CqlIdentifier determineName(String value, boolean forceQuote) {
108+
CqlIdentifier determineTableName(
109+
BiFunction<NamingStrategy, CassandraPersistentEntity<?>, String> defaultNameGenerator,
110+
@Nullable Annotation annotation) {
115111

116-
if (!StringUtils.hasText(value)) {
117-
return IdentifierFactory.create(getNamingStrategy().getTableName(this), forceQuote);
112+
if (annotation != null) {
113+
return this.namingAccessor.generate((String) AnnotationUtils.getValue(annotation),
114+
(Boolean) AnnotationUtils.getValue(annotation, "forceQuote"), defaultNameGenerator, this, this.spelContext);
118115
}
119116

120-
String name = Optional.ofNullable(this.spelContext).map(it -> SpelUtils.evaluate(value, it)).orElse(value);
121-
122-
Assert.state(name != null, () -> String.format("Cannot determine default name for %s", this));
123-
124-
return IdentifierFactory.create(name, forceQuote);
117+
return this.namingAccessor.generate(null, forceQuote != null ? forceQuote : false, defaultNameGenerator, this,
118+
this.spelContext);
125119
}
126120

127121
/* (non-Javadoc)
@@ -186,7 +180,7 @@ public void setForceQuote(boolean forceQuote) {
186180
this.forceQuote = forceQuote;
187181

188182
if (changed) {
189-
setTableName(IdentifierFactory.create(getTableName().asInternal(), forceQuote));
183+
setTableName(CqlIdentifierGenerator.createIdentifier(getTableName().asInternal(), forceQuote));
190184
}
191185
}
192186

@@ -208,14 +202,7 @@ public void setTableName(CqlIdentifier tableName) {
208202
* @since 3.0
209203
*/
210204
public void setNamingStrategy(NamingStrategy namingStrategy) {
211-
212-
Assert.notNull(namingStrategy, "NamingStrategy must not be null");
213-
214-
this.namingStrategy = namingStrategy;
215-
}
216-
217-
NamingStrategy getNamingStrategy() {
218-
return namingStrategy;
205+
this.namingAccessor.setNamingStrategy(namingStrategy);
219206
}
220207

221208
/* (non-Javadoc)

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentProperty.java

+5-32
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import java.lang.reflect.Method;
2323
import java.util.Map;
2424
import java.util.Optional;
25-
import java.util.function.Supplier;
2625

2726
import org.springframework.context.ApplicationContext;
2827
import org.springframework.context.ApplicationContextAware;
@@ -31,7 +30,6 @@
3130
import org.springframework.core.annotation.AnnotatedElementUtils;
3231
import org.springframework.data.cassandra.core.cql.Ordering;
3332
import org.springframework.data.cassandra.core.cql.PrimaryKeyType;
34-
import org.springframework.data.cassandra.util.SpelUtils;
3533
import org.springframework.data.mapping.Association;
3634
import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
3735
import org.springframework.data.mapping.model.Property;
@@ -43,7 +41,6 @@
4341
import org.springframework.util.Assert;
4442
import org.springframework.util.ClassUtils;
4543
import org.springframework.util.ObjectUtils;
46-
import org.springframework.util.StringUtils;
4744

4845
import com.datastax.oss.driver.api.core.CqlIdentifier;
4946

@@ -60,13 +57,13 @@
6057
public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentProperty<CassandraPersistentProperty>
6158
implements CassandraPersistentProperty, ApplicationContextAware {
6259

60+
private final CqlIdentifierGenerator namingAccessor = new CqlIdentifierGenerator();
61+
6362
// Indicates whether this property has been explicitly instructed to force quoted column names.
6463
private Boolean forceQuote;
6564

6665
private @Nullable CqlIdentifier columnName;
6766

68-
private NamingStrategy namingStrategy = NamingStrategy.INSTANCE;
69-
7067
private @Nullable StandardEvaluationContext spelContext;
7168

7269
/**
@@ -198,8 +195,6 @@ private CqlIdentifier determineColumnName() {
198195
return null;
199196
}
200197

201-
Supplier<String> defaultName = () -> getNamingStrategy().getColumnName(this);
202-
203198
String overriddenName = null;
204199

205200
boolean forceQuote = false;
@@ -230,7 +225,7 @@ private CqlIdentifier determineColumnName() {
230225
}
231226
}
232227

233-
return createColumnName(defaultName, overriddenName, forceQuote);
228+
return namingAccessor.generate(overriddenName, forceQuote, NamingStrategy::getColumnName, this, this.spelContext);
234229
}
235230

236231
@Override
@@ -259,21 +254,6 @@ public boolean hasExplicitColumnName() {
259254
}
260255
}
261256

262-
@Nullable
263-
private CqlIdentifier createColumnName(Supplier<String> defaultName, @Nullable String overriddenName,
264-
boolean forceQuote) {
265-
266-
String name;
267-
268-
if (StringUtils.hasText(overriddenName)) {
269-
name = this.spelContext != null ? SpelUtils.evaluate(overriddenName, this.spelContext) : overriddenName;
270-
} else {
271-
name = defaultName.get();
272-
}
273-
274-
return name != null ? IdentifierFactory.create(name, forceQuote) : null;
275-
}
276-
277257
/* (non-Javadoc)
278258
* @see org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty#setColumnName(org.springframework.data.cassandra.core.cql.CqlIdentifier)
279259
*/
@@ -292,14 +272,7 @@ public void setColumnName(CqlIdentifier columnName) {
292272
* @since 3.0
293273
*/
294274
public void setNamingStrategy(NamingStrategy namingStrategy) {
295-
296-
Assert.notNull(namingStrategy, "NamingStrategy must not be null");
297-
298-
this.namingStrategy = namingStrategy;
299-
}
300-
301-
NamingStrategy getNamingStrategy() {
302-
return this.namingStrategy;
275+
this.namingAccessor.setNamingStrategy(namingStrategy);
303276
}
304277

305278
/* (non-Javadoc)
@@ -313,7 +286,7 @@ public void setForceQuote(boolean forceQuote) {
313286
this.forceQuote = forceQuote;
314287

315288
if (changed) {
316-
setColumnName(IdentifierFactory.create(getRequiredColumnName().asInternal(), forceQuote));
289+
setColumnName(CqlIdentifierGenerator.createIdentifier(getRequiredColumnName().asInternal(), forceQuote));
317290
}
318291
}
319292

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraMappingContext.java

+17-15
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public class CassandraMappingContext
7171

7272
private Mapping mapping = new Mapping();
7373

74-
private NamingStrategy namingStrategy = NamingStrategy.INSTANCE;
74+
private @Nullable NamingStrategy namingStrategy;
7575

7676
private @Deprecated @Nullable UserTypeResolver userTypeResolver;
7777

@@ -131,7 +131,8 @@ private void processMappingOverrides() {
131131
String entityTableName = entityMapping.getTableName();
132132

133133
if (StringUtils.hasText(entityTableName)) {
134-
entity.setTableName(IdentifierFactory.create(entityTableName, Boolean.valueOf(entityMapping.getForceQuote())));
134+
entity.setTableName(
135+
CqlIdentifierGenerator.createIdentifier(entityTableName, Boolean.valueOf(entityMapping.getForceQuote())));
135136
}
136137

137138
processMappingOverrides(entity, entityMapping);
@@ -163,7 +164,7 @@ private static void processMappingOverride(CassandraPersistentEntity<?> entity,
163164
property.setForceQuote(forceQuote);
164165

165166
if (StringUtils.hasText(mapping.getColumnName())) {
166-
property.setColumnName(IdentifierFactory.create(mapping.getColumnName(), forceQuote));
167+
property.setColumnName(CqlIdentifierGenerator.createIdentifier(mapping.getColumnName(), forceQuote));
167168
}
168169
}
169170

@@ -200,7 +201,7 @@ public void setCustomConversions(CustomConversions customConversions) {
200201

201202
/**
202203
* @deprecated since 3.0. Use custom conversion through
203-
* {@link org.springframework.data.cassandra.core.convert.MappingCassandraConverter}.
204+
* {@link org.springframework.data.cassandra.core.convert.MappingCassandraConverter}.
204205
*/
205206
@Deprecated
206207
public CustomConversions getCustomConversions() {
@@ -255,7 +256,7 @@ public void setCodecRegistry(CodecRegistry codecRegistry) {
255256

256257
/**
257258
* @deprecated since 3.0. Retrieve {@link CodecRegistry} directly from
258-
* {@link org.springframework.data.cassandra.core.convert.CassandraConverter}.
259+
* {@link org.springframework.data.cassandra.core.convert.CassandraConverter}.
259260
*/
260261
@Deprecated
261262
public CodecRegistry getCodecRegistry() {
@@ -304,7 +305,7 @@ public void setUserTypeResolver(UserTypeResolver userTypeResolver) {
304305

305306
/**
306307
* @deprecated since 3.0. Retrieve {@link UserTypeResolver} directly from
307-
* {@link org.springframework.data.cassandra.core.convert.CassandraConverter}.
308+
* {@link org.springframework.data.cassandra.core.convert.CassandraConverter}.
308309
*/
309310
@Nullable
310311
@Deprecated
@@ -352,7 +353,6 @@ protected Optional<BasicCassandraPersistentEntity<?>> addPersistentEntity(TypeIn
352353
if (!entity.isUserDefinedType() && !entity.isTupleType() && entity.isAnnotationPresent(Table.class)) {
353354
this.tableEntities.add(entity);
354355
}
355-
356356
});
357357

358358
return optional;
@@ -375,11 +375,12 @@ protected <T> BasicCassandraPersistentEntity<T> createPersistentEntity(TypeInfor
375375

376376
BasicCassandraPersistentEntity<T> entity = isUserDefinedType(typeInformation)
377377
? new CassandraUserTypePersistentEntity<>(typeInformation, getVerifier())
378-
: isTuple(typeInformation)
379-
? new BasicCassandraPersistentTupleEntity<>(typeInformation)
380-
: new BasicCassandraPersistentEntity<>(typeInformation, getVerifier());
378+
: isTuple(typeInformation) ? new BasicCassandraPersistentTupleEntity<>(typeInformation)
379+
: new BasicCassandraPersistentEntity<>(typeInformation, getVerifier());
381380

382-
entity.setNamingStrategy(this.namingStrategy);
381+
if (this.namingStrategy != null) {
382+
entity.setNamingStrategy(this.namingStrategy);
383+
}
383384
Optional.ofNullable(this.applicationContext).ifPresent(entity::setApplicationContext);
384385

385386
return entity;
@@ -404,7 +405,10 @@ protected CassandraPersistentProperty createPersistentProperty(Property property
404405
? new BasicCassandraPersistentTupleProperty(property, owner, simpleTypeHolder)
405406
: new CachingCassandraPersistentProperty(property, owner, simpleTypeHolder);
406407

407-
persistentProperty.setNamingStrategy(this.namingStrategy);
408+
if (this.namingStrategy != null) {
409+
persistentProperty.setNamingStrategy(this.namingStrategy);
410+
}
411+
408412
Optional.ofNullable(this.applicationContext).ifPresent(persistentProperty::setApplicationContext);
409413

410414
return persistentProperty;
@@ -445,9 +449,7 @@ private boolean hasReferencedUserType(CqlIdentifier identifier) {
445449

446450
return getPersistentEntities().stream().flatMap(entity -> StreamSupport.stream(entity.spliterator(), false))
447451
.flatMap(it -> Optionals.toStream(Optional.ofNullable(it.findAnnotation(CassandraType.class))))
448-
.map(CassandraType::userTypeName)
449-
.filter(StringUtils::hasText)
450-
.map(CqlIdentifier::fromCql)
452+
.map(CassandraType::userTypeName).filter(StringUtils::hasText).map(CqlIdentifier::fromCql)
451453
.anyMatch(identifier::equals);
452454
}
453455
}

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraUserTypePersistentEntity.java

+1-8
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,7 @@ public CassandraUserTypePersistentEntity(TypeInformation<T> typeInformation,
4646
*/
4747
@Override
4848
protected CqlIdentifier determineTableName() {
49-
50-
UserDefinedType annotation = findAnnotation(UserDefinedType.class);
51-
52-
if (annotation != null) {
53-
return determineName(annotation.value(), annotation.forceQuote());
54-
}
55-
56-
return IdentifierFactory.create(getNamingStrategy().getUserDefinedTypeName(this), false);
49+
return determineTableName(NamingStrategy::getUserDefinedTypeName, findAnnotation(UserDefinedType.class));
5750
}
5851

5952
/* (non-Javadoc)

0 commit comments

Comments
 (0)