diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraPersistentEntitySchemaDropper.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraPersistentEntitySchemaDropper.java index fa0f69b2c..14cfb86f3 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraPersistentEntitySchemaDropper.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraPersistentEntitySchemaDropper.java @@ -23,6 +23,8 @@ import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity import org.springframework.data.cql.core.CqlIdentifier; import org.springframework.util.Assert; +import com.datastax.driver.core.AbstractTableMetadata; + /** * Schema drop support for Cassandra based on {@link CassandraMappingContext} and {@link CassandraPersistentEntity}. * This class generates CQL to drop user types (UDT) and tables. @@ -63,9 +65,11 @@ public class CassandraPersistentEntitySchemaDropper { */ public void dropTables(boolean dropUnused) { - cassandraAdminOperations.getKeyspaceMetadata().getTables().stream() - .filter(table -> dropUnused || mappingContext.usesTable(table)) - .forEach(table -> cassandraAdminOperations.dropTable(CqlIdentifier.cqlId(table.getName()))); + cassandraAdminOperations.getKeyspaceMetadata().getTables() // + .stream() // + .map(AbstractTableMetadata::getName) // + .map(CqlIdentifier::cqlId) // + .filter(table -> dropUnused || mappingContext.usesTable(table)).forEach(cassandraAdminOperations::dropTable); } /** @@ -81,12 +85,13 @@ public class CassandraPersistentEntitySchemaDropper { .map(CassandraPersistentEntity::getTableName).collect(Collectors.toSet()); cassandraAdminOperations.getKeyspaceMetadata().getUserTypes().forEach(userType -> { - CqlIdentifier identifier = CqlIdentifier.cqlId(userType.getTypeName()); - if (canRecreate.contains(identifier)) { - cassandraAdminOperations.dropUserType(identifier); - } else if (dropUnused && !mappingContext.usesUserType(userType)) { - cassandraAdminOperations.dropUserType(identifier); + CqlIdentifier typeName = CqlIdentifier.cqlId(userType.getTypeName()); + + if (canRecreate.contains(typeName)) { + cassandraAdminOperations.dropUserType(typeName); + } else if (dropUnused && !mappingContext.usesUserType(typeName)) { + cassandraAdminOperations.dropUserType(typeName); } }); } 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 9dd599e56..4f4ab75d5 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 @@ -29,6 +29,7 @@ import java.util.Optional; import java.util.Set; import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.core.annotation.AnnotatedElementUtils; @@ -52,8 +53,6 @@ import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import com.datastax.driver.core.DataType; -import com.datastax.driver.core.TableMetadata; -import com.datastax.driver.core.UserType; /** * Default implementation of a {@link MappingContext} for Cassandra using {@link CassandraPersistentEntity} and @@ -67,7 +66,7 @@ import com.datastax.driver.core.UserType; */ public class CassandraMappingContext extends AbstractMappingContext, CassandraPersistentProperty> - implements ApplicationContextAware { + implements ApplicationContextAware, BeanClassLoaderAware { private CassandraPersistentEntityMetadataVerifier verifier = new CompositeCassandraPersistentEntityMetadataVerifier(); @@ -82,10 +81,7 @@ public class CassandraMappingContext private ClassLoader beanClassLoader; // useful caches - private final Map, CassandraPersistentEntity> entitiesByType = new HashMap<>(); private final Map>> entitySetsByTableName = new HashMap<>(); - - private final Set> primaryKeyEntities = new HashSet<>(); private final Set> userDefinedTypes = new HashSet<>(); private final Set> tableEntities = new HashSet<>(); @@ -110,29 +106,32 @@ public class CassandraMappingContext @SuppressWarnings("all") protected void processMappingOverrides() { - mapping.getEntityMappings().stream()// - .filter(entityMapping -> entityMapping != null).forEach(entityMapping -> { - String entityClassName = entityMapping.getEntityClassName(); + mapping.getEntityMappings().stream() // + .filter(entityMapping -> entityMapping != null) // + .forEach(entityMapping -> { - try { - Class entityClass = ClassUtils.forName(entityClassName, beanClassLoader); + Class entityClass = getEntityClass(entityMapping.getEntityClassName()); + CassandraPersistentEntity entity = getRequiredPersistentEntity(entityClass); - CassandraPersistentEntity entity = getRequiredPersistentEntity(entityClass); + String entityTableName = entityMapping.getTableName(); - String entityTableName = entityMapping.getTableName(); - - if (StringUtils.hasText(entityTableName)) { - entity.setTableName(cqlId(entityTableName, Boolean.valueOf(entityMapping.getForceQuote()))); - } - - processMappingOverrides(entity, entityMapping); - - } catch (ClassNotFoundException e) { - throw new IllegalStateException(String.format("Unknown persistent entity name [%s]", entityClassName), e); + if (StringUtils.hasText(entityTableName)) { + entity.setTableName(cqlId(entityTableName, Boolean.valueOf(entityMapping.getForceQuote()))); } + + processMappingOverrides(entity, entityMapping); }); } + private Class getEntityClass(String entityClassName) { + + try { + return ClassUtils.forName(entityClassName, beanClassLoader); + } catch (ClassNotFoundException e) { + throw new IllegalStateException(String.format("Unknown persistent entity name [%s]", entityClassName), e); + } + } + protected void processMappingOverrides(CassandraPersistentEntity entity, EntityMapping entityMapping) { entityMapping.getPropertyMappings() .forEach((key, propertyMapping) -> processMappingOverride(entity, propertyMapping)); @@ -159,6 +158,9 @@ public class CassandraMappingContext this.context = applicationContext; } + /* (non-Javadoc) + * @see org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader(java.lang.ClassLoader) + */ public void setBeanClassLoader(ClassLoader beanClassLoader) { this.beanClassLoader = beanClassLoader; } @@ -223,29 +225,12 @@ public class CassandraMappingContext /** * Returns only those entities representing a user defined type. * - * @see #getPersistentEntities(boolean) * @since 1.5 */ public Collection> getUserDefinedTypeEntities() { return Collections.unmodifiableSet(userDefinedTypes); } - /** - * Returns all persistent entities or only non-primary-key entities. - * - * @param includePrimaryKeyTypesAndUdts If {@literal true}, returns all entities, including entities that represent - * primary key types and user-defined types. If {@literal false}, returns only entities that don't represent - * primary key types and no user-defined types. - */ - public Collection> getPersistentEntities(boolean includePrimaryKeyTypesAndUdts) { - - if (includePrimaryKeyTypesAndUdts) { - return super.getPersistentEntities(); - } - - return getTableEntities(); - } - /* (non-Javadoc) * @see org.springframework.data.mapping.context.AbstractMappingContext#addPersistentEntity(org.springframework.data.util.TypeInformation) */ @@ -275,8 +260,6 @@ public class CassandraMappingContext entity.findAnnotation(Table.class).ifPresent(table -> tableEntities.add(entity)); } - - entitiesByType.put(entity.getType(), entity); }); return optional; @@ -328,25 +311,28 @@ public class CassandraMappingContext /** * Returns whether this mapping context has any entities mapped to the given table. * - * @param table must not be {@literal null}. + * @param name must not be {@literal null}. * @return @return {@literal true} is this {@literal TableMetadata} is used by a mapping. */ - public boolean usesTable(TableMetadata table) { - return entitySetsByTableName.containsKey(cqlId(table.getName())); + public boolean usesTable(CqlIdentifier name) { + + Assert.notNull(name, "Table name must not be null!"); + + return entitySetsByTableName.containsKey(name); } /** * Returns whether this mapping context has any entities using the given user type. * - * @param userType must not be {@literal null}. + * @param name must not be {@literal null}. * @return {@literal true} is this {@literal UserType} is used. * @since 1.5 */ - public boolean usesUserType(final UserType userType) { + public boolean usesUserType(CqlIdentifier name) { - CqlIdentifier identifier = CqlIdentifier.cqlId(userType.getTypeName()); + Assert.notNull(name, "User type name must not be null!"); - return (hasMappedUserType(identifier) || hasReferencedUserType(identifier)); + return hasMappedUserType(name) || hasReferencedUserType(name); } private boolean hasReferencedUserType(final CqlIdentifier identifier) { @@ -356,10 +342,10 @@ public class CassandraMappingContext .map(it -> it.findAnnotation(CassandraType.class)) // .filter(Optional::isPresent) // .flatMap(Optionals::toStream) // - .anyMatch(it -> { - return StringUtils.hasText(it.userTypeName()) // - && CqlIdentifier.cqlId(it.userTypeName()).equals(identifier); - }); // + .map(CassandraType::userTypeName) // + .filter(StringUtils::hasText) // + .map(CqlIdentifier::cqlId) // + .anyMatch(identifier::equals); // } private boolean hasMappedUserType(CqlIdentifier identifier) { @@ -537,14 +523,6 @@ public class CassandraMappingContext .orElseGet(() -> getDataTypeFor(type)); } - /** - * Returns whether this {@link CassandraMappingContext} already contains a {@link CassandraPersistentEntity} for the - * given type. - */ - public boolean contains(Class type) { - return entitiesByType.containsKey(type); - } - /** * @author Jens Schauder * @since 1.5.1 diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/CassandraMappingContextUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/CassandraMappingContextUnitTests.java index badcd5452..21340a17a 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/CassandraMappingContextUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/CassandraMappingContextUnitTests.java @@ -68,7 +68,7 @@ public class CassandraMappingContextUnitTests { private static class Transient {} - @Test // DATACASS-282 + @Test // DATACASS-282, DATACASS-455 public void testGetExistingPersistentEntityHappyPath() { TableMetadata tableMetadata = mock(TableMetadata.class); @@ -76,11 +76,10 @@ public class CassandraMappingContextUnitTests { mappingContext.getRequiredPersistentEntity(X.class); - assertThat(mappingContext.contains(Y.class)).isFalse(); assertThat(mappingContext.getUserDefinedTypeEntities()).isEmpty(); assertThat(mappingContext.getTableEntities()).hasSize(1); - assertThat(mappingContext.contains(X.class)).isTrue(); - assertThat(mappingContext.usesTable(tableMetadata)).isTrue(); + assertThat(mappingContext.getPersistentEntities()).hasSize(1); + assertThat(mappingContext.usesTable(CqlIdentifier.cqlId(tableMetadata.getName()))).isTrue(); } @Test // DATACASS-248 @@ -353,7 +352,7 @@ public class CassandraMappingContextUnitTests { .isEqualTo(DataType.list(DataType.varchar())); } - @Test // DATACASS-172 + @Test // DATACASS-172, DATACASS-455 public void shouldRegisterUdtTypes() { CassandraPersistentEntity persistentEntity = mappingContext.getRequiredPersistentEntity(MappedUdt.class); @@ -361,8 +360,8 @@ public class CassandraMappingContextUnitTests { assertThat(persistentEntity.isUserDefinedType()).isTrue(); assertThat(mappingContext.getUserDefinedTypeEntities()).hasSize(1); + assertThat(mappingContext.getPersistentEntities()).hasSize(1); assertThat(mappingContext.getTableEntities()).hasSize(0); - assertThat(mappingContext.contains(MappedUdt.class)).isTrue(); } @Test // DATACASS-172 @@ -380,45 +379,38 @@ public class CassandraMappingContextUnitTests { BasicCassandraPersistentEntity existingPersistentEntity = mappingContext .getRequiredPersistentEntity(MappedUdt.class); - assertThat(mappingContext.getPersistentEntities(true)).contains(existingPersistentEntity); + assertThat(mappingContext.getPersistentEntities()).contains(existingPersistentEntity); assertThat(mappingContext.getUserDefinedTypeEntities()).contains(existingPersistentEntity); - assertThat(mappingContext.getPersistentEntities(false)).doesNotContain(existingPersistentEntity); assertThat(mappingContext.getTableEntities()).doesNotContain(existingPersistentEntity); } - @Test // DATACASS-172 + @Test // DATACASS-172, DATACASS-455 public void usesTypeShouldNotReportTypeUsage() { - - UserType myTypeMock = mock(UserType.class, "mappedudt"); - when(myTypeMock.getTypeName()).thenReturn("mappedudt"); - - assertThat(mappingContext.usesUserType(myTypeMock)).isFalse(); + assertThat(mappingContext.usesUserType(CqlIdentifier.cqlId("mappedudt"))).isFalse(); } - @Test // DATACASS-172 + @Test // DATACASS-172, DATACASS-455 public void usesTypeShouldReportTypeUsageInMappedUdt() { UserType myTypeMock = mock(UserType.class, "mappedudt"); - when(myTypeMock.getTypeName()).thenReturn("mappedudt"); mappingContext.setUserTypeResolver(typeName -> myTypeMock); mappingContext.getRequiredPersistentEntity(WithUdt.class); - assertThat(mappingContext.usesUserType(myTypeMock)).isTrue(); + assertThat(mappingContext.usesUserType(CqlIdentifier.cqlId("mappedudt"))).isTrue(); } - @Test // DATACASS-172 + @Test // DATACASS-172, DATACASS-455 public void usesTypeShouldReportTypeUsageInColumn() { UserType myTypeMock = mock(UserType.class, "mappedudt"); - when(myTypeMock.getTypeName()).thenReturn("mappedudt"); mappingContext.setUserTypeResolver(typeName -> myTypeMock); mappingContext.getRequiredPersistentEntity(MappedUdt.class); - assertThat(mappingContext.usesUserType(myTypeMock)).isTrue(); + assertThat(mappingContext.usesUserType(CqlIdentifier.cqlId("mappedudt"))).isTrue(); } @Test // DATACASS-172 @@ -449,7 +441,7 @@ public class CassandraMappingContextUnitTests { } } - @Test // DATACASS-282 + @Test // DATACASS-282, DATACASS-455 public void shouldNotRetainInvalidEntitiesInCache() { TableMetadata tableMetadata = mock(TableMetadata.class); @@ -465,8 +457,8 @@ public class CassandraMappingContextUnitTests { assertThat(mappingContext.getUserDefinedTypeEntities()).isEmpty(); assertThat(mappingContext.getTableEntities()).isEmpty(); - assertThat(mappingContext.contains(InvalidEntityWithIdAndPrimaryKeyColumn.class)).isFalse(); - assertThat(mappingContext.usesTable(tableMetadata)).isFalse(); + assertThat(mappingContext.getPersistentEntities()).isEmpty(); + assertThat(mappingContext.usesTable(CqlIdentifier.cqlId(tableMetadata.getName()))).isFalse(); } @Table