diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractCassandraConfiguration.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractCassandraConfiguration.java index c26f3a039..c43802432 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractCassandraConfiguration.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractCassandraConfiguration.java @@ -37,7 +37,6 @@ import org.springframework.data.cassandra.core.mapping.SimpleUserTypeResolver; import org.springframework.data.cassandra.core.mapping.Table; import org.springframework.data.cassandra.core.mapping.UserTypeResolver; import org.springframework.data.convert.CustomConversions; -import org.springframework.data.domain.ManagedTypes; import org.springframework.data.mapping.context.MappingContext; import org.springframework.lang.Nullable; @@ -101,7 +100,7 @@ public abstract class AbstractCassandraConfiguration extends AbstractSessionConf * Return the {@link MappingContext} instance to map Entities to {@link Object Java Objects}. * * @see org.springframework.data.cassandra.core.mapping.CassandraMappingContext - * @deprecated since 4.0, use {@link #cassandraMappingContext(ManagedTypes)} instead. + * @deprecated since 4.0, use {@link #cassandraMappingContext(CassandraManagedTypes)} instead. */ @Deprecated(since = "4.0", forRemoval = true) public CassandraMappingContext cassandraMapping() throws ClassNotFoundException { diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentEntity.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentEntity.java index e8b91d0fd..688865243 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentEntity.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentEntity.java @@ -15,15 +15,17 @@ */ package org.springframework.data.cassandra.core.mapping; +import java.lang.annotation.Annotation; import java.util.Comparator; import java.util.Optional; +import java.util.function.BiFunction; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.expression.BeanFactoryAccessor; import org.springframework.context.expression.BeanFactoryResolver; -import org.springframework.data.cassandra.util.SpelUtils; +import org.springframework.core.annotation.AnnotationUtils; import org.springframework.data.mapping.Association; import org.springframework.data.mapping.AssociationHandler; import org.springframework.data.mapping.MappingException; @@ -32,7 +34,6 @@ import org.springframework.data.util.TypeInformation; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.lang.Nullable; import org.springframework.util.Assert; -import org.springframework.util.StringUtils; import com.datastax.oss.driver.api.core.CqlIdentifier; @@ -49,14 +50,14 @@ public class BasicCassandraPersistentEntity extends BasicPersistentEntity extends BasicPersistentEntity, String> defaultNameGenerator, + @Nullable Annotation annotation) { - if (!StringUtils.hasText(value)) { - return IdentifierFactory.create(getNamingStrategy().getTableName(this), forceQuote); + if (annotation != null) { + return this.namingAccessor.generate((String) AnnotationUtils.getValue(annotation), + (Boolean) AnnotationUtils.getValue(annotation, "forceQuote"), defaultNameGenerator, this, this.spelContext); } - String name = Optional.ofNullable(this.spelContext).map(it -> SpelUtils.evaluate(value, it)).orElse(value); - - Assert.state(name != null, () -> String.format("Cannot determine default name for %s", this)); - - return IdentifierFactory.create(name, forceQuote); + return this.namingAccessor.generate(null, forceQuote != null ? forceQuote : false, defaultNameGenerator, this, + this.spelContext); } @Override @@ -168,7 +162,7 @@ public class BasicCassandraPersistentEntity extends BasicPersistentEntity extends BasicPersistentEntity implements CassandraPersistentProperty, ApplicationContextAware { + private final CqlIdentifierGenerator namingAccessor = new CqlIdentifierGenerator(); + // Indicates whether this property has been explicitly instructed to force quoted column names. private Boolean forceQuote; private @Nullable CqlIdentifier columnName; - private NamingStrategy namingStrategy = NamingStrategy.INSTANCE; - private @Nullable StandardEvaluationContext spelContext; /** @@ -168,8 +165,6 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP return null; } - Supplier defaultName = () -> getNamingStrategy().getColumnName(this); - String overriddenName = null; boolean forceQuote = false; @@ -200,7 +195,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP } } - return createColumnName(defaultName, overriddenName, forceQuote); + return namingAccessor.generate(overriddenName, forceQuote, NamingStrategy::getColumnName, this, this.spelContext); } @Override @@ -229,21 +224,6 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP } } - @Nullable - private CqlIdentifier createColumnName(Supplier defaultName, @Nullable String overriddenName, - boolean forceQuote) { - - String name; - - if (StringUtils.hasText(overriddenName)) { - name = this.spelContext != null ? SpelUtils.evaluate(overriddenName, this.spelContext) : overriddenName; - } else { - name = defaultName.get(); - } - - return name != null ? IdentifierFactory.create(name, forceQuote) : null; - } - @Override public void setColumnName(CqlIdentifier columnName) { @@ -259,14 +239,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP * @since 3.0 */ public void setNamingStrategy(NamingStrategy namingStrategy) { - - Assert.notNull(namingStrategy, "NamingStrategy must not be null"); - - this.namingStrategy = namingStrategy; - } - - NamingStrategy getNamingStrategy() { - return this.namingStrategy; + this.namingAccessor.setNamingStrategy(namingStrategy); } @Override @@ -277,7 +250,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP this.forceQuote = forceQuote; if (changed) { - setColumnName(IdentifierFactory.create(getRequiredColumnName().asInternal(), forceQuote)); + setColumnName(CqlIdentifierGenerator.createIdentifier(getRequiredColumnName().asInternal(), forceQuote)); } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraMappingContext.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraMappingContext.java index 5dfa33583..bbdb629a6 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraMappingContext.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraMappingContext.java @@ -73,7 +73,7 @@ public class CassandraMappingContext private Mapping mapping = new Mapping(); - private NamingStrategy namingStrategy = NamingStrategy.INSTANCE; + private @Nullable NamingStrategy namingStrategy; private @Deprecated @Nullable UserTypeResolver userTypeResolver; @@ -128,7 +128,8 @@ public class CassandraMappingContext String entityTableName = entityMapping.getTableName(); if (StringUtils.hasText(entityTableName)) { - entity.setTableName(IdentifierFactory.create(entityTableName, Boolean.valueOf(entityMapping.getForceQuote()))); + entity.setTableName( + CqlIdentifierGenerator.createIdentifier(entityTableName, Boolean.valueOf(entityMapping.getForceQuote()))); } processMappingOverrides(entity, entityMapping); @@ -160,7 +161,7 @@ public class CassandraMappingContext property.setForceQuote(forceQuote); if (StringUtils.hasText(mapping.getColumnName())) { - property.setColumnName(IdentifierFactory.create(mapping.getColumnName(), forceQuote)); + property.setColumnName(CqlIdentifierGenerator.createIdentifier(mapping.getColumnName(), forceQuote)); } } @@ -191,7 +192,7 @@ public class CassandraMappingContext /** * @deprecated since 3.0. Use custom conversion through - * {@link org.springframework.data.cassandra.core.convert.MappingCassandraConverter}. + * {@link org.springframework.data.cassandra.core.convert.MappingCassandraConverter}. */ @Deprecated public CustomConversions getCustomConversions() { @@ -246,7 +247,7 @@ public class CassandraMappingContext /** * @deprecated since 3.0. Retrieve {@link CodecRegistry} directly from - * {@link org.springframework.data.cassandra.core.convert.CassandraConverter}. + * {@link org.springframework.data.cassandra.core.convert.CassandraConverter}. */ @Deprecated public CodecRegistry getCodecRegistry() { @@ -295,7 +296,7 @@ public class CassandraMappingContext /** * @deprecated since 3.0. Retrieve {@link UserTypeResolver} directly from - * {@link org.springframework.data.cassandra.core.convert.CassandraConverter}. + * {@link org.springframework.data.cassandra.core.convert.CassandraConverter}. */ @Nullable @Deprecated @@ -340,7 +341,6 @@ public class CassandraMappingContext if (!entity.isUserDefinedType() && !entity.isTupleType() && entity.isAnnotationPresent(Table.class)) { this.tableEntities.add(entity); } - }); return optional; @@ -357,11 +357,12 @@ public class CassandraMappingContext BasicCassandraPersistentEntity entity = isUserDefinedType(typeInformation) ? new CassandraUserTypePersistentEntity<>(typeInformation, getVerifier()) - : isTuple(typeInformation) - ? new BasicCassandraPersistentTupleEntity<>(typeInformation) - : new BasicCassandraPersistentEntity<>(typeInformation, getVerifier()); + : isTuple(typeInformation) ? new BasicCassandraPersistentTupleEntity<>(typeInformation) + : new BasicCassandraPersistentEntity<>(typeInformation, getVerifier()); - entity.setNamingStrategy(this.namingStrategy); + if (this.namingStrategy != null) { + entity.setNamingStrategy(this.namingStrategy); + } Optional.ofNullable(this.applicationContext).ifPresent(entity::setApplicationContext); return entity; @@ -383,7 +384,10 @@ public class CassandraMappingContext ? new BasicCassandraPersistentTupleProperty(property, owner, simpleTypeHolder) : new CachingCassandraPersistentProperty(property, owner, simpleTypeHolder); - persistentProperty.setNamingStrategy(this.namingStrategy); + if (this.namingStrategy != null) { + persistentProperty.setNamingStrategy(this.namingStrategy); + } + Optional.ofNullable(this.applicationContext).ifPresent(persistentProperty::setApplicationContext); return persistentProperty; @@ -424,9 +428,7 @@ public class CassandraMappingContext return getPersistentEntities().stream().flatMap(entity -> StreamSupport.stream(entity.spliterator(), false)) .flatMap(it -> Optionals.toStream(Optional.ofNullable(it.findAnnotation(CassandraType.class)))) - .map(CassandraType::userTypeName) - .filter(StringUtils::hasText) - .map(CqlIdentifier::fromCql) + .map(CassandraType::userTypeName).filter(StringUtils::hasText).map(CqlIdentifier::fromCql) .anyMatch(identifier::equals); } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraUserTypePersistentEntity.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraUserTypePersistentEntity.java index c2d98ebaa..6c3a661f1 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraUserTypePersistentEntity.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraUserTypePersistentEntity.java @@ -43,14 +43,7 @@ public class CassandraUserTypePersistentEntity extends BasicCassandraPersiste @Override protected CqlIdentifier determineTableName() { - - UserDefinedType annotation = findAnnotation(UserDefinedType.class); - - if (annotation != null) { - return determineName(annotation.value(), annotation.forceQuote()); - } - - return IdentifierFactory.create(getNamingStrategy().getUserDefinedTypeName(this), false); + return determineTableName(NamingStrategy::getUserDefinedTypeName, findAnnotation(UserDefinedType.class)); } @Override diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CqlIdentifierGenerator.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CqlIdentifierGenerator.java new file mode 100644 index 000000000..afd2e2897 --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CqlIdentifierGenerator.java @@ -0,0 +1,103 @@ +/* + * Copyright 2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.cassandra.core.mapping; + +import java.util.function.BiFunction; +import java.util.function.Function; + +import org.springframework.data.cassandra.util.SpelUtils; +import org.springframework.expression.EvaluationContext; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +import com.datastax.oss.driver.api.core.CqlIdentifier; +import com.datastax.oss.driver.internal.core.util.Strings; + +/** + * Strategy class to generate {@link CqlIdentifier identifier names} using {@link NamingStrategy} and contextual details + * from entities and properties. + * + * @author Mark Paluch + * @since 3.4.2 + */ +class CqlIdentifierGenerator { + + private @Nullable NamingStrategy namingStrategy; + + static CqlIdentifier createIdentifier(String simpleName, boolean forceQuote) { + + if (Strings.isDoubleQuoted(simpleName)) { + return CqlIdentifier.fromCql(simpleName); + } + + if (forceQuote || Strings.needsDoubleQuotes(simpleName)) { + return CqlIdentifier.fromInternal(simpleName); + } + + return CqlIdentifier.fromCql(simpleName); + } + + /** + * Generate a {@link CqlIdentifier name} using the provided name or fall back to the default {@link Function name + * generator} using a {@link NamingStrategy}. + * + * @param providedName the name to use if provided. + * @param forceQuote whether to enforce quoting. + * @param defaultNameGenerator the default name generator. + * @param source source to be used for name generation. + * @param spelContext the SpEL evaluation context for evaluating SpEL expressions provided through + * {@code providedName}. + * @return the generated name. + */ + public CqlIdentifier generate(@Nullable String providedName, boolean forceQuote, + BiFunction defaultNameGenerator, T source, @Nullable EvaluationContext spelContext) { + + String name; + boolean useForceQuote = forceQuote; + + if (StringUtils.hasText(providedName)) { + name = spelContext != null ? SpelUtils.evaluate(providedName, spelContext) : providedName; + useForceQuote = true; + } else { + name = defaultNameGenerator.apply(getNamingStrategy(forceQuote), source); + } + + Assert.state(name != null, () -> String.format("Cannot determine default name for %s", source)); + + return createIdentifier(name, useForceQuote); + } + + public void setNamingStrategy(@Nullable NamingStrategy namingStrategy) { + + Assert.notNull(namingStrategy, "NamingStrategy must not be null"); + + this.namingStrategy = namingStrategy; + } + + private NamingStrategy getNamingStrategy(boolean forceQuote) { + + if (namingStrategy == null) { + if (forceQuote) { + return new NamingStrategy() {}; + } else { + return NamingStrategy.INSTANCE; + } + } + + return namingStrategy; + } +} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/IdentifierFactory.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/IdentifierFactory.java deleted file mode 100644 index 6ae734237..000000000 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/IdentifierFactory.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2019-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.cassandra.core.mapping; - -import com.datastax.oss.driver.api.core.CqlIdentifier; -import com.datastax.oss.driver.internal.core.util.Strings; - -/** - * Factory for {@link CqlIdentifier}. - * - * @author Mark Paluch - */ -class IdentifierFactory { - - static CqlIdentifier create(String simpleName, boolean forceQuote) { - - if (forceQuote) { - return CqlIdentifier.fromCql("\"" + simpleName + "\""); - } - - if (Strings.needsDoubleQuotes(simpleName.toLowerCase())) { - return CqlIdentifier.fromCql("\"" + simpleName.toLowerCase() + "\""); - } - - return CqlIdentifier.fromInternal(simpleName.toLowerCase()); - } -} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/NamingStrategy.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/NamingStrategy.java index d5e79aa09..c51ef8ebb 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/NamingStrategy.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/NamingStrategy.java @@ -15,13 +15,15 @@ */ package org.springframework.data.cassandra.core.mapping; +import java.util.Locale; import java.util.function.UnaryOperator; import org.springframework.util.Assert; /** * Interface and default implementation of a naming strategy. Defaults to table name based on {@link Class} and column - * name based on property names. + * name based on property names. Names are used as-is without quoting. Lower-case, non-keyword names are used without + * quoting. Upper-case, keyword or other names requiring quoting are used with quotes. *

* NOTE: Can also be used as an adapter. Create a lambda or an anonymous subclass and override any settings to implement * a different strategy on the fly. @@ -35,8 +37,15 @@ public interface NamingStrategy { * Empty implementation of the interface utilizing only the default implementation. *

* Using this avoids creating essentially the same class over and over again. + * + * @since 3.3.6 */ - NamingStrategy INSTANCE = new NamingStrategy() {}; + NamingStrategy CASE_SENSITIVE = new NamingStrategy() {}; + + /** + * Default implementation converting all names to {@link String#toLowerCase()}. + */ + NamingStrategy INSTANCE = CASE_SENSITIVE.transform(s -> s.toLowerCase(Locale.ROOT)); /** * Naming strategy that renders CamelCase name parts to {@code snake_case}. @@ -74,10 +83,8 @@ public interface NamingStrategy { } /** - * Apply a {@link UnaryOperator transformation function} to create a new {@link NamingStrategy} - * that applies the given transformation to each name component. - * - * Example: + * Apply a {@link UnaryOperator transformation function} to create a new {@link NamingStrategy} that applies the given + * transformation to each name component. Example: *

* NamingStrategy lower = NamingStrategy.INSTANCE.transform(String::toLowerCase); *

diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentEntityUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentEntityUnitTests.java index ae524a1f3..034f86713 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentEntityUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentEntityUnitTests.java @@ -52,12 +52,12 @@ class BasicCassandraPersistentEntityUnitTests { @Mock ApplicationContext context; @Test - void subclassInheritsAtDocumentAnnotation() { + void subclassInheritsAtTableAnnotation() { BasicCassandraPersistentEntity entity = new BasicCassandraPersistentEntity<>( ClassTypeInformation.from(Notification.class)); - assertThat(entity.getTableName()).hasToString("messages"); + assertThat(entity.getTableName().asCql(true)).isEqualTo("messages"); } @Test diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/NamingStrategyUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/NamingStrategyUnitTests.java index a74fe62be..b47932ed5 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/NamingStrategyUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/NamingStrategyUnitTests.java @@ -21,6 +21,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.data.annotation.Id; +import org.springframework.data.util.ClassTypeInformation; +import org.springframework.util.StringUtils; import com.datastax.oss.driver.api.core.CqlIdentifier; @@ -38,7 +40,48 @@ class NamingStrategyUnitTests { context.setUserTypeResolver(typeName -> { throw new IllegalStateException(""); }); - context.setNamingStrategy(NamingStrategy.INSTANCE); + } + + @Test + void getTableNameGeneratesTableName() { + + BasicCassandraPersistentEntity entity = new BasicCassandraPersistentEntity<>( + ClassTypeInformation.from(TableNameHolderThingy.class)); + + assertThat(entity.getTableName().asCql(true)).isEqualTo("tablenameholderthingy"); + } + + @Test + void getTableNameGeneratesQuotedTableName() { + + BasicCassandraPersistentEntity entity = new BasicCassandraPersistentEntity<>( + ClassTypeInformation.from(TableNameHolderThingy.class)); + entity.setNamingStrategy(NamingStrategy.SNAKE_CASE.transform(it -> "\"" + StringUtils.capitalize(it) + "\"")); + + assertThat(entity.getTableName().asCql(true)).isEqualTo("\"Table_name_holder_thingy\""); + + entity = new BasicCassandraPersistentEntity<>(ClassTypeInformation.from(TableNameHolderThingy.class)); + entity.setNamingStrategy(NamingStrategy.SNAKE_CASE.transform(String::toUpperCase)); + + assertThat(entity.getTableName().asCql(true)).isEqualTo("\"TABLE_NAME_HOLDER_THINGY\""); + } + + @Test + void atTableIsCaseSensitive() { + + BasicCassandraPersistentEntity entity = new BasicCassandraPersistentEntity<>( + ClassTypeInformation.from(ProvidedTableName.class)); + + assertThat(entity.getTableName().asCql(true)).isEqualTo("\"iAmProvided\""); + } + + @Test + void atTableWithQuotedNameShouldRetainQuotes() { + + BasicCassandraPersistentEntity entity = new BasicCassandraPersistentEntity<>( + ClassTypeInformation.from(QuotedTableName.class)); + + assertThat(entity.getTableName().asCql(true)).isEqualTo("\"IAmQuoted\""); } @Test // DATACASS-84 @@ -105,6 +148,17 @@ class NamingStrategyUnitTests { @Id String firstName; } + @Table("messages") + static class Message {} + + static class TableNameHolderThingy {} + + @Table("iAmProvided") + private static class ProvidedTableName {} + + @Table("\"IAmQuoted\"") + private static class QuotedTableName {} + @UserDefinedType private static class MyUserType { @@ -122,4 +176,5 @@ class NamingStrategyUnitTests { String firstName; } + } diff --git a/src/main/asciidoc/reference/mapping.adoc b/src/main/asciidoc/reference/mapping.adoc index 2f41f3dd7..7394ecae8 100644 --- a/src/main/asciidoc/reference/mapping.adoc +++ b/src/main/asciidoc/reference/mapping.adoc @@ -138,8 +138,8 @@ The conventions are: * The simple (short) Java class name is mapped to the table name by being changed to lower case. For example, `com.bigbank.SavingsAccount` maps to a table named `savingsaccount`. -* The converter uses any registered Spring `Converter` instances to override the default mapping of object properties to tables fields. -* The properties of an object are used to convert to and from properties in the table. +* The converter uses any registered Spring `Converter` instances to override the default mapping of object properties to tables columns. +* The properties of an object are used to convert to and from columns in the table. You can adjust conventions by configuring a `NamingStrategy` on `CassandraMappingContext`. Naming strategy objects implement the convention by which a table, column or user-defined type is derived from an entity class and from an actual property.