Skip to content

Commit c120e8f

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 c64978e commit c120e8f

File tree

11 files changed

+216
-137
lines changed

11 files changed

+216
-137
lines changed

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractCassandraConfiguration.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
import org.springframework.data.cassandra.core.mapping.Table;
3838
import org.springframework.data.cassandra.core.mapping.UserTypeResolver;
3939
import org.springframework.data.convert.CustomConversions;
40-
import org.springframework.data.domain.ManagedTypes;
4140
import org.springframework.data.mapping.context.MappingContext;
4241
import org.springframework.lang.Nullable;
4342

@@ -101,7 +100,7 @@ public CassandraManagedTypes cassandraManagedTypes() throws ClassNotFoundExcepti
101100
* Return the {@link MappingContext} instance to map Entities to {@link Object Java Objects}.
102101
*
103102
* @see org.springframework.data.cassandra.core.mapping.CassandraMappingContext
104-
* @deprecated since 4.0, use {@link #cassandraMappingContext(ManagedTypes)} instead.
103+
* @deprecated since 4.0, use {@link #cassandraMappingContext(CassandraManagedTypes)} instead.
105104
*/
106105
@Deprecated(since = "4.0", forRemoval = true)
107106
public CassandraMappingContext cassandraMapping() throws ClassNotFoundException {

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
@Override
@@ -168,7 +162,7 @@ public void setForceQuote(boolean forceQuote) {
168162
this.forceQuote = forceQuote;
169163

170164
if (changed) {
171-
setTableName(IdentifierFactory.create(getTableName().asInternal(), forceQuote));
165+
setTableName(CqlIdentifierGenerator.createIdentifier(getTableName().asInternal(), forceQuote));
172166
}
173167
}
174168

@@ -187,14 +181,7 @@ public void setTableName(CqlIdentifier tableName) {
187181
* @since 3.0
188182
*/
189183
public void setNamingStrategy(NamingStrategy namingStrategy) {
190-
191-
Assert.notNull(namingStrategy, "NamingStrategy must not be null");
192-
193-
this.namingStrategy = namingStrategy;
194-
}
195-
196-
NamingStrategy getNamingStrategy() {
197-
return namingStrategy;
184+
this.namingAccessor.setNamingStrategy(namingStrategy);
198185
}
199186

200187
@Override

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
/**
@@ -168,8 +165,6 @@ private CqlIdentifier determineColumnName() {
168165
return null;
169166
}
170167

171-
Supplier<String> defaultName = () -> getNamingStrategy().getColumnName(this);
172-
173168
String overriddenName = null;
174169

175170
boolean forceQuote = false;
@@ -200,7 +195,7 @@ private CqlIdentifier determineColumnName() {
200195
}
201196
}
202197

203-
return createColumnName(defaultName, overriddenName, forceQuote);
198+
return namingAccessor.generate(overriddenName, forceQuote, NamingStrategy::getColumnName, this, this.spelContext);
204199
}
205200

206201
@Override
@@ -229,21 +224,6 @@ public boolean hasExplicitColumnName() {
229224
}
230225
}
231226

232-
@Nullable
233-
private CqlIdentifier createColumnName(Supplier<String> defaultName, @Nullable String overriddenName,
234-
boolean forceQuote) {
235-
236-
String name;
237-
238-
if (StringUtils.hasText(overriddenName)) {
239-
name = this.spelContext != null ? SpelUtils.evaluate(overriddenName, this.spelContext) : overriddenName;
240-
} else {
241-
name = defaultName.get();
242-
}
243-
244-
return name != null ? IdentifierFactory.create(name, forceQuote) : null;
245-
}
246-
247227
@Override
248228
public void setColumnName(CqlIdentifier columnName) {
249229

@@ -259,14 +239,7 @@ public void setColumnName(CqlIdentifier columnName) {
259239
* @since 3.0
260240
*/
261241
public void setNamingStrategy(NamingStrategy namingStrategy) {
262-
263-
Assert.notNull(namingStrategy, "NamingStrategy must not be null");
264-
265-
this.namingStrategy = namingStrategy;
266-
}
267-
268-
NamingStrategy getNamingStrategy() {
269-
return this.namingStrategy;
242+
this.namingAccessor.setNamingStrategy(namingStrategy);
270243
}
271244

272245
@Override
@@ -277,7 +250,7 @@ public void setForceQuote(boolean forceQuote) {
277250
this.forceQuote = forceQuote;
278251

279252
if (changed) {
280-
setColumnName(IdentifierFactory.create(getRequiredColumnName().asInternal(), forceQuote));
253+
setColumnName(CqlIdentifierGenerator.createIdentifier(getRequiredColumnName().asInternal(), forceQuote));
281254
}
282255
}
283256

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

+17-15
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public class CassandraMappingContext
7373

7474
private Mapping mapping = new Mapping();
7575

76-
private NamingStrategy namingStrategy = NamingStrategy.INSTANCE;
76+
private @Nullable NamingStrategy namingStrategy;
7777

7878
private @Deprecated @Nullable UserTypeResolver userTypeResolver;
7979

@@ -128,7 +128,8 @@ private void processMappingOverrides() {
128128
String entityTableName = entityMapping.getTableName();
129129

130130
if (StringUtils.hasText(entityTableName)) {
131-
entity.setTableName(IdentifierFactory.create(entityTableName, Boolean.valueOf(entityMapping.getForceQuote())));
131+
entity.setTableName(
132+
CqlIdentifierGenerator.createIdentifier(entityTableName, Boolean.valueOf(entityMapping.getForceQuote())));
132133
}
133134

134135
processMappingOverrides(entity, entityMapping);
@@ -160,7 +161,7 @@ private static void processMappingOverride(CassandraPersistentEntity<?> entity,
160161
property.setForceQuote(forceQuote);
161162

162163
if (StringUtils.hasText(mapping.getColumnName())) {
163-
property.setColumnName(IdentifierFactory.create(mapping.getColumnName(), forceQuote));
164+
property.setColumnName(CqlIdentifierGenerator.createIdentifier(mapping.getColumnName(), forceQuote));
164165
}
165166
}
166167

@@ -191,7 +192,7 @@ public void setCustomConversions(CustomConversions customConversions) {
191192

192193
/**
193194
* @deprecated since 3.0. Use custom conversion through
194-
* {@link org.springframework.data.cassandra.core.convert.MappingCassandraConverter}.
195+
* {@link org.springframework.data.cassandra.core.convert.MappingCassandraConverter}.
195196
*/
196197
@Deprecated
197198
public CustomConversions getCustomConversions() {
@@ -246,7 +247,7 @@ public void setCodecRegistry(CodecRegistry codecRegistry) {
246247

247248
/**
248249
* @deprecated since 3.0. Retrieve {@link CodecRegistry} directly from
249-
* {@link org.springframework.data.cassandra.core.convert.CassandraConverter}.
250+
* {@link org.springframework.data.cassandra.core.convert.CassandraConverter}.
250251
*/
251252
@Deprecated
252253
public CodecRegistry getCodecRegistry() {
@@ -295,7 +296,7 @@ public void setUserTypeResolver(UserTypeResolver userTypeResolver) {
295296

296297
/**
297298
* @deprecated since 3.0. Retrieve {@link UserTypeResolver} directly from
298-
* {@link org.springframework.data.cassandra.core.convert.CassandraConverter}.
299+
* {@link org.springframework.data.cassandra.core.convert.CassandraConverter}.
299300
*/
300301
@Nullable
301302
@Deprecated
@@ -340,7 +341,6 @@ protected Optional<BasicCassandraPersistentEntity<?>> addPersistentEntity(TypeIn
340341
if (!entity.isUserDefinedType() && !entity.isTupleType() && entity.isAnnotationPresent(Table.class)) {
341342
this.tableEntities.add(entity);
342343
}
343-
344344
});
345345

346346
return optional;
@@ -357,11 +357,12 @@ protected <T> BasicCassandraPersistentEntity<T> createPersistentEntity(TypeInfor
357357

358358
BasicCassandraPersistentEntity<T> entity = isUserDefinedType(typeInformation)
359359
? new CassandraUserTypePersistentEntity<>(typeInformation, getVerifier())
360-
: isTuple(typeInformation)
361-
? new BasicCassandraPersistentTupleEntity<>(typeInformation)
362-
: new BasicCassandraPersistentEntity<>(typeInformation, getVerifier());
360+
: isTuple(typeInformation) ? new BasicCassandraPersistentTupleEntity<>(typeInformation)
361+
: new BasicCassandraPersistentEntity<>(typeInformation, getVerifier());
363362

364-
entity.setNamingStrategy(this.namingStrategy);
363+
if (this.namingStrategy != null) {
364+
entity.setNamingStrategy(this.namingStrategy);
365+
}
365366
Optional.ofNullable(this.applicationContext).ifPresent(entity::setApplicationContext);
366367

367368
return entity;
@@ -383,7 +384,10 @@ protected CassandraPersistentProperty createPersistentProperty(Property property
383384
? new BasicCassandraPersistentTupleProperty(property, owner, simpleTypeHolder)
384385
: new CachingCassandraPersistentProperty(property, owner, simpleTypeHolder);
385386

386-
persistentProperty.setNamingStrategy(this.namingStrategy);
387+
if (this.namingStrategy != null) {
388+
persistentProperty.setNamingStrategy(this.namingStrategy);
389+
}
390+
387391
Optional.ofNullable(this.applicationContext).ifPresent(persistentProperty::setApplicationContext);
388392

389393
return persistentProperty;
@@ -424,9 +428,7 @@ private boolean hasReferencedUserType(CqlIdentifier identifier) {
424428

425429
return getPersistentEntities().stream().flatMap(entity -> StreamSupport.stream(entity.spliterator(), false))
426430
.flatMap(it -> Optionals.toStream(Optional.ofNullable(it.findAnnotation(CassandraType.class))))
427-
.map(CassandraType::userTypeName)
428-
.filter(StringUtils::hasText)
429-
.map(CqlIdentifier::fromCql)
431+
.map(CassandraType::userTypeName).filter(StringUtils::hasText).map(CqlIdentifier::fromCql)
430432
.anyMatch(identifier::equals);
431433
}
432434
}

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

+1-8
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,7 @@ public CassandraUserTypePersistentEntity(TypeInformation<T> typeInformation,
4343

4444
@Override
4545
protected CqlIdentifier determineTableName() {
46-
47-
UserDefinedType annotation = findAnnotation(UserDefinedType.class);
48-
49-
if (annotation != null) {
50-
return determineName(annotation.value(), annotation.forceQuote());
51-
}
52-
53-
return IdentifierFactory.create(getNamingStrategy().getUserDefinedTypeName(this), false);
46+
return determineTableName(NamingStrategy::getUserDefinedTypeName, findAnnotation(UserDefinedType.class));
5447
}
5548

5649
@Override

0 commit comments

Comments
 (0)