Skip to content

Commit 3a2b9c9

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 17850b7 commit 3a2b9c9

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

Lines changed: 16 additions & 29 deletions
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

Lines changed: 5 additions & 32 deletions
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;
@@ -42,7 +40,6 @@
4240
import org.springframework.lang.Nullable;
4341
import org.springframework.util.Assert;
4442
import org.springframework.util.ClassUtils;
45-
import org.springframework.util.StringUtils;
4643

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

@@ -59,13 +56,13 @@
5956
public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentProperty<CassandraPersistentProperty>
6057
implements CassandraPersistentProperty, ApplicationContextAware {
6158

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

6564
private @Nullable CqlIdentifier columnName;
6665

67-
private NamingStrategy namingStrategy = NamingStrategy.INSTANCE;
68-
6966
private @Nullable StandardEvaluationContext spelContext;
7067

7168
/**
@@ -197,8 +194,6 @@ private CqlIdentifier determineColumnName() {
197194
return null;
198195
}
199196

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

204199
boolean forceQuote = false;
@@ -231,22 +226,7 @@ private CqlIdentifier determineColumnName() {
231226
}
232227
}
233228

234-
return createColumnName(defaultName, overriddenName, forceQuote);
235-
}
236-
237-
@Nullable
238-
private CqlIdentifier createColumnName(Supplier<String> defaultName, @Nullable String overriddenName,
239-
boolean forceQuote) {
240-
241-
String name;
242-
243-
if (StringUtils.hasText(overriddenName)) {
244-
name = this.spelContext != null ? SpelUtils.evaluate(overriddenName, this.spelContext) : overriddenName;
245-
} else {
246-
name = defaultName.get();
247-
}
248-
249-
return name != null ? IdentifierFactory.create(name, forceQuote) : null;
229+
return namingAccessor.generate(overriddenName, forceQuote, NamingStrategy::getColumnName, this, this.spelContext);
250230
}
251231

252232
/* (non-Javadoc)
@@ -267,14 +247,7 @@ public void setColumnName(CqlIdentifier columnName) {
267247
* @since 3.0
268248
*/
269249
public void setNamingStrategy(NamingStrategy namingStrategy) {
270-
271-
Assert.notNull(namingStrategy, "NamingStrategy must not be null");
272-
273-
this.namingStrategy = namingStrategy;
274-
}
275-
276-
NamingStrategy getNamingStrategy() {
277-
return this.namingStrategy;
250+
this.namingAccessor.setNamingStrategy(namingStrategy);
278251
}
279252

280253
/* (non-Javadoc)
@@ -288,7 +261,7 @@ public void setForceQuote(boolean forceQuote) {
288261
this.forceQuote = forceQuote;
289262

290263
if (changed) {
291-
setColumnName(IdentifierFactory.create(getRequiredColumnName().asInternal(), forceQuote));
264+
setColumnName(CqlIdentifierGenerator.createIdentifier(getRequiredColumnName().asInternal(), forceQuote));
292265
}
293266
}
294267

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

Lines changed: 17 additions & 15 deletions
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

Lines changed: 1 addition & 8 deletions
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)