From 94d6a3ddc791b30242d25e7d214905a4aa1b19ab Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 28 Jul 2017 15:45:30 +0200 Subject: [PATCH] DATACASS-482 - Introduce usage of nullable annotations for API validation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mark all packages with Spring Frameworks @NonNullApi. Add Spring's @Nullable to methods, parameters and fields that take or produce null values. Adapted using code to make sure the IDE can evaluate the null flow properly. Fix Javadoc in places where an invalid null handling policy was advertised. Strengthened null requirements for types that expose null-instances. Encapsulate KeyspaceIdentifier and CqlIdentifier with static factory methods to avoid temporary null state of fields. Require non-null QueryOptions and provide empty option instances. Introduce methods returning non-null values (getRequired…()) for code paths known to operate on values that are available. --- .../CassandraWriteTimeoutException.java | 7 +- .../AbstractCassandraConfiguration.java | 56 ++++-- .../config/AbstractClusterConfiguration.java | 39 +++- ...bstractReactiveCassandraConfiguration.java | 10 +- .../config/AbstractSessionConfiguration.java | 21 +- .../config/CassandraClusterFactoryBean.java | 102 +++++----- .../config/CassandraCqlClusterParser.java | 3 +- .../CassandraCqlSessionFactoryBean.java | 28 +-- .../CassandraCqlTemplateFactoryBean.java | 6 +- .../config/CassandraEntityClassScanner.java | 127 ++++++++++-- .../config/CassandraMappingContextParser.java | 5 +- ...gXmlBeanFactoryPostProcessorRegistrar.java | 4 +- .../config/CassandraSessionFactoryBean.java | 7 +- .../config/CassandraTemplateFactoryBean.java | 7 +- ...eyspaceActionSpecificationFactoryBean.java | 30 +-- .../data/cassandra/config/ParsingUtils.java | 10 +- .../config/PoolingOptionsFactoryBean.java | 126 +++++------- .../data/cassandra/config/SchemaAction.java | 17 -- .../config/SocketOptionsFactoryBean.java | 44 +++-- .../data/cassandra/config/package-info.java | 3 + .../core/AsyncCassandraOperations.java | 10 +- .../core/AsyncCassandraTemplate.java | 12 +- .../core/CassandraAdminOperations.java | 1 - .../core/CassandraAdminTemplate.java | 1 + .../core/CassandraBatchOperations.java | 1 - .../core/CassandraBatchTemplate.java | 16 +- .../cassandra/core/CassandraOperations.java | 15 +- .../cassandra/core/CassandraTemplate.java | 61 +++--- .../data/cassandra/core/InsertOptions.java | 73 ++++--- .../data/cassandra/core/QueryUtils.java | 10 +- .../core/ReactiveCassandraOperations.java | 10 +- .../core/ReactiveCassandraTemplate.java | 13 +- .../data/cassandra/core/StatementFactory.java | 12 +- .../data/cassandra/core/UpdateOptions.java | 73 ++++--- .../data/cassandra/core/WriteResult.java | 1 - .../convert/AbstractCassandraConverter.java | 24 ++- .../BasicCassandraRowValueProvider.java | 2 + .../core/convert/CassandraConverter.java | 7 +- .../core/convert/CassandraConverters.java | 2 +- .../convert/CassandraCustomConversions.java | 1 + .../convert/CassandraUDTValueProvider.java | 2 + .../cassandra/core/convert/ColumnReader.java | 9 + .../convert/MappingCassandraConverter.java | 59 ++++-- .../cassandra/core/convert/QueryMapper.java | 37 ++-- .../convert/RowReaderPropertyAccessor.java | 15 +- .../cassandra/core/convert/UpdateMapper.java | 12 +- .../cassandra/core/convert/package-info.java | 3 + .../cql/ArgumentPreparedStatementBinder.java | 6 +- .../core/cql/AsyncCqlOperations.java | 117 ++++++----- .../cassandra/core/cql/AsyncCqlTemplate.java | 87 +++++---- .../cql/AsyncPreparedStatementCreator.java | 1 + .../core/cql/AsyncSessionCallback.java | 2 +- .../cassandra/core/cql/CassandraAccessor.java | 35 ++-- .../cql/CassandraExceptionTranslator.java | 8 +- .../core/cql/ColumnMapRowMapper.java | 2 + .../core/cql/CqlExceptionTranslator.java | 11 +- .../cassandra/core/cql/CqlIdentifier.java | 62 +++--- .../cassandra/core/cql/CqlOperations.java | 71 ++++--- .../data/cassandra/core/cql/CqlProvider.java | 3 + .../cassandra/core/cql/CqlStringUtils.java | 56 +++--- .../data/cassandra/core/cql/CqlTemplate.java | 69 ++++--- ...ionTranslatingListenableFutureAdapter.java | 6 +- .../cql/GuavaListenableFutureAdapter.java | 4 +- .../core/cql/KeyspaceIdentifier.java | 51 ++--- .../core/cql/PreparedStatementCallback.java | 6 +- .../data/cassandra/core/cql/QueryOptions.java | 181 +++++++----------- .../cassandra/core/cql/QueryOptionsUtil.java | 64 +++---- .../core/cql/ReactiveCassandraAccessor.java | 13 +- .../core/cql/ReactiveCqlOperations.java | 32 ++-- .../core/cql/ReactiveCqlTemplate.java | 50 +++-- .../core/cql/ResultSetExtractor.java | 2 + .../core/cql/RingMemberHostMapper.java | 1 - .../core/cql/RowCallbackHandler.java | 6 +- .../data/cassandra/core/cql/RowMapper.java | 3 + .../data/cassandra/core/cql/RowUtils.java | 7 +- .../cassandra/core/cql/SessionCallback.java | 2 +- .../cql/SimplePreparedStatementCreator.java | 1 + .../core/cql/SingleColumnRowMapper.java | 13 +- .../data/cassandra/core/cql/WriteOptions.java | 95 ++++++--- .../converter/AbstractResultSetConverter.java | 22 +-- .../converter/ResultSetToArrayConverter.java | 4 - .../ResultSetToByteBufferConverter.java | 3 +- .../converter/ResultSetToListConverter.java | 4 - .../ResultSetToListOfStringConverter.java | 8 +- .../converter/ResultSetToStringConverter.java | 2 +- .../cql/converter/RowToListConverter.java | 4 - .../core/cql/converter/RowToMapConverter.java | 4 - .../core/cql/converter/package-info.java | 3 + .../cql/generator/AddColumnCqlGenerator.java | 4 +- .../generator/AlterColumnCqlGenerator.java | 4 +- .../generator/AlterKeyspaceCqlGenerator.java | 20 +- .../cql/generator/AlterTableCqlGenerator.java | 39 ++-- .../generator/AlterUserTypeCqlGenerator.java | 13 +- .../generator/ColumnChangeCqlGenerator.java | 4 +- .../generator/CreateIndexCqlGenerator.java | 12 +- .../generator/CreateKeyspaceCqlGenerator.java | 23 +-- .../generator/CreateTableCqlGenerator.java | 47 ++--- .../generator/CreateUserTypeCqlGenerator.java | 14 +- .../cql/generator/DropColumnCqlGenerator.java | 4 +- .../cql/generator/DropIndexCqlGenerator.java | 4 +- .../generator/DropKeyspaceCqlGenerator.java | 4 +- .../cql/generator/DropTableCqlGenerator.java | 4 +- .../generator/DropUserTypeCqlGenerator.java | 12 +- .../cql/generator/IndexNameCqlGenerator.java | 8 +- .../cql/generator/KeyspaceCqlGenerator.java | 37 ---- .../generator/KeyspaceNameCqlGenerator.java | 8 +- .../KeyspaceOptionsCqlGenerator.java | 9 +- .../generator/RenameColumnCqlGenerator.java | 4 +- .../core/cql/generator/TableCqlGenerator.java | 37 ---- .../cql/generator/TableNameCqlGenerator.java | 16 +- .../generator/TableOptionsCqlGenerator.java | 13 +- .../generator/UserTypeNameCqlGenerator.java | 17 +- .../core/cql/generator/package-info.java | 3 + .../cql/keyspace/AddColumnSpecification.java | 16 +- .../keyspace/AlterColumnSpecification.java | 28 ++- .../keyspace/AlterKeyspaceSpecification.java | 26 ++- .../cql/keyspace/AlterTableSpecification.java | 24 +-- .../keyspace/AlterUserTypeSpecification.java | 20 +- .../keyspace/ColumnChangeSpecification.java | 22 +-- .../cql/keyspace/ColumnSpecification.java | 40 ++-- .../ColumnTypeChangeSpecification.java | 16 +- .../keyspace/CreateIndexSpecification.java | 9 +- .../keyspace/CreateKeyspaceSpecification.java | 46 ++--- .../keyspace/CreateTableSpecification.java | 22 +-- .../keyspace/CreateUserTypeSpecification.java | 12 +- .../core/cql/keyspace/DefaultOption.java | 59 +++--- .../cql/keyspace/DefaultTableDescriptor.java | 32 ---- .../cql/keyspace/DropColumnSpecification.java | 6 +- .../cql/keyspace/DropIndexSpecification.java | 32 ++-- .../keyspace/DropKeyspaceSpecification.java | 27 +-- .../cql/keyspace/DropTableSpecification.java | 31 +-- .../keyspace/DropUserTypeSpecification.java | 12 +- .../core/cql/keyspace/FieldSpecification.java | 59 +++--- .../cql/keyspace/IndexNameSpecification.java | 14 +- .../keyspace/KeyspaceActionSpecification.java | 54 +----- .../core/cql/keyspace/KeyspaceOption.java | 1 + .../KeyspaceOptionsSpecification.java | 20 +- .../cql/keyspace/KeyspaceSpecification.java | 26 --- .../cassandra/core/cql/keyspace/Option.java | 6 +- .../keyspace/RenameColumnSpecification.java | 1 + .../cql/keyspace/TableNameSpecification.java | 21 +- .../core/cql/keyspace/TableOption.java | 4 +- .../keyspace/TableOptionsSpecification.java | 27 +-- .../core/cql/keyspace/TableSpecification.java | 6 +- .../keyspace/UserTypeNameSpecification.java | 23 +-- .../cql/keyspace/UserTypeSpecification.java | 6 +- .../core/cql/keyspace/package-info.java | 3 + .../data/cassandra/core/cql/package-info.java | 3 + .../lookup/AbstractRoutingSessionFactory.java | 28 ++- .../BeanFactorySessionFactoryLookup.java | 3 +- .../lookup/MapSessionFactoryLookup.java | 5 +- .../session/lookup/SessionFactoryLookup.java | 2 +- .../core/cql/session/lookup/package-info.java | 5 +- .../core/cql/session/package-info.java | 5 +- .../CachedPreparedStatementCreator.java | 2 +- .../core/cql/support/package-info.java | 7 + .../BasicCassandraPersistentEntity.java | 21 +- .../BasicCassandraPersistentProperty.java | 70 +++---- .../cassandra/core/mapping/BasicMapId.java | 3 +- .../core/mapping/CassandraMappingContext.java | 52 +++-- .../mapping/CassandraPersistentEntity.java | 6 +- .../mapping/CassandraPersistentProperty.java | 3 + .../mapping/CassandraSimpleTypeHolder.java | 8 +- .../CassandraUserTypePersistentEntity.java | 3 +- .../cassandra/core/mapping/EntityMapping.java | 6 +- .../core/mapping/IdInterfaceException.java | 9 +- .../data/cassandra/core/mapping/MapId.java | 4 +- .../cassandra/core/mapping/MapIdFactory.java | 1 + .../core/mapping/MapIdProxyDelegate.java | 120 ++++++------ .../data/cassandra/core/mapping/Mapping.java | 4 +- .../core/mapping/PropertyMapping.java | 23 ++- .../core/mapping/SimpleUserTypeResolver.java | 2 + .../core/mapping/UserTypeResolver.java | 2 + .../cassandra/core/mapping/package-info.java | 3 + .../data/cassandra/core/package-info.java | 3 + .../data/cassandra/core/query/Columns.java | 2 +- .../data/cassandra/core/query/Criteria.java | 11 +- .../core/query/CriteriaDefinition.java | 6 +- .../core/query/SerializationUtils.java | 17 +- .../data/cassandra/core/query/Update.java | 13 +- .../cassandra/core/query/package-info.java | 7 + .../data/cassandra/package-info.java | 3 + .../data/cassandra/repository/Query.java | 1 - .../cdi/CassandraRepositoryBean.java | 5 +- .../cdi/CassandraRepositoryExtension.java | 2 +- .../repository/cdi/package-info.java | 3 + .../CassandraRepositoryNamespaceHandler.java | 4 +- .../config/EnableCassandraRepositories.java | 11 -- .../EnableReactiveCassandraRepositories.java | 12 -- .../repository/config/package-info.java | 3 + .../cassandra/repository/package-info.java | 3 + .../query/AbstractCassandraQuery.java | 2 + .../query/CassandraParameterAccessor.java | 2 + .../repository/query/CassandraParameters.java | 15 +- .../CassandraParametersParameterAccessor.java | 2 + .../query/CassandraQueryCreator.java | 26 ++- .../query/CassandraQueryExecution.java | 10 +- .../query/CassandraQueryMethod.java | 26 ++- .../query/ConvertingParameterAccessor.java | 20 +- .../query/DtoInstantiatingConverter.java | 11 +- .../ExpressionEvaluatingParameterBinder.java | 38 ++-- .../ReactiveCassandraParameterAccessor.java | 5 +- .../ReactiveCassandraQueryExecution.java | 3 +- .../ReactiveStringBasedCassandraQuery.java | 2 +- .../query/SimpleCassandraEntityMetadata.java | 2 +- .../query/StringBasedCassandraQuery.java | 2 +- .../repository/query/StringBasedQuery.java | 9 +- ...portedCassandraQueryOperatorException.java | 17 -- .../repository/query/package-info.java | 3 + .../support/CassandraRepositoryFactory.java | 3 +- .../CassandraRepositoryFactoryBean.java | 14 +- .../MappingCassandraEntityInformation.java | 10 +- .../ReactiveCassandraRepositoryFactory.java | 3 +- ...eactiveCassandraRepositoryFactoryBean.java | 8 +- .../repository/support/package-info.java | 3 + .../data/cassandra/util/MapBuilder.java | 5 +- .../data/cassandra/util/SpelUtils.java | 26 +++ .../data/cassandra/util/package-info.java | 7 + ...AbstractClusterConfigurationUnitTests.java | 12 +- ...aceCreatingJavaConfigIntegrationTests.java | 2 +- .../core/InsertOptionsUnitTests.java | 4 +- .../core/UpdateOptionsUnitTests.java | 6 +- .../core/convert/ColumnReaderUnitTests.java | 10 +- .../core/cql/CassandraAccessorUnitTests.java | 8 +- .../core/cql/QueryOptionsUnitTests.java | 3 +- .../core/cql/QueryOptionsUtilUnitTests.java | 10 +- .../core/cql/WriteOptionsUnitTests.java | 7 +- ...bstractTableOperationCqlGeneratorTest.java | 2 +- .../AlterKeyspaceCqlGeneratorUnitTests.java | 4 +- ...rUserTypeCqlGeneratorIntegrationTests.java | 4 +- .../AlterUserTypeCqlGeneratorUnitTests.java | 6 +- .../CreateKeyspaceCqlGeneratorUnitTests.java | 6 +- .../CreateTableCqlGeneratorUnitTests.java | 10 +- ...eUserTypeCqlGeneratorIntegrationTests.java | 9 +- .../CreateUserTypeCqlGeneratorUnitTests.java | 10 +- .../DropIndexCqlGeneratorUnitTests.java | 4 +- .../DropKeyspaceCqlGeneratorUnitTests.java | 2 +- .../DropTableCqlGeneratorUnitTests.java | 2 +- .../TableLifecycleIntegrationTests.java | 2 +- .../core/cql/keyspace/OptionUnitTests.java | 16 +- .../QueryDerivationIntegrationTests.java | 10 +- .../cdi/CassandraOperationsProducer.java | 2 +- .../ParameterConversionTestSupport.java | 2 +- .../CompositeKeyCrudIntegrationTests.java | 3 +- .../ConvertingParameterAccessorUnitTests.java | 10 - .../support/IntegrationTestConfig.java | 4 +- 246 files changed, 2132 insertions(+), 2184 deletions(-) delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/KeyspaceCqlGenerator.java delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/TableCqlGenerator.java delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/DefaultTableDescriptor.java delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/KeyspaceSpecification.java create mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/support/package-info.java create mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/package-info.java delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/UnsupportedCassandraQueryOperatorException.java create mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/util/package-info.java diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/CassandraWriteTimeoutException.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/CassandraWriteTimeoutException.java index a99ffee75..8feb10c60 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/CassandraWriteTimeoutException.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/CassandraWriteTimeoutException.java @@ -16,23 +16,26 @@ package org.springframework.data.cassandra; import org.springframework.dao.QueryTimeoutException; +import org.springframework.lang.Nullable; /** * Spring data access exception for a Cassandra write timeout. * * @author Matthew T. Adams + * @author Mark Paluch */ public class CassandraWriteTimeoutException extends QueryTimeoutException { private static final long serialVersionUID = -4374826375213670718L; - private String writeType; + private @Nullable String writeType; - public CassandraWriteTimeoutException(String writeType, String msg, Throwable cause) { + public CassandraWriteTimeoutException(@Nullable String writeType, String msg, Throwable cause) { super(msg, cause); this.writeType = writeType; } + @Nullable public String getWriteType() { return writeType; } 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 86dc868d1..ecbc63f3a 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 @@ -34,6 +34,10 @@ import org.springframework.data.cassandra.core.mapping.SimpleUserTypeResolver; import org.springframework.data.cassandra.core.mapping.Table; import org.springframework.data.convert.CustomConversions; import org.springframework.data.mapping.context.MappingContext; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; + +import com.datastax.driver.core.Session; /** * Base class for Spring Data Cassandra configuration using JavaConfig. @@ -47,7 +51,21 @@ import org.springframework.data.mapping.context.MappingContext; public abstract class AbstractCassandraConfiguration extends AbstractClusterConfiguration implements BeanClassLoaderAware { - private ClassLoader beanClassLoader; + private @Nullable ClassLoader beanClassLoader; + + /** + * Returns the initialized {@link Session} instance. + * + * @return the {@link Session}. + * @throws IllegalStateException if the session factory is not initialized. + */ + protected Session getRequiredSession() { + + CassandraSessionFactoryBean factoryBean = session(); + Assert.state(factoryBean.getObject() != null, "Session factory not initialized"); + + return factoryBean.getObject(); + } /** * Creates a {@link CassandraSessionFactoryBean} that provides a Cassandra {@link com.datastax.driver.core.Session}. @@ -55,8 +73,6 @@ public abstract class AbstractCassandraConfiguration extends AbstractClusterConf * {@link #getKeyspaceName() configured keyspace}. * * @return the {@link CassandraSessionFactoryBean}. - * @throws ClassNotFoundException if an error occurs initializing the initial entity set, see - * {@link #cassandraMapping()} * @see #cluster() * @see #cassandraConverter() * @see #getKeyspaceName() @@ -65,11 +81,11 @@ public abstract class AbstractCassandraConfiguration extends AbstractClusterConf * @see #getShutdownScripts() */ @Bean - public CassandraSessionFactoryBean session() throws ClassNotFoundException { + public CassandraSessionFactoryBean session() { CassandraSessionFactoryBean session = new CassandraSessionFactoryBean(); - session.setCluster(cluster().getObject()); + session.setCluster(getRequiredCluster()); session.setConverter(cassandraConverter()); session.setKeyspaceName(getKeyspaceName()); session.setSchemaAction(getSchemaAction()); @@ -84,13 +100,11 @@ public abstract class AbstractCassandraConfiguration extends AbstractClusterConf * {@link org.springframework.data.cassandra.core.CassandraTemplate}. * * @return {@link SessionFactory} used to initialize the Template API. - * @throws ClassNotFoundException if an error occurs initializing the initial entity set, see - * {@link #cassandraMapping()} * @since 2.0 */ @Bean - public SessionFactory sessionFactory() throws ClassNotFoundException { - return new DefaultSessionFactory(session().getObject()); + public SessionFactory sessionFactory() { + return new DefaultSessionFactory(getRequiredSession()); } /** @@ -98,19 +112,21 @@ public abstract class AbstractCassandraConfiguration extends AbstractClusterConf * {@link #customConversions()}. * * @return {@link CassandraConverter} used to convert Java and Cassandra value types during the mapping process. - * @throws ClassNotFoundException if an error occurs initializing the initial entity set, see - * {@link #cassandraMapping()} * @see #cassandraMapping() * @see #customConversions() */ @Bean - public CassandraConverter cassandraConverter() throws ClassNotFoundException { + public CassandraConverter cassandraConverter() { - MappingCassandraConverter mappingCassandraConverter = new MappingCassandraConverter(cassandraMapping()); + try { + MappingCassandraConverter mappingCassandraConverter = new MappingCassandraConverter(cassandraMapping()); - mappingCassandraConverter.setCustomConversions(customConversions()); + mappingCassandraConverter.setCustomConversions(customConversions()); - return mappingCassandraConverter; + return mappingCassandraConverter; + } catch (ClassNotFoundException e) { + throw new IllegalStateException(e); + } } /** @@ -138,14 +154,17 @@ public abstract class AbstractCassandraConfiguration extends AbstractClusterConf CassandraMappingContext mappingContext = new CassandraMappingContext(); - mappingContext.setBeanClassLoader(beanClassLoader); + if (beanClassLoader != null) { + mappingContext.setBeanClassLoader(beanClassLoader); + } + mappingContext.setInitialEntitySet(getInitialEntitySet()); CustomConversions customConversions = customConversions(); mappingContext.setCustomConversions(customConversions); mappingContext.setSimpleTypeHolder(customConversions.getSimpleTypeHolder()); - mappingContext.setUserTypeResolver(new SimpleUserTypeResolver(cluster().getObject(), getKeyspaceName())); + mappingContext.setUserTypeResolver(new SimpleUserTypeResolver(getRequiredCluster(), getKeyspaceName())); return mappingContext; } @@ -156,7 +175,7 @@ public abstract class AbstractCassandraConfiguration extends AbstractClusterConf * of entity classes. * * @return {@link Set} of initial entity classes. - * @throws ClassNotFoundException + * @throws ClassNotFoundException if the entity scan fails. * @see #getEntityBasePackages() * @see CassandraEntityClassScanner * @since 2.0 @@ -201,4 +220,5 @@ public abstract class AbstractCassandraConfiguration extends AbstractClusterConf public SchemaAction getSchemaAction() { return SchemaAction.NONE; } + } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractClusterConfiguration.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractClusterConfiguration.java index bb1c09a5c..c6f6d37d5 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractClusterConfiguration.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractClusterConfiguration.java @@ -22,8 +22,11 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.cassandra.core.cql.keyspace.CreateKeyspaceSpecification; import org.springframework.data.cassandra.core.cql.keyspace.DropKeyspaceSpecification; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import com.datastax.driver.core.AuthProvider; +import com.datastax.driver.core.Cluster; import com.datastax.driver.core.NettyOptions; import com.datastax.driver.core.PoolingOptions; import com.datastax.driver.core.ProtocolVersion; @@ -48,6 +51,20 @@ import com.datastax.driver.core.policies.SpeculativeExecutionPolicy; @Configuration public abstract class AbstractClusterConfiguration { + /** + * Returns the initialized {@link Cluster} instance. + * + * @return the {@link Cluster}. + * @throws IllegalStateException if the cluster factory is not initialized. + */ + protected Cluster getRequiredCluster() { + + CassandraClusterFactoryBean factoryBean = cluster(); + Assert.state(factoryBean.getObject() != null, "Cluster factory not initialized"); + + return factoryBean.getObject(); + } + /** * Creates a {@link CassandraClusterFactoryBean} that provides a Cassandra {@link com.datastax.driver.core.Cluster}. * The lifecycle of {@link CassandraClusterFactoryBean} executes {@link #getStartupScripts() startup} and @@ -97,6 +114,7 @@ public abstract class AbstractClusterConfiguration { * @return the {@link AddressTranslator}; may be {@literal null}. * @since 1.5 */ + @Nullable protected AddressTranslator getAddressTranslator() { return null; } @@ -106,6 +124,7 @@ public abstract class AbstractClusterConfiguration { * * @return the {@link AuthProvider}, may be {@literal null}. */ + @Nullable protected AuthProvider getAuthProvider() { return null; } @@ -116,6 +135,7 @@ public abstract class AbstractClusterConfiguration { * @return the {@link ClusterBuilderConfigurer}; may be {@literal null}. * @since 1.5 */ + @Nullable protected ClusterBuilderConfigurer getClusterBuilderConfigurer() { return null; } @@ -126,6 +146,7 @@ public abstract class AbstractClusterConfiguration { * @return the cluster name; may be {@literal null}. * @since 1.5 */ + @Nullable protected String getClusterName() { return null; } @@ -135,6 +156,7 @@ public abstract class AbstractClusterConfiguration { * * @return the {@link CompressionType}, may be {@literal null}. */ + @Nullable protected CompressionType getCompressionType() { return null; } @@ -154,6 +176,7 @@ public abstract class AbstractClusterConfiguration { * * @return the {@link LoadBalancingPolicy}, may be {@literal null}. */ + @Nullable protected LoadBalancingPolicy getLoadBalancingPolicy() { return null; } @@ -180,7 +203,7 @@ public abstract class AbstractClusterConfiguration { /** * Returns the {@link NettyOptions}. Defaults to {@link NettyOptions#DEFAULT_INSTANCE}. * - * @return + * @return the {@link NettyOptions} to customize netty behavior. * @since 1.5 */ protected NettyOptions getNettyOptions() { @@ -192,6 +215,7 @@ public abstract class AbstractClusterConfiguration { * * @return the {@link PoolingOptions}, may be {@literal null}. */ + @Nullable protected PoolingOptions getPoolingOptions() { return null; } @@ -207,12 +231,13 @@ public abstract class AbstractClusterConfiguration { } /** - * Returns the {@link ProtocolVersion}. + * Returns the {@link ProtocolVersion}. Defaults to {@link ProtocolVersion#NEWEST_SUPPORTED} * - * @return the {@link ProtocolVersion}, may be {@literal null}. + * @return the {@link ProtocolVersion}. + * @see ProtocolVersion#NEWEST_SUPPORTED. */ protected ProtocolVersion getProtocolVersion() { - return null; + return ProtocolVersion.NEWEST_SUPPORTED; } /** @@ -221,6 +246,7 @@ public abstract class AbstractClusterConfiguration { * @return the {@link QueryOptions}, may be {@literal null}. * @since 1.5 */ + @Nullable protected QueryOptions getQueryOptions() { return null; } @@ -230,6 +256,7 @@ public abstract class AbstractClusterConfiguration { * * @return the {@link ReconnectionPolicy}, may be {@literal null}. */ + @Nullable protected ReconnectionPolicy getReconnectionPolicy() { return null; } @@ -239,6 +266,7 @@ public abstract class AbstractClusterConfiguration { * * @return the {@link RetryPolicy}, may be {@literal null}. */ + @Nullable protected RetryPolicy getRetryPolicy() { return null; } @@ -249,6 +277,7 @@ public abstract class AbstractClusterConfiguration { * @return the {@link SpeculativeExecutionPolicy}; may be {@literal null}. * @since 1.5 */ + @Nullable protected SpeculativeExecutionPolicy getSpeculativeExecutionPolicy() { return null; } @@ -258,6 +287,7 @@ public abstract class AbstractClusterConfiguration { * * @return the {@link SocketOptions}, may be {@literal null}. */ + @Nullable protected SocketOptions getSocketOptions() { return null; } @@ -268,6 +298,7 @@ public abstract class AbstractClusterConfiguration { * @return the {@link TimestampGenerator}; may be {@literal null}. * @since 1.5 */ + @Nullable protected TimestampGenerator getTimestampGenerator() { return null; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractReactiveCassandraConfiguration.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractReactiveCassandraConfiguration.java index b53ddc931..815f9dffd 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractReactiveCassandraConfiguration.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractReactiveCassandraConfiguration.java @@ -46,8 +46,8 @@ public abstract class AbstractReactiveCassandraConfiguration extends AbstractCas * @see DefaultBridgedReactiveSession */ @Bean - public ReactiveSession reactiveSession() throws Exception { - return new DefaultBridgedReactiveSession(session().getObject(), Schedulers.elastic()); + public ReactiveSession reactiveSession() { + return new DefaultBridgedReactiveSession(getRequiredSession(), Schedulers.elastic()); } /** @@ -59,7 +59,7 @@ public abstract class AbstractReactiveCassandraConfiguration extends AbstractCas * @see #reactiveCassandraTemplate() */ @Bean - public ReactiveSessionFactory reactiveSessionFactory() throws Exception { + public ReactiveSessionFactory reactiveSessionFactory() { return new DefaultReactiveSessionFactory(reactiveSession()); } @@ -71,7 +71,7 @@ public abstract class AbstractReactiveCassandraConfiguration extends AbstractCas * @see #cassandraConverter() */ @Bean - public ReactiveCassandraOperations reactiveCassandraTemplate() throws Exception { + public ReactiveCassandraOperations reactiveCassandraTemplate() { return new ReactiveCassandraTemplate(reactiveSessionFactory(), cassandraConverter()); } @@ -82,7 +82,7 @@ public abstract class AbstractReactiveCassandraConfiguration extends AbstractCas * @see #reactiveSessionFactory() */ @Bean - public ReactiveCqlOperations reactiveCqlTemplate() throws Exception { + public ReactiveCqlOperations reactiveCqlTemplate() { return new ReactiveCqlTemplate(reactiveSessionFactory()); } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractSessionConfiguration.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractSessionConfiguration.java index c05a79b47..efac4e6ac 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractSessionConfiguration.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractSessionConfiguration.java @@ -20,6 +20,9 @@ import org.springframework.context.annotation.Configuration; import org.springframework.data.cassandra.SessionFactory; import org.springframework.data.cassandra.core.cql.CqlTemplate; import org.springframework.data.cassandra.core.cql.session.DefaultSessionFactory; +import org.springframework.util.Assert; + +import com.datastax.driver.core.Session; /** * Spring {@link @Configuration} class used to configure a Cassandra client application @@ -35,6 +38,20 @@ import org.springframework.data.cassandra.core.cql.session.DefaultSessionFactory @Configuration public abstract class AbstractSessionConfiguration extends AbstractClusterConfiguration { + /** + * Returns the initialized {@link Session} instance. + * + * @return the {@link Session}. + * @throws IllegalStateException if the session factory is not initialized. + */ + protected Session getRequiredSession() { + + CassandraCqlSessionFactoryBean factoryBean = session(); + Assert.state(factoryBean.getObject() != null, "Session factory not initialized"); + + return factoryBean.getObject(); + } + /** * Creates a {@link CassandraCqlSessionFactoryBean} that provides a Cassandra * {@link com.datastax.driver.core.Session}. @@ -48,7 +65,7 @@ public abstract class AbstractSessionConfiguration extends AbstractClusterConfig CassandraCqlSessionFactoryBean bean = new CassandraCqlSessionFactoryBean(); - bean.setCluster(cluster().getObject()); + bean.setCluster(getRequiredCluster()); bean.setKeyspaceName(getKeyspaceName()); return bean; @@ -63,7 +80,7 @@ public abstract class AbstractSessionConfiguration extends AbstractClusterConfig */ @Bean public SessionFactory sessionFactory() { - return new DefaultSessionFactory(session().getObject()); + return new DefaultSessionFactory(getRequiredSession()); } /** diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraClusterFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraClusterFactoryBean.java index 520af453c..8052e5efb 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraClusterFactoryBean.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraClusterFactoryBean.java @@ -36,6 +36,7 @@ import org.springframework.data.cassandra.core.cql.generator.DropKeyspaceCqlGene import org.springframework.data.cassandra.core.cql.keyspace.CreateKeyspaceSpecification; import org.springframework.data.cassandra.core.cql.keyspace.DropKeyspaceSpecification; import org.springframework.data.cassandra.core.cql.keyspace.KeyspaceActionSpecification; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -89,39 +90,39 @@ public class CassandraClusterFactoryBean private final PersistenceExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator(); - private Cluster cluster; - private ClusterBuilderConfigurer clusterBuilderConfigurer; + private @Nullable Cluster cluster; + private @Nullable ClusterBuilderConfigurer clusterBuilderConfigurer; - private AddressTranslator addressTranslator; - private AuthProvider authProvider; - private CompressionType compressionType; - private Host.StateListener hostStateListener; - private LatencyTracker latencyTracker; + private @Nullable AddressTranslator addressTranslator; + private @Nullable AuthProvider authProvider; + private @Nullable CompressionType compressionType; + private @Nullable Host.StateListener hostStateListener; + private @Nullable LatencyTracker latencyTracker; private List keyspaceCreations = new ArrayList<>(); private List keyspaceDrops = new ArrayList<>(); - private Set> keyspaceSpecifications = new HashSet<>(); + private Set keyspaceSpecifications = new HashSet<>(); private List startupScripts = new ArrayList<>(); private List shutdownScripts = new ArrayList<>(); - private LoadBalancingPolicy loadBalancingPolicy; - private NettyOptions nettyOptions; - private PoolingOptions poolingOptions; - private ProtocolVersion protocolVersion; - private QueryOptions queryOptions; - private ReconnectionPolicy reconnectionPolicy; - private RetryPolicy retryPolicy; - private SpeculativeExecutionPolicy speculativeExecutionPolicy; - private SocketOptions socketOptions; - private SSLOptions sslOptions; - private TimestampGenerator timestampGenerator; + private @Nullable LoadBalancingPolicy loadBalancingPolicy; + private NettyOptions nettyOptions = NettyOptions.DEFAULT_INSTANCE; + private @Nullable PoolingOptions poolingOptions; + private @Nullable ProtocolVersion protocolVersion; + private @Nullable QueryOptions queryOptions; + private @Nullable ReconnectionPolicy reconnectionPolicy; + private @Nullable RetryPolicy retryPolicy; + private @Nullable SpeculativeExecutionPolicy speculativeExecutionPolicy; + private @Nullable SocketOptions socketOptions; + private @Nullable SSLOptions sslOptions; + private @Nullable TimestampGenerator timestampGenerator; - private String beanName; - private String clusterName; + private @Nullable String beanName; + private @Nullable String clusterName; private String contactPoints = DEFAULT_CONTACT_POINTS; - private String password; - private String username; + private @Nullable String password; + private @Nullable String username; /* * (non-Javadoc) @@ -142,7 +143,7 @@ public class CassandraClusterFactoryBean Optional.ofNullable(addressTranslator).ifPresent(clusterBuilder::withAddressTranslator); Optional.ofNullable(loadBalancingPolicy).ifPresent(clusterBuilder::withLoadBalancingPolicy); - Optional.ofNullable(nettyOptions).ifPresent(clusterBuilder::withNettyOptions); + clusterBuilder.withNettyOptions(nettyOptions); Optional.ofNullable(poolingOptions).ifPresent(clusterBuilder::withPoolingOptions); Optional.ofNullable(protocolVersion).ifPresent(clusterBuilder::withProtocolVersion); Optional.ofNullable(queryOptions).ifPresent(clusterBuilder::withQueryOptions); @@ -186,7 +187,7 @@ public class CassandraClusterFactoryBean Optional.ofNullable(latencyTracker).ifPresent(cluster::register); generateSpecificationsFromFactoryBeans(); - executeSpecsAndScripts(keyspaceCreations, startupScripts); + executeSpecsAndScripts(keyspaceCreations, startupScripts, cluster); } /* @@ -198,8 +199,9 @@ public class CassandraClusterFactoryBean } /* (non-Javadoc) */ + @Nullable private String resolveClusterName() { - return (StringUtils.hasText(clusterName) ? clusterName : beanName); + return StringUtils.hasText(clusterName) ? clusterName : beanName; } /* @@ -207,9 +209,13 @@ public class CassandraClusterFactoryBean * @see org.springframework.beans.factory.DisposableBean#destroy() */ @Override - public void destroy() throws Exception { - executeSpecsAndScripts(keyspaceDrops, shutdownScripts); - cluster.close(); + public void destroy() { + + if (cluster != null) { + + executeSpecsAndScripts(keyspaceDrops, shutdownScripts, cluster); + cluster.close(); + } } /* @@ -266,8 +272,8 @@ public class CassandraClusterFactoryBean }); } - protected void executeSpecsAndScripts(List> kepspaceActionSpecifications, - List scripts) { + protected void executeSpecsAndScripts(List kepspaceActionSpecifications, + List scripts, Cluster cluster) { if (!CollectionUtils.isEmpty(kepspaceActionSpecifications) || !CollectionUtils.isEmpty(scripts)) { @@ -288,7 +294,7 @@ public class CassandraClusterFactoryBean } } - private String toCql(KeyspaceActionSpecification keyspaceActionSpecification) { + private String toCql(KeyspaceActionSpecification keyspaceActionSpecification) { return (keyspaceActionSpecification instanceof CreateKeyspaceSpecification ? new CreateKeyspaceCqlGenerator((CreateKeyspaceSpecification) keyspaceActionSpecification).toCql() @@ -329,7 +335,7 @@ public class CassandraClusterFactoryBean * * @param compressionType the {@link CompressionType} used by the new cluster. */ - public void setCompressionType(CompressionType compressionType) { + public void setCompressionType(@Nullable CompressionType compressionType) { this.compressionType = compressionType; } @@ -338,7 +344,7 @@ public class CassandraClusterFactoryBean * * @param poolingOptions the {@link PoolingOptions} used by the new cluster. */ - public void setPoolingOptions(PoolingOptions poolingOptions) { + public void setPoolingOptions(@Nullable PoolingOptions poolingOptions) { this.poolingOptions = poolingOptions; } @@ -348,7 +354,7 @@ public class CassandraClusterFactoryBean * @param protocolVersion the {@link ProtocolVersion} used by the new cluster. * @since 1.4 */ - public void setProtocolVersion(ProtocolVersion protocolVersion) { + public void setProtocolVersion(@Nullable ProtocolVersion protocolVersion) { this.protocolVersion = protocolVersion; } @@ -357,7 +363,7 @@ public class CassandraClusterFactoryBean * * @param socketOptions the {@link SocketOptions} used by the new cluster. */ - public void setSocketOptions(SocketOptions socketOptions) { + public void setSocketOptions(@Nullable SocketOptions socketOptions) { this.socketOptions = socketOptions; } @@ -366,7 +372,7 @@ public class CassandraClusterFactoryBean * * @param queryOptions the {@link QueryOptions} used by the new cluster. */ - public void setQueryOptions(QueryOptions queryOptions) { + public void setQueryOptions(@Nullable QueryOptions queryOptions) { this.queryOptions = queryOptions; } @@ -375,7 +381,7 @@ public class CassandraClusterFactoryBean * * @param authProvider the {@link AuthProvider} used by the new cluster. */ - public void setAuthProvider(AuthProvider authProvider) { + public void setAuthProvider(@Nullable AuthProvider authProvider) { this.authProvider = authProvider; } @@ -394,7 +400,7 @@ public class CassandraClusterFactoryBean * * @param loadBalancingPolicy the {@link LoadBalancingPolicy} used by the new cluster. */ - public void setLoadBalancingPolicy(LoadBalancingPolicy loadBalancingPolicy) { + public void setLoadBalancingPolicy(@Nullable LoadBalancingPolicy loadBalancingPolicy) { this.loadBalancingPolicy = loadBalancingPolicy; } @@ -403,7 +409,7 @@ public class CassandraClusterFactoryBean * * @param reconnectionPolicy the {@link ReconnectionPolicy} used by the new cluster. */ - public void setReconnectionPolicy(ReconnectionPolicy reconnectionPolicy) { + public void setReconnectionPolicy(@Nullable ReconnectionPolicy reconnectionPolicy) { this.reconnectionPolicy = reconnectionPolicy; } @@ -412,7 +418,7 @@ public class CassandraClusterFactoryBean * * @param retryPolicy the {@link RetryPolicy} used by the new cluster. */ - public void setRetryPolicy(RetryPolicy retryPolicy) { + public void setRetryPolicy(@Nullable RetryPolicy retryPolicy) { this.retryPolicy = retryPolicy; } @@ -499,14 +505,14 @@ public class CassandraClusterFactoryBean /** * @param keyspaceSpecifications The {@link KeyspaceActionSpecification} to set. */ - public void setKeyspaceSpecifications(Set> keyspaceSpecifications) { + public void setKeyspaceSpecifications(Set keyspaceSpecifications) { this.keyspaceSpecifications = keyspaceSpecifications; } /** * @return the {@link KeyspaceActionSpecification} associated with this factory. */ - public Set> getKeyspaceSpecifications() { + public Set getKeyspaceSpecifications() { return keyspaceSpecifications; } @@ -576,7 +582,7 @@ public class CassandraClusterFactoryBean * @see com.datastax.driver.core.policies.AddressTranslator * @since 1.5 */ - public void setAddressTranslator(AddressTranslator addressTranslator) { + public void setAddressTranslator(@Nullable AddressTranslator addressTranslator) { this.addressTranslator = addressTranslator; } @@ -590,7 +596,7 @@ public class CassandraClusterFactoryBean * {@link com.datastax.driver.core.Cluster.Builder}. * @see org.springframework.data.cql.config.ClusterBuilderConfigurer */ - public void setClusterBuilderConfigurer(ClusterBuilderConfigurer clusterBuilderConfigurer) { + public void setClusterBuilderConfigurer(@Nullable ClusterBuilderConfigurer clusterBuilderConfigurer) { this.clusterBuilderConfigurer = clusterBuilderConfigurer; } @@ -601,7 +607,7 @@ public class CassandraClusterFactoryBean * @see com.datastax.driver.core.Cluster.Builder#withClusterName(String) * @since 1.5 */ - public void setClusterName(String clusterName) { + public void setClusterName(@Nullable String clusterName) { this.clusterName = clusterName; } @@ -625,7 +631,7 @@ public class CassandraClusterFactoryBean * @see com.datastax.driver.core.policies.SpeculativeExecutionPolicy * @since 1.5 */ - public void setSpeculativeExecutionPolicy(SpeculativeExecutionPolicy speculativeExecutionPolicy) { + public void setSpeculativeExecutionPolicy(@Nullable SpeculativeExecutionPolicy speculativeExecutionPolicy) { this.speculativeExecutionPolicy = speculativeExecutionPolicy; } @@ -637,7 +643,7 @@ public class CassandraClusterFactoryBean * @see com.datastax.driver.core.TimestampGenerator * @since 1.5 */ - public void setTimestampGenerator(TimestampGenerator timestampGenerator) { + public void setTimestampGenerator(@Nullable TimestampGenerator timestampGenerator) { this.timestampGenerator = timestampGenerator; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraCqlClusterParser.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraCqlClusterParser.java index 0e51b18d2..7314a5e9b 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraCqlClusterParser.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraCqlClusterParser.java @@ -30,6 +30,7 @@ import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.data.cassandra.core.cql.keyspace.KeyspaceActionSpecification; import org.springframework.data.cassandra.core.cql.keyspace.KeyspaceAttributes; +import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; @@ -205,7 +206,7 @@ class CassandraCqlClusterParser extends AbstractBeanDefinitionParser { * @param element {@link Element} to parse. * @param builder The {@link BeanDefinitionBuilder} to add the replication to */ - private void parseReplication(Element element, BeanDefinitionBuilder builder) { + private void parseReplication(@Nullable Element element, BeanDefinitionBuilder builder) { ManagedList networkTopologyDataCenters = new ManagedList<>(); ManagedList networkTopologyReplicationFactors = new ManagedList<>(); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraCqlSessionFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraCqlSessionFactoryBean.java index cfaae3de3..70ead16ea 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraCqlSessionFactoryBean.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraCqlSessionFactoryBean.java @@ -20,6 +20,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; @@ -28,13 +30,11 @@ import org.springframework.dao.support.PersistenceExceptionTranslator; import org.springframework.data.cassandra.core.cql.CassandraExceptionTranslator; import org.springframework.data.cassandra.core.cql.CqlOperations; import org.springframework.data.cassandra.core.cql.CqlTemplate; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.datastax.driver.core.Cluster; import com.datastax.driver.core.Session; @@ -45,6 +45,7 @@ import com.datastax.driver.core.Session; * @author Alex Shvid * @author Matthew T. Adams * @author John Blum + * @author Mark Paluch * @see org.springframework.beans.factory.DisposableBean * @see org.springframework.beans.factory.FactoryBean * @see org.springframework.beans.factory.InitializingBean @@ -60,15 +61,15 @@ public class CassandraCqlSessionFactoryBean protected final Logger logger = LoggerFactory.getLogger(getClass()); protected final PersistenceExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator(); - private Cluster cluster; + private @Nullable Cluster cluster; private List startupScripts = Collections.emptyList(); private List shutdownScripts = Collections.emptyList(); - private Session session; + private @Nullable Session session; - private String keyspaceName; + private @Nullable String keyspaceName; /* * (non-Javadoc) @@ -83,7 +84,7 @@ public class CassandraCqlSessionFactoryBean } /* (non-Javadoc) */ - Session connect(String keyspaceName) { + Session connect(@Nullable String keyspaceName) { return (StringUtils.hasText(keyspaceName) ? getCluster().connect(keyspaceName) : getCluster().connect()); } @@ -178,7 +179,9 @@ public class CassandraCqlSessionFactoryBean * @see #getCluster() */ public void setCluster(Cluster cluster) { + Assert.notNull(cluster, "Cluster must not be null"); + this.cluster = cluster; } @@ -191,18 +194,20 @@ public class CassandraCqlSessionFactoryBean * @see #setCluster(Cluster) */ protected Cluster getCluster() { + Assert.state(this.cluster != null, "Cluster was not properly initialized"); + return this.cluster; } /** - * Sets the name of the Cassandra Keyspace to connect to. Passing {@code null}, an empty String, or whitespace will + * Sets the name of the Cassandra Keyspace to connect to. Passing {@literal null}, an empty String, or whitespace will * cause the Cassandra System Keyspace to be used. * * @param keyspaceName a String indicating the name of the Keyspace in which to connect. * @see #getKeyspaceName() */ - public void setKeyspaceName(String keyspaceName) { + public void setKeyspaceName(@Nullable String keyspaceName) { this.keyspaceName = keyspaceName; } @@ -212,6 +217,7 @@ public class CassandraCqlSessionFactoryBean * @return the name of the Cassandra Keyspace to connect to as a String. * @see #setKeyspaceName(String) */ + @Nullable protected String getKeyspaceName() { return this.keyspaceName; } @@ -235,7 +241,7 @@ public class CassandraCqlSessionFactoryBean /** * Sets CQL scripts to be executed immediately after the session is connected. */ - public void setStartupScripts(List scripts) { + public void setStartupScripts(@Nullable List scripts) { this.startupScripts = (scripts != null ? new ArrayList<>(scripts) : Collections.emptyList()); } @@ -249,7 +255,7 @@ public class CassandraCqlSessionFactoryBean /** * Sets CQL scripts to be executed immediately before the session is shutdown. */ - public void setShutdownScripts(List scripts) { + public void setShutdownScripts(@Nullable List scripts) { this.shutdownScripts = (scripts != null ? new ArrayList<>(scripts) : Collections.emptyList()); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraCqlTemplateFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraCqlTemplateFactoryBean.java index 8d7ece5ff..2bcb89af3 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraCqlTemplateFactoryBean.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraCqlTemplateFactoryBean.java @@ -18,6 +18,7 @@ package org.springframework.data.cassandra.config; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.data.cassandra.core.cql.CqlTemplate; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import com.datastax.driver.core.Session; @@ -30,8 +31,9 @@ import com.datastax.driver.core.Session; */ public class CassandraCqlTemplateFactoryBean implements FactoryBean, InitializingBean { - private CqlTemplate template; - private Session session; + private @Nullable CqlTemplate template; + + private @Nullable Session session; /* (non-Javadoc) * @see org.springframework.beans.factory.FactoryBean#getObject() diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraEntityClassScanner.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraEntityClassScanner.java index 1e9d6af2d..828ad5101 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraEntityClassScanner.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraEntityClassScanner.java @@ -28,51 +28,110 @@ import org.springframework.core.type.filter.AnnotationTypeFilter; import org.springframework.data.annotation.Persistent; import org.springframework.data.cassandra.core.mapping.PrimaryKeyClass; import org.springframework.data.cassandra.core.mapping.Table; +import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; /** - * Scans packages for Cassandra entities. + * Scans packages for Cassandra entities. The entity scanner scans for entity classes annotated with + * {@link #getEntityAnnotations() entity annotations} on the class path using either base package names, base package + * classes or both. * * @author Matthew T. Adams + * @author Mark Paluch + * @see ClassUtils#forName(String, ClassLoader) */ public class CassandraEntityClassScanner { + private Set entityBasePackages = new HashSet<>(); + private Set> entityBasePackageClasses = new HashSet<>(); + private @Nullable ClassLoader beanClassLoader; + + /** + * Scan one or more base packages for entity classes. Classes are loaded using the current class loader. + * + * @param entityBasePackages must not be {@literal null}. + * @return + * @throws ClassNotFoundException + */ public static Set> scan(String... entityBasePackages) throws ClassNotFoundException { return new CassandraEntityClassScanner(entityBasePackages).scanForEntityClasses(); } + /** + * Scan one or more base packages for entity classes. Classes are loaded using the current class loader. + * + * @param entityBasePackageClasses must not be {@literal null}. + * @return + * @throws ClassNotFoundException + */ public static Set> scan(Class... entityBasePackageClasses) throws ClassNotFoundException { return new CassandraEntityClassScanner(entityBasePackageClasses).scanForEntityClasses(); } + /** + * Scan one or more base packages for entity classes. Classes are loaded using the current class loader. + * + * @param entityBasePackages must not be {@literal null}. + * @return + * @throws ClassNotFoundException + */ public static Set> scan(Collection entityBasePackages) throws ClassNotFoundException { return new CassandraEntityClassScanner(entityBasePackages).scanForEntityClasses(); } + /** + * Scan one or more base packages for entity classes. Classes are loaded using the current class loader. + * + * @param entityBasePackages must not be {@literal null}. + * @param entityBasePackageClasses must not be {@literal null}. + * @return + * @throws ClassNotFoundException + */ public static Set> scan(Collection entityBasePackages, Collection> entityBasePackageClasses) throws ClassNotFoundException { return new CassandraEntityClassScanner(entityBasePackages, entityBasePackageClasses).scanForEntityClasses(); } - protected Set entityBasePackages = new HashSet<>(); - protected Set> entityBasePackageClasses = new HashSet<>(); - protected ClassLoader beanClassLoader; - + /** + * Creates a new {@link CassandraEntityClassScanner}. + */ public CassandraEntityClassScanner() {} + /** + * Creates a new {@link CassandraEntityClassScanner} given {@code entityBasePackageClasses}. + * + * @param entityBasePackageClasses must not be {@literal null}. + */ public CassandraEntityClassScanner(Class... entityBasePackageClasses) { - this(null, Arrays.asList(entityBasePackageClasses)); + setEntityBasePackageClasses(Arrays.asList(entityBasePackageClasses)); } + /** + * Creates a new {@link CassandraEntityClassScanner} given {@code entityBasePackages}. + * + * @param entityBasePackages must not be {@literal null}. + */ public CassandraEntityClassScanner(String... entityBasePackages) { this(Arrays.asList(entityBasePackages)); } + /** + * Creates a new {@link CassandraEntityClassScanner} given {@code entityBasePackages}. + * + * @param entityBasePackages must not be {@literal null}. + */ public CassandraEntityClassScanner(Collection entityBasePackages) { - this(entityBasePackages, null); + setEntityBasePackages(entityBasePackages); } + /** + * Creates a new {@link CassandraEntityClassScanner} given {@code entityBasePackages} and + * {@code entityBasePackageClasses}. + * + * @param entityBasePackages must not be {@literal null}. + * @param entityBasePackageClasses must not be {@literal null}. + */ public CassandraEntityClassScanner(Collection entityBasePackages, Collection> entityBasePackageClasses) { @@ -80,23 +139,43 @@ public class CassandraEntityClassScanner { setEntityBasePackageClasses(entityBasePackageClasses); } + /** + * @return base package names used for the entity scan. + */ public Set getEntityBasePackages() { return Collections.unmodifiableSet(entityBasePackages); } + /** + * Set the base package names to be used for the entity scan. + * + * @param entityBasePackages must not be {@literal null}. + */ public void setEntityBasePackages(Collection entityBasePackages) { - this.entityBasePackages = entityBasePackages == null ? new HashSet<>() : new HashSet<>(entityBasePackages); + this.entityBasePackages = new HashSet<>(entityBasePackages); } + /** + * @return base package classes used for the entity scan. + */ public Set> getEntityBasePackageClasses() { return Collections.unmodifiableSet(entityBasePackageClasses); } + /** + * Set the base package classes to be used for the entity scan. + * + * @param entityBasePackageClasses must not be {@literal null}. + */ public void setEntityBasePackageClasses(Collection> entityBasePackageClasses) { - this.entityBasePackageClasses = entityBasePackageClasses == null ? new HashSet<>() - : new HashSet<>(entityBasePackageClasses); + this.entityBasePackageClasses = new HashSet<>(entityBasePackageClasses); } + /** + * Set the bean {@link ClassLoader} to load class candidates discovered by the class path scan. + * + * @param beanClassLoader must not be {@literal null}. + */ public void setBeanClassLoader(ClassLoader beanClassLoader) { this.beanClassLoader = beanClassLoader; } @@ -127,14 +206,20 @@ public class CassandraEntityClassScanner { HashSet> classes = new HashSet<>(); - if (StringUtils.hasText(basePackage)) { - ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider( - false); - for (Class annoClass : getEntityAnnotations()) { - componentProvider.addIncludeFilter(new AnnotationTypeFilter(annoClass)); - } + if (StringUtils.isEmpty(basePackage)) { + return classes; + } - for (BeanDefinition candidate : componentProvider.findCandidateComponents(basePackage)) { + ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider( + false); + + for (Class annotation : getEntityAnnotations()) { + componentProvider.addIncludeFilter(new AnnotationTypeFilter(annotation)); + } + + for (BeanDefinition candidate : componentProvider.findCandidateComponents(basePackage)) { + + if (candidate.getBeanClassName() != null) { classes.add(ClassUtils.forName(candidate.getBeanClassName(), beanClassLoader)); } } @@ -142,8 +227,14 @@ public class CassandraEntityClassScanner { return classes; } + /** + * @return entity annotations. + * @see Table + * @see Persistent + * @see PrimaryKeyClass + */ @SuppressWarnings("unchecked") - public Class[] getEntityAnnotations() { + protected Class[] getEntityAnnotations() { return new Class[] { Table.class, Persistent.class, PrimaryKeyClass.class }; } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingContextParser.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingContextParser.java index 75cb9991d..65d153ba7 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingContextParser.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingContextParser.java @@ -97,10 +97,7 @@ class CassandraMappingContextParser extends AbstractSingleBeanDefinitionParser { DomUtils.getChildElementsByTagName(element, "entity").forEach(entity -> { EntityMapping entityMapping = parseEntity(entity); - - if (entityMapping != null) { - mappings.add(entityMapping); - } + mappings.add(entityMapping); }); List userTypeResolvers = DomUtils.getChildElementsByTagName(element, "user-type-resolver"); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingXmlBeanFactoryPostProcessorRegistrar.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingXmlBeanFactoryPostProcessorRegistrar.java index c0672123e..1c9f488ef 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingXmlBeanFactoryPostProcessorRegistrar.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraMappingXmlBeanFactoryPostProcessorRegistrar.java @@ -28,14 +28,16 @@ import org.w3c.dom.Element; * Ensures that a {@link CassandraMappingBeanFactoryPostProcessor} is registered. * * @author Matthew T. Adams + * @author Mark Paluch */ +@Deprecated class CassandraMappingXmlBeanFactoryPostProcessorRegistrar { /** * Ensures that a {@link CassandraMappingBeanFactoryPostProcessor} is registered. This method is a no-op if one is * already registered. */ - public static void ensureRegistration(Element element, ParserContext parserContext) { + static void ensureRegistration(Element element, ParserContext parserContext) { BeanDefinitionRegistry registry = parserContext.getRegistry(); if (!(registry instanceof GenericApplicationContext)) { diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraSessionFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraSessionFactoryBean.java index 9e0e21d2e..09a97e4e1 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraSessionFactoryBean.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraSessionFactoryBean.java @@ -21,6 +21,7 @@ import org.springframework.data.cassandra.core.CassandraPersistentEntitySchemaCr import org.springframework.data.cassandra.core.CassandraPersistentEntitySchemaDropper; import org.springframework.data.cassandra.core.convert.CassandraConverter; import org.springframework.data.cassandra.core.mapping.CassandraMappingContext; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -40,9 +41,9 @@ public class CassandraSessionFactoryBean extends CassandraCqlSessionFactoryBean protected static final boolean DEFAULT_DROP_TABLES = false; protected static final boolean DEFAULT_DROP_UNUSED_TABLES = false; - private CassandraAdminOperations admin; + private @Nullable CassandraAdminOperations admin; - private CassandraConverter converter; + private @Nullable CassandraConverter converter; private SchemaAction schemaAction = SchemaAction.NONE; @@ -107,6 +108,7 @@ public class CassandraSessionFactoryBean extends CassandraCqlSessionFactoryBean /** * @return the {@link CassandraConverter}. */ + @Nullable public CassandraConverter getConverter() { return this.converter; } @@ -114,6 +116,7 @@ public class CassandraSessionFactoryBean extends CassandraCqlSessionFactoryBean /** * @return the {@link CassandraMappingContext}. */ + @Nullable protected CassandraMappingContext getMappingContext() { return getConverter().getMappingContext(); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraTemplateFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraTemplateFactoryBean.java index b3c11b450..c838c481e 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraTemplateFactoryBean.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraTemplateFactoryBean.java @@ -22,6 +22,7 @@ import org.springframework.data.cassandra.core.CassandraTemplate; import org.springframework.data.cassandra.core.convert.CassandraConverter; import org.springframework.data.cassandra.core.cql.CqlOperations; import org.springframework.data.cassandra.core.cql.session.DefaultSessionFactory; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import com.datastax.driver.core.Session; @@ -34,11 +35,11 @@ import com.datastax.driver.core.Session; */ public class CassandraTemplateFactoryBean implements FactoryBean, InitializingBean { - protected SessionFactory sessionFactory; + protected @Nullable SessionFactory sessionFactory; - protected CqlOperations cqlOperations; + protected @Nullable CqlOperations cqlOperations; - protected CassandraConverter converter; + protected @Nullable CassandraConverter converter; /* * (non-Javadoc) diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/KeyspaceActionSpecificationFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/KeyspaceActionSpecificationFactoryBean.java index 604b201ac..6bdd374f1 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/KeyspaceActionSpecificationFactoryBean.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/KeyspaceActionSpecificationFactoryBean.java @@ -32,6 +32,7 @@ import org.springframework.data.cassandra.core.cql.keyspace.KeyspaceActionSpecif import org.springframework.data.cassandra.core.cql.keyspace.KeyspaceOption; import org.springframework.data.cassandra.core.cql.keyspace.KeyspaceOption.ReplicationStrategy; import org.springframework.data.cassandra.core.cql.keyspace.Option; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -42,16 +43,16 @@ import org.springframework.util.Assert; * @author David Webb */ public class KeyspaceActionSpecificationFactoryBean - implements FactoryBean>>, InitializingBean, DisposableBean { + implements FactoryBean>, InitializingBean, DisposableBean { - private KeyspaceAction action; + private @Nullable KeyspaceAction action; - private String name; + private @Nullable String name; private List networkTopologyDataCenters = new LinkedList<>(); private List networkTopologyReplicationFactors = new LinkedList<>(); - private ReplicationStrategy replicationStrategy; + private @Nullable ReplicationStrategy replicationStrategy; private long replicationFactor; @@ -59,7 +60,7 @@ public class KeyspaceActionSpecificationFactoryBean private boolean ifNotExists = false; - private Set> specs = new HashSet<>(); + private Set specs = new HashSet<>(); /* (non-Javadoc) * @see org.springframework.beans.factory.DisposableBean#destroy() @@ -68,10 +69,10 @@ public class KeyspaceActionSpecificationFactoryBean public void destroy() { action = null; name = null; - networkTopologyDataCenters = null; - networkTopologyReplicationFactors = null; + networkTopologyDataCenters = new LinkedList<>(); + networkTopologyReplicationFactors = new LinkedList<>(); replicationStrategy = null; - specs = null; + specs = new HashSet<>(); } /* (non-Javadoc) @@ -102,8 +103,8 @@ public class KeyspaceActionSpecificationFactoryBean */ private CreateKeyspaceSpecification generateCreateKeyspaceSpecification() { - CreateKeyspaceSpecification create = new CreateKeyspaceSpecification(); - create.name(name).ifNotExists(ifNotExists).with(KeyspaceOption.DURABLE_WRITES, durableWrites); + CreateKeyspaceSpecification create = CreateKeyspaceSpecification.createKeyspace(name).ifNotExists(ifNotExists) + .with(KeyspaceOption.DURABLE_WRITES, durableWrites); Map replicationStrategyMap = new HashMap<>(); replicationStrategyMap.put(new DefaultOption("class", String.class, true, false, true), @@ -133,16 +134,14 @@ public class KeyspaceActionSpecificationFactoryBean * @return The {@link DropKeyspaceSpecification} */ private DropKeyspaceSpecification generateDropKeyspaceSpecification() { - DropKeyspaceSpecification drop = new DropKeyspaceSpecification(); - drop.name(getName()); - return drop; + return DropKeyspaceSpecification.dropKeyspace(getName()); } /* (non-Javadoc) * @see org.springframework.beans.factory.FactoryBean#getObject() */ @Override - public Set> getObject() throws Exception { + public Set getObject() { return specs; } @@ -165,6 +164,7 @@ public class KeyspaceActionSpecificationFactoryBean /** * @return Returns the name. */ + @Nullable public String getName() { return name; } @@ -193,6 +193,7 @@ public class KeyspaceActionSpecificationFactoryBean /** * @return Returns the action. */ + @Nullable public KeyspaceAction getAction() { return action; } @@ -221,6 +222,7 @@ public class KeyspaceActionSpecificationFactoryBean /** * @return Returns the replicationStrategy. */ + @Nullable public ReplicationStrategy getReplicationStrategy() { return replicationStrategy; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/ParsingUtils.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/ParsingUtils.java index 77152ba9a..c01c4b80d 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/ParsingUtils.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/ParsingUtils.java @@ -19,6 +19,7 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.w3c.dom.Attr; @@ -29,11 +30,6 @@ import org.w3c.dom.Element; * * @author John Blum * @author Mark Paluch - * @see org.springframework.beans.factory.config.BeanDefinition - * @see org.springframework.beans.factory.support.BeanDefinitionBuilder - * @see org.springframework.beans.factory.xml.ParserContext - * @see org.w3c.dom.Attr - * @see org.w3c.dom.Element */ abstract class ParsingUtils { @@ -129,7 +125,7 @@ abstract class ParsingUtils { * {@link #addProperty(BeanDefinitionBuilder, String, String, String, boolean, boolean)}. */ public static void addOptionalPropertyValue(BeanDefinitionBuilder builder, String propertyName, Element element, - String attributeName, String defaultValue) { + String attributeName, @Nullable String defaultValue) { addProperty(builder, propertyName, element.getAttribute(attributeName), defaultValue, false, false); } @@ -233,7 +229,7 @@ abstract class ParsingUtils { * @see BeanDefinitionBuilder#addPropertyValue(String, Object) */ public static BeanDefinitionBuilder addProperty(BeanDefinitionBuilder builder, String propertyName, String value, - String defaultValue, boolean required, boolean reference) { + @Nullable String defaultValue, boolean required, boolean reference) { Assert.notNull(builder, "BeanDefinitionBuilder must not be null"); Assert.hasText(propertyName, "Property name must not be null"); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/PoolingOptionsFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/PoolingOptionsFactoryBean.java index ad89db84c..3578117a9 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/PoolingOptionsFactoryBean.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/PoolingOptionsFactoryBean.java @@ -23,6 +23,7 @@ import java.util.concurrent.Executor; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.lang.Nullable; import org.springframework.util.ReflectionUtils; import com.datastax.driver.core.HostDistance; @@ -39,7 +40,7 @@ import com.datastax.driver.core.PoolingOptions; * @see org.springframework.beans.factory.InitializingBean * @see com.datastax.driver.core.PoolingOptions */ -@SuppressWarnings("unused") +@SuppressWarnings({ "unused", "WeakerAccess" }) public class PoolingOptionsFactoryBean implements FactoryBean, InitializingBean { private static final PoolingOptions DEFAULT = new PoolingOptions(); @@ -56,26 +57,26 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I GET_MAX_QUEUE_SIZE = Optional.ofNullable(ReflectionUtils.findMethod(PoolingOptions.class, "getMaxQueueSize")); } - private Executor initializationExecutor; + private @Nullable Executor initializationExecutor; private int heartbeatIntervalSeconds; private int idleTimeoutSeconds; - private Integer localCoreConnections; - private Integer localMaxConnections; - private Integer localMaxSimultaneousRequests; - private Integer localMinSimultaneousRequests; + private @Nullable Integer localCoreConnections; + private @Nullable Integer localMaxConnections; + private @Nullable Integer localMaxSimultaneousRequests; + private @Nullable Integer localMinSimultaneousRequests; // Deprecated since Cassandra Driver 3.1.1 private int poolTimeoutMilliseconds; // Available since Cassandra Driver 3.1.1 private int maxQueueSize; - private Integer remoteCoreConnections; - private Integer remoteMaxConnections; - private Integer remoteMaxSimultaneousRequests; - private Integer remoteMinSimultaneousRequests; + private @Nullable Integer remoteCoreConnections; + private @Nullable Integer remoteMaxConnections; + private @Nullable Integer remoteMaxSimultaneousRequests; + private @Nullable Integer remoteMinSimultaneousRequests; - private PoolingOptions poolingOptions; + private @Nullable PoolingOptions poolingOptions; /* * (non-Javadoc) @@ -137,7 +138,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * @see PoolingOptionsFactoryBean.LocalHostDistancePoolingOptions */ protected HostDistancePoolingOptions newLocalHostDistancePoolingOptions() { - return LocalHostDistancePoolingOptions.create(getLocalCoreConnections(), getLocalMaxConnections(), + return new LocalHostDistancePoolingOptions(getLocalCoreConnections(), getLocalMaxConnections(), getLocalMaxSimultaneousRequests(), getLocalMinSimultaneousRequests()); } @@ -153,7 +154,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * @see PoolingOptionsFactoryBean.RemoteHostDistancePoolingOptions */ protected HostDistancePoolingOptions newRemoteHostDistancePoolingOptions() { - return RemoteHostDistancePoolingOptions.create(getRemoteCoreConnections(), getRemoteMaxConnections(), + return new RemoteHostDistancePoolingOptions(getRemoteCoreConnections(), getRemoteMaxConnections(), getRemoteMaxSimultaneousRequests(), getRemoteMinSimultaneousRequests()); } @@ -260,6 +261,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * * @return the {@code initializationExecutor}. */ + @Nullable public Executor getInitializationExecutor() { return initializationExecutor; } @@ -305,7 +307,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * * @param localCoreConnections core number of local connections per host. */ - public void setLocalCoreConnections(Integer localCoreConnections) { + public void setLocalCoreConnections(@Nullable Integer localCoreConnections) { this.localCoreConnections = localCoreConnections; } @@ -314,6 +316,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * * @return the {@code localCoreConnections). */ + @Nullable public Integer getLocalCoreConnections() { return localCoreConnections; } @@ -323,7 +326,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * * @param localMaxConnections max number of local connections per host. */ - public void setLocalMaxConnections(Integer localMaxConnections) { + public void setLocalMaxConnections(@Nullable Integer localMaxConnections) { this.localMaxConnections = localMaxConnections; } @@ -332,6 +335,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * * @return the {@code localMaxConnections}. */ + @Nullable public Integer getLocalMaxConnections() { return localMaxConnections; } @@ -341,7 +345,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * * @param localMaxSimultaneousRequests max number of requests for local connections. */ - public void setLocalMaxSimultaneousRequests(Integer localMaxSimultaneousRequests) { + public void setLocalMaxSimultaneousRequests(@Nullable Integer localMaxSimultaneousRequests) { this.localMaxSimultaneousRequests = localMaxSimultaneousRequests; } @@ -350,6 +354,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * * @return the {@code localMaxSimultaneousRequests}. */ + @Nullable public Integer getLocalMaxSimultaneousRequests() { return localMaxSimultaneousRequests; } @@ -360,7 +365,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * * @param localMinSimultaneousRequests threshold triggering the creation of local connections to a host. */ - public void setLocalMinSimultaneousRequests(Integer localMinSimultaneousRequests) { + public void setLocalMinSimultaneousRequests(@Nullable Integer localMinSimultaneousRequests) { this.localMinSimultaneousRequests = localMinSimultaneousRequests; } @@ -370,6 +375,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * * @return the {@code localMinSimultaneousRequests}. */ + @Nullable public Integer getLocalMinSimultaneousRequests() { return localMinSimultaneousRequests; } @@ -379,7 +385,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * * @param remoteCoreConnections core number of remote connections per host. */ - public void setRemoteCoreConnections(Integer remoteCoreConnections) { + public void setRemoteCoreConnections(@Nullable Integer remoteCoreConnections) { this.remoteCoreConnections = remoteCoreConnections; } @@ -388,6 +394,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * * @return the {@code remoteCoreConnections). */ + @Nullable public Integer getRemoteCoreConnections() { return remoteCoreConnections; } @@ -397,7 +404,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * * @param remoteMaxConnections max number of remote connections per host. */ - public void setRemoteMaxConnections(Integer remoteMaxConnections) { + public void setRemoteMaxConnections(@Nullable Integer remoteMaxConnections) { this.remoteMaxConnections = remoteMaxConnections; } @@ -406,6 +413,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * * @return the {@code remoteMaxConnections}. */ + @Nullable public Integer getRemoteMaxConnections() { return remoteMaxConnections; } @@ -415,7 +423,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * * @param remoteMaxSimultaneousRequests max number of requests for local connections. */ - public void setRemoteMaxSimultaneousRequests(Integer remoteMaxSimultaneousRequests) { + public void setRemoteMaxSimultaneousRequests(@Nullable Integer remoteMaxSimultaneousRequests) { this.remoteMaxSimultaneousRequests = remoteMaxSimultaneousRequests; } @@ -424,6 +432,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * * @return the {@code remoteMaxSimultaneousRequests}. */ + @Nullable public Integer getRemoteMaxSimultaneousRequests() { return remoteMaxSimultaneousRequests; } @@ -434,7 +443,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * * @param remoteMinSimultaneousRequests threshold triggering the creation of remote connections to a host. */ - public void setRemoteMinSimultaneousRequests(Integer remoteMinSimultaneousRequests) { + public void setRemoteMinSimultaneousRequests(@Nullable Integer remoteMinSimultaneousRequests) { this.remoteMinSimultaneousRequests = remoteMinSimultaneousRequests; } @@ -444,6 +453,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * * @return the {@code remoteMinSimultaneousRequests}. */ + @Nullable public Integer getRemoteMinSimultaneousRequests() { return remoteMinSimultaneousRequests; } @@ -457,10 +467,10 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I */ protected static abstract class HostDistancePoolingOptions { - private final Integer coreConnectionsPerHost; - private final Integer maxConnectionsPerHost; - private final Integer maxRequestsPerConnection; - private final Integer newConnectionThreshold; + private final @Nullable Integer coreConnectionsPerHost; + private final @Nullable Integer maxConnectionsPerHost; + private final @Nullable Integer maxRequestsPerConnection; + private final @Nullable Integer newConnectionThreshold; /** * Constructs an instance of {@link HostDistancePoolingOptions} with {@link PoolingOptions} connection settings @@ -471,8 +481,9 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * @param maxRequestsPerConnection maximum number of requests per connection. * @param newConnectionThreshold threshold that triggers the creation of a new connection to a host. */ - protected HostDistancePoolingOptions(Integer coreConnectionsPerHost, Integer maxConnectionsPerHost, - Integer maxRequestsPerConnection, Integer newConnectionThreshold) { + protected HostDistancePoolingOptions(@Nullable Integer coreConnectionsPerHost, + @Nullable Integer maxConnectionsPerHost, @Nullable Integer maxRequestsPerConnection, + @Nullable Integer newConnectionThreshold) { this.coreConnectionsPerHost = coreConnectionsPerHost; this.maxConnectionsPerHost = maxConnectionsPerHost; @@ -492,12 +503,10 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * (non-Javadoc) * @see com.datastax.driver.core.PoolingOptions#setCoreConnectionsPerHost(HostDistance, int) */ - PoolingOptions setCoreConnectionsPerHost(PoolingOptions poolingOptions) { + void setCoreConnectionsPerHost(PoolingOptions poolingOptions) { if (coreConnectionsPerHost != null) { poolingOptions.setCoreConnectionsPerHost(getHostDistance(), coreConnectionsPerHost); } - - return poolingOptions; } /** @@ -507,6 +516,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * @see com.datastax.driver.core.PoolingOptions#getCoreConnectionsPerHost(HostDistance) * @see #getHostDistance() */ + @Nullable protected Integer getCoreConnectionsPerHost() { return coreConnectionsPerHost; } @@ -515,12 +525,10 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * (non-Javadoc) * @see com.datastax.driver.core.PoolingOptions#setMaxConnectionsPerHost(HostDistance, int) */ - PoolingOptions setMaxConnectionsPerHost(PoolingOptions poolingOptions) { + void setMaxConnectionsPerHost(PoolingOptions poolingOptions) { if (maxConnectionsPerHost != null) { poolingOptions.setMaxConnectionsPerHost(getHostDistance(), maxConnectionsPerHost); } - - return poolingOptions; } /** @@ -530,6 +538,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * @see com.datastax.driver.core.PoolingOptions#getMaxConnectionsPerHost(HostDistance) * @see #getHostDistance() */ + @Nullable protected Integer getMaxConnectionsPerHost() { return maxConnectionsPerHost; } @@ -538,12 +547,10 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * (non-Javadoc) * @see com.datastax.driver.core.PoolingOptions#setMaxRequestsPerConnection(HostDistance, int) */ - PoolingOptions setMaxRequestsPerConnection(PoolingOptions poolingOptions) { + void setMaxRequestsPerConnection(PoolingOptions poolingOptions) { if (maxRequestsPerConnection != null) { poolingOptions.setMaxRequestsPerConnection(getHostDistance(), maxRequestsPerConnection); } - - return poolingOptions; } /** @@ -553,6 +560,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * @see com.datastax.driver.core.PoolingOptions#getMaxRequestsPerConnection(HostDistance) * @see #getHostDistance() */ + @Nullable protected Integer getMaxRequestsPerConnection() { return maxRequestsPerConnection; } @@ -564,7 +572,8 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * * @see com.datastax.driver.core.PoolingOptions#setNewConnectionThreshold(HostDistance, int) */ - PoolingOptions setNewConnectionThreshold(PoolingOptions poolingOptions) { + void setNewConnectionThreshold(PoolingOptions poolingOptions) { + if (newConnectionThreshold != null) { int currentNewConnectionThreshold = poolingOptions.getNewConnectionThreshold(getHostDistance()); @@ -572,8 +581,6 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I poolingOptions.setNewConnectionThreshold(getHostDistance(), newConnectionThreshold); } } - - return poolingOptions; } /** @@ -583,6 +590,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * @see com.datastax.driver.core.PoolingOptions#getNewConnectionThreshold(HostDistance) * @see #getHostDistance() */ + @Nullable protected Integer getNewConnectionThreshold() { return newConnectionThreshold; } @@ -611,22 +619,6 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I */ static class LocalHostDistancePoolingOptions extends HostDistancePoolingOptions { - /** - * Creates an instance of {@link LocalHostDistancePoolingOptions} initialized with {@link PoolingOptions} based on - * {@link HostDistance#LOCAL}. - * - * @param coreConnectionsPerHost core number of connections per host. - * @param maxConnectionsPerHost maximum number of connections per host. - * @param maxRequestsPerConnection maximum number of requests per connection. - * @param newConnectionThreshold threshold that triggers the creation of a new connection to a host. - */ - static LocalHostDistancePoolingOptions create(Integer coreConnectionsPerHost, Integer maxConnectionsPerHost, - Integer maxRequestsPerConnection, Integer newConnectionThreshold) { - - return new LocalHostDistancePoolingOptions(coreConnectionsPerHost, maxConnectionsPerHost, - maxRequestsPerConnection, newConnectionThreshold); - } - /** * Constructs an instance of {@link LocalHostDistancePoolingOptions} initialized with {@link PoolingOptions} based * on {@link HostDistance#LOCAL}. @@ -636,8 +628,8 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * @param maxRequestsPerConnection maximum number of requests per connection. * @param newConnectionThreshold threshold that triggers the creation of a new connection to a host. */ - LocalHostDistancePoolingOptions(Integer coreConnectionsPerHost, Integer maxConnectionsPerHost, - Integer maxRequestsPerConnection, Integer newConnectionThreshold) { + LocalHostDistancePoolingOptions(@Nullable Integer coreConnectionsPerHost, @Nullable Integer maxConnectionsPerHost, + @Nullable Integer maxRequestsPerConnection, @Nullable Integer newConnectionThreshold) { super(coreConnectionsPerHost, maxConnectionsPerHost, maxRequestsPerConnection, newConnectionThreshold); } @@ -662,22 +654,6 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I */ static class RemoteHostDistancePoolingOptions extends HostDistancePoolingOptions { - /** - * Creates an instance of {@link RemoteHostDistancePoolingOptions} initialized with {@link PoolingOptions} based on - * {@link HostDistance#REMOTE}. - * - * @param coreConnectionsPerHost core number of connections per host. - * @param maxConnectionsPerHost maximum number of connections per host. - * @param maxRequestsPerConnection maximum number of requests per connection. - * @param newConnectionThreshold threshold that triggers the creation of a new connection to a host. - */ - static RemoteHostDistancePoolingOptions create(Integer coreConnectionsPerHost, Integer maxConnectionsPerHost, - Integer maxRequestsPerConnection, Integer newConnectionThreshold) { - - return new RemoteHostDistancePoolingOptions(coreConnectionsPerHost, maxConnectionsPerHost, - maxRequestsPerConnection, newConnectionThreshold); - } - /** * Constructs an instance of {@link RemoteHostDistancePoolingOptions} initialized with {@link PoolingOptions} based * on {@link HostDistance#REMOTE}. @@ -687,8 +663,8 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I * @param maxRequestsPerConnection maximum number of requests per connection. * @param newConnectionThreshold threshold that triggers the creation of a new connection to a host. */ - RemoteHostDistancePoolingOptions(Integer coreConnectionsPerHost, Integer maxConnectionsPerHost, - Integer maxRequestsPerConnection, Integer newConnectionThreshold) { + RemoteHostDistancePoolingOptions(@Nullable Integer coreConnectionsPerHost, @Nullable Integer maxConnectionsPerHost, + @Nullable Integer maxRequestsPerConnection, @Nullable Integer newConnectionThreshold) { super(coreConnectionsPerHost, maxConnectionsPerHost, maxRequestsPerConnection, newConnectionThreshold); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/SchemaAction.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/SchemaAction.java index 68ad1ea05..96673f895 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/SchemaAction.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/SchemaAction.java @@ -48,21 +48,4 @@ public enum SchemaAction { * Drop all tables in the keyspace, then create each table as necessary. */ RECREATE_DROP_UNUSED - - // TODO: - // /** - // * Alter or create each table and column as necessary, leaving unused tables and columns untouched. - // */ - // UPDATE, - // - // /** - // * Alter or create each table and column as necessary, removing unused tables and columns. - // */ - // UPDATE_DROP_UNUNSED, - // - // /** - // * Validate that each required table and column exists. Fail if any required table or column does not exists. - // */ - // VALIDATE - } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/SocketOptionsFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/SocketOptionsFactoryBean.java index 119418b2f..d386dbc5d 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/SocketOptionsFactoryBean.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/SocketOptionsFactoryBean.java @@ -18,6 +18,7 @@ package org.springframework.data.cassandra.config; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.lang.Nullable; import com.datastax.driver.core.SocketOptions; @@ -27,18 +28,19 @@ import com.datastax.driver.core.SocketOptions; * @author Matthew T. Adams * @author David Webb */ +@SuppressWarnings({ "unused", "WeakerAccess" }) public class SocketOptionsFactoryBean implements FactoryBean, InitializingBean, DisposableBean { - private Integer connectTimeoutMillis; - private Boolean keepAlive; - private Integer readTimeoutMillis; - private Boolean reuseAddress; - private Integer soLinger; - private Boolean tcpNoDelay; - private Integer receiveBufferSize; - private Integer sendBufferSize; + private @Nullable Integer connectTimeoutMillis; + private @Nullable Boolean keepAlive; + private @Nullable Integer readTimeoutMillis; + private @Nullable Boolean reuseAddress; + private @Nullable Integer soLinger; + private @Nullable Boolean tcpNoDelay; + private @Nullable Integer receiveBufferSize; + private @Nullable Integer sendBufferSize; - private SocketOptions socketOptions; + private @Nullable SocketOptions socketOptions; /* (non-Javadoc) * @see org.springframework.beans.factory.FactoryBean#getObject() @@ -122,57 +124,64 @@ public class SocketOptionsFactoryBean implements FactoryBean, Ini return true; } + @Nullable public Boolean getKeepAlive() { return keepAlive; } - public void setKeepAlive(Boolean keepAlive) { + public void setKeepAlive(@Nullable Boolean keepAlive) { this.keepAlive = keepAlive; } + @Nullable public Boolean getReuseAddress() { return reuseAddress; } - public void setReuseAddress(Boolean reuseAddress) { + public void setReuseAddress(@Nullable Boolean reuseAddress) { this.reuseAddress = reuseAddress; } + @Nullable public Integer getSoLinger() { return soLinger; } - public void setSoLinger(Integer soLinger) { + public void setSoLinger(@Nullable Integer soLinger) { this.soLinger = soLinger; } + @Nullable public Boolean getTcpNoDelay() { return tcpNoDelay; } - public void setTcpNoDelay(Boolean tcpNoDelay) { + public void setTcpNoDelay(@Nullable Boolean tcpNoDelay) { this.tcpNoDelay = tcpNoDelay; } + @Nullable public Integer getReceiveBufferSize() { return receiveBufferSize; } - public void setReceiveBufferSize(Integer receiveBufferSize) { + public void setReceiveBufferSize(@Nullable Integer receiveBufferSize) { this.receiveBufferSize = receiveBufferSize; } + @Nullable public Integer getSendBufferSize() { return sendBufferSize; } - public void setSendBufferSize(Integer sendBufferSize) { + public void setSendBufferSize(@Nullable Integer sendBufferSize) { this.sendBufferSize = sendBufferSize; } /** * @return Returns the connectTimeoutMillis. */ + @Nullable public Integer getConnectTimeoutMillis() { return connectTimeoutMillis; } @@ -180,13 +189,14 @@ public class SocketOptionsFactoryBean implements FactoryBean, Ini /** * @param connectTimeoutMillis The connectTimeoutMillis to set. */ - public void setConnectTimeoutMillis(Integer connectTimeoutMillis) { + public void setConnectTimeoutMillis(@Nullable Integer connectTimeoutMillis) { this.connectTimeoutMillis = connectTimeoutMillis; } /** * @return Returns the readTimeoutMillis. */ + @Nullable public Integer getReadTimeoutMillis() { return readTimeoutMillis; } @@ -194,7 +204,7 @@ public class SocketOptionsFactoryBean implements FactoryBean, Ini /** * @param readTimeoutMillis The readTimeoutMillis to set. */ - public void setReadTimeoutMillis(Integer readTimeoutMillis) { + public void setReadTimeoutMillis(@Nullable Integer readTimeoutMillis) { this.readTimeoutMillis = readTimeoutMillis; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/package-info.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/package-info.java index a22c3ade0..0619da9a4 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/package-info.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/package-info.java @@ -1,4 +1,7 @@ /** * Spring Data Cassandra {@link org.springframework.beans.factory.FactoryBean factory beans} and configuration. */ +@NonNullApi package org.springframework.data.cassandra.config; + +import org.springframework.lang.NonNullApi; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraOperations.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraOperations.java index 0f7170b29..cf2a907d4 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraOperations.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraOperations.java @@ -240,9 +240,10 @@ public interface AsyncCassandraOperations { * Insert the given entity applying {@link WriteOptions} and return the entity if the insert was applied. * * @param entity The entity to insert, must not be {@literal null}. - * @param options may be {@literal null}. + * @param options must not be {@literal null}. * @return the {@link WriteResult} for this operation. * @throws DataAccessException if there is any problem executing the query. + * @see InsertOptions#empty() */ ListenableFuture insert(Object entity, InsertOptions options) throws DataAccessException; @@ -259,9 +260,10 @@ public interface AsyncCassandraOperations { * Update the given entity applying {@link WriteOptions} and return the entity if the update was applied. * * @param entity The entity to update, must not be {@literal null}. - * @param options may be {@literal null}. + * @param options must not be {@literal null}. * @return the {@link WriteResult} for this operation. * @throws DataAccessException if there is any problem executing the query. + * @see UpdateOptions#empty() */ ListenableFuture update(Object entity, UpdateOptions options) throws DataAccessException; @@ -278,9 +280,10 @@ public interface AsyncCassandraOperations { * Delete the given entity applying {@link QueryOptions} and return the entity if the delete was applied. * * @param entity must not be {@literal null}. - * @param options may be {@literal null}. + * @param options must not be {@literal null}. * @return the {@link WriteResult} for this operation. * @throws DataAccessException if there is any problem executing the query. + * @see QueryOptions#empty() */ ListenableFuture delete(Object entity, QueryOptions options) throws DataAccessException; @@ -303,5 +306,4 @@ public interface AsyncCassandraOperations { * @throws DataAccessException if there is any problem executing the query. */ ListenableFuture truncate(Class entityClass) throws DataAccessException; - } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraTemplate.java index 9d32a0433..7cc2382d2 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraTemplate.java @@ -40,6 +40,7 @@ import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty; import org.springframework.data.cassandra.core.query.Query; import org.springframework.data.mapping.context.MappingContext; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.concurrent.ListenableFuture; @@ -417,7 +418,7 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations { */ @Override public ListenableFuture insert(T entity) { - return new MappingListenableFutureAdapter<>(insert(entity, null), writeResult -> entity); + return new MappingListenableFutureAdapter<>(insert(entity, InsertOptions.empty()), writeResult -> entity); } /* @@ -428,6 +429,7 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations { public ListenableFuture insert(Object entity, InsertOptions options) { Assert.notNull(entity, "Entity must not be null"); + Assert.notNull(options, "InsertOptions must not be null"); Insert insert = QueryUtils.createInsertQuery(getTableName(entity).toCql(), entity, options, getConverter()); @@ -441,7 +443,7 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations { */ @Override public ListenableFuture update(T entity) { - return new MappingListenableFutureAdapter<>(update(entity, null), writeResult -> entity); + return new MappingListenableFutureAdapter<>(update(entity, UpdateOptions.empty()), writeResult -> entity); } /* @@ -452,6 +454,7 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations { public ListenableFuture update(Object entity, UpdateOptions options) { Assert.notNull(entity, "Entity must not be null"); + Assert.notNull(options, "UpdateOptions must not be null"); Update update = QueryUtils.createUpdateQuery(getTableName(entity).toCql(), entity, options, getConverter()); @@ -465,7 +468,7 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations { */ @Override public ListenableFuture delete(T entity) { - return new MappingListenableFutureAdapter<>(delete(entity, null), writeResult -> entity); + return new MappingListenableFutureAdapter<>(delete(entity, QueryOptions.empty()), writeResult -> entity); } /* @@ -476,6 +479,7 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations { public ListenableFuture delete(Object entity, QueryOptions options) { Assert.notNull(entity, "Entity must not be null"); + Assert.notNull(options, "QueryOptions must not be null"); Delete delete = QueryUtils.createDeleteQuery(getTableName(entity).toCql(), entity, options, getConverter()); @@ -528,7 +532,7 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations { } @Override - protected T adapt(S adapteeResult) throws ExecutionException { + protected T adapt(@Nullable S adapteeResult) throws ExecutionException { return mapper.apply(adapteeResult); } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraAdminOperations.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraAdminOperations.java index 8c5f71695..c8d51d583 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraAdminOperations.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraAdminOperations.java @@ -78,5 +78,4 @@ public interface CassandraAdminOperations extends CassandraOperations { * @since 1.5 */ void dropUserType(CqlIdentifier typeName); - } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraAdminTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraAdminTemplate.java index f2351fe04..e50c0ee15 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraAdminTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraAdminTemplate.java @@ -126,6 +126,7 @@ public class CassandraAdminTemplate extends CassandraTemplate implements Cassand @Override public KeyspaceMetadata getKeyspaceMetadata() { + // noinspection ConstantConditions return getCqlOperations().execute((SessionCallback) session -> { KeyspaceMetadata keyspaceMetadata = session.getCluster().getMetadata().getKeyspace(session.getLoggedKeyspace()); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraBatchOperations.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraBatchOperations.java index 319367096..b14ccccfb 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraBatchOperations.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraBatchOperations.java @@ -129,5 +129,4 @@ public interface CassandraBatchOperations { * @throws IllegalStateException if the batch was already executed. */ CassandraBatchOperations delete(Iterable entities); - } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraBatchTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraBatchTemplate.java index 2aa15fc92..d4f251fdf 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraBatchTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraBatchTemplate.java @@ -18,6 +18,7 @@ package org.springframework.data.cassandra.core; import java.util.Arrays; import java.util.concurrent.atomic.AtomicBoolean; +import org.springframework.data.cassandra.core.cql.QueryOptions; import org.springframework.data.cassandra.core.cql.WriteOptions; import org.springframework.util.Assert; @@ -34,8 +35,6 @@ import com.datastax.driver.core.querybuilder.QueryBuilder; */ class CassandraBatchTemplate implements CassandraBatchOperations { - private static final WriteOptions EMPTY = new WriteOptions(); - private AtomicBoolean executed = new AtomicBoolean(); private final Batch batch; @@ -47,7 +46,7 @@ class CassandraBatchTemplate implements CassandraBatchOperations { * * @param operations must not be {@literal null}. */ - public CassandraBatchTemplate(CassandraOperations operations) { + CassandraBatchTemplate(CassandraOperations operations) { Assert.notNull(operations, "CassandraOperations must not be null"); @@ -65,9 +64,7 @@ class CassandraBatchTemplate implements CassandraBatchOperations { return WriteResult.of(operations.getCqlOperations().queryForResultSet(batch)); } - assertNotExecuted(); - - return null; // code won't reach this line + throw new IllegalStateException("This Cassandra Batch was already executed"); } /* (non-Javadoc) @@ -99,7 +96,7 @@ class CassandraBatchTemplate implements CassandraBatchOperations { */ @Override public CassandraBatchOperations insert(Iterable entities) { - return insert(entities, EMPTY); + return insert(entities, InsertOptions.empty()); } /* (non-Javadoc) @@ -137,7 +134,7 @@ class CassandraBatchTemplate implements CassandraBatchOperations { */ @Override public CassandraBatchOperations update(Iterable entities) { - return update(entities, EMPTY); + return update(entities, UpdateOptions.empty()); } /* (non-Javadoc) @@ -181,7 +178,8 @@ class CassandraBatchTemplate implements CassandraBatchOperations { for (Object entity : entities) { Assert.notNull(entity, "Entity must not be null"); - batch.add(QueryUtils.createDeleteQuery(getTableName(entity), entity, null, operations.getConverter())); + batch.add( + QueryUtils.createDeleteQuery(getTableName(entity), entity, QueryOptions.empty(), operations.getConverter())); } return this; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraOperations.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraOperations.java index e8d58a43a..1a42f50f1 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraOperations.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraOperations.java @@ -27,6 +27,7 @@ import org.springframework.data.cassandra.core.cql.QueryOptions; import org.springframework.data.cassandra.core.cql.WriteOptions; import org.springframework.data.cassandra.core.query.Query; import org.springframework.data.cassandra.core.query.Update; +import org.springframework.lang.Nullable; import com.datastax.driver.core.Statement; @@ -113,6 +114,7 @@ public interface CassandraOperations { * @return the converted object or {@literal null}. * @throws DataAccessException if there is any problem executing the query. */ + @Nullable T selectOne(String cql, Class entityClass) throws DataAccessException; // ------------------------------------------------------------------------- @@ -151,6 +153,7 @@ public interface CassandraOperations { * @return the converted object or {@literal null}. * @throws DataAccessException if there is any problem executing the query. */ + @Nullable T selectOne(Statement statement, Class entityClass) throws DataAccessException; // ------------------------------------------------------------------------- @@ -190,6 +193,7 @@ public interface CassandraOperations { * @throws DataAccessException if there is any problem executing the query. * @since 2.0 */ + @Nullable T selectOne(Query query, Class entityClass) throws DataAccessException; /** @@ -246,6 +250,7 @@ public interface CassandraOperations { * @return the converted object or {@literal null}. * @throws DataAccessException if there is any problem executing the query. */ + @Nullable T selectOneById(Object id, Class entityClass) throws DataAccessException; /** @@ -260,9 +265,10 @@ public interface CassandraOperations { * Insert the given entity applying {@link WriteOptions} and return the entity if the insert was applied. * * @param entity The entity to insert, must not be {@literal null}. - * @param options may be {@literal null}. + * @param options must not be {@literal null}. * @return the {@link WriteResult} for this operation. * @throws DataAccessException if there is any problem executing the query. + * @see InsertOptions#empty() */ WriteResult insert(Object entity, InsertOptions options) throws DataAccessException; @@ -278,9 +284,10 @@ public interface CassandraOperations { * Update the given entity applying {@link WriteOptions} and return the entity if the update was applied. * * @param entity The entity to update, must not be {@literal null}. - * @param options may be {@literal null}. + * @param options must not be {@literal null}. * @return the {@link WriteResult} for this operation. * @throws DataAccessException if there is any problem executing the query. + * @see UpdateOptions#empty() */ WriteResult update(Object entity, UpdateOptions options) throws DataAccessException; @@ -296,9 +303,10 @@ public interface CassandraOperations { * Delete the given entity applying {@link QueryOptions} and return the entity if the delete was applied. * * @param entity must not be {@literal null}. - * @param options may be {@literal null}. + * @param options must not be {@literal null}. * @return the {@link WriteResult} for this operation. * @throws DataAccessException if there is any problem executing the query. + * @see QueryOptions#empty() */ WriteResult delete(Object entity, QueryOptions options) throws DataAccessException; @@ -320,5 +328,4 @@ public interface CassandraOperations { * @throws DataAccessException if there is any problem executing the query. */ void truncate(Class entityClass) throws DataAccessException; - } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java index e9901c4bb..10f987b14 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java @@ -18,10 +18,7 @@ package org.springframework.data.cassandra.core; import lombok.NonNull; import lombok.Value; -import java.util.ArrayList; -import java.util.Collection; import java.util.List; -import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -286,8 +283,8 @@ public class CassandraTemplate implements CassandraOperations { Assert.notNull(query, "Query must not be null"); Assert.notNull(entityClass, "Entity type must not be null"); - return select(getStatementFactory().select(query, - getMappingContext().getRequiredPersistentEntity(entityClass)), entityClass); + return select(getStatementFactory().select(query, getMappingContext().getRequiredPersistentEntity(entityClass)), + entityClass); } /* (non-Javadoc) @@ -299,8 +296,8 @@ public class CassandraTemplate implements CassandraOperations { Assert.notNull(query, "Query must not be null"); Assert.notNull(entityClass, "Entity type must not be null"); - return stream(getStatementFactory().select(query, - getMappingContext().getRequiredPersistentEntity(entityClass)), entityClass); + return stream(getStatementFactory().select(query, getMappingContext().getRequiredPersistentEntity(entityClass)), + entityClass); } /* (non-Javadoc) @@ -325,8 +322,8 @@ public class CassandraTemplate implements CassandraOperations { Assert.notNull(update, "Update must not be null"); Assert.notNull(entityClass, "Entity type must not be null"); - return getCqlOperations().execute(getStatementFactory().update(query, update, - getMappingContext().getRequiredPersistentEntity(entityClass))); + return getCqlOperations().execute( + getStatementFactory().update(query, update, getMappingContext().getRequiredPersistentEntity(entityClass))); } /* (non-Javadoc) @@ -338,8 +335,8 @@ public class CassandraTemplate implements CassandraOperations { Assert.notNull(query, "Query must not be null"); Assert.notNull(entityClass, "Entity type must not be null"); - return getCqlOperations().execute(getStatementFactory().delete(query, - getMappingContext().getRequiredPersistentEntity(entityClass))); + return getCqlOperations() + .execute(getStatementFactory().delete(query, getMappingContext().getRequiredPersistentEntity(entityClass))); } // ------------------------------------------------------------------------- @@ -358,7 +355,9 @@ public class CassandraTemplate implements CassandraOperations { Select select = QueryBuilder.select().countAll() .from(getMappingContext().getRequiredPersistentEntity(entityClass).getTableName().toCql()); - return getCqlOperations().queryForObject(select, Long.class); + Long count = getCqlOperations().queryForObject(select, Long.class); + + return count != null ? count : 0L; } /* @@ -405,7 +404,7 @@ public class CassandraTemplate implements CassandraOperations { */ @Override public void insert(Object entity) { - insert(entity, null); + insert(entity, InsertOptions.empty()); } /* @@ -416,10 +415,11 @@ public class CassandraTemplate implements CassandraOperations { public WriteResult insert(Object entity, InsertOptions options) { Assert.notNull(entity, "Entity must not be null"); + Assert.notNull(options, "InsertOptions must not be null"); - Insert insert = QueryUtils.createInsertQuery( - getTableName(entity.getClass()).toCql(), entity, options, converter); + Insert insert = QueryUtils.createInsertQuery(getTableName(entity.getClass()).toCql(), entity, options, converter); + // noinspection ConstantConditions return getCqlOperations().execute(new StatementCallback(insert)); } @@ -429,7 +429,7 @@ public class CassandraTemplate implements CassandraOperations { */ @Override public void update(Object entity) { - update(entity, null); + update(entity, UpdateOptions.empty()); } /* @@ -440,10 +440,11 @@ public class CassandraTemplate implements CassandraOperations { public WriteResult update(Object entity, UpdateOptions options) { Assert.notNull(entity, "Entity must not be null"); + Assert.notNull(options, "UpdateOptions must not be null"); - Update update = QueryUtils.createUpdateQuery( - getTableName(entity.getClass()).toCql(), entity, options, converter); + Update update = QueryUtils.createUpdateQuery(getTableName(entity.getClass()).toCql(), entity, options, converter); + // noinspection ConstantConditions return getCqlOperations().execute(new StatementCallback(update)); } @@ -453,7 +454,7 @@ public class CassandraTemplate implements CassandraOperations { */ @Override public void delete(Object entity) { - delete(entity, null); + delete(entity, QueryOptions.empty()); } /* @@ -464,10 +465,11 @@ public class CassandraTemplate implements CassandraOperations { public WriteResult delete(Object entity, QueryOptions options) { Assert.notNull(entity, "Entity must not be null"); + Assert.notNull(options, "QueryOptions must not be null"); - Delete delete = QueryUtils.createDeleteQuery( - getTableName(entity.getClass()).toCql(), entity, options, converter); + Delete delete = QueryUtils.createDeleteQuery(getTableName(entity.getClass()).toCql(), entity, options, converter); + // noinspection ConstantConditions return getCqlOperations().execute(new StatementCallback(delete)); } @@ -499,8 +501,8 @@ public class CassandraTemplate implements CassandraOperations { Assert.notNull(entityClass, "Entity type must not be null"); - Truncate truncate = QueryBuilder.truncate( - getMappingContext().getRequiredPersistentEntity(entityClass).getTableName().toCql()); + Truncate truncate = QueryBuilder + .truncate(getMappingContext().getRequiredPersistentEntity(entityClass).getTableName().toCql()); getCqlOperations().execute(truncate); } @@ -528,19 +530,6 @@ public class CassandraTemplate implements CassandraOperations { return new CassandraBatchTemplate(this); } - private List toList(Iterable iterable) { - - if (iterable instanceof List) { - return (List) iterable; - } - - if (iterable instanceof Collection) { - return new ArrayList<>((Collection) iterable); - } - - return StreamSupport.stream(iterable.spliterator(), false).collect(Collectors.toList()); - } - @Value static class StatementCallback implements SessionCallback, CqlProvider { diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/InsertOptions.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/InsertOptions.java index fbe9f1b70..b1c831103 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/InsertOptions.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/InsertOptions.java @@ -15,9 +15,14 @@ */ package org.springframework.data.cassandra.core; +import java.time.Duration; import java.util.concurrent.TimeUnit; import org.springframework.data.cassandra.core.cql.WriteOptions; +import org.springframework.lang.Nullable; + +import com.datastax.driver.core.ConsistencyLevel; +import com.datastax.driver.core.policies.RetryPolicy; /** * Extension to {@link WriteOptions} for use with {@code INSERT} operations. @@ -27,12 +32,26 @@ import org.springframework.data.cassandra.core.cql.WriteOptions; */ public class InsertOptions extends WriteOptions { + private static final InsertOptions EMPTY = new InsertOptionsBuilder().build(); + private boolean ifNotExists; + private InsertOptions(@Nullable ConsistencyLevel consistencyLevel, @Nullable RetryPolicy retryPolicy, + @Nullable Boolean tracing, @Nullable Integer fetchSize, Duration readTimeout, Duration ttl, boolean ifNotExists) { + + super(consistencyLevel, retryPolicy, tracing, fetchSize, readTimeout, ttl); + this.ifNotExists = ifNotExists; + } + /** - * Creates new {@link InsertOptions}. + * Create default {@link InsertOptions}. + * + * @return default {@link InsertOptions}. + * @since 2.0 */ - InsertOptions() {} + public static InsertOptions empty() { + return EMPTY; + } /** * Create a new {@link InsertOptionsBuilder}. @@ -62,73 +81,52 @@ public class InsertOptions extends WriteOptions { private InsertOptionsBuilder() {} - /* - * (non-Javadoc) - * @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#consistencyLevel(com.datastax.driver.core.ConsistencyLevel) - */ @Override public InsertOptionsBuilder consistencyLevel(com.datastax.driver.core.ConsistencyLevel consistencyLevel) { return (InsertOptionsBuilder) super.consistencyLevel(consistencyLevel); } - /* - * (non-Javadoc) - * @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#retryPolicy(org.springframework.data.cassandra.core.cql.RetryPolicy) - */ @Override public InsertOptionsBuilder retryPolicy(com.datastax.driver.core.policies.RetryPolicy driverRetryPolicy) { return (InsertOptionsBuilder) super.retryPolicy(driverRetryPolicy); } - /* - * (non-Javadoc) - * @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#fetchSize(int) - */ @Override public InsertOptionsBuilder fetchSize(int fetchSize) { return (InsertOptionsBuilder) super.fetchSize(fetchSize); } - /* - * (non-Javadoc) - * @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#readTimeout(long) - */ @Override public InsertOptionsBuilder readTimeout(long readTimeout) { return (InsertOptionsBuilder) super.readTimeout(readTimeout); } - /* - * (non-Javadoc) - * @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#readTimeout(long, java.util.concurrent.TimeUnit) - */ @Override + @Deprecated public InsertOptionsBuilder readTimeout(long readTimeout, TimeUnit timeUnit) { return (InsertOptionsBuilder) super.readTimeout(readTimeout, timeUnit); } - /* - * (non-Javadoc) - * @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#tracing(boolean) - */ + @Override + public InsertOptionsBuilder readTimeout(Duration readTimeout) { + return (InsertOptionsBuilder) super.readTimeout(readTimeout); + } + + @Override + public InsertOptionsBuilder ttl(Duration ttl) { + return (InsertOptionsBuilder) super.ttl(ttl); + } + @Override public InsertOptionsBuilder tracing(boolean tracing) { return (InsertOptionsBuilder) super.tracing(tracing); } - /* - * (non-Javadoc) - * @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#withTracing() - */ @Override public InsertOptionsBuilder withTracing() { return (InsertOptionsBuilder) super.withTracing(); } - /* - * (non-Javadoc) - * @see org.springframework.data.cassandra.core.cql.WriteOptions.WriteOptionsBuilder#ttl(int) - */ public InsertOptionsBuilder ttl(int ttl) { return (InsertOptionsBuilder) super.ttl(ttl); } @@ -161,12 +159,7 @@ public class InsertOptions extends WriteOptions { * @return a new {@link InsertOptions} with the configured values */ public InsertOptions build() { - - InsertOptions insertOptions = applyOptions(new InsertOptions()); - - insertOptions.ifNotExists = this.ifNotExists; - - return insertOptions; + return new InsertOptions(consistencyLevel, retryPolicy, tracing, fetchSize, readTimeout, ttl, ifNotExists); } } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/QueryUtils.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/QueryUtils.java index 04680c4ca..16a0b015a 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/QueryUtils.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/QueryUtils.java @@ -46,7 +46,7 @@ class QueryUtils { * @param entityWriter the {@link EntityWriter} to write insert values. * @return The Query object to run with session.execute(); */ - public static Insert createInsertQuery(String tableName, Object objectToUpdate, WriteOptions options, + static Insert createInsertQuery(String tableName, Object objectToUpdate, WriteOptions options, EntityWriter entityWriter) { Assert.hasText(tableName, "TableName must not be empty"); @@ -75,11 +75,11 @@ class QueryUtils { * * @param tableName the table name, must not be empty and not {@literal null}. * @param objectToUpdate the object to update, must not be {@literal null}. - * @param options optional {@link WriteOptions} to apply to the {@link Update} statement, may be {@literal null}. + * @param options optional {@link WriteOptions} to apply to the {@link Update} statement. * @param entityWriter the {@link EntityWriter} to write update assignments and where clauses. * @return The Query object to run with session.execute(); */ - public static Update createUpdateQuery(String tableName, Object objectToUpdate, WriteOptions options, + static Update createUpdateQuery(String tableName, Object objectToUpdate, WriteOptions options, EntityWriter entityWriter) { Assert.hasText(tableName, "TableName must not be empty"); @@ -108,11 +108,11 @@ class QueryUtils { * * @param tableName the table name, must not be empty and not {@literal null}. * @param objectToDelete the object to delete, must not be {@literal null}. - * @param options optional {@link QueryOptions} to apply to the {@link Delete} statement, may be {@literal null}. + * @param options optional {@link QueryOptions} to apply to the {@link Delete} statement. * @param entityWriter the {@link EntityWriter} to write delete where clauses. * @return The Query object to run with session.execute(); */ - public static Delete createDeleteQuery(String tableName, Object objectToDelete, QueryOptions options, + static Delete createDeleteQuery(String tableName, Object objectToDelete, QueryOptions options, EntityWriter entityWriter) { Assert.hasText(tableName, "TableName must not be empty"); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraOperations.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraOperations.java index 33a6f783d..513ea417a 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraOperations.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraOperations.java @@ -186,9 +186,10 @@ public interface ReactiveCassandraOperations { * Insert the given entity applying {@link WriteOptions} and emit the entity if the insert was applied. * * @param entity The entity to insert, must not be {@literal null}. - * @param options may be {@literal null}. + * @param options must not be {@literal null}. * @return the {@link WriteResult} for this operation. * @throws DataAccessException if there is any problem issuing the execution. + * @see InsertOptions#empty() */ Mono insert(Object entity, InsertOptions options) throws DataAccessException; @@ -205,9 +206,10 @@ public interface ReactiveCassandraOperations { * Update the given entity applying {@link WriteOptions} and emit the entity if the update was applied. * * @param entity The entity to update, must not be {@literal null}. - * @param options may be {@literal null}. + * @param options must not be {@literal null}. * @return the {@link WriteResult} for this operation. * @throws DataAccessException if there is any problem issuing the execution. + * @see UpdateOptions#empty() */ Mono update(Object entity, UpdateOptions options) throws DataAccessException; @@ -224,9 +226,10 @@ public interface ReactiveCassandraOperations { * Delete the given entity applying {@link QueryOptions} and emit the entity if the delete was applied. * * @param entity must not be {@literal null}. - * @param options may be {@literal null}. + * @param options must not be {@literal null}. * @return the {@link WriteResult} for this operation. * @throws DataAccessException if there is any problem issuing the execution. + * @see QueryOptions#empty() */ Mono delete(Object entity, QueryOptions options) throws DataAccessException; @@ -264,5 +267,4 @@ public interface ReactiveCassandraOperations { * @see ReactiveCqlOperations */ ReactiveCqlOperations getReactiveCqlOperations(); - } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplate.java index 3187ba136..15a1b9fc9 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplate.java @@ -17,10 +17,10 @@ package org.springframework.data.cassandra.core; import lombok.NonNull; import lombok.Value; - import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import org.reactivestreams.Publisher; import org.springframework.dao.DataAccessException; import org.springframework.data.cassandra.ReactiveResultSet; import org.springframework.data.cassandra.ReactiveSession; @@ -44,8 +44,6 @@ import org.springframework.data.mapping.context.MappingContext; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; -import org.reactivestreams.Publisher; - import com.datastax.driver.core.Session; import com.datastax.driver.core.SimpleStatement; import com.datastax.driver.core.Statement; @@ -378,7 +376,7 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations { */ @Override public Mono insert(T entity) { - return insert(entity, null).map(writeResult -> entity); + return insert(entity, InsertOptions.empty()).map(writeResult -> entity); } /* @@ -389,6 +387,7 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations { public Mono insert(Object entity, InsertOptions options) { Assert.notNull(entity, "Entity must not be null"); + Assert.notNull(options, "InsertOptions must not be null"); Insert insert = QueryUtils.createInsertQuery(getTableName(entity).toCql(), entity, options, getConverter()); @@ -401,7 +400,7 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations { */ @Override public Mono update(T entity) { - return update(entity, null).map(writeResult -> entity); + return update(entity, UpdateOptions.empty()).map(writeResult -> entity); } /* @@ -412,6 +411,7 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations { public Mono update(Object entity, UpdateOptions options) { Assert.notNull(entity, "Entity must not be null"); + Assert.notNull(options, "UpdateOptions must not be null"); Update update = QueryUtils.createUpdateQuery(getTableName(entity).toCql(), entity, options, converter); @@ -424,7 +424,7 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations { */ @Override public Mono delete(T entity) { - return delete(entity, null).map(reactiveWriteResult -> entity); + return delete(entity, QueryOptions.empty()).map(reactiveWriteResult -> entity); } /* @@ -435,6 +435,7 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations { public Mono delete(Object entity, QueryOptions options) { Assert.notNull(entity, "Entity must not be null"); + Assert.notNull(options, "QueryOptions must not be null"); Delete delete = QueryUtils.createDeleteQuery(getTableName(entity).toCql(), entity, options, getConverter()); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/StatementFactory.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/StatementFactory.java index daa7182ad..3b4f31b6c 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/StatementFactory.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/StatementFactory.java @@ -140,8 +140,8 @@ public class StatementFactory { List selectors = getQueryMapper().getMappedSelectors(query.getColumns(), entity); - Sort sort = Optional.ofNullable(query.getSort()).map(querySort -> getQueryMapper().getMappedSort(querySort, entity)) - .orElse(null); + Sort sort = Optional.of(query.getSort()).map(querySort -> getQueryMapper().getMappedSort(querySort, entity)) + .orElse(Sort.unsorted()); Select select = select(selectors, entity.getTableName(), filter, sort); @@ -178,7 +178,7 @@ public class StatementFactory { select.where(toClause(criteriaDefinition)); } - if (sort != null) { + if (sort.isSorted()) { List orderings = new ArrayList<>(); for (Order order : sort) { @@ -412,7 +412,7 @@ public class StatementFactory { return QueryBuilder.in(columnName, (List) predicate.getValue()); } - if (predicate.getValue().getClass().isArray()) { + if (predicate.getValue() != null && predicate.getValue().getClass().isArray()) { return QueryBuilder.in(columnName, (Object[]) predicate.getValue()); } @@ -422,9 +422,13 @@ public class StatementFactory { return QueryBuilder.like(columnName, predicate.getValue()); case "CONTAINS": + Assert.state(predicate.getValue() != null, + () -> String.format("CONTAINS value for column %s is null", columnName)); return QueryBuilder.contains(columnName, predicate.getValue()); case "CONTAINS KEY": + Assert.state(predicate.getValue() != null, + () -> String.format("CONTAINS KEY value for column %s is null", columnName)); return QueryBuilder.containsKey(columnName, predicate.getValue()); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/UpdateOptions.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/UpdateOptions.java index 7d15edeaf..58f95f243 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/UpdateOptions.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/UpdateOptions.java @@ -15,9 +15,14 @@ */ package org.springframework.data.cassandra.core; +import java.time.Duration; import java.util.concurrent.TimeUnit; import org.springframework.data.cassandra.core.cql.WriteOptions; +import org.springframework.lang.Nullable; + +import com.datastax.driver.core.ConsistencyLevel; +import com.datastax.driver.core.policies.RetryPolicy; /** * Extension to {@link WriteOptions} for use with {@code UPDATE} operations. @@ -27,12 +32,26 @@ import org.springframework.data.cassandra.core.cql.WriteOptions; */ public class UpdateOptions extends WriteOptions { + private static final UpdateOptions EMPTY = new UpdateOptionsBuilder().build(); + private boolean ifExists; + private UpdateOptions(@Nullable ConsistencyLevel consistencyLevel, @Nullable RetryPolicy retryPolicy, + @Nullable Boolean tracing, @Nullable Integer fetchSize, Duration readTimeout, Duration ttl, boolean ifExists) { + + super(consistencyLevel, retryPolicy, tracing, fetchSize, readTimeout, ttl); + this.ifExists = ifExists; + } + /** - * Creates new {@link UpdateOptions}. + * Create default {@link UpdateOptions}. + * + * @return default {@link UpdateOptions}. + * @since 2.0 */ - UpdateOptions() {} + public static UpdateOptions empty() { + return EMPTY; + } /** * Create a new {@link UpdateOptionsBuilder}. @@ -62,73 +81,52 @@ public class UpdateOptions extends WriteOptions { private UpdateOptionsBuilder() {} - /* - * (non-Javadoc) - * @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#consistencyLevel(com.datastax.driver.core.ConsistencyLevel) - */ @Override public UpdateOptionsBuilder consistencyLevel(com.datastax.driver.core.ConsistencyLevel consistencyLevel) { return (UpdateOptionsBuilder) super.consistencyLevel(consistencyLevel); } - /* - * (non-Javadoc) - * @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#retryPolicy(org.springframework.data.cassandra.core.cql.RetryPolicy) - */ @Override public UpdateOptionsBuilder retryPolicy(com.datastax.driver.core.policies.RetryPolicy driverRetryPolicy) { return (UpdateOptionsBuilder) super.retryPolicy(driverRetryPolicy); } - /* - * (non-Javadoc) - * @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#fetchSize(int) - */ @Override public UpdateOptionsBuilder fetchSize(int fetchSize) { return (UpdateOptionsBuilder) super.fetchSize(fetchSize); } - /* - * (non-Javadoc) - * @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#readTimeout(long) - */ @Override public UpdateOptionsBuilder readTimeout(long readTimeout) { return (UpdateOptionsBuilder) super.readTimeout(readTimeout); } - /* - * (non-Javadoc) - * @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#readTimeout(long, java.util.concurrent.TimeUnit) - */ @Override + @Deprecated public UpdateOptionsBuilder readTimeout(long readTimeout, TimeUnit timeUnit) { return (UpdateOptionsBuilder) super.readTimeout(readTimeout, timeUnit); } - /* - * (non-Javadoc) - * @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#tracing(boolean) - */ + @Override + public UpdateOptionsBuilder readTimeout(Duration readTimeout) { + return (UpdateOptionsBuilder) super.readTimeout(readTimeout); + } + + @Override + public UpdateOptionsBuilder ttl(Duration ttl) { + return (UpdateOptionsBuilder) super.ttl(ttl); + } + @Override public UpdateOptionsBuilder tracing(boolean tracing) { return (UpdateOptionsBuilder) super.tracing(tracing); } - /* - * (non-Javadoc) - * @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#withTracing() - */ @Override public UpdateOptionsBuilder withTracing() { return (UpdateOptionsBuilder) super.withTracing(); } - /* - * (non-Javadoc) - * @see org.springframework.data.cassandra.core.cql.WriteOptions.WriteOptionsBuilder#ttl(int) - */ public UpdateOptionsBuilder ttl(int ttl) { return (UpdateOptionsBuilder) super.ttl(ttl); } @@ -161,12 +159,7 @@ public class UpdateOptions extends WriteOptions { * @return a new {@link UpdateOptions} with the configured values */ public UpdateOptions build() { - - UpdateOptions insertOptions = applyOptions(new UpdateOptions()); - - insertOptions.ifExists = this.ifExists; - - return insertOptions; + return new UpdateOptions(consistencyLevel, retryPolicy, tracing, fetchSize, readTimeout, ttl, ifExists); } } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/WriteResult.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/WriteResult.java index 536e054b8..f1583deb8 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/WriteResult.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/WriteResult.java @@ -35,7 +35,6 @@ import com.datastax.driver.core.Row; public class WriteResult { private final boolean wasApplied; - private final List executionInfo; private final List rows; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/AbstractCassandraConverter.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/AbstractCassandraConverter.java index bf6b56dac..c5d2164ce 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/AbstractCassandraConverter.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/AbstractCassandraConverter.java @@ -19,10 +19,10 @@ import java.util.Collections; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.convert.ConversionService; -import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.core.convert.support.GenericConversionService; import org.springframework.data.convert.CustomConversions; import org.springframework.data.convert.EntityInstantiators; +import org.springframework.util.Assert; /** * Base class for {@link CassandraConverter} implementations. Sets up a {@link ConversionService} and populates basic @@ -36,32 +36,36 @@ import org.springframework.data.convert.EntityInstantiators; */ public abstract class AbstractCassandraConverter implements CassandraConverter, InitializingBean { - protected final ConversionService conversionService; + private final ConversionService conversionService; - protected CustomConversions conversions = new CassandraCustomConversions(Collections.emptyList()); + private CustomConversions conversions = new CassandraCustomConversions(Collections.emptyList()); - protected EntityInstantiators instantiators = new EntityInstantiators(); + EntityInstantiators instantiators = new EntityInstantiators(); /** * Create a new {@link AbstractCassandraConverter} using the given {@link ConversionService}. */ - public AbstractCassandraConverter(ConversionService conversionService) { - this.conversionService = conversionService == null ? new DefaultConversionService() : conversionService; + protected AbstractCassandraConverter(ConversionService conversionService) { + + Assert.notNull(conversionService, "ConversionService must not be null"); + + this.conversionService = conversionService; } /** * Registers {@link EntityInstantiators} to customize entity instantiation. * - * @param instantiators + * @param instantiators must not be {@literal null}. */ public void setInstantiators(EntityInstantiators instantiators) { - this.instantiators = instantiators == null ? new EntityInstantiators() : instantiators; + + Assert.notNull(instantiators, "EntityInstantiators must not be null"); + + this.instantiators = instantiators; } /** * Registers the given custom conversions with the converter. - * - * @param conversions */ public void setCustomConversions(CustomConversions conversions) { this.conversions = conversions; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/BasicCassandraRowValueProvider.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/BasicCassandraRowValueProvider.java index ea86930da..05fe68cde 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/BasicCassandraRowValueProvider.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/BasicCassandraRowValueProvider.java @@ -18,6 +18,7 @@ package org.springframework.data.cassandra.core.convert; import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty; import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator; import org.springframework.data.mapping.model.SpELExpressionEvaluator; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import com.datastax.driver.core.Row; @@ -55,6 +56,7 @@ public class BasicCassandraRowValueProvider implements CassandraRowValueProvider /* (non-Javadoc) * @see org.springframework.data.mapping.model.PropertyValueProvider#getPropertyValue(org.springframework.data.mapping.PersistentProperty) */ + @Nullable @Override @SuppressWarnings("unchecked") public T getPropertyValue(CassandraPersistentProperty property) { diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/CassandraConverter.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/CassandraConverter.java index e485c1931..d0c4fe670 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/CassandraConverter.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/CassandraConverter.java @@ -22,6 +22,7 @@ import org.springframework.data.cassandra.core.mapping.MapId; import org.springframework.data.convert.CustomConversions; import org.springframework.data.convert.EntityConverter; import org.springframework.data.util.TypeInformation; +import org.springframework.lang.Nullable; /** * Central Cassandra specific converter interface from Object to Row. @@ -61,6 +62,7 @@ public interface CassandraConverter * @param entity must not be {@literal null}. * @return */ + @Nullable Object getId(Object object, CassandraPersistentEntity entity); /** @@ -76,7 +78,7 @@ public interface CassandraConverter * Converts the given object into a value Cassandra will be able to store natively in a column. * * @param value {@link Object} to convert; must not be {@literal null}. - * @param typeInformation {@link TypeInformation} used to describe the object type; may be {@literal null}. + * @param typeInformation {@link TypeInformation} used to describe the object type; must not be {@literal null}. * @return the result of the conversion. * @since 1.5 */ @@ -85,10 +87,9 @@ public interface CassandraConverter /** * Converts and writes a {@code source} object into a {@code sink} using the given {@link CassandraPersistentEntity}. * - * @param source the source, may be {@literal null}. + * @param source the source, must not be {@literal null}. * @param sink must not be {@literal null}. * @param entity must not be {@literal null}. */ void write(Object source, Object sink, CassandraPersistentEntity entity); - } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/CassandraConverters.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/CassandraConverters.java index 9ae0582a8..de82dd3ba 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/CassandraConverters.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/CassandraConverters.java @@ -140,7 +140,7 @@ abstract class CassandraConverters { private final Class targetType; - public RowToNumber(Class targetType) { + RowToNumber(Class targetType) { this.targetType = targetType; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/CassandraCustomConversions.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/CassandraCustomConversions.java index 18b51f3d3..50e591832 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/CassandraCustomConversions.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/CassandraCustomConversions.java @@ -38,6 +38,7 @@ public class CassandraCustomConversions extends org.springframework.data.convert private static final List STORE_CONVERTERS; static { + List converters = new ArrayList<>(); converters.addAll(CassandraConverters.getConvertersToRegister()); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/CassandraUDTValueProvider.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/CassandraUDTValueProvider.java index 2503fd478..0e464911f 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/CassandraUDTValueProvider.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/CassandraUDTValueProvider.java @@ -18,6 +18,7 @@ package org.springframework.data.cassandra.core.convert; import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty; import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator; import org.springframework.data.mapping.model.SpELExpressionEvaluator; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import com.datastax.driver.core.CodecRegistry; @@ -61,6 +62,7 @@ public class CassandraUDTValueProvider implements CassandraValueProvider { /* (non-Javadoc) * @see org.springframework.data.mapping.model.PropertyValueProvider#getPropertyValue(org.springframework.data.mapping.PersistentProperty) */ + @Nullable @SuppressWarnings("unchecked") public T getPropertyValue(CassandraPersistentProperty property) { diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/ColumnReader.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/ColumnReader.java index 1cd6b233e..df7d0b5c5 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/ColumnReader.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/ColumnReader.java @@ -18,6 +18,7 @@ package org.springframework.data.cassandra.core.convert; import java.util.List; import org.springframework.data.cassandra.core.cql.CqlIdentifier; +import org.springframework.lang.Nullable; import com.datastax.driver.core.CodecRegistry; import com.datastax.driver.core.ColumnDefinitions; @@ -40,6 +41,7 @@ public class ColumnReader { private final CodecRegistry codecRegistry; public ColumnReader(Row row) { + this.row = row; this.columns = row.getColumnDefinitions(); this.codecRegistry = CodecRegistry.DEFAULT_INSTANCE; @@ -48,6 +50,7 @@ public class ColumnReader { /** * Returns the row's column value. */ + @Nullable public Object get(CqlIdentifier name) { return get(name.toCql()); } @@ -55,6 +58,7 @@ public class ColumnReader { /** * Returns the row's column value. */ + @Nullable public Object get(String name) { int indexOf = getColumnIndex(name); return get(indexOf); @@ -66,6 +70,7 @@ public class ColumnReader { * @param index * @return */ + @Nullable public Object get(int index) { if (row.isNull(index)) { @@ -89,6 +94,7 @@ public class ColumnReader { return row.getObject(index); } + @Nullable public Object getCollection(int i, DataType type) { List collectionTypes = type.getTypeArguments(); @@ -131,6 +137,7 @@ public class ColumnReader { * * @throws ClassCastException if the value cannot be converted to the requested type. */ + @Nullable public T get(CqlIdentifier name, Class requestedType) { return get(getColumnIndex(name.toCql()), requestedType); } @@ -140,6 +147,7 @@ public class ColumnReader { * * @throws ClassCastException if the value cannot be converted to the requested type. */ + @Nullable public T get(String name, Class requestedType) { return get(columns.getIndexOf(name), requestedType); } @@ -149,6 +157,7 @@ public class ColumnReader { * * @throws ClassCastException if the value cannot be converted to the requested type. */ + @Nullable @SuppressWarnings("unchecked") public T get(int i, Class requestedType) { diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverter.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverter.java index b7a3ea68b..79207d540 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverter.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverter.java @@ -51,6 +51,7 @@ import org.springframework.data.mapping.model.PersistentEntityParameterValueProv import org.springframework.data.mapping.model.SpELContext; import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.TypeInformation; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; @@ -86,7 +87,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter private final CassandraMappingContext mappingContext; - private ClassLoader beanClassLoader; + private @Nullable ClassLoader beanClassLoader; private SpELContext spELContext; @@ -151,6 +152,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter * @param row must not be {@literal null}. * @return the converted valued. */ + @Nullable @SuppressWarnings("unchecked") public R readRow(Class type, Row row) { @@ -302,24 +304,22 @@ public class MappingCassandraConverter extends AbstractCassandraConverter @Override public Object convertToColumnType(Object value, TypeInformation typeInformation) { + Assert.notNull(value, "Value must not be null"); Assert.notNull(typeInformation, "TypeInformation must not be null"); - if (value == null) { - return null; - } - + // noinspection ConstantConditions return value.getClass().isArray() ? value : getWriteValue(value, typeInformation); } @Override public void write(Object source, Object sink) { - if (source != null) { - Class beanClassLoaderClass = transformClassToBeanClassLoaderClass(source.getClass()); - CassandraPersistentEntity entity = getMappingContext().getRequiredPersistentEntity(beanClassLoaderClass); + Assert.notNull(source, "Value must not be null"); - write(source, sink, entity); - } + Class beanClassLoaderClass = transformClassToBeanClassLoaderClass(source.getClass()); + CassandraPersistentEntity entity = getMappingContext().getRequiredPersistentEntity(beanClassLoaderClass); + + write(source, sink, entity); } @SuppressWarnings("unchecked") @@ -335,9 +335,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter @SuppressWarnings("unchecked") public void write(Object source, Object sink, CassandraPersistentEntity entity) { - if (source == null) { - return; - } + Assert.notNull(source, "Value must not be null"); if (entity == null) { throw new MappingException("No mapping metadata found for " + source.getClass()); @@ -360,11 +358,11 @@ public class MappingCassandraConverter extends AbstractCassandraConverter } } - protected void writeInsertFromObject(final Object object, final Insert insert, CassandraPersistentEntity entity) { + protected void writeInsertFromObject(Object object, Insert insert, CassandraPersistentEntity entity) { writeInsertFromWrapper(getConvertingAccessor(object, entity), insert, entity); } - private void writeMapFromWrapper(final ConvertingPropertyAccessor accessor, final Map insert, + private void writeMapFromWrapper(ConvertingPropertyAccessor accessor, Map insert, CassandraPersistentEntity entity) { for (CassandraPersistentProperty property : entity) { @@ -381,6 +379,10 @@ public class MappingCassandraConverter extends AbstractCassandraConverter log.debug("Property is a compositeKey"); } + if (value == null) { + continue; + } + CassandraPersistentEntity compositePrimaryKey = mappingContext.getRequiredPersistentEntity(property); writeMapFromWrapper(getConvertingAccessor(value, compositePrimaryKey), insert, compositePrimaryKey); @@ -412,6 +414,10 @@ public class MappingCassandraConverter extends AbstractCassandraConverter log.debug("Property is a compositeKey"); } + if (value == null) { + continue; + } + CassandraPersistentEntity compositePrimaryKey = mappingContext.getRequiredPersistentEntity(property); writeInsertFromWrapper(getConvertingAccessor(value, compositePrimaryKey), insert, compositePrimaryKey); @@ -445,7 +451,12 @@ public class MappingCassandraConverter extends AbstractCassandraConverter CassandraPersistentEntity compositePrimaryKey = mappingContext.getRequiredPersistentEntity(property); + if (value == null) { + continue; + } + writeUpdateFromWrapper(getConvertingAccessor(value, compositePrimaryKey), update, compositePrimaryKey); + continue; } @@ -696,6 +707,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter * @param accessor the property accessor * @return the return value, may be {@literal null}. */ + @Nullable @SuppressWarnings("unchecked") private T getWriteValue(CassandraPersistentProperty property, ConvertingPropertyAccessor accessor) { return (T) getWriteValue(accessor.getProperty(property, (Class) getTargetType(property)), @@ -710,8 +722,9 @@ public class MappingCassandraConverter extends AbstractCassandraConverter * @param typeInformation the type information. * @return the return value, may be {@literal null}. */ + @Nullable @SuppressWarnings("unchecked") - private Object getWriteValue(Object value, TypeInformation typeInformation) { + private Object getWriteValue(@Nullable Object value, @Nullable TypeInformation typeInformation) { if (value == null) { return null; @@ -735,7 +748,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter TypeInformation type = typeInformation != null ? typeInformation : ClassTypeInformation.from((Class) value.getClass()); - TypeInformation actualType = type.getActualType(); + TypeInformation actualType = type.getRequiredActualType(); if (value instanceof Collection) { @@ -771,7 +784,8 @@ public class MappingCassandraConverter extends AbstractCassandraConverter * @see CassandraType */ @SuppressWarnings("unchecked") - private Object getPotentiallyConvertedSimpleValue(Object value, Class requestedTargetType) { + @Nullable + private Object getPotentiallyConvertedSimpleValue(@Nullable Object value, @Nullable Class requestedTargetType) { if (value == null) { return null; @@ -800,8 +814,9 @@ public class MappingCassandraConverter extends AbstractCassandraConverter * @param target must not be {@literal null}. * @return the converted value. */ + @Nullable @SuppressWarnings({ "rawtypes", "unchecked" }) - private Object getPotentiallyConvertedSimpleRead(Object value, Class target) { + private Object getPotentiallyConvertedSimpleRead(@Nullable Object value, @Nullable Class target) { if (value == null || target == null || target.isAssignableFrom(value.getClass())) { return value; @@ -847,6 +862,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter * @param property the property. * @return the return value, may be {@literal null}. */ + @Nullable @SuppressWarnings("unchecked") protected Object getReadValue(CassandraValueProvider row, CassandraPersistentProperty property) { @@ -899,6 +915,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter * @param sourceValue must not be {@literal null}. * @return the converted {@link Collection} or array, will never be {@literal null}. */ + @Nullable @SuppressWarnings({ "rawtypes", "unchecked" }) private Object readCollectionOrArray(TypeInformation targetType, Collection sourceValue) { @@ -917,7 +934,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter return getPotentiallyConvertedSimpleRead(items, collectionType); } - BasicCassandraPersistentEntity entity = getMappingContext().getPersistentEntity(componentType); + BasicCassandraPersistentEntity entity = getMappingContext().getPersistentEntity(rawComponentType); if (entity != null && entity.isUserDefinedType()) { @@ -961,7 +978,9 @@ public class MappingCassandraConverter extends AbstractCassandraConverter /* (non-Javadoc) * @see org.springframework.data.mapping.model.PropertyValueProvider#getPropertyValue(org.springframework.data.mapping.PersistentProperty) */ + @Nullable @Override + @SuppressWarnings("unchecked") public T getPropertyValue(CassandraPersistentProperty property) { return (T) getReadValue(parent, property); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/QueryMapper.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/QueryMapper.java index 92d03e004..18015690c 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/QueryMapper.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/QueryMapper.java @@ -46,22 +46,18 @@ import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.context.PersistentPropertyPath; import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.TypeInformation; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** * Map {@link org.springframework.data.cassandra.core.query.Query} to CQL-specific data types. * * @author Mark Paluch - * @see org.springframework.data.cassandra.core.query.ColumnName - * @see org.springframework.data.cassandra.core.query.Columns - * @see org.springframework.data.cassandra.core.query.Criteria - * @see org.springframework.data.cassandra.core.query.Filter - * @see org.springframework.data.domain.Sort - * @see org.springframework.data.mapping.PersistentProperty - * @see org.springframework.data.mapping.PropertyPath - * @see org.springframework.data.mapping.context.MappingContext - * @see org.springframework.data.mapping.context.PersistentPropertyPath - * @see org.springframework.data.util.TypeInformation + * @see ColumnName + * @see Columns + * @see Criteria + * @see Filter + * @see Sort * @since 2.0 */ public class QueryMapper { @@ -131,7 +127,7 @@ public class QueryMapper { Object value = predicate.getValue(); TypeInformation typeInformation = getTypeInformation(field, value); - Object mappedValue = getConverter().convertToColumnType(value, typeInformation); + Object mappedValue = value != null ? getConverter().convertToColumnType(value, typeInformation) : null; Predicate mappedPredicate = new Predicate(predicate.getOperator(), mappedValue); @@ -328,18 +324,13 @@ public class QueryMapper { } } - /** - * @param entity - * @param key - * @return - */ protected Field createPropertyField(CassandraPersistentEntity entity, ColumnName key) { - return Optional.ofNullable(entity). map(e -> new MetadataBackedField(key, e, getMappingContext())) + return Optional.of(entity). map(e -> new MetadataBackedField(key, e, getMappingContext())) .orElseGet(() -> new Field(key)); } @SuppressWarnings("unchecked") - TypeInformation getTypeInformation(Field field, Object value) { + TypeInformation getTypeInformation(Field field, @Nullable Object value) { if (field.getProperty().isPresent()) { return field.getProperty().get().getTypeInformation(); @@ -366,7 +357,7 @@ public class QueryMapper { * * @param name must not be {@literal null} or empty. */ - public Field(ColumnName name) { + Field(ColumnName name) { Assert.notNull(name, "Name must not be null!"); this.name = name; } @@ -385,8 +376,6 @@ public class QueryMapper { * Returns the underlying {@link CassandraPersistentProperty} backing the field. For path traversals this will be * the property that represents the value to handle. This means it'll be the leaf property for plain paths or the * association property in case we refer to an association somewhere in the path. - * - * @return */ public Optional getProperty() { return Optional.empty(); @@ -394,8 +383,6 @@ public class QueryMapper { /** * Returns the key to be used in the mapped document eventually. - * - * @return */ public ColumnName getMappedKey() { return name; @@ -412,7 +399,7 @@ public class QueryMapper { private final CassandraPersistentEntity entity; private final MappingContext, CassandraPersistentProperty> mappingContext; private final Optional> path; - private final CassandraPersistentProperty property; + private final @Nullable CassandraPersistentProperty property; private final Optional optionalProperty; /** @@ -440,7 +427,7 @@ public class QueryMapper { */ public MetadataBackedField(ColumnName name, CassandraPersistentEntity entity, MappingContext, CassandraPersistentProperty> mappingContext, - CassandraPersistentProperty property) { + @Nullable CassandraPersistentProperty property) { super(name); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/RowReaderPropertyAccessor.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/RowReaderPropertyAccessor.java index 76cacee0a..997b88e92 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/RowReaderPropertyAccessor.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/RowReaderPropertyAccessor.java @@ -18,6 +18,7 @@ package org.springframework.data.cassandra.core.convert; import org.springframework.expression.EvaluationContext; import org.springframework.expression.PropertyAccessor; import org.springframework.expression.TypedValue; +import org.springframework.lang.Nullable; import com.datastax.driver.core.Row; @@ -38,12 +39,16 @@ enum RowReaderPropertyAccessor implements PropertyAccessor { } @Override - public boolean canRead(EvaluationContext context, Object target, String name) { - return ((Row) target).getColumnDefinitions().contains(name); + public boolean canRead(EvaluationContext context, @Nullable Object target, String name) { + return target != null && ((Row) target).getColumnDefinitions().contains(name); } @Override - public TypedValue read(EvaluationContext context, Object target, String name) { + public TypedValue read(EvaluationContext context, @Nullable Object target, String name) { + + if (target == null) { + return TypedValue.NULL; + } Row row = (Row) target; @@ -55,12 +60,12 @@ enum RowReaderPropertyAccessor implements PropertyAccessor { } @Override - public boolean canWrite(EvaluationContext context, Object target, String name) { + public boolean canWrite(EvaluationContext context, @Nullable Object target, String name) { return false; } @Override - public void write(EvaluationContext context, Object target, String name, Object newValue) { + public void write(EvaluationContext context, @Nullable Object target, String name, @Nullable Object newValue) { throw new UnsupportedOperationException(); } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/UpdateMapper.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/UpdateMapper.java index 6ca8eb899..3c292b415 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/UpdateMapper.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/UpdateMapper.java @@ -120,12 +120,13 @@ public class UpdateMapper extends QueryMapper { Object rawValue = updateOp.getValue(); - Object value = rawValue; - if (updateOp instanceof SetAtKeyOp) { SetAtKeyOp op = (SetAtKeyOp) updateOp; + Assert.state(op.getValue() != null, + () -> String.format("SetAtKeyOp for %s attempts to set null", field.getProperty())); + Optional> typeInformation = field.getProperty() .map(PersistentProperty::getTypeInformation); @@ -141,12 +142,15 @@ public class UpdateMapper extends QueryMapper { return new SetAtKeyOp(field.getMappedKey(), mappedKey, mappedValue); } - TypeInformation typeInformation = getTypeInformation(field, value); + TypeInformation typeInformation = getTypeInformation(field, rawValue); if (updateOp instanceof SetAtIndexOp) { SetAtIndexOp op = (SetAtIndexOp) updateOp; + Assert.state(op.getValue() != null, + () -> String.format("SetAtIndexOp for %s attempts to set null", field.getProperty())); + Object mappedValue = getConverter().convertToColumnType(op.getValue(), typeInformation); return new SetAtIndexOp(field.getMappedKey(), op.getIndex(), mappedValue); @@ -169,7 +173,7 @@ public class UpdateMapper extends QueryMapper { } } - Object mappedValue = getConverter().convertToColumnType(value, typeInformation); + Object mappedValue = rawValue == null ? null : getConverter().convertToColumnType(rawValue, typeInformation); return new SetOp(field.getMappedKey(), mappedValue); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/package-info.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/package-info.java index 44c551c3f..089ec1bce 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/package-info.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/package-info.java @@ -1,4 +1,7 @@ /** * Spring Data Cassandra specific converter infrastructure. */ +@NonNullApi package org.springframework.data.cassandra.core.convert; + +import org.springframework.lang.NonNullApi; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ArgumentPreparedStatementBinder.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ArgumentPreparedStatementBinder.java index b9f8f83bf..baab58548 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ArgumentPreparedStatementBinder.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ArgumentPreparedStatementBinder.java @@ -15,6 +15,8 @@ */ package org.springframework.data.cassandra.core.cql; +import org.springframework.lang.Nullable; + import com.datastax.driver.core.BoundStatement; import com.datastax.driver.core.PreparedStatement; import com.datastax.driver.core.exceptions.DriverException; @@ -27,14 +29,14 @@ import com.datastax.driver.core.exceptions.DriverException; */ public class ArgumentPreparedStatementBinder implements PreparedStatementBinder { - private final Object[] args; + private final @Nullable Object[] args; /** * Create a new {@link ArgumentPreparedStatementBinder} for the given arguments. * * @param args the arguments to set. May be empty or {@link null} if no arguments are provided. */ - public ArgumentPreparedStatementBinder(Object[] args) { + public ArgumentPreparedStatementBinder(@Nullable Object[] args) { this.args = args; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/AsyncCqlOperations.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/AsyncCqlOperations.java index ce641eb9a..69235e58a 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/AsyncCqlOperations.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/AsyncCqlOperations.java @@ -22,6 +22,7 @@ import java.util.Map; import org.springframework.dao.DataAccessException; import org.springframework.dao.IncorrectResultSizeDataAccessException; +import org.springframework.lang.Nullable; import org.springframework.util.concurrent.ListenableFuture; import com.datastax.driver.core.PreparedStatement; @@ -42,9 +43,6 @@ import com.datastax.driver.core.Statement; */ public interface AsyncCqlOperations { - // TODO many of these data access operations could be implemented as default methods, in terms of other data access - // operations - // ------------------------------------------------------------------------- // Methods dealing with a plain com.datastax.driver.core.Session // ------------------------------------------------------------------------- @@ -70,7 +68,7 @@ public interface AsyncCqlOperations { /** * Issue a single CQL execute, typically a DDL statement, insert, update or delete statement. * - * @param cql static CQL to execute, must not be empty or {@literal null}. + * @param cql static CQL to execute, must not be {@literal null} or empty. * @return boolean value whether the statement was applied. * @throws DataAccessException if there is any problem executing the query. */ @@ -80,7 +78,7 @@ public interface AsyncCqlOperations { * Issue a single CQL operation (such as an insert, update or delete statement) via a prepared statement, binding the * given arguments. * - * @param cql static CQL to execute, must not be empty or {@literal null}. + * @param cql static CQL to execute, must not be {@literal null} or empty. * @param args arguments to bind to the query (leaving it to the {@link PreparedStatement} to guess the corresponding * CQL type). * @return boolean value whether the statement was applied. @@ -93,14 +91,14 @@ public interface AsyncCqlOperations { * using a {@link AsyncPreparedStatementCreator} as this method will create the {@link PreparedStatement}: The * {@link PreparedStatementBinder} just needs to set parameters. * - * @param cql static CQL to execute, must not be empty or {@literal null}. - * @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is - * {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind - * parameters, this object may be used to set fetch size and other performance options. + * @param cql static CQL to execute, must not be {@literal null} or empty. + * @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will + * be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to + * set fetch size and other performance options. * @return boolean value whether the statement was applied. * @throws DataAccessException if there is any problem issuing the execution. */ - ListenableFuture execute(String cql, PreparedStatementBinder preparedStatementBinder) + ListenableFuture execute(String cql, @Nullable PreparedStatementBinder psb) throws DataAccessException; /** @@ -111,7 +109,7 @@ public interface AsyncCqlOperations { *

* The callback action can return a result object, for example a domain object or a collection of domain objects. * - * @param cql static CQL to execute, must not be empty or {@literal null}. + * @param cql static CQL to execute, must not be {@literal null} or empty. * @param action callback object that specifies the action, must not be {@literal null}. * @return a result object returned by the action, or {@literal null} * @throws DataAccessException if there is any problem TODO: Lambda-usage clashes with execute(cql, @@ -125,7 +123,7 @@ public interface AsyncCqlOperations { * Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a * {@link PreparedStatement}, use the overloaded {@code query} method with {@literal null} as argument array. * - * @param cql static CQL to execute, must not be empty or {@literal null}. + * @param cql static CQL to execute, must not be {@literal null} or empty. * @param resultSetExtractor object that will extract all rows of results, must not be {@literal null}. * @return an arbitrary result object, as returned by the ResultSetExtractor. * @throws DataAccessException if there is any problem executing the query. @@ -138,9 +136,9 @@ public interface AsyncCqlOperations { * {@link RowCallbackHandler}. *

* Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a - * {@link PreparedStatement}, use the overloaded {@code query} method with {@code null} as argument array. + * {@link PreparedStatement}, use the overloaded {@code query} method with {@literal null} as argument array. * - * @param cql static CQL to execute, must not be empty or {@literal null}. + * @param cql static CQL to execute, must not be {@literal null} or empty. * @param rowCallbackHandler object that will extract results, one row at a time, must not be {@literal null}. * @throws DataAccessException if there is any problem executing the query * @see #query(String, RowCallbackHandler, Object[]) @@ -153,7 +151,7 @@ public interface AsyncCqlOperations { * Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a * {@link PreparedStatement}, use the overloaded {@code query} method with {@literal null} as argument array. * - * @param cql static CQL to execute, must not be empty or {@literal null}. + * @param cql static CQL to execute, must not be {@literal null} or empty. * @param rowMapper object that will map one object per row, must not be {@literal null}. * @return the result {@link List}, containing mapped objects. * @throws DataAccessException if there is any problem executing the query @@ -165,7 +163,7 @@ public interface AsyncCqlOperations { * Query given CQL to create a prepared statement from CQL and a list of arguments to bind to the query, reading the * {@link ResultSet} with a {@link ResultSetExtractor}. * - * @param cql static CQL to execute, must not be empty or {@literal null}. + * @param cql static CQL to execute, must not be {@literal null} or empty. * @param resultSetExtractor object that will extract results, must not be {@literal null}. * @param args arguments to bind to the query (leaving it to the {@link PreparedStatement} to guess the corresponding * CQL type). @@ -179,7 +177,7 @@ public interface AsyncCqlOperations { * Query given CQL to create a prepared statement from CQL and a list of arguments to bind to the query, reading the * {@link ResultSet} on a per-row basis with a {@link RowCallbackHandler}. * - * @param cql static CQL to execute, must not be empty or {@literal null}. + * @param cql static CQL to execute, must not be {@literal null} or empty. * @param rowCallbackHandler object that will extract results, one row at a time, must not be {@literal null}. * @param args arguments to bind to the query (leaving it to the {@link PreparedStatement} to guess the corresponding * CQL type) @@ -192,7 +190,7 @@ public interface AsyncCqlOperations { * Query given CQL to create a prepared statement from CQL and a list of arguments to bind to the query, mapping each * row to a Java object via a {@link RowMapper}. * - * @param cql static CQL to execute, must not be empty or {@literal null}. + * @param cql static CQL to execute, must not be {@literal null} or empty. * @param rowMapper object that will map one object per row * @param args arguments to bind to the query (leaving it to the {@link PreparedStatement} to guess the corresponding * CQL type) @@ -204,15 +202,15 @@ public interface AsyncCqlOperations { /** * Query using a prepared statement, reading the {@link ResultSet} with a {@link ResultSetExtractor}. * - * @param cql static CQL to execute, must not be empty or {@literal null}. - * @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is - * {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind - * parameters, this object may be used to set fetch size and other performance options. + * @param cql static CQL to execute, must not be {@literal null} or empty. + * @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will + * be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to + * set fetch size and other performance options. * @param resultSetExtractor object that will extract results, must not be {@literal null}. * @return an arbitrary result object, as returned by the {@link ResultSetExtractor}. * @throws DataAccessException if there is any problem */ - ListenableFuture query(String cql, PreparedStatementBinder preparedStatementBinder, + ListenableFuture query(String cql, @Nullable PreparedStatementBinder psb, ResultSetExtractor resultSetExtractor) throws DataAccessException; /** @@ -220,29 +218,29 @@ public interface AsyncCqlOperations { * knows how to bind values to the query, reading the {@link ResultSet} on a per-row basis with a * {@link RowCallbackHandler}. * - * @param cql static CQL to execute, must not be empty or {@literal null}. - * @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is - * {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind - * parameters, this object may be used to set fetch size and other performance options. + * @param cql static CQL to execute, must not be {@literal null} or empty. + * @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will + * be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to + * set fetch size and other performance options. * @param rowCallbackHandler object that will extract results, one row at a time, must not be {@literal null}. * @throws DataAccessException if there is any problem executing the query. */ - ListenableFuture query(String cql, PreparedStatementBinder preparedStatementBinder, + ListenableFuture query(String cql, @Nullable PreparedStatementBinder psb, RowCallbackHandler rowCallbackHandler) throws DataAccessException; /** * Query given CQL to create a prepared statement from CQL and a {@link PreparedStatementBinder} implementation that * knows how to bind values to the query, mapping each row to a Java object via a {@link RowMapper}. * - * @param cql static CQL to execute, must not be empty or {@literal null}. - * @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is - * {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind - * parameters, this object may be used to set fetch size and other performance options. + * @param cql static CQL to execute, must not be {@literal null} or empty. + * @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will + * be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to + * set fetch size and other performance options. * @param rowMapper object that will map one object per row, must not be {@literal null}. * @return the result {@link List}, containing mapped objects. * @throws DataAccessException if there is any problem executing the query. */ - ListenableFuture> query(String cql, PreparedStatementBinder preparedStatementBinder, + ListenableFuture> query(String cql, @Nullable PreparedStatementBinder psb, RowMapper rowMapper) throws DataAccessException; /** @@ -255,7 +253,7 @@ public interface AsyncCqlOperations { * using the column name as the key). Each item in the {@link List} will be of the form returned by this interface's * queryForMap() methods. * - * @param cql static CQL to execute, must not be empty or {@literal null}. + * @param cql static CQL to execute, must not be {@literal null} or empty. * @return a {@link List} that contains a {@link Map} per row. * @throws DataAccessException if there is any problem executing the query. * @see #queryForList(String, Object[]) @@ -270,7 +268,7 @@ public interface AsyncCqlOperations { * using the column name as the key). Each item in the {@link List} will be of the form returned by this interface's * queryForMap() methods. * - * @param cql static CQL to execute, must not be empty or {@literal null}. + * @param cql static CQL to execute, must not be {@literal null} or empty. * @param args arguments to bind to the query (leaving it to the {@link PreparedStatement} to guess the corresponding * CQL type). * @return a {@link List} that contains a {@link Map} per row @@ -288,7 +286,7 @@ public interface AsyncCqlOperations { * The results will be mapped to a {@link List} (one item for each row) of result objects, each of them matching the * specified element type. * - * @param cql static CQL to execute, must not be empty or {@literal null}. + * @param cql static CQL to execute, must not be {@literal null} or empty. * @param elementType the required type of element in the result {@link List} (for example, {@code Integer.class}), * must not be {@literal null}. * @return a {@link List} of objects that match the specified element type. @@ -305,7 +303,7 @@ public interface AsyncCqlOperations { * The results will be mapped to a {@link List} (one item for each row) of result objects, each of them matching the * specified element type. * - * @param cql static CQL to execute, must not be empty or {@literal null}. + * @param cql static CQL to execute, must not be {@literal null} or empty. * @param elementType the required type of element in the result {@link List} (for example, {@code Integer.class}), * must not be {@literal null}. * @param args arguments to bind to the query (leaving it to the {@link PreparedStatement} to guess the corresponding @@ -328,7 +326,7 @@ public interface AsyncCqlOperations { * The query is expected to be a single row query; the result row will be mapped to a Map (one entry for each column, * using the column name as the key). * - * @param cql static CQL to execute, must not be empty or {@literal null}. + * @param cql static CQL to execute, must not be {@literal null} or empty. * @return the result Map (one entry for each column, using the column name as the key), must not be {@literal null}. * @throws IncorrectResultSizeDataAccessException if the query does not return exactly one row. * @throws DataAccessException if there is any problem executing the query. @@ -345,7 +343,7 @@ public interface AsyncCqlOperations { * The query is expected to be a single row query; the result row will be mapped to a Map (one entry for each column, * using the column name as the key). * - * @param cql static CQL to execute, must not be empty or {@literal null}. + * @param cql static CQL to execute, must not be {@literal null} or empty. * @param args arguments to bind to the query (leaving it to the {@link PreparedStatement} to guess the corresponding * CQL type). * @return the result Map (one entry for each column, using the column name as the key). @@ -366,7 +364,7 @@ public interface AsyncCqlOperations { * This method is useful for running static CQL with a known outcome. The query is expected to be a single row/single * column query; the returned result will be directly mapped to the corresponding object type. * - * @param cql static CQL to execute, must not be empty or {@literal null}. + * @param cql static CQL to execute, must not be {@literal null} or empty. * @param requiredType the type that the result object is expected to match, must not be {@literal null}. * @return the result object of the required type, or {@link Mono#empty()} in case of CQL NULL. * @throws IncorrectResultSizeDataAccessException if the query does not return exactly one row, or does not return @@ -383,7 +381,7 @@ public interface AsyncCqlOperations { * The query is expected to be a single row/single column query; the returned result will be directly mapped to the * corresponding object type. * - * @param cql static CQL to execute, must not be empty or {@literal null}. + * @param cql static CQL to execute, must not be {@literal null} or empty. * @param requiredType the type that the result object is expected to match, must not be {@literal null}. * @param args arguments to bind to the query (leaving it to the PreparedStatement to guess the corresponding CQL * type) @@ -402,7 +400,7 @@ public interface AsyncCqlOperations { * {@link PreparedStatement}, use the overloaded {@link #queryForObject(String, RowMapper, Object...)} method with * {@literal null} as argument array. * - * @param cql static CQL to execute, must not be empty or {@literal null}. + * @param cql static CQL to execute, must not be {@literal null} or empty. * @param rowMapper object that will map one object per row, must not be {@literal null}. * @return the single mapped object. * @throws IncorrectResultSizeDataAccessException if the query does not return exactly one row. @@ -415,7 +413,7 @@ public interface AsyncCqlOperations { * Query given CQL to create a prepared statement from CQL and a list of arguments to bind to the query, mapping a * single result row to a Java object via a {@link RowMapper}. * - * @param cql static CQL to execute, must not be empty or {@literal null}. + * @param cql static CQL to execute, must not be {@literal null} or empty. * @param rowMapper object that will map one object per row, must not be {@literal null}. * @param args arguments to bind to the query (leaving it to the {@link PreparedStatement} to guess the corresponding * CQL type) @@ -434,7 +432,7 @@ public interface AsyncCqlOperations { *

* The results will be mapped to an {@link ResultSet}. * - * @param cql static CQL to execute, must not be empty or {@literal null}. + * @param cql static CQL to execute, must not be {@literal null} or empty. * @return a {@link ResultSet} representation. * @throws DataAccessException if there is any problem executing the query. * @see #queryForResultSet(String, Object[]) @@ -447,7 +445,7 @@ public interface AsyncCqlOperations { *

* The results will be mapped to an {@link ResultSet}. * - * @param cql static CQL to execute, must not be empty or {@literal null}. + * @param cql static CQL to execute, must not be {@literal null} or empty. * @param args arguments to bind to the query (leaving it to the {@link PreparedStatement} to guess the corresponding * CQL type). * @return a {@link ResultSet} representation. @@ -489,7 +487,7 @@ public interface AsyncCqlOperations { * {@link RowCallbackHandler}. *

* Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a - * {@link PreparedStatement}, use the overloaded {@code query} method with {@code null} as argument array. + * {@link PreparedStatement}, use the overloaded {@code query} method with {@literal null} as argument array. * * @param statement static CQL {@link Statement}, must not be {@literal null}. * @param rowCallbackHandler object that will extract results, one row at a time, must not be {@literal null}. @@ -522,7 +520,7 @@ public interface AsyncCqlOperations { * using the column name as the key). Each item in the {@link List} will be of the form returned by this interface's * queryForMap() methods. * - * @param statement static CQL {@link Statement} to execute, must not be empty or {@literal null}. + * @param statement static CQL {@link Statement} to execute, must not be {@literal null} or empty. * @return a {@link List} that contains a {@link Map} per row. * @throws DataAccessException if there is any problem executing the query. * @see #queryForList(String, Object[]) @@ -693,15 +691,15 @@ public interface AsyncCqlOperations { * * @param preparedStatementCreator object that can create a {@link PreparedStatement} given a * {@link com.datastax.driver.core.Session}, must not be {@literal null}. - * @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is - * {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind - * parameters, this object may be used to set fetch size and other performance options. + * @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will + * be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to + * set fetch size and other performance options. * @param resultSetExtractor object that will extract results, must not be {@literal null}. * @return an arbitrary result object, as returned by the {@link ResultSetExtractor}. * @throws DataAccessException if there is any problem */ ListenableFuture query(AsyncPreparedStatementCreator preparedStatementCreator, - PreparedStatementBinder preparedStatementBinder, ResultSetExtractor resultSetExtractor) + @Nullable PreparedStatementBinder psb, ResultSetExtractor resultSetExtractor) throws DataAccessException; /** @@ -710,14 +708,14 @@ public interface AsyncCqlOperations { * * @param preparedStatementCreator object that can create a {@link PreparedStatement} given a * {@link com.datastax.driver.core.Session}, must not be {@literal null}. - * @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is - * {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind - * parameters, this object may be used to set fetch size and other performance options. + * @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will + * be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to + * set fetch size and other performance options. * @param rowCallbackHandler object that will extract results, one row at a time, must not be {@literal null}. * @throws DataAccessException if there is any problem executing the query. */ ListenableFuture query(AsyncPreparedStatementCreator preparedStatementCreator, - PreparedStatementBinder preparedStatementBinder, RowCallbackHandler rowCallbackHandler) + @Nullable PreparedStatementBinder psb, RowCallbackHandler rowCallbackHandler) throws DataAccessException; /** @@ -726,14 +724,13 @@ public interface AsyncCqlOperations { * * @param preparedStatementCreator object that can create a {@link PreparedStatement} given a * {@link com.datastax.driver.core.Session}, must not be {@literal null}. - * @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is - * {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind - * parameters, this object may be used to set fetch size and other performance options. + * @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will + * be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to + * set fetch size and other performance options. * @param rowMapper object that will map one object per row, must not be {@literal null}. * @return the result {@link List}, containing mapped objects. * @throws DataAccessException if there is any problem executing the query. */ ListenableFuture> query(AsyncPreparedStatementCreator preparedStatementCreator, - PreparedStatementBinder preparedStatementBinder, RowMapper rowMapper) throws DataAccessException; - + @Nullable PreparedStatementBinder psb, RowMapper rowMapper) throws DataAccessException; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/AsyncCqlTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/AsyncCqlTemplate.java index 487e77b8a..d996de4e6 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/AsyncCqlTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/AsyncCqlTemplate.java @@ -24,6 +24,7 @@ import org.springframework.dao.DataAccessException; import org.springframework.dao.support.DataAccessUtils; import org.springframework.dao.support.PersistenceExceptionTranslator; import org.springframework.data.cassandra.SessionFactory; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.concurrent.ListenableFuture; import org.springframework.util.concurrent.SettableListenableFuture; @@ -412,13 +413,13 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera /* * (non-Javadoc) - * @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#execute(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementBinder) + * @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#execute(java.lang.String, org.springframework.data.cassandra.core.cql.@Nullablender) */ @Override - public ListenableFuture execute(String cql, PreparedStatementBinder preparedStatementBinder) + public ListenableFuture execute(String cql, @Nullable PreparedStatementBinder psb) throws DataAccessException { - return query(newAsyncPreparedStatementCreator(cql), preparedStatementBinder, ResultSet::wasApplied); + return query(newAsyncPreparedStatementCreator(cql), psb, ResultSet::wasApplied); } /* @@ -441,6 +442,8 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera Assert.notNull(preparedStatementCreator, "PreparedStatementCreator must not be null"); Assert.notNull(action, "PreparedStatementCallback object must not be null"); + PersistenceExceptionTranslator exceptionTranslator = ex -> translateExceptionIfPossible("PreparedStatementCallback", + toCql(preparedStatementCreator), ex); try { if (logger.isDebugEnabled()) { logger.debug("Preparing statement [{}] using {}", toCql(preparedStatementCreator), preparedStatementCreator); @@ -452,12 +455,12 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera try { return action.doInPreparedStatement(currentSession, applyStatementSettings(preparedStatement)); } catch (DriverException e) { - throw translateException("PreparedStatementCallback", preparedStatement.toString(), e); + throw translateException(exceptionTranslator, e); } }), getExceptionTranslator()); } catch (DriverException e) { - throw translateException("PreparedStatementCallback", toCql(preparedStatementCreator), e); + throw translateException(exceptionTranslator, e); } } @@ -503,30 +506,30 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera */ @Override public ListenableFuture query(AsyncPreparedStatementCreator preparedStatementCreator, - PreparedStatementBinder preparedStatementBinder, ResultSetExtractor resultSetExtractor) + @Nullable PreparedStatementBinder psb, ResultSetExtractor resultSetExtractor) throws DataAccessException { Assert.notNull(preparedStatementCreator, "AsyncPreparedStatementCreator must not be null"); Assert.notNull(resultSetExtractor, "ResultSetExtractor object must not be null"); + PersistenceExceptionTranslator exceptionTranslator = ex -> translateExceptionIfPossible("Query", + toCql(preparedStatementCreator), ex); + try { + if (logger.isDebugEnabled()) { logger.debug("Preparing statement [{}] using {}", toCql(preparedStatementCreator), preparedStatementCreator); } Session session = getCurrentSession(); - PersistenceExceptionTranslator exceptionTranslator = ex -> translateExceptionIfPossible("Query", - toCql(preparedStatementCreator), ex); - ListenableFuture statementFuture = new MappingListenableFutureAdapter<>( preparedStatementCreator.createPreparedStatement(session), preparedStatement -> { if (logger.isDebugEnabled()) { logger.debug("Executing prepared statement [{}]", preparedStatement); } - return applyStatementSettings(preparedStatementBinder != null - ? preparedStatementBinder.bindValues(preparedStatement) : preparedStatement.bind()); + return applyStatementSettings(psb != null ? psb.bindValues(preparedStatement) : preparedStatement.bind()); }); SettableListenableFuture settableListenableFuture = new SettableListenableFuture<>(); @@ -534,27 +537,25 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera statementFuture.addCallback( boundStatement -> Futures.addCallback(session.executeAsync(boundStatement), new FutureCallback() { @Override - public void onSuccess(ResultSet result) { + public void onSuccess(@Nullable ResultSet result) { try { - settableListenableFuture.set(resultSetExtractor.extractData(result)); + settableListenableFuture.set(result != null ? resultSetExtractor.extractData(result) : null); } catch (DriverException e) { - settableListenableFuture.setException(exceptionTranslator.translateExceptionIfPossible(e)); + settableListenableFuture.setException(translateException(exceptionTranslator, e)); } } @Override public void onFailure(Throwable ex) { if (ex instanceof DriverException) { - settableListenableFuture - .setException(exceptionTranslator.translateExceptionIfPossible((DriverException) ex)); + settableListenableFuture.setException(translateException(exceptionTranslator, (DriverException) ex)); } else { settableListenableFuture.setException(ex); } } }), ex -> { if (ex instanceof DriverException) { - settableListenableFuture - .setException(exceptionTranslator.translateExceptionIfPossible((DriverException) ex)); + settableListenableFuture.setException(translateException(exceptionTranslator, (DriverException) ex)); } else { settableListenableFuture.setException(ex); } @@ -563,7 +564,7 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera return settableListenableFuture; } catch (DriverException e) { - throw translateException("Query", toCql(preparedStatementCreator), e); + throw translateException(exceptionTranslator, e); } } @@ -573,10 +574,10 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera */ @Override public ListenableFuture query(AsyncPreparedStatementCreator preparedStatementCreator, - PreparedStatementBinder preparedStatementBinder, RowCallbackHandler rowCallbackHandler) + @Nullable PreparedStatementBinder psb, RowCallbackHandler rowCallbackHandler) throws DataAccessException { - ListenableFuture results = query(preparedStatementCreator, preparedStatementBinder, + ListenableFuture results = query(preparedStatementCreator, psb, newResultSetExtractor(rowCallbackHandler)); return new ExceptionTranslatingListenableFutureAdapter<>(new MappingListenableFutureAdapter<>(results, o -> null), @@ -589,9 +590,8 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera */ @Override public ListenableFuture> query(AsyncPreparedStatementCreator preparedStatementCreator, - PreparedStatementBinder preparedStatementBinder, RowMapper rowMapper) throws DataAccessException { - - return query(preparedStatementCreator, preparedStatementBinder, newResultSetExtractor(rowMapper)); + @Nullable PreparedStatementBinder psb, RowMapper rowMapper) throws DataAccessException { + return query(preparedStatementCreator, psb, newResultSetExtractor(rowMapper)); } /* @@ -601,7 +601,6 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera @Override public ListenableFuture query(String cql, ResultSetExtractor resultSetExtractor, Object... args) throws DataAccessException { - return query(newAsyncPreparedStatementCreator(cql), newPreparedStatementBinder(args), resultSetExtractor); } @@ -627,7 +626,6 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera @Override public ListenableFuture> query(String cql, RowMapper rowMapper, Object... args) throws DataAccessException { - return query(newAsyncPreparedStatementCreator(cql), newPreparedStatementBinder(args), newResultSetExtractor(rowMapper)); } @@ -637,10 +635,10 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera * @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#query(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.ResultSetExtractor) */ @Override - public ListenableFuture query(String cql, PreparedStatementBinder preparedStatementBinder, + public ListenableFuture query(String cql, @Nullable PreparedStatementBinder psb, ResultSetExtractor resultSetExtractor) throws DataAccessException { - return query(newAsyncPreparedStatementCreator(cql), preparedStatementBinder, resultSetExtractor); + return query(newAsyncPreparedStatementCreator(cql), psb, resultSetExtractor); } /* @@ -648,10 +646,10 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera * @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#query(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.RowCallbackHandler) */ @Override - public ListenableFuture query(String cql, PreparedStatementBinder preparedStatementBinder, + public ListenableFuture query(String cql, @Nullable PreparedStatementBinder psb, RowCallbackHandler rowCallbackHandler) throws DataAccessException { - ListenableFuture results = query(newAsyncPreparedStatementCreator(cql), preparedStatementBinder, + ListenableFuture results = query(newAsyncPreparedStatementCreator(cql), psb, newResultSetExtractor(rowCallbackHandler)); return new ExceptionTranslatingListenableFutureAdapter<>(new MappingListenableFutureAdapter<>(results, o -> null), @@ -663,10 +661,10 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera * @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#query(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.RowMapper) */ @Override - public ListenableFuture> query(String cql, PreparedStatementBinder preparedStatementBinder, + public ListenableFuture> query(String cql, @Nullable PreparedStatementBinder psb, RowMapper rowMapper) throws DataAccessException { - return query(newAsyncPreparedStatementCreator(cql), preparedStatementBinder, newResultSetExtractor(rowMapper)); + return query(newAsyncPreparedStatementCreator(cql), psb, newResultSetExtractor(rowMapper)); } /* @@ -757,13 +755,12 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera * Translate the given {@link DriverException} into a generic {@link DataAccessException}. * * @param task readable text describing the task being attempted - * @param cql CQL query or update that caused the problem (may be {@code null}) + * @param cql CQL query or update that caused the problem (may be {@literal null}) * @param ex the offending {@code RuntimeException}. * @return the exception translation {@link Function} * @see CqlProvider */ - @SuppressWarnings("ThrowableResultOfMethodCallIgnored") - protected DataAccessException translateException(String task, String cql, DriverException ex) { + protected DataAccessException translateException(String task, @Nullable String cql, DriverException ex) { return translate(task, cql, ex); } @@ -771,18 +768,30 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera * Translate the given {@link DriverException} into a generic {@link DataAccessException}. * * @param task readable text describing the task being attempted - * @param cql CQL query or update that caused the problem (may be {@code null}) + * @param cql CQL query or update that caused the problem (may be {@literal null}) * @param ex the offending {@code RuntimeException}. * @return the translated {@link DataAccessException} or {@literal null} if translation not possible. * @see CqlProvider */ - @SuppressWarnings("ThrowableResultOfMethodCallIgnored") - protected DataAccessException translateExceptionIfPossible(String task, String cql, RuntimeException ex) { + @Nullable + protected DataAccessException translateExceptionIfPossible(String task, @Nullable String cql, RuntimeException ex) { return (ex instanceof DriverException ? translate(task, cql, (DriverException) ex) : null); } private Session getCurrentSession() { - return getSessionFactory().getSession(); + + SessionFactory sessionFactory = getSessionFactory(); + + Assert.state(sessionFactory != null, "SessionFactory is null"); + + return sessionFactory.getSession(); + } + + private static RuntimeException translateException(PersistenceExceptionTranslator exceptionTranslator, + DriverException e) { + + DataAccessException translated = exceptionTranslator.translateExceptionIfPossible(e); + return translated == null ? e : translated; } private static class SimpleAsyncPreparedStatementCreator implements AsyncPreparedStatementCreator, CqlProvider { diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/AsyncPreparedStatementCreator.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/AsyncPreparedStatementCreator.java index 00783c531..9c7b47f7f 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/AsyncPreparedStatementCreator.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/AsyncPreparedStatementCreator.java @@ -36,6 +36,7 @@ import com.datastax.driver.core.exceptions.DriverException; * * @author Mark Paluch * @since 2.0 + * @see AsyncCqlTemplate#execute(AsyncPreparedStatementCreator, PreparedStatementCallback) */ @FunctionalInterface public interface AsyncPreparedStatementCreator { diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/AsyncSessionCallback.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/AsyncSessionCallback.java index 27da3e275..d2882c2ef 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/AsyncSessionCallback.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/AsyncSessionCallback.java @@ -48,7 +48,7 @@ public interface AsyncSessionCallback { * template. * * @param session active Cassandra Session, must not be {@literal null}. - * @return a result object, or {@code null} if none. + * @return a result object, or {@code ListenableFuture} if none. * @throws DriverException if thrown by a Session method, to be auto-converted to a {@link DataAccessException}. * @throws DataAccessException in case of custom exceptions. * @see AsyncCqlTemplate#queryForObject(String, Class) diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CassandraAccessor.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CassandraAccessor.java index 9a33093aa..aa46202a2 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CassandraAccessor.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CassandraAccessor.java @@ -25,6 +25,7 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.dao.DataAccessException; import org.springframework.data.cassandra.SessionFactory; import org.springframework.data.cassandra.core.cql.session.DefaultSessionFactory; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import com.datastax.driver.core.ConsistencyLevel; @@ -59,7 +60,7 @@ public class CassandraAccessor implements InitializingBean { /** Logger available to subclasses */ protected final Logger logger = LoggerFactory.getLogger(getClass()); - protected CqlExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator(); + private CqlExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator(); /** * If this variable is set to a non-negative value, it will be used for setting the {@code fetchSize} property on @@ -71,15 +72,15 @@ public class CassandraAccessor implements InitializingBean { * If this variable is set to a value, it will be used for setting the {@code consistencyLevel} property on statements * used for query processing. */ - private com.datastax.driver.core.ConsistencyLevel consistencyLevel; + private @Nullable com.datastax.driver.core.ConsistencyLevel consistencyLevel; /** * If this variable is set to a value, it will be used for setting the {@code retryPolicy} property on statements used * for query processing. */ - private com.datastax.driver.core.policies.RetryPolicy retryPolicy; + private @Nullable com.datastax.driver.core.policies.RetryPolicy retryPolicy; - private SessionFactory sessionFactory; + private @Nullable SessionFactory sessionFactory; /** * Ensures the Cassandra {@link Session} and exception translator has been propertly set. @@ -97,13 +98,14 @@ public class CassandraAccessor implements InitializingBean { * @see Statement#setConsistencyLevel(ConsistencyLevel) * @see RetryPolicy */ - public void setConsistencyLevel(ConsistencyLevel consistencyLevel) { + public void setConsistencyLevel(@Nullable ConsistencyLevel consistencyLevel) { this.consistencyLevel = consistencyLevel; } /** * @return the {@link ConsistencyLevel} specified for this template. */ + @Nullable public ConsistencyLevel getConsistencyLevel() { return this.consistencyLevel; } @@ -118,6 +120,7 @@ public class CassandraAccessor implements InitializingBean { public void setExceptionTranslator(CqlExceptionTranslator exceptionTranslator) { Assert.notNull(exceptionTranslator, "CQLExceptionTranslator must not be null"); + this.exceptionTranslator = exceptionTranslator; } @@ -129,9 +132,6 @@ public class CassandraAccessor implements InitializingBean { * @see CqlExceptionTranslator */ public CqlExceptionTranslator getExceptionTranslator() { - - Assert.state(this.exceptionTranslator != null, "CQLExceptionTranslator was not properly initialized"); - return this.exceptionTranslator; } @@ -160,13 +160,14 @@ public class CassandraAccessor implements InitializingBean { * @see Statement#setRetryPolicy(RetryPolicy) * @see RetryPolicy */ - public void setRetryPolicy(RetryPolicy retryPolicy) { + public void setRetryPolicy(@Nullable RetryPolicy retryPolicy) { this.retryPolicy = retryPolicy; } /** * @return the {@link RetryPolicy} specified for this template. */ + @Nullable public RetryPolicy getRetryPolicy() { return this.retryPolicy; } @@ -224,6 +225,7 @@ public class CassandraAccessor implements InitializingBean { * @since 2.0 * @see SessionFactory */ + @Nullable public SessionFactory getSessionFactory() { return this.sessionFactory; } @@ -300,6 +302,7 @@ public class CassandraAccessor implements InitializingBean { * exception hierarchy * @see DataAccessException */ + @Nullable protected DataAccessException translateExceptionIfPossible(DriverException ex) { Assert.notNull(ex, "DriverException must not be null"); @@ -316,7 +319,7 @@ public class CassandraAccessor implements InitializingBean { * subsequent cast) is considered reliable when expecting Cassandra-based access to have happened. * * @param task readable text describing the task being attempted - * @param cql CQL query or update that caused the problem (may be {@code null}) + * @param cql CQL query or update that caused the problem (may be {@literal null}) * @param ex the offending {@link DriverException} * @return the DataAccessException, wrapping the {@code DriverException} * @see org.springframework.dao.DataAccessException#getRootCause() @@ -324,7 +327,7 @@ public class CassandraAccessor implements InitializingBean { * "http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#dao-exceptions">Consistent * exception hierarchy */ - protected DataAccessException translate(String task, String cql, DriverException ex) { + protected DataAccessException translate(String task, @Nullable String cql, DriverException ex) { Assert.notNull(ex, "DriverException must not be null"); @@ -410,10 +413,12 @@ public class CassandraAccessor implements InitializingBean { * Determine CQL from potential provider object. * * @param cqlProvider object that's potentially a {@link CqlProvider} - * @return the CQL string, or {@code null} + * @return the CQL string, or {@literal null} * @see CqlProvider */ - protected static String toCql(Object cqlProvider) { + @Nullable + protected static String toCql(@Nullable Object cqlProvider) { + return Optional.ofNullable(cqlProvider) // .filter(o -> o instanceof CqlProvider) // .map(o -> (CqlProvider) o) // @@ -433,10 +438,10 @@ public class CassandraAccessor implements InitializingBean { } /* (non-Javadoc) - * - @see org.springframework.data.cassandra.core.cql.ResultSetExtractor#extractData(com.datastax.driver.core.ResultSet) + * @see org.springframework.data.cassandra.core.cql.ResultSetExtractor#extractData(com.datastax.driver.core.ResultSet) */ @Override + @Nullable public Object extractData(ResultSet resultSet) { StreamSupport.stream(resultSet.spliterator(), false).forEach(rowCallbackHandler::processRow); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CassandraExceptionTranslator.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CassandraExceptionTranslator.java index 0d6c41afe..56d0be6aa 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CassandraExceptionTranslator.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CassandraExceptionTranslator.java @@ -27,6 +27,7 @@ import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.dao.TransientDataAccessResourceException; import org.springframework.dao.support.PersistenceExceptionTranslator; import org.springframework.data.cassandra.*; +import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; @@ -59,6 +60,7 @@ public class CassandraExceptionTranslator implements CqlExceptionTranslator { * @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException) */ @Override + @Nullable public DataAccessException translateExceptionIfPossible(RuntimeException exception) { if (exception instanceof DataAccessException) { @@ -76,7 +78,7 @@ public class CassandraExceptionTranslator implements CqlExceptionTranslator { * @see org.springframework.data.cassandra.cql.CQLExceptionTranslator#translate(java.lang.String, java.lang.String, com.datastax.driver.core.exceptions.DriverException) */ @Override - public DataAccessException translate(String task, String cql, DriverException exception) { + public DataAccessException translate(@Nullable String task, @Nullable String cql, DriverException exception) { String message = buildMessage(task, cql, exception); @@ -183,11 +185,11 @@ public class CassandraExceptionTranslator implements CqlExceptionTranslator { * {@link org.springframework.dao.DataAccessException} class. * * @param task readable text describing the task being attempted - * @param cql the CQL statement that caused the problem (may be {@code null}) + * @param cql the CQL statement that caused the problem (may be {@literal null}) * @param ex the offending {@code DriverException} * @return the message {@code String} to use */ - protected String buildMessage(String task, String cql, DriverException ex) { + protected String buildMessage(@Nullable String task, @Nullable String cql, DriverException ex) { if (StringUtils.hasText(task) || StringUtils.hasText(cql)) { return task + "; CQL [" + cql + "]; " + ex.getMessage(); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ColumnMapRowMapper.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ColumnMapRowMapper.java index 0e0111e87..9a664ad2e 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ColumnMapRowMapper.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ColumnMapRowMapper.java @@ -17,6 +17,7 @@ package org.springframework.data.cassandra.core.cql; import java.util.Map; +import org.springframework.lang.Nullable; import org.springframework.util.LinkedCaseInsensitiveMap; import com.datastax.driver.core.ColumnDefinitions; @@ -94,6 +95,7 @@ public class ColumnMapRowMapper implements RowMapper> { * @param index is the column index. * @return the Object returned */ + @Nullable protected Object getColumnValue(Row row, int index) { return row.getObject(index); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlExceptionTranslator.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlExceptionTranslator.java index 3e5d6113f..bd738aad4 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlExceptionTranslator.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlExceptionTranslator.java @@ -17,6 +17,8 @@ package org.springframework.data.cassandra.core.cql; import org.springframework.dao.DataAccessException; import org.springframework.dao.support.PersistenceExceptionTranslator; +import org.springframework.data.cassandra.core.mapping.UnsupportedCassandraOperationException; +import org.springframework.lang.Nullable; import com.datastax.driver.core.exceptions.DriverException; @@ -40,12 +42,15 @@ public interface CqlExceptionTranslator extends PersistenceExceptionTranslator { * subsequent cast) is considered reliable when expecting Cassandra-based access to have happened. * * @param task readable text describing the task being attempted. - * @param cql CQL query or update that caused the problem (may be {@code null}). + * @param cql CQL query or update that caused the problem (may be {@literal null}). * @param ex the offending {@link DriverException}. * @return the DataAccessException, wrapping the {@link DriverException}. * @see org.springframework.dao.DataAccessException#getRootCause() */ - default DataAccessException translate(String task, String cql, DriverException ex) { - return translateExceptionIfPossible(ex); + default DataAccessException translate(@Nullable String task, @Nullable String cql, DriverException ex) { + + DataAccessException translated = translateExceptionIfPossible(ex); + return translated == null ? new UnsupportedCassandraOperationException("Cannot translate exception", ex) + : translated; } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlIdentifier.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlIdentifier.java index 55459ab4b..d1f4d4ee5 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlIdentifier.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlIdentifier.java @@ -35,7 +35,6 @@ import com.datastax.driver.core.TableMetadata; * @author Mark Paluch * @author John Blum * @see #toCql() - * @see #toCql(StringBuilder) * @see #toString() */ public final class CqlIdentifier implements Comparable, Serializable { @@ -50,18 +49,18 @@ public final class CqlIdentifier implements Comparable, Serializa public static final Pattern QUOTED = Pattern.compile(QUOTED_REGEX); - private String identifier; + private final String identifier; - private String unquoted; + private final String unquoted; - private boolean quoted; + private final boolean quoted; /** * Create a new {@link CqlIdentifier} without force-quoting it. It may end up quoted, depending on its value. * * @see #cqlId(CharSequence) */ - public CqlIdentifier(CharSequence identifier) { + private CqlIdentifier(CharSequence identifier) { this(identifier, false); } @@ -78,8 +77,25 @@ public final class CqlIdentifier implements Comparable, Serializa * @see #cqlId(CharSequence, boolean) * @see #quotedCqlId(CharSequence) */ - public CqlIdentifier(CharSequence identifier, boolean forceQuote) { - setIdentifier(identifier, forceQuote); + private CqlIdentifier(CharSequence identifier, boolean forceQuote) { + + Assert.notNull(identifier, "Identifier must not be null"); + + String string = identifier.toString(); + + Assert.hasText(string, "Identifier must not be empty"); + + if (forceQuote || isQuotedIdentifier(string)) { + this.unquoted = string; + this.identifier = "\"" + string + "\""; + this.quoted = true; + } else if (isUnquotedIdentifier(string)) { + this.identifier = this.unquoted = string.toLowerCase(); + this.quoted = false; + } else { + throw new IllegalArgumentException( + String.format("given string [%s] is not a valid quoted or unquoted identifier", identifier)); + } } /** @@ -123,29 +139,6 @@ public final class CqlIdentifier implements Comparable, Serializa return QUOTED.matcher(chars).matches() || ReservedKeyword.isReserved(chars); } - /** - * Tests & sets the given identifier. - */ - private void setIdentifier(CharSequence identifier, boolean forceQuoting) { - - Assert.notNull(identifier, "Identifier must not be null"); - - String string = identifier.toString(); - - Assert.hasText(string, "Identifier must not be empty"); - - if (forceQuoting || isQuotedIdentifier(string)) { - this.unquoted = string; - this.identifier = "\"" + string + "\""; - quoted = true; - } else if (isUnquotedIdentifier(string)) { - this.identifier = this.unquoted = string.toLowerCase(); - } else { - throw new IllegalArgumentException( - String.format("given string [%s] is not a valid quoted or unquoted identifier", identifier)); - } - } - /** * Returns the identifier without encasing quotes, regardless of the value of {@link #isQuoted()}. For * example, if {@link #isQuoted()} is {@code true}, then this value will be the same as {@link #toCql()} and @@ -167,10 +160,11 @@ public final class CqlIdentifier implements Comparable, Serializa /** * Appends the rendering of this identifier to the given {@link StringBuilder}, then returns that - * {@link StringBuilder}. If {@code null} is given, a new {@link StringBuilder} is created, appended to, and returned. + * {@link StringBuilder}. If {@literal null} is given, a new {@link StringBuilder} is created, appended to, and + * returned. */ public StringBuilder toCql(StringBuilder builder) { - return (builder != null ? builder : new StringBuilder()).append(toCql()); + return builder.append(toCql()); } /** @@ -211,7 +205,7 @@ public final class CqlIdentifier implements Comparable, Serializa if (quoted != that.quoted) return false; - return identifier != null ? identifier.equals(that.identifier) : that.identifier == null; + return identifier.equals(that.identifier); } /* (non-Javadoc) @@ -220,7 +214,7 @@ public final class CqlIdentifier implements Comparable, Serializa @Override public int hashCode() { - int result = identifier != null ? identifier.hashCode() : 0; + int result = identifier.hashCode(); result = 31 * result + (quoted ? 1 : 0); return result; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlOperations.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlOperations.java index 939dfbe2c..8dc44fc0e 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlOperations.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlOperations.java @@ -23,6 +23,7 @@ import java.util.Map; import org.springframework.dao.DataAccessException; import org.springframework.dao.IncorrectResultSizeDataAccessException; +import org.springframework.lang.Nullable; import com.datastax.driver.core.PreparedStatement; import com.datastax.driver.core.ResultSet; @@ -56,6 +57,7 @@ public interface CqlOperations { * @return a result object returned by the action, or {@literal null}. * @throws DataAccessException if there is any problem executing the query. */ + @Nullable T execute(SessionCallback action) throws DataAccessException; // ------------------------------------------------------------------------- @@ -95,7 +97,7 @@ public interface CqlOperations { * @return boolean value whether the statement was applied. * @throws DataAccessException if there is any problem issuing the execution. */ - boolean execute(String cql, PreparedStatementBinder psb) throws DataAccessException; + boolean execute(String cql, @Nullable PreparedStatementBinder psb) throws DataAccessException; /** * Execute a CQL data access operation, implemented as callback action working on a CQL {@link PreparedStatement}. @@ -110,6 +112,7 @@ public interface CqlOperations { * @return a result object returned by the action, or {@literal null} * @throws DataAccessException if there is any problem */ + @Nullable T execute(String cql, PreparedStatementCallback action) throws DataAccessException; /** @@ -124,6 +127,7 @@ public interface CqlOperations { * @throws DataAccessException if there is any problem executing the query. * @see #query(String, ResultSetExtractor, Object...) */ + @Nullable T query(String cql, ResultSetExtractor resultSetExtractor) throws DataAccessException; /** @@ -131,7 +135,7 @@ public interface CqlOperations { * {@link RowCallbackHandler}. *

* Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a - * {@link PreparedStatement}, use the overloaded {@code query} method with {@code null} as argument array. + * {@link PreparedStatement}, use the overloaded {@code query} method with {@literal null} as argument array. * * @param cql static CQL to execute, must not be empty or {@literal null}. * @param rowCallbackHandler object that will extract results, one row at a time, must not be {@literal null}. @@ -165,6 +169,7 @@ public interface CqlOperations { * @return an arbitrary result object, as returned by the {@link ResultSetExtractor} * @throws DataAccessException if there is any problem executing the query. */ + @Nullable T query(String cql, ResultSetExtractor resultSetExtractor, Object... args) throws DataAccessException; /** @@ -196,14 +201,15 @@ public interface CqlOperations { * Query using a prepared statement, reading the {@link ResultSet} with a {@link ResultSetExtractor}. * * @param cql static CQL to execute, must not be empty or {@literal null}. - * @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is - * {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind - * parameters, this object may be used to set fetch size and other performance options. + * @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will + * be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to + * set fetch size and other performance options. * @param resultSetExtractor object that will extract results, must not be {@literal null}. * @return an arbitrary result object, as returned by the {@link ResultSetExtractor}. * @throws DataAccessException if there is any problem */ - T query(String cql, PreparedStatementBinder preparedStatementBinder, ResultSetExtractor resultSetExtractor) + @Nullable + T query(String cql, @Nullable PreparedStatementBinder psb, ResultSetExtractor resultSetExtractor) throws DataAccessException; /** @@ -212,13 +218,13 @@ public interface CqlOperations { * {@link RowCallbackHandler}. * * @param cql static CQL to execute, must not be empty or {@literal null}. - * @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is - * {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind - * parameters, this object may be used to set fetch size and other performance options. + * @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will + * be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to + * set fetch size and other performance options. * @param rowCallbackHandler object that will extract results, one row at a time, must not be {@literal null}. * @throws DataAccessException if there is any problem executing the query. */ - void query(String cql, PreparedStatementBinder preparedStatementBinder, RowCallbackHandler rowCallbackHandler) + void query(String cql, @Nullable PreparedStatementBinder psb, RowCallbackHandler rowCallbackHandler) throws DataAccessException; /** @@ -226,14 +232,14 @@ public interface CqlOperations { * knows how to bind values to the query, mapping each row to a Java object via a {@link RowMapper}. * * @param cql static CQL to execute, must not be empty or {@literal null}. - * @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is - * {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind - * parameters, this object may be used to set fetch size and other performance options. + * @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will + * be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to + * set fetch size and other performance options. * @param rowMapper object that will map one object per row, must not be {@literal null}. * @return the result {@link List}, containing mapped objects. * @throws DataAccessException if there is any problem executing the query. */ - List query(String cql, PreparedStatementBinder preparedStatementBinder, RowMapper rowMapper) + List query(String cql, @Nullable PreparedStatementBinder psb, RowMapper rowMapper) throws DataAccessException; /** @@ -364,6 +370,7 @@ public interface CqlOperations { * @throws DataAccessException if there is any problem executing the query. * @see #queryForObject(String, Class, Object[]) */ + @Nullable T queryForObject(String cql, Class requiredType) throws DataAccessException; /** @@ -383,6 +390,7 @@ public interface CqlOperations { * @throws DataAccessException if there is any problem executing the query. * @see #queryForObject(String, Class) */ + @Nullable T queryForObject(String cql, Class requiredType, Object... args) throws DataAccessException; /** @@ -502,6 +510,7 @@ public interface CqlOperations { * @throws DataAccessException if there is any problem executing the query. * @see #query(String, ResultSetExtractor, Object...) */ + @Nullable T query(Statement statement, ResultSetExtractor resultSetExtractor) throws DataAccessException; /** @@ -509,7 +518,7 @@ public interface CqlOperations { * {@link RowCallbackHandler}. *

* Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a - * {@link PreparedStatement}, use the overloaded {@code query} method with {@code null} as argument array. + * {@link PreparedStatement}, use the overloaded {@code query} method with {@literal null} as argument array. * * @param statement static CQL {@link Statement}, must not be {@literal null}. * @param rowCallbackHandler object that will extract results, one row at a time, must not be {@literal null}. @@ -605,6 +614,7 @@ public interface CqlOperations { * @throws DataAccessException if there is any problem executing the query. * @see #queryForObject(String, Class, Object[]) */ + @Nullable T queryForObject(Statement statement, Class requiredType) throws DataAccessException; /** @@ -621,6 +631,7 @@ public interface CqlOperations { * @throws DataAccessException if there is any problem executing the query. * @see #queryForObject(String, RowMapper, Object[]) */ + @Nullable T queryForObject(Statement statement, RowMapper rowMapper) throws DataAccessException; /** @@ -684,6 +695,7 @@ public interface CqlOperations { * @return a result object returned by the action, or {@literal null}. * @throws DataAccessException if there is any problem */ + @Nullable T execute(PreparedStatementCreator preparedStatementCreator, PreparedStatementCallback action) throws DataAccessException; @@ -696,6 +708,7 @@ public interface CqlOperations { * @return an arbitrary result object, as returned by the {@link ResultSetExtractor} * @throws DataAccessException if there is any problem */ + @Nullable T query(PreparedStatementCreator preparedStatementCreator, ResultSetExtractor resultSetExtractor) throws DataAccessException; @@ -729,14 +742,15 @@ public interface CqlOperations { * * @param preparedStatementCreator object that can create a {@link PreparedStatement} given a * {@link com.datastax.driver.core.Session}, must not be {@literal null}. - * @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is - * {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind - * parameters, this object may be used to set fetch size and other performance options. + * @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will + * be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to + * set fetch size and other performance options. * @param resultSetExtractor object that will extract results, must not be {@literal null}. * @return an arbitrary result object, as returned by the {@link ResultSetExtractor}. * @throws DataAccessException if there is any problem */ - T query(PreparedStatementCreator preparedStatementCreator, PreparedStatementBinder preparedStatementBinder, + @Nullable + T query(PreparedStatementCreator preparedStatementCreator, @Nullable PreparedStatementBinder psb, ResultSetExtractor resultSetExtractor) throws DataAccessException; /** @@ -745,13 +759,13 @@ public interface CqlOperations { * * @param preparedStatementCreator object that can create a {@link PreparedStatement} given a * {@link com.datastax.driver.core.Session}, must not be {@literal null}. - * @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is - * {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind - * parameters, this object may be used to set fetch size and other performance options. + * @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will + * be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to + * set fetch size and other performance options. * @param rowCallbackHandler object that will extract results, one row at a time, must not be {@literal null}. * @throws DataAccessException if there is any problem executing the query. */ - void query(PreparedStatementCreator preparedStatementCreator, PreparedStatementBinder preparedStatementBinder, + void query(PreparedStatementCreator preparedStatementCreator, @Nullable PreparedStatementBinder psb, RowCallbackHandler rowCallbackHandler) throws DataAccessException; /** @@ -760,14 +774,14 @@ public interface CqlOperations { * * @param preparedStatementCreator object that can create a {@link PreparedStatement} given a * {@link com.datastax.driver.core.Session}, must not be {@literal null}. - * @param preparedStatementBinder object that knows how to set values on the prepared statement. If this is - * {@literal null}, the CQL will be assumed to contain no bind parameters. Even if there are no bind - * parameters, this object may be used to set fetch size and other performance options. + * @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will + * be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to + * set fetch size and other performance options. * @param rowMapper object that will map one object per row, must not be {@literal null}. * @return the result {@link List}, containing mapped objects. * @throws DataAccessException if there is any problem executing the query. */ - List query(PreparedStatementCreator preparedStatementCreator, PreparedStatementBinder preparedStatementBinder, + List query(PreparedStatementCreator preparedStatementCreator, @Nullable PreparedStatementBinder psb, RowMapper rowMapper) throws DataAccessException; // ------------------------------------------------------------------------- @@ -788,8 +802,7 @@ public interface CqlOperations { * * @param hostMapper The implementation to use for host mapping. * @return Collection generated by the provided HostMapper. - * @throws DataAccessException + * @throws DataAccessException if there is any problem executing the query. */ Collection describeRing(HostMapper hostMapper) throws DataAccessException; - } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlProvider.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlProvider.java index e6920173f..8d4d32886 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlProvider.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlProvider.java @@ -15,6 +15,8 @@ */ package org.springframework.data.cassandra.core.cql; +import org.springframework.lang.Nullable; + /** * Interface to be implemented by objects that can provide CQL strings. *

@@ -35,5 +37,6 @@ public interface CqlProvider { * * @return the CQL string, or {@literal null}. */ + @Nullable String getCql(); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlStringUtils.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlStringUtils.java index 55ab59594..87d69a22a 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlStringUtils.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlStringUtils.java @@ -15,62 +15,68 @@ */ package org.springframework.data.cassandra.core.cql; +import org.springframework.lang.Nullable; + import com.datastax.driver.core.DataType; public class CqlStringUtils { - protected static final String DOUBLE_QUOTE = "\""; - protected static final String DOUBLE_DOUBLE_QUOTE = "\"\""; - protected static final String DOUBLE_SINGLE_QUOTE = "\'\'"; - protected static final String SINGLE_QUOTE = "\'"; - protected static final String EMPTY_STRING = ""; - protected static final String TYPE_PARAMETER_PREFIX = "<"; - protected static final String TYPE_PARAMETER_SUFFIX = ">"; - - public static StringBuilder noNull(StringBuilder builder) { - return (builder == null ? new StringBuilder() : builder); - } + private static final String DOUBLE_QUOTE = "\""; + private static final String DOUBLE_DOUBLE_QUOTE = "\"\""; + private static final String DOUBLE_SINGLE_QUOTE = "\'\'"; + private static final String SINGLE_QUOTE = "\'"; + private static final String EMPTY_STRING = ""; + private static final String TYPE_PARAMETER_PREFIX = "<"; + private static final String TYPE_PARAMETER_SUFFIX = ">"; /** * Renders the given string as a legal Cassandra string column or table option value, by escaping single quotes and - * encasing the result in single quotes. Given {@code null}, returns null. + * encasing the result in single quotes. Given {@literal null}, returns null. */ - public static String valuize(String candidate) { + @Nullable + public static String valuize(@Nullable String candidate) { return (candidate != null ? singleQuote(escapeSingle(candidate)) : null); } /** - * Doubles single quote characters (' -> ''). Given {@code null}, returns null. + * Doubles single quote characters (' -> ''). Given {@literal null}, returns null. */ - public static String escapeSingle(Object thing) { + @Nullable + public static String escapeSingle(@Nullable Object thing) { return (thing == null ? null : thing.toString().replace(SINGLE_QUOTE, DOUBLE_SINGLE_QUOTE)); } /** - * Doubles double quote characters (" -> ""). Given {@code null}, returns null. + * Doubles double quote characters (" -> ""). Given {@literal null}, returns null. */ - public static String escapeDouble(Object thing) { + @Nullable + public static String escapeDouble(@Nullable Object thing) { return (thing == null ? null : thing.toString().replace(DOUBLE_QUOTE, DOUBLE_DOUBLE_QUOTE)); } /** - * Surrounds given object's {@link Object#toString()} with single quotes. Given {@code null}, returns {@code null}. + * Surrounds given object's {@link Object#toString()} with single quotes. Given {@literal null}, returns + * {@literal null}. */ - public static String singleQuote(Object thing) { + @Nullable + public static String singleQuote(@Nullable Object thing) { return (thing == null ? null : SINGLE_QUOTE.concat(thing.toString()).concat(SINGLE_QUOTE)); } /** - * Surrounds given object's {@link Object#toString()} with double quotes. Given {@code null}, returns {@code null}. + * Surrounds given object's {@link Object#toString()} with double quotes. Given {@literal null}, returns + * {@literal null}. */ - public static String doubleQuote(Object thing) { + @Nullable + public static String doubleQuote(@Nullable Object thing) { return (thing == null ? null : DOUBLE_QUOTE.concat(thing.toString()).concat(DOUBLE_QUOTE)); } /** * Removed single quotes from quoted String option values */ - public static String removeSingleQuotes(Object thing) { + @Nullable + public static String removeSingleQuotes(@Nullable Object thing) { return (thing == null ? null : thing.toString().replaceAll(SINGLE_QUOTE, EMPTY_STRING)); } @@ -105,11 +111,13 @@ public class CqlStringUtils { return builder.append(TYPE_PARAMETER_SUFFIX).toString(); } - public static String unquote(String value) { + @Nullable + public static String unquote(@Nullable String value) { return unquote(value, "\""); } - public static String unquote(String value, String quoteChar) { + @Nullable + public static String unquote(@Nullable String value, String quoteChar) { if (value == null) { return null; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlTemplate.java index 5c2822727..979992f62 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlTemplate.java @@ -24,6 +24,7 @@ import java.util.function.Function; import org.springframework.dao.DataAccessException; import org.springframework.dao.support.DataAccessUtils; import org.springframework.data.cassandra.SessionFactory; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import com.datastax.driver.core.BoundStatement; @@ -154,6 +155,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { * @see org.springframework.data.cassandra.core.cqlOperations#query(java.lang.String, org.springframework.data.cassandra.core.cql.ResultSetExtractor) */ @Override + @Nullable public T query(String cql, ResultSetExtractor resultSetExtractor) throws DataAccessException { Assert.hasText(cql, "CQL must not be empty"); @@ -189,6 +191,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { */ @Override public List query(String cql, RowMapper rowMapper) throws DataAccessException { + // noinspection ConstantConditions return query(cql, newResultSetExtractor(rowMapper)); } @@ -198,6 +201,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { */ @Override public List> queryForList(String cql) throws DataAccessException { + // noinspection ConstantConditions return query(cql, newResultSetExtractor(newColumnMapRowMapper())); } @@ -207,6 +211,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { */ @Override public List queryForList(String cql, Class elementType) throws DataAccessException { + // noinspection ConstantConditions return query(cql, newResultSetExtractor(newSingleColumnRowMapper(elementType))); } @@ -243,6 +248,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { */ @Override public ResultSet queryForResultSet(String cql) throws DataAccessException { + // noinspection ConstantConditions return query(cql, rs -> rs); } @@ -307,6 +313,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { */ @Override public List query(Statement statement, RowMapper rowMapper) throws DataAccessException { + // noinspection ConstantConditions return query(statement, newResultSetExtractor(rowMapper)); } @@ -316,6 +323,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { */ @Override public List> queryForList(Statement statement) throws DataAccessException { + // noinspection ConstantConditions return query(statement, newResultSetExtractor(newColumnMapRowMapper())); } @@ -325,6 +333,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { */ @Override public List queryForList(Statement statement, Class elementType) throws DataAccessException { + // noinspection ConstantConditions return query(statement, newResultSetExtractor(newSingleColumnRowMapper(elementType))); } @@ -334,6 +343,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { */ @Override public Map queryForMap(Statement statement) throws DataAccessException { + // noinspection ConstantConditions return queryForObject(statement, newColumnMapRowMapper()); } @@ -361,6 +371,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { */ @Override public ResultSet queryForResultSet(Statement statement) throws DataAccessException { + // noinspection ConstantConditions return query(statement, rs -> rs); } @@ -391,14 +402,16 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { * @see org.springframework.data.cassandra.core.cqlOperations#execute(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementBinder) */ @Override - public boolean execute(String cql, PreparedStatementBinder preparedStatementBinder) throws DataAccessException { - return query(new SimplePreparedStatementCreator(cql), preparedStatementBinder, ResultSet::wasApplied); + public boolean execute(String cql, @Nullable PreparedStatementBinder psb) throws DataAccessException { + // noinspection ConstantConditions + return query(new SimplePreparedStatementCreator(cql), psb, ResultSet::wasApplied); } /* * (non-Javadoc) * @see org.springframework.data.cassandra.core.cqlOperations#execute(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementCallback) */ + @Nullable @Override public T execute(String cql, PreparedStatementCallback action) throws DataAccessException { return execute(newPreparedStatementCreator(cql), action); @@ -410,6 +423,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { */ @Override public boolean execute(PreparedStatementCreator preparedStatementCreator) throws DataAccessException { + // noinspection ConstantConditions return query(preparedStatementCreator, ResultSet::wasApplied); } @@ -418,6 +432,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { * @see org.springframework.data.cassandra.core.cqlOperations#execute(org.springframework.data.cassandra.core.cql.PreparedStatementCreator, org.springframework.data.cassandra.core.cql.PreparedStatementCallback) */ @Override + @Nullable public T execute(PreparedStatementCreator preparedStatementCreator, PreparedStatementCallback action) throws DataAccessException { @@ -468,7 +483,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { @Override public List query(PreparedStatementCreator preparedStatementCreator, RowMapper rowMapper) throws DataAccessException { - + // noinspection ConstantConditions return query(preparedStatementCreator, null, newResultSetExtractor(rowMapper)); } @@ -476,8 +491,9 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { * (non-Javadoc) * @see org.springframework.data.cassandra.core.cqlOperations#query(org.springframework.data.cassandra.core.cql.PreparedStatementCreator, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.ResultSetExtractor) */ + @Nullable @Override - public T query(PreparedStatementCreator preparedStatementCreator, PreparedStatementBinder preparedStatementBinder, + public T query(PreparedStatementCreator preparedStatementCreator, @Nullable PreparedStatementBinder psb, ResultSetExtractor resultSetExtractor) throws DataAccessException { Assert.notNull(preparedStatementCreator, "PreparedStatementCreator must not be null"); @@ -496,8 +512,8 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { logger.debug("Executing prepared statement [{}]", preparedStatement); } - BoundStatement boundStatement = applyStatementSettings(preparedStatementBinder != null - ? preparedStatementBinder.bindValues(preparedStatement) : preparedStatement.bind()); + BoundStatement boundStatement = applyStatementSettings( + psb != null ? psb.bindValues(preparedStatement) : preparedStatement.bind()); ResultSet results = session.execute(boundStatement); @@ -513,10 +529,10 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { * @see org.springframework.data.cassandra.core.cqlOperations#query(org.springframework.data.cassandra.core.cql.PreparedStatementCreator, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.RowCallbackHandler) */ @Override - public void query(PreparedStatementCreator preparedStatementCreator, PreparedStatementBinder preparedStatementBinder, + public void query(PreparedStatementCreator preparedStatementCreator, @Nullable PreparedStatementBinder psb, RowCallbackHandler rowCallbackHandler) throws DataAccessException { - query(preparedStatementCreator, preparedStatementBinder, newResultSetExtractor(rowCallbackHandler)); + query(preparedStatementCreator, psb, newResultSetExtractor(rowCallbackHandler)); } /* @@ -525,9 +541,9 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { */ @Override public List query(PreparedStatementCreator preparedStatementCreator, - PreparedStatementBinder preparedStatementBinder, RowMapper rowMapper) throws DataAccessException { - - return query(preparedStatementCreator, preparedStatementBinder, newResultSetExtractor(rowMapper)); + @Nullable PreparedStatementBinder psb, RowMapper rowMapper) throws DataAccessException { + // noinspection ConstantConditions + return query(preparedStatementCreator, psb, newResultSetExtractor(rowMapper)); } /* @@ -556,6 +572,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { */ @Override public List query(String cql, RowMapper rowMapper, Object... args) throws DataAccessException { + // noinspection ConstantConditions return query(newPreparedStatementCreator(cql), newPreparedStatementBinder(args), newResultSetExtractor(rowMapper)); } @@ -564,10 +581,10 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { * @see org.springframework.data.cassandra.core.cqlOperations#query(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.ResultSetExtractor) */ @Override - public T query(String cql, PreparedStatementBinder preparedStatementBinder, + public T query(String cql, @Nullable PreparedStatementBinder psb, ResultSetExtractor resultSetExtractor) throws DataAccessException { - return query(newPreparedStatementCreator(cql), preparedStatementBinder, resultSetExtractor); + return query(newPreparedStatementCreator(cql), psb, resultSetExtractor); } /* @@ -575,10 +592,9 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { * @see org.springframework.data.cassandra.core.cqlOperations#query(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.RowCallbackHandler) */ @Override - public void query(String cql, PreparedStatementBinder preparedStatementBinder, RowCallbackHandler rowCallbackHandler) + public void query(String cql, @Nullable PreparedStatementBinder psb, RowCallbackHandler rowCallbackHandler) throws DataAccessException { - - query(newPreparedStatementCreator(cql), preparedStatementBinder, newResultSetExtractor(rowCallbackHandler)); + query(newPreparedStatementCreator(cql), psb, newResultSetExtractor(rowCallbackHandler)); } /* @@ -586,10 +602,10 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { * @see org.springframework.data.cassandra.core.cqlOperations#query(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.RowMapper) */ @Override - public List query(String cql, PreparedStatementBinder preparedStatementBinder, RowMapper rowMapper) + public List query(String cql, @Nullable PreparedStatementBinder psb, RowMapper rowMapper) throws DataAccessException { - - return query(newPreparedStatementCreator(cql), preparedStatementBinder, newResultSetExtractor(rowMapper)); + // noinspection ConstantConditions + return query(newPreparedStatementCreator(cql), psb, newResultSetExtractor(rowMapper)); } /* @@ -598,6 +614,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { */ @Override public List> queryForList(String cql, Object... args) throws DataAccessException { + // noinspection ConstantConditions return query(newPreparedStatementCreator(cql), newPreparedStatementBinder(args), newResultSetExtractor(newColumnMapRowMapper())); } @@ -608,6 +625,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { */ @Override public List queryForList(String cql, Class elementType, Object... args) throws DataAccessException { + // noinspection ConstantConditions return query(newPreparedStatementCreator(cql), newPreparedStatementBinder(args), newResultSetExtractor(newSingleColumnRowMapper(elementType))); } @@ -646,6 +664,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { */ @Override public ResultSet queryForResultSet(String cql, Object... args) throws DataAccessException { + // noinspection ConstantConditions return query(newPreparedStatementCreator(cql), newPreparedStatementBinder(args), rs -> rs); } @@ -697,18 +716,22 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { * Translate the given {@link DriverException} into a generic {@link DataAccessException}. * * @param task readable text describing the task being attempted - * @param cql CQL query or update that caused the problem (may be {@code null}) + * @param cql CQL query or update that caused the problem (may be {@literal null}) * @param driverException the offending {@code RuntimeException}. * @return the exception translation {@link Function} * @see CqlProvider */ - @SuppressWarnings("ThrowableResultOfMethodCallIgnored") - protected DataAccessException translateException(String task, String cql, DriverException driverException) { + protected DataAccessException translateException(String task, @Nullable String cql, DriverException driverException) { return translate(task, cql, driverException); } private Session getCurrentSession() { - return getSessionFactory().getSession(); + + SessionFactory sessionFactory = getSessionFactory(); + + Assert.state(sessionFactory != null, "SessionFactory is null"); + + return sessionFactory.getSession(); } private class SimplePreparedStatementCreator implements PreparedStatementCreator, CqlProvider { diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ExceptionTranslatingListenableFutureAdapter.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ExceptionTranslatingListenableFutureAdapter.java index 5caf208d9..cd4875aaa 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ExceptionTranslatingListenableFutureAdapter.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ExceptionTranslatingListenableFutureAdapter.java @@ -21,6 +21,7 @@ import java.util.concurrent.TimeoutException; import org.springframework.dao.DataAccessException; import org.springframework.dao.support.PersistenceExceptionTranslator; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.concurrent.FailureCallback; import org.springframework.util.concurrent.ListenableFuture; @@ -38,6 +39,7 @@ import org.springframework.util.concurrent.SuccessCallback; class ExceptionTranslatingListenableFutureAdapter implements ListenableFuture { private final ListenableFuture adaptee; + private final ListenableFuture future; /** @@ -47,7 +49,7 @@ class ExceptionTranslatingListenableFutureAdapter implements ListenableFuture * @param adaptee must not be {@literal null}. * @param persistenceExceptionTranslator must not be {@literal null}. */ - public ExceptionTranslatingListenableFutureAdapter(ListenableFuture adaptee, + ExceptionTranslatingListenableFutureAdapter(ListenableFuture adaptee, PersistenceExceptionTranslator persistenceExceptionTranslator) { Assert.notNull(adaptee, "ListenableFuture must not be null"); @@ -65,7 +67,7 @@ class ExceptionTranslatingListenableFutureAdapter implements ListenableFuture listenableFuture.addCallback(new ListenableFutureCallback() { @Override - public void onSuccess(T result) { + public void onSuccess(@Nullable T result) { settableFuture.set(result); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/GuavaListenableFutureAdapter.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/GuavaListenableFutureAdapter.java index 8b09edbcc..b4d838b59 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/GuavaListenableFutureAdapter.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/GuavaListenableFutureAdapter.java @@ -21,6 +21,7 @@ import java.util.concurrent.TimeoutException; import org.springframework.dao.DataAccessException; import org.springframework.dao.support.PersistenceExceptionTranslator; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.concurrent.FailureCallback; import org.springframework.util.concurrent.ListenableFuture; @@ -41,6 +42,7 @@ import com.google.common.util.concurrent.Futures; public class GuavaListenableFutureAdapter implements ListenableFuture { private final com.google.common.util.concurrent.ListenableFuture adaptee; + private final ListenableFuture future; /** @@ -68,7 +70,7 @@ public class GuavaListenableFutureAdapter implements ListenableFuture { Futures.addCallback(guavaFuture, new FutureCallback() { @Override - public void onSuccess(T result) { + public void onSuccess(@Nullable T result) { settableFuture.set(result); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/KeyspaceIdentifier.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/KeyspaceIdentifier.java index 2f0391f15..066097ad1 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/KeyspaceIdentifier.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/KeyspaceIdentifier.java @@ -25,9 +25,7 @@ import org.springframework.util.Assert; * Keyspace identifiers are converted to lower case. To render, use any of the methods {@link #toCql()}, * {@link #toCql(StringBuilder)}, or {@link #toString()}. * - * @see #KeyspaceIdentifier(String) * @see #toCql() - * @see #toCql(StringBuilder) * @see #toString() * @author Matthew T. Adams */ @@ -36,6 +34,25 @@ public final class KeyspaceIdentifier implements Comparable public static final String REGEX = "(?i)[a-z][\\w]{0,47}"; public static final Pattern PATTERN = Pattern.compile(REGEX); + private final String identifier; + + /** + * Create a new {@link KeyspaceIdentifier}. + */ + private KeyspaceIdentifier(CharSequence identifier) { + + Assert.notNull(identifier, "Identifier must not be null"); + + String string = identifier.toString(); + Assert.hasText(string, "Identifier must not be empty"); + + if (!isIdentifier(string)) { + throw new IllegalArgumentException( + String.format("given string [%s] is not a valid keyspace identifier", identifier)); + } + this.identifier = string.toLowerCase(); + } + /** * Factory method for {@link KeyspaceIdentifier}. Convenient if imported statically. */ @@ -50,32 +67,6 @@ public final class KeyspaceIdentifier implements Comparable return PATTERN.matcher(chars).matches() && !ReservedKeyword.isReserved(chars); } - private String identifier; - - /** - * Create a new {@link KeyspaceIdentifier}. - */ - public KeyspaceIdentifier(CharSequence identifier) { - setIdentifier(identifier); - } - - /** - * Tests & sets the given identifier. - */ - private void setIdentifier(CharSequence identifier) { - - Assert.notNull(identifier, "Identifier must not be null"); - - String string = identifier.toString(); - Assert.hasText(string, "Identifier must not be empty"); - - if (!isIdentifier(string)) { - throw new IllegalArgumentException( - String.format("given string [%s] is not a valid keyspace identifier", identifier)); - } - this.identifier = string.toLowerCase(); - } - /** * Renders this identifier appropriately. */ @@ -85,10 +76,10 @@ public final class KeyspaceIdentifier implements Comparable /** * Appends the rendering of this identifier to the given {@link StringBuilder}, then returns that - * {@link StringBuilder}. If {@code null} is given, a new {@link StringBuilder} is created, appended to, and returned. + * {@link StringBuilder}. If {@literal null} is given, a new {@link StringBuilder} is created, appended to, and + * returned. */ public StringBuilder toCql(StringBuilder sb) { - sb = sb == null ? new StringBuilder() : sb; return sb.append(toCql()); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/PreparedStatementCallback.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/PreparedStatementCallback.java index 6bc733c7d..31cc54c00 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/PreparedStatementCallback.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/PreparedStatementCallback.java @@ -16,6 +16,7 @@ package org.springframework.data.cassandra.core.cql; import org.springframework.dao.DataAccessException; +import org.springframework.lang.Nullable; import com.datastax.driver.core.PreparedStatement; import com.datastax.driver.core.Session; @@ -36,7 +37,7 @@ import com.datastax.driver.core.exceptions.DriverException; * @author Mark Paluch * @see AsyncCqlTemplate#execute(String, PreparedStatementCallback) * @see AsyncCqlTemplate#execute(AsyncPreparedStatementCreator, PreparedStatementCallback) - * @see CqlTemplate#execute(String, PreparedStatementCallback) + * @see CqlTemplate#execute(String, PreparedStatementCallback)} * @see CqlTemplate#execute(PreparedStatementCreator, PreparedStatementCallback) */ @FunctionalInterface @@ -58,10 +59,11 @@ public interface PreparedStatementCallback { * @throws DriverException if thrown by a session method, to be auto-converted to a {@link DataAccessException}. * @throws DataAccessException in case of custom exceptions. * @see AsyncCqlTemplate#queryForObject(String, Class, Object...) - * @see AsyncCqlTemplate#queryForList(String, Class, Object...) + * @see AsyncCqlOperations#queryForList(String, Class, Object...) * @see CqlTemplate#queryForObject(String, Class, Object...) * @see CqlTemplate#queryForList(String, Object...) */ + @Nullable T doInPreparedStatement(Session session, PreparedStatement preparedStatement) throws DriverException, DataAccessException; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/QueryOptions.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/QueryOptions.java index 9d73f0f67..dad353e92 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/QueryOptions.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/QueryOptions.java @@ -15,9 +15,10 @@ */ package org.springframework.data.cassandra.core.cql; -import java.util.Optional; +import java.time.Duration; import java.util.concurrent.TimeUnit; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import com.datastax.driver.core.ConsistencyLevel; @@ -33,30 +34,53 @@ import com.datastax.driver.core.policies.RetryPolicy; */ public class QueryOptions { - private ConsistencyLevel consistencyLevel; + private static final QueryOptions EMPTY = QueryOptions.builder().build(); - private RetryPolicy retryPolicy; + private final @Nullable ConsistencyLevel consistencyLevel; - private Boolean tracing; + private final @Nullable RetryPolicy retryPolicy; - private Integer fetchSize; + private final @Nullable Boolean tracing; - private Long readTimeout; + private final @Nullable Integer fetchSize; - /** - * Creates new {@link QueryOptions}. - */ - public QueryOptions() {} + private final Duration readTimeout; + + protected QueryOptions(@Nullable ConsistencyLevel consistencyLevel, @Nullable RetryPolicy retryPolicy, + @Nullable Boolean tracing, @Nullable Integer fetchSize, Duration readTimeout) { + + this.consistencyLevel = consistencyLevel; + this.retryPolicy = retryPolicy; + this.tracing = tracing; + this.fetchSize = fetchSize; + this.readTimeout = readTimeout; + } /** * Creates new {@link QueryOptions} for the given {@link ConsistencyLevel} and {@link RetryPolicy}. * * @param consistencyLevel the consistency level, may be {@literal null}. * @param retryPolicy the retry policy, may be {@literal null}. + * @deprecated since 2.0, use {@link #builder()}. */ - public QueryOptions(ConsistencyLevel consistencyLevel, RetryPolicy retryPolicy) { - setConsistencyLevel(consistencyLevel); - setRetryPolicy(retryPolicy); + @Deprecated + public QueryOptions(@Nullable ConsistencyLevel consistencyLevel, @Nullable RetryPolicy retryPolicy) { + + this.consistencyLevel = consistencyLevel; + this.retryPolicy = retryPolicy; + this.tracing = false; + this.fetchSize = null; + this.readTimeout = Duration.ofMillis(-1); + } + + /** + * Create default {@link QueryOptions}. + * + * @return default {@link QueryOptions}. + * @since 2.0 + */ + public static QueryOptions empty() { + return EMPTY; } /** @@ -69,111 +93,45 @@ public class QueryOptions { return new QueryOptionsBuilder(); } - /** - * Sets the driver {@link ConsistencyLevel}. Setting both ({@link ConsistencyLevel} and {@link ConsistencyLevel driver - * ConsistencyLevel}) consistency levels is not supported. - * - * @param consistencyLevel the driver {@link ConsistencyLevel} to set. - * @since 1.5 - */ - public void setConsistencyLevel(ConsistencyLevel consistencyLevel) { - this.consistencyLevel = consistencyLevel; - } - /** * @return the the driver {@link ConsistencyLevel} * @since 1.5 */ + @Nullable protected ConsistencyLevel getConsistencyLevel() { return this.consistencyLevel; } - /** - * Sets the {@link RetryPolicy}. Setting both ({@link RetryPolicy} and {@link RetryPolicy driver RetryPolicy}) retry - * policies is not supported. - * - * @param retryPolicy the driver {@link RetryPolicy} to set. - * @since 1.5 - * @throws IllegalStateException if the {@link RetryPolicy} is set - */ - public void setRetryPolicy(RetryPolicy retryPolicy) { - this.retryPolicy = retryPolicy; - } - /** * @return the driver {@link RetryPolicy} * @since 1.5 */ + @Nullable protected RetryPolicy getRetryPolicy() { return this.retryPolicy; } - /** - * Sets the query fetch size for {@link com.datastax.driver.core.ResultSet} chunks. - *

- * The fetch size controls how much resulting rows will be retrieved simultaneously (the goal being to avoid loading - * too much results in memory for queries yielding large results). Please note that while value as low as 1 can be - * used, it is *highly* discouraged to use such a low value in practice as it will yield very poor performance. - * - * @param fetchSize the number of rows to fetch per chunking request. To disable chunking of the result set, use - * {@code fetchSize == Integer.MAX_VALUE}. Negative values are not allowed. - * @since 1.5 - * @see com.datastax.driver.core.QueryOptions#getFetchSize() - * @see com.datastax.driver.core.Cluster.Builder#withQueryOptions(com.datastax.driver.core.QueryOptions) - */ - public void setFetchSize(int fetchSize) { - - Assert.isTrue(fetchSize >= 0, "FetchSize must be greater than equal to zero"); - - this.fetchSize = fetchSize; - } - /** * @return the number of rows to fetch per chunking request. May be {@literal null} if not set. * @since 1.5 */ + @Nullable protected Integer getFetchSize() { return fetchSize; } - /** - * Sets the read timeout in milliseconds. Overrides the default per-host read timeout ( - * {@link SocketOptions#getReadTimeoutMillis()}). - * - * @param readTimeout the read timeout in milliseconds. Negative values are not allowed. If it is {@code 0}, the read - * timeout will be disabled for this statement. - * @since 1.5 - * @see SocketOptions#getReadTimeoutMillis() - * @see com.datastax.driver.core.Cluster.Builder#withSocketOptions(SocketOptions) - */ - public void setReadTimeout(long readTimeout) { - - Assert.isTrue(readTimeout >= 0, "ReadTimeout must be greater than equal to zero"); - - this.readTimeout = readTimeout; - } - /** * @return the read timeout in milliseconds. May be {@literal null} if not set. * @since 1.5 */ - protected Long getReadTimeout() { + protected Duration getReadTimeout() { return this.readTimeout; } - /** - * Enables statement tracing. - * - * @param tracing {@literal true} to enable statement tracing to the executed statements. - * @since 1.5 - */ - public void setTracing(boolean tracing) { - this.tracing = tracing; - } - /** * @return whether to enable tracing. May be {@literal null} if not set. */ + @Nullable protected Boolean getTracing() { return this.tracing; } @@ -186,15 +144,15 @@ public class QueryOptions { */ public static class QueryOptionsBuilder { - private ConsistencyLevel consistencyLevel; + protected @Nullable ConsistencyLevel consistencyLevel; - private RetryPolicy retryPolicy; + protected @Nullable RetryPolicy retryPolicy; - private Boolean tracing; + protected @Nullable Boolean tracing; - private Integer fetchSize; + protected @Nullable Integer fetchSize; - private Long readTimeout; + protected Duration readTimeout = Duration.ofMillis(-1); QueryOptionsBuilder() {} @@ -261,12 +219,7 @@ public class QueryOptions { * @see com.datastax.driver.core.Cluster.Builder#withSocketOptions(SocketOptions) */ public QueryOptionsBuilder readTimeout(long readTimeout) { - - Assert.isTrue(readTimeout >= 0, "ReadTimeout must be greater than equal to zero"); - - this.readTimeout = readTimeout; - - return this; + return readTimeout(Duration.ofMillis(readTimeout)); } /** @@ -278,13 +231,33 @@ public class QueryOptions { * @return {@code this} {@link QueryOptionsBuilder} * @see SocketOptions#getReadTimeoutMillis() * @see com.datastax.driver.core.Cluster.Builder#withSocketOptions(SocketOptions) + * @deprecated since 2.0, use {@link #readTimeout(Duration)}. */ + @Deprecated public QueryOptionsBuilder readTimeout(long readTimeout, TimeUnit timeUnit) { Assert.isTrue(readTimeout >= 0, "ReadTimeout must be greater than equal to zero"); Assert.notNull(timeUnit, "TimeUnit must not be null"); - this.readTimeout = timeUnit.toMillis(readTimeout); + return readTimeout(Duration.ofMillis(timeUnit.toMillis(readTimeout))); + } + + /** + * Sets the read timeout. Overrides the default per-host read timeout. + * + * @param readTimeout the read timeout. Negative values are not allowed. If it is {@code 0}, the read timeout will + * be disabled for this statement. + * @return {@code this} {@link QueryOptionsBuilder} + * @see SocketOptions#getReadTimeoutMillis() + * @see com.datastax.driver.core.Cluster.Builder#withSocketOptions(SocketOptions) + * @since 2.0 + */ + public QueryOptionsBuilder readTimeout(Duration readTimeout) { + + Assert.isTrue(!readTimeout.isZero() && !readTimeout.isNegative(), + "ReadTimeout must be greater than equal to zero"); + + this.readTimeout = readTimeout; return this; } @@ -317,21 +290,7 @@ public class QueryOptions { * @return a new {@link QueryOptions} with the configured values */ public QueryOptions build() { - return applyOptions(new QueryOptions()); - } - - protected T applyOptions(T options) { - - QueryOptions queryOptions = (QueryOptions) options; - - queryOptions.setConsistencyLevel(consistencyLevel); - queryOptions.setRetryPolicy(retryPolicy); - - Optional.ofNullable(this.fetchSize).ifPresent(queryOptions::setFetchSize); - Optional.ofNullable(this.readTimeout).ifPresent(queryOptions::setReadTimeout); - Optional.ofNullable(this.tracing).ifPresent(queryOptions::setTracing); - - return options; + return new QueryOptions(consistencyLevel, retryPolicy, tracing, fetchSize, readTimeout); } } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/QueryOptionsUtil.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/QueryOptionsUtil.java index ad5448fe5..2b41b8fcc 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/QueryOptionsUtil.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/QueryOptionsUtil.java @@ -42,13 +42,11 @@ public abstract class QueryOptionsUtil { Assert.notNull(preparedStatement, "PreparedStatement must not be null"); - if (queryOptions != null) { - if (queryOptions.getConsistencyLevel() != null) { - preparedStatement.setConsistencyLevel(queryOptions.getConsistencyLevel()); - } - if (queryOptions.getRetryPolicy() != null) { - preparedStatement.setRetryPolicy(queryOptions.getRetryPolicy()); - } + if (queryOptions.getConsistencyLevel() != null) { + preparedStatement.setConsistencyLevel(queryOptions.getConsistencyLevel()); + } + if (queryOptions.getRetryPolicy() != null) { + preparedStatement.setRetryPolicy(queryOptions.getRetryPolicy()); } return preparedStatement; @@ -65,29 +63,27 @@ public abstract class QueryOptionsUtil { Assert.notNull(statement, "Statement must not be null"); - if (queryOptions != null) { - if (queryOptions.getConsistencyLevel() != null) { - statement.setConsistencyLevel(queryOptions.getConsistencyLevel()); - } + if (queryOptions.getConsistencyLevel() != null) { + statement.setConsistencyLevel(queryOptions.getConsistencyLevel()); + } - if (queryOptions.getRetryPolicy() != null) { - statement.setRetryPolicy(queryOptions.getRetryPolicy()); - } + if (queryOptions.getRetryPolicy() != null) { + statement.setRetryPolicy(queryOptions.getRetryPolicy()); + } - if (queryOptions.getFetchSize() != null) { - statement.setFetchSize(queryOptions.getFetchSize()); - } + if (queryOptions.getFetchSize() != null) { + statement.setFetchSize(queryOptions.getFetchSize()); + } - if (queryOptions.getReadTimeout() != null) { - statement.setReadTimeoutMillis(queryOptions.getReadTimeout().intValue()); - } + if (!queryOptions.getReadTimeout().isNegative()) { + statement.setReadTimeoutMillis(Math.toIntExact(queryOptions.getReadTimeout().toMillis())); + } - if (queryOptions.getTracing() != null) { - if (queryOptions.getTracing()) { - statement.enableTracing(); - } else { - statement.disableTracing(); - } + if (queryOptions.getTracing() != null) { + if (queryOptions.getTracing()) { + statement.enableTracing(); + } else { + statement.disableTracing(); } } @@ -105,12 +101,10 @@ public abstract class QueryOptionsUtil { Assert.notNull(insert, "Insert must not be null"); - if (writeOptions != null) { - addQueryOptions(insert, writeOptions); + addQueryOptions(insert, writeOptions); - if (writeOptions.getTtl() != null) { - insert.using(QueryBuilder.ttl(writeOptions.getTtl())); - } + if (!writeOptions.getTtl().isNegative()) { + insert.using(QueryBuilder.ttl(Math.toIntExact(writeOptions.getTtl().getSeconds()))); } return insert; @@ -127,12 +121,10 @@ public abstract class QueryOptionsUtil { Assert.notNull(update, "Update must not be null"); - if (writeOptions != null) { - addQueryOptions(update, writeOptions); + addQueryOptions(update, writeOptions); - if (writeOptions.getTtl() != null) { - update.using(QueryBuilder.ttl(writeOptions.getTtl())); - } + if (!writeOptions.getTtl().isNegative()) { + update.using(QueryBuilder.ttl(Math.toIntExact(writeOptions.getTtl().getSeconds()))); } return update; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ReactiveCassandraAccessor.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ReactiveCassandraAccessor.java index cc537e072..d122c1221 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ReactiveCassandraAccessor.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ReactiveCassandraAccessor.java @@ -21,6 +21,7 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.dao.DataAccessException; import org.springframework.data.cassandra.ReactiveSession; import org.springframework.data.cassandra.ReactiveSessionFactory; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import com.datastax.driver.core.exceptions.DriverException; @@ -44,7 +45,7 @@ public abstract class ReactiveCassandraAccessor implements InitializingBean { private CqlExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator(); - private ReactiveSessionFactory sessionFactory; + private @Nullable ReactiveSessionFactory sessionFactory; /** * Sets the {@link ReactiveSessionFactory} to use. @@ -63,6 +64,7 @@ public abstract class ReactiveCassandraAccessor implements InitializingBean { * * @return the configured {@link ReactiveSessionFactory}. */ + @Nullable public ReactiveSessionFactory getSessionFactory() { return sessionFactory; } @@ -97,9 +99,7 @@ public abstract class ReactiveCassandraAccessor implements InitializingBean { */ @Override public void afterPropertiesSet() { - - Assert.notNull(sessionFactory != null, "ReactiveSessionFactory must not be null"); - Assert.notNull(exceptionTranslator != null, "CassandraExceptionTranslator must not be null"); + Assert.notNull(sessionFactory, "ReactiveSessionFactory must not be null"); } /** @@ -117,6 +117,7 @@ public abstract class ReactiveCassandraAccessor implements InitializingBean { * exception hierarchy * @see DataAccessException */ + @Nullable protected DataAccessException translateExceptionIfPossible(DriverException ex) { Assert.notNull(ex, "DriverException must not be null"); @@ -133,7 +134,7 @@ public abstract class ReactiveCassandraAccessor implements InitializingBean { * subsequent cast) is considered reliable when expecting Cassandra-based access to have happened. * * @param task readable text describing the task being attempted - * @param cql CQL query or update that caused the problem (may be {@code null}) + * @param cql CQL query or update that caused the problem (may be {@literal null}) * @param ex the offending {@link DriverException} * @return the DataAccessException, wrapping the {@code DriverException} * @see org.springframework.dao.DataAccessException#getRootCause() @@ -141,7 +142,7 @@ public abstract class ReactiveCassandraAccessor implements InitializingBean { * "http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#dao-exceptions">Consistent * exception hierarchy */ - protected DataAccessException translate(String task, String cql, DriverException ex) { + protected DataAccessException translate(String task, @Nullable String cql, DriverException ex) { Assert.notNull(ex, "DriverException must not be null"); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ReactiveCqlOperations.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ReactiveCqlOperations.java index 7809303a6..7034fe642 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ReactiveCqlOperations.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ReactiveCqlOperations.java @@ -24,6 +24,7 @@ import org.reactivestreams.Publisher; import org.springframework.dao.DataAccessException; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.data.cassandra.ReactiveResultSet; +import org.springframework.lang.Nullable; import com.datastax.driver.core.PreparedStatement; import com.datastax.driver.core.Row; @@ -47,10 +48,10 @@ public interface ReactiveCqlOperations { // ------------------------------------------------------------------------- /** - * Execute a CQL data access operation, implemented as callback action working on a {@link ReactiveSession}. This - * allows for implementing arbitrary data access operations, within Spring's managed CQL environment: that is, - * converting CQL {@link com.datastax.driver.core.exceptions.DriverException}s into Spring's - * {@link DataAccessException} hierarchy. + * Execute a CQL data access operation, implemented as callback action working on a + * {@link org.springframework.data.cassandra.ReactiveSession}. This allows for implementing arbitrary data access + * operations, within Spring's managed CQL environment: that is, converting CQL + * {@link com.datastax.driver.core.exceptions.DriverException}s into Spring's {@link DataAccessException} hierarchy. *

* The callback action can return a result object, for example a domain object or a collection of domain objects. * @@ -409,8 +410,8 @@ public interface ReactiveCqlOperations { *

* The callback action can return a result object, for example a domain object or a collection of domain objects. * - * @param psc object that can create a {@link PreparedStatement} given a {@link ReactiveSession}, must not be - * {@literal null}. + * @param psc object that can create a {@link PreparedStatement} given a + * {@link org.springframework.data.cassandra.ReactiveSession}, must not be {@literal null}. * @param action callback object that specifies the action, must not be {@literal null}. * @return a result object returned by the action, or {@literal null}. * @throws DataAccessException if there is any problem @@ -436,8 +437,8 @@ public interface ReactiveCqlOperations { /** * Query using a prepared statement, reading the {@link ReactiveResultSet} with a {@link ReactiveResultSetExtractor}. * - * @param psc object that can create a {@link PreparedStatement} given a {@link ReactiveSession}, must not be - * {@literal null}. + * @param psc object that can create a {@link PreparedStatement} given a + * {@link org.springframework.data.cassandra.ReactiveSession}, must not be {@literal null}. * @param rse object that will extract results, must not be {@literal null}. * @return an arbitrary result object, as returned by the {@link ReactiveResultSetExtractor} * @throws DataAccessException if there is any problem @@ -455,7 +456,7 @@ public interface ReactiveCqlOperations { * @return an arbitrary result object, as returned by the {@link ReactiveResultSetExtractor}. * @throws DataAccessException if there is any problem */ - Flux query(String cql, PreparedStatementBinder psb, ReactiveResultSetExtractor rse) + Flux query(String cql, @Nullable PreparedStatementBinder psb, ReactiveResultSetExtractor rse) throws DataAccessException; /** @@ -471,7 +472,7 @@ public interface ReactiveCqlOperations { * @return an arbitrary result object, as returned by the {@link ResultSetExtractor}. * @throws DataAccessException if there is any problem */ - Flux query(ReactivePreparedStatementCreator psc, PreparedStatementBinder psb, + Flux query(ReactivePreparedStatementCreator psc, @Nullable PreparedStatementBinder psb, ReactiveResultSetExtractor rse) throws DataAccessException; /** @@ -490,8 +491,8 @@ public interface ReactiveCqlOperations { /** * Query using a prepared statement, mapping each row to a Java object via a {@link RowMapper}. * - * @param psc object that can create a {@link PreparedStatement} given a {@link ReactiveSession}, must not be - * {@literal null}. + * @param psc object that can create a {@link PreparedStatement} given a + * {@link org.springframework.data.cassandra.ReactiveSession}, must not be {@literal null}. * @param rowMapper object that will map one object per row, must not be {@literal null}. * @return the result {@link Flux}, containing mapped objects. * @throws DataAccessException if there is any problem executing the query. @@ -510,7 +511,8 @@ public interface ReactiveCqlOperations { * @return the result {@link Flux}, containing mapped objects. * @throws DataAccessException if there is any problem executing the query. */ - Flux query(String cql, PreparedStatementBinder psb, RowMapper rowMapper) throws DataAccessException; + Flux query(String cql, @Nullable PreparedStatementBinder psb, RowMapper rowMapper) + throws DataAccessException; /** * Query using a prepared statement and a {@link PreparedStatementBinder} implementation that knows how to bind values @@ -525,7 +527,7 @@ public interface ReactiveCqlOperations { * @return the result {@link Flux}, containing mapped objects. * @throws DataAccessException if there is any problem executing the query. */ - Flux query(ReactivePreparedStatementCreator psc, PreparedStatementBinder psb, RowMapper rowMapper) + Flux query(ReactivePreparedStatementCreator psc, @Nullable PreparedStatementBinder psb, RowMapper rowMapper) throws DataAccessException; /** @@ -682,7 +684,7 @@ public interface ReactiveCqlOperations { * @return boolean value whether the statement was applied. * @throws DataAccessException if there is any problem issuing the execution. */ - Mono execute(String cql, PreparedStatementBinder psb) throws DataAccessException; + Mono execute(String cql, @Nullable PreparedStatementBinder psb) throws DataAccessException; /** * Issue a single CQL operation (such as an insert, update or delete statement) via a prepared statement, binding the diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ReactiveCqlTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ReactiveCqlTemplate.java index 6dc9d405b..36f16711d 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ReactiveCqlTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ReactiveCqlTemplate.java @@ -29,6 +29,7 @@ import org.springframework.data.cassandra.ReactiveResultSet; import org.springframework.data.cassandra.ReactiveSession; import org.springframework.data.cassandra.ReactiveSessionFactory; import org.springframework.data.cassandra.core.cql.session.DefaultReactiveSessionFactory; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import com.datastax.driver.core.BoundStatement; @@ -95,13 +96,13 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re * If this variable is set to a value, it will be used for setting the {@code retryPolicy} property on statements used * for query processing. */ - private RetryPolicy retryPolicy; + private @Nullable RetryPolicy retryPolicy; /** * If this variable is set to a value, it will be used for setting the {@code consistencyLevel} property on statements * used for query processing. */ - private com.datastax.driver.core.ConsistencyLevel consistencyLevel; + private @Nullable com.datastax.driver.core.ConsistencyLevel consistencyLevel; /** * Construct a new {@link ReactiveCqlTemplate Note: The {@link ReactiveSessionFactory} has to be set before using the @@ -132,6 +133,7 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re * be {@literal null}. */ public ReactiveCqlTemplate(ReactiveSessionFactory reactiveSessionFactory) { + setSessionFactory(reactiveSessionFactory); afterPropertiesSet(); } @@ -145,13 +147,14 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re * @see Statement#setConsistencyLevel(ConsistencyLevel) * @see RetryPolicy */ - public void setConsistencyLevel(ConsistencyLevel consistencyLevel) { + public void setConsistencyLevel(@Nullable ConsistencyLevel consistencyLevel) { this.consistencyLevel = consistencyLevel; } /** * @return the {@link ConsistencyLevel} specified for this {@link ReactiveCqlTemplate}. */ + @Nullable public ConsistencyLevel getConsistencyLevel() { return consistencyLevel; } @@ -183,13 +186,14 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re * @see Statement#setRetryPolicy(RetryPolicy) * @see RetryPolicy */ - public void setRetryPolicy(RetryPolicy retryPolicy) { + public void setRetryPolicy(@Nullable RetryPolicy retryPolicy) { this.retryPolicy = retryPolicy; } /** * @return the {@link RetryPolicy} specified for this {@link ReactiveCqlTemplate}. */ + @Nullable public RetryPolicy getRetryPolicy() { return retryPolicy; } @@ -479,8 +483,9 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re * @return an arbitrary result object, as returned by the {@link ReactiveResultSetExtractor} * @throws DataAccessException if there is any problem */ - public Flux query(ReactivePreparedStatementCreator psc, PreparedStatementBinder preparedStatementBinder, - ReactiveResultSetExtractor rse) throws DataAccessException { + public Flux query(ReactivePreparedStatementCreator psc, + @Nullable PreparedStatementBinder preparedStatementBinder, ReactiveResultSetExtractor rse) + throws DataAccessException { Assert.notNull(psc, "ReactivePreparedStatementCreator must not be null"); Assert.notNull(rse, "ReactiveResultSetExtractor object must not be null"); @@ -506,7 +511,6 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re @Override public Flux query(ReactivePreparedStatementCreator psc, ReactiveResultSetExtractor rse) throws DataAccessException { - return query(psc, null, rse); } @@ -514,9 +518,8 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re * @see org.springframework.data.cassandra.core.cql.ReactiveCqlOperations#query(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.ReactiveResultSetExtractor) */ @Override - public Flux query(String cql, PreparedStatementBinder psb, ReactiveResultSetExtractor rse) + public Flux query(String cql, @Nullable PreparedStatementBinder psb, ReactiveResultSetExtractor rse) throws DataAccessException { - return query(new SimpleReactivePreparedStatementCreator(cql), psb, rse); } @@ -540,7 +543,8 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re * @see org.springframework.data.cassandra.core.cql.ReactiveCqlOperations#query(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.RowMapper) */ @Override - public Flux query(String cql, PreparedStatementBinder psb, RowMapper rowMapper) throws DataAccessException { + public Flux query(String cql, @Nullable PreparedStatementBinder psb, RowMapper rowMapper) + throws DataAccessException { return query(cql, psb, new ReactiveRowMapperResultSetExtractor<>(rowMapper)); } @@ -548,8 +552,8 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re * @see org.springframework.data.cassandra.core.cql.ReactiveCqlOperations#query(org.springframework.data.cassandra.core.cql.ReactivePreparedStatementCreator, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.RowMapper) */ @Override - public Flux query(ReactivePreparedStatementCreator psc, PreparedStatementBinder psb, RowMapper rowMapper) - throws DataAccessException { + public Flux query(ReactivePreparedStatementCreator psc, @Nullable PreparedStatementBinder psb, + RowMapper rowMapper) throws DataAccessException { return query(psc, psb, new ReactiveRowMapperResultSetExtractor<>(rowMapper)); } @@ -636,7 +640,7 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re * @see org.springframework.data.cassandra.core.cql.ReactiveCqlOperations#execute(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementBinder) */ @Override - public Mono execute(String cql, PreparedStatementBinder psb) throws DataAccessException { + public Mono execute(String cql, @Nullable PreparedStatementBinder psb) throws DataAccessException { return query(new SimpleReactivePreparedStatementCreator(cql), psb, resultSet -> Mono.just(resultSet.wasApplied())) .next(); } @@ -699,7 +703,7 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re * Create a reusable {@link Mono} given a {@link ReactiveStatementCallback} without exception translation. * * @param callback must not be {@literal null}. - * @return a reusable {@link Mono} wrapping the {@link ReactiveStatementCallback }. + * @return a reusable {@link Mono} wrapping the {@link ReactiveStatementCallback}. */ protected Mono createMono(Statement statement, ReactiveStatementCallback callback) { @@ -731,11 +735,11 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re * Exception translation {@link Function} intended for {@link Mono#otherwise(Function)} usage. * * @param task readable text describing the task being attempted - * @param cql CQL query or update that caused the problem (may be {@code null}) + * @param cql CQL query or update that caused the problem (may be {@literal null}) * @return the exception translation {@link Function} * @see CqlProvider */ - protected Function translateException(String task, String cql) { + protected Function translateException(String task, @Nullable String cql) { return throwable -> throwable instanceof DriverException ? translate(task, cql, (DriverException) throwable) : throwable; } @@ -828,17 +832,23 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re } private ReactiveSession getSession() { - return getSessionFactory().getSession(); + + ReactiveSessionFactory sessionFactory = getSessionFactory(); + + Assert.state(sessionFactory != null, "SessionFactory is null"); + + return sessionFactory.getSession(); } /** * Determine CQL from potential provider object. * * @param cqlProvider object that's potentially a {@link CqlProvider} - * @return the CQL string, or {@code null} + * @return the CQL string, or {@literal null} * @see CqlProvider */ - private static String getCql(Object cqlProvider) { + @Nullable + private static String getCql(@Nullable Object cqlProvider) { return Optional.ofNullable(cqlProvider) // .filter(o -> o instanceof CqlProvider) // @@ -847,7 +857,7 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re .orElse(null); } - private class SimpleReactivePreparedStatementCreator implements ReactivePreparedStatementCreator, CqlProvider { + class SimpleReactivePreparedStatementCreator implements ReactivePreparedStatementCreator, CqlProvider { private final String cql; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ResultSetExtractor.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ResultSetExtractor.java index 4db93212d..03f4a0bd8 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ResultSetExtractor.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ResultSetExtractor.java @@ -16,6 +16,7 @@ package org.springframework.data.cassandra.core.cql; import org.springframework.dao.DataAccessException; +import org.springframework.lang.Nullable; import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.exceptions.DriverException; @@ -52,5 +53,6 @@ public interface ResultSetExtractor { * there's no need to catch {@link DriverException}) * @throws DataAccessException in case of custom exceptions */ + @Nullable T extractData(ResultSet resultSet) throws DriverException, DataAccessException; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/RingMemberHostMapper.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/RingMemberHostMapper.java index f422bd4d8..b74a64441 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/RingMemberHostMapper.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/RingMemberHostMapper.java @@ -29,7 +29,6 @@ import com.datastax.driver.core.exceptions.DriverException; * * @author David Webb * @author Mark Paluch - * @param */ public enum RingMemberHostMapper implements HostMapper { diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/RowCallbackHandler.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/RowCallbackHandler.java index bfe17c006..ce2e988d0 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/RowCallbackHandler.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/RowCallbackHandler.java @@ -39,15 +39,15 @@ import com.datastax.driver.core.exceptions.DriverException; public interface RowCallbackHandler { /** - * Implementations must implement this method to process each row of data in the {@link ResultSet}. This method is - * only supposed to extract values of the current row. + * Implementations must implement this method to process each row of data in the + * {@link com.datastax.driver.core.ResultSet}. This method is only supposed to extract values of the current row. *

* Exactly what the implementation chooses to do is up to it: A trivial implementation might simply count rows, while * another implementation might build an XML document. * * @param row the {@link Row} to process (pre-initialized for the current row). * @throws DriverException if a {@link DriverException} is encountered getting column values (that is, there's no need - * to catch {@link DriverException}) + * to catch {@link DriverException}). */ void processRow(Row row) throws DriverException; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/RowMapper.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/RowMapper.java index 61ff83c9f..c9e99724c 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/RowMapper.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/RowMapper.java @@ -15,6 +15,8 @@ */ package org.springframework.data.cassandra.core.cql; +import org.springframework.lang.Nullable; + import com.datastax.driver.core.Row; import com.datastax.driver.core.exceptions.DriverException; @@ -46,5 +48,6 @@ public interface RowMapper { * @throws DriverException if a {@link DriverException} is encountered getting column values (that is, there's no need * to catch {@link DriverException}) */ + @Nullable T mapRow(Row row, int rowNum) throws DriverException; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/RowUtils.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/RowUtils.java index 1d82aa742..c5facca1c 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/RowUtils.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/RowUtils.java @@ -19,6 +19,8 @@ import java.math.BigDecimal; import java.nio.ByteBuffer; import java.util.UUID; +import org.springframework.lang.Nullable; + import com.datastax.driver.core.LocalDate; import com.datastax.driver.core.Row; import com.datastax.driver.core.TupleValue; @@ -44,10 +46,11 @@ public abstract class RowUtils { * * @param row is the {@link Row} holding the data * @param index is the column index - * @param requiredType the required value type (may be {@code null}) + * @param requiredType the required value type (may be {@literal null}) * @return the value object */ - public static Object getRowValue(Row row, int index, Class requiredType) { + @Nullable + public static Object getRowValue(Row row, int index, @Nullable Class requiredType) { if (requiredType == null) { return row.getObject(index); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/SessionCallback.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/SessionCallback.java index 03540172c..e8ec8023c 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/SessionCallback.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/SessionCallback.java @@ -47,7 +47,7 @@ public interface SessionCallback { * template. * * @param session active Cassandra Session, must not be {@literal null}. - * @return a result object, or {@code null} if none. + * @return a result object, or {@literal null} if none. * @throws DriverException if thrown by a Session method, to be auto-converted to a {@link DataAccessException}. * @throws DataAccessException in case of custom exceptions. * @see CqlTemplate#queryForObject(String, Class) diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/SimplePreparedStatementCreator.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/SimplePreparedStatementCreator.java index 0fe334f00..24859d108 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/SimplePreparedStatementCreator.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/SimplePreparedStatementCreator.java @@ -44,6 +44,7 @@ public class SimplePreparedStatementCreator implements PreparedStatementCreator, public SimplePreparedStatementCreator(String cql) { Assert.notNull(cql, "CQL is required to create a PreparedStatement"); + this.cql = cql; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/SingleColumnRowMapper.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/SingleColumnRowMapper.java index adde84b1d..9e07b7a67 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/SingleColumnRowMapper.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/SingleColumnRowMapper.java @@ -16,6 +16,7 @@ package org.springframework.data.cassandra.core.cql; import org.springframework.dao.TypeMismatchDataAccessException; +import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; import org.springframework.util.NumberUtils; @@ -41,7 +42,7 @@ import com.datastax.driver.core.exceptions.DriverException; */ public class SingleColumnRowMapper implements RowMapper { - private Class requiredType; + private @Nullable Class requiredType; /** * Create a new {@link SingleColumnRowMapper} for bean-style configuration. @@ -119,13 +120,14 @@ public class SingleColumnRowMapper implements RowMapper { * * @param row is the {@link Row} holding the data, must not be {@literal null}. * @param index is the column index - * @param requiredType the type that each result object is expected to match (or {@code null} if none specified). + * @param requiredType the type that each result object is expected to match (or {@literal null} if none specified). * @return the Object value. * @throws DriverException in case of extraction failure * @see RowUtils#getRowValue(Row, int, Class) * @see #getColumnValue(Row, int) */ - protected Object getColumnValue(Row row, int index, Class requiredType) throws DriverException { + @Nullable + protected Object getColumnValue(Row row, int index, @Nullable Class requiredType) throws DriverException { if (requiredType != null) { return RowUtils.getRowValue(row, index, requiredType); @@ -148,6 +150,7 @@ public class SingleColumnRowMapper implements RowMapper { * @throws DriverException in case of extraction failure. * @see RowUtils#getRowValue(Row, int, Class) */ + @Nullable protected Object getColumnValue(Row row, int index) { return RowUtils.getRowValue(row, index, null); } @@ -160,8 +163,8 @@ public class SingleColumnRowMapper implements RowMapper { * the value will be converted into a Number, either through number conversion or through String parsing (depending on * the value type). * - * @param value the column value as extracted from {@code getColumnValue()} (never {@code null}) - * @param requiredType the type that each result object is expected to match (never {@code null}) + * @param value the column value as extracted from {@code getColumnValue()} (never {@literal null}) + * @param requiredType the type that each result object is expected to match (never {@literal null}) * @return the converted value * @see #getColumnValue(Row, int, Class) */ diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/WriteOptions.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/WriteOptions.java index 2a9723c1f..e3d64679c 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/WriteOptions.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/WriteOptions.java @@ -15,8 +15,12 @@ */ package org.springframework.data.cassandra.core.cql; +import java.time.Duration; import java.util.concurrent.TimeUnit; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; + import com.datastax.driver.core.ConsistencyLevel; import com.datastax.driver.core.policies.RetryPolicy; @@ -30,20 +34,19 @@ import com.datastax.driver.core.policies.RetryPolicy; */ public class WriteOptions extends QueryOptions { - private Integer ttl; + private static final WriteOptions EMPTY = new WriteOptionsBuilder().build(); - /** - * Creates new {@link WriteOptions}. - */ - public WriteOptions() {} + private final Duration ttl; /** * Creates new {@link WriteOptions} for the given {@link ConsistencyLevel} and {@link RetryPolicy}. * * @param consistencyLevel the consistency level, may be {@literal null}. * @param retryPolicy the retry policy, may be {@literal null}. + * @deprecated since 2.0, use {@link #builder()} or {@link #empty()}. */ - public WriteOptions(ConsistencyLevel consistencyLevel, RetryPolicy retryPolicy) { + @Deprecated + public WriteOptions(@Nullable ConsistencyLevel consistencyLevel, @Nullable RetryPolicy retryPolicy) { this(consistencyLevel, retryPolicy, null); } @@ -53,10 +56,32 @@ public class WriteOptions extends QueryOptions { * @param consistencyLevel the consistency level, may be {@literal null}. * @param retryPolicy the retry policy, may be {@literal null}. * @param ttl the ttl, may be {@literal null}. + * @deprecated since 2.0, use {@link #builder()}. */ - public WriteOptions(ConsistencyLevel consistencyLevel, RetryPolicy retryPolicy, Integer ttl) { + @Deprecated + public WriteOptions(@Nullable ConsistencyLevel consistencyLevel, @Nullable RetryPolicy retryPolicy, + @Nullable Integer ttl) { + super(consistencyLevel, retryPolicy); - setTtl(ttl); + + this.ttl = ttl == null ? Duration.ofMillis(-1) : Duration.ofSeconds(ttl); + } + + protected WriteOptions(@Nullable ConsistencyLevel consistencyLevel, @Nullable RetryPolicy retryPolicy, + @Nullable Boolean tracing, @Nullable Integer fetchSize, Duration readTimeout, Duration ttl) { + + super(consistencyLevel, retryPolicy, tracing, fetchSize, readTimeout); + this.ttl = ttl; + } + + /** + * Create default {@link WriteOptions}. + * + * @return default {@link WriteOptions}. + * @since 2.0 + */ + public static WriteOptions empty() { + return EMPTY; } /** @@ -72,19 +97,10 @@ public class WriteOptions extends QueryOptions { /** * @return the time to live, if set. */ - public Integer getTtl() { + public Duration getTtl() { return this.ttl; } - /** - * Sets the time to live for write operations. - * - * @param ttl the ttl to set. - */ - public void setTtl(Integer ttl) { - this.ttl = ttl; - } - /** * Builder for {@link QueryOptions}. * @@ -93,7 +109,7 @@ public class WriteOptions extends QueryOptions { */ public static class WriteOptionsBuilder extends QueryOptionsBuilder { - private Integer ttl; + protected Duration ttl = Duration.ofMillis(-1); protected WriteOptionsBuilder() {} @@ -138,10 +154,16 @@ public class WriteOptions extends QueryOptions { * @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#readTimeout(long, java.util.concurrent.TimeUnit) */ @Override + @Deprecated public WriteOptionsBuilder readTimeout(long readTimeout, TimeUnit timeUnit) { return (WriteOptionsBuilder) super.readTimeout(readTimeout, timeUnit); } + @Override + public WriteOptionsBuilder readTimeout(Duration readTimeout) { + return (WriteOptionsBuilder) super.readTimeout(readTimeout); + } + /* * (non-Javadoc) * @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#tracing(boolean) @@ -161,13 +183,34 @@ public class WriteOptions extends QueryOptions { } /** - * Sets the time to live for write operations. + * Sets the time to live in seconds for write operations. * * @param ttl the time to live. * @return {@code this} {@link WriteOptionsBuilder} */ public WriteOptionsBuilder ttl(int ttl) { + + Assert.isTrue(ttl >= 0, "TTL must be greater than equal to zero"); + + this.ttl = Duration.ofSeconds(ttl); + + return this; + } + + /** + * Sets the time to live in seconds for write operations. + * + * @param ttl the time to live. + * @return {@code this} {@link WriteOptionsBuilder} + * @since 2.0 + */ + public WriteOptionsBuilder ttl(Duration ttl) { + + Assert.notNull(ttl, "TTL must not be null"); + Assert.isTrue(!ttl.isNegative(), "TTL must be greater than equal to zero"); + this.ttl = ttl; + return this; } @@ -177,17 +220,7 @@ public class WriteOptions extends QueryOptions { * @return a new {@link WriteOptions} with the configured values */ public WriteOptions build() { - return applyOptions(new WriteOptions()); - } - - @Override - protected T applyOptions(T queryOptions) { - - WriteOptions writeOptions = (WriteOptions) queryOptions; - - writeOptions.setTtl(this.ttl); - - return super.applyOptions(queryOptions); + return new WriteOptions(consistencyLevel, retryPolicy, tracing, fetchSize, readTimeout, ttl); } } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/AbstractResultSetConverter.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/AbstractResultSetConverter.java index 10d35332b..9c46d3230 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/AbstractResultSetConverter.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/AbstractResultSetConverter.java @@ -19,6 +19,7 @@ import java.util.List; import java.util.Map; import org.springframework.core.convert.converter.Converter; +import org.springframework.lang.Nullable; import com.datastax.driver.core.ResultSet; @@ -59,6 +60,7 @@ public abstract class AbstractResultSetConverter implements Converter implements Converter implements Converter> list = converter.convert(source); + if (list == null) { + return getNullResultSetValue(); + } + if (list.size() == 1) { Map map = list.get(0); @@ -97,8 +100,9 @@ public abstract class AbstractResultSetConverter implements Converter> resultSet) { - doThrow("result set"); - return null; + + throw new IllegalArgumentException( + String.format("Cannot convert %s to desired type [%s]", "result set", getType().getName())); } /** @@ -106,12 +110,8 @@ public abstract class AbstractResultSetConverter implements Converter row) { - doThrow("row"); - return null; - } - void doThrow(String string) { throw new IllegalArgumentException( - String.format("Cannot convert %s to desired type [%s]", string, getType().getName())); + String.format("Cannot convert %s to desired type [%s]", "row", getType().getName())); } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/ResultSetToArrayConverter.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/ResultSetToArrayConverter.java index f3e210cc4..9b14d2f71 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/ResultSetToArrayConverter.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/ResultSetToArrayConverter.java @@ -51,10 +51,6 @@ public class ResultSetToArrayConverter implements Converter @Override public Object[] convert(ResultSet resultSet) { - if (resultSet == null) { - return null; - } - List list = new ArrayList<>(); for (Row row : resultSet) { list.add(rowConverter.convert(row)); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/ResultSetToByteBufferConverter.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/ResultSetToByteBufferConverter.java index e7a9ec2d1..0336c737b 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/ResultSetToByteBufferConverter.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/ResultSetToByteBufferConverter.java @@ -37,7 +37,8 @@ public class ResultSetToByteBufferConverter extends AbstractResultSetConverter> convert(ResultSet resultSet) { - if (resultSet == null) { - return null; - } - List> list = new ArrayList<>(); for (Row row : resultSet) { list.add(rowConverter.convert(row)); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/ResultSetToListOfStringConverter.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/ResultSetToListOfStringConverter.java index 9dcc0b654..03adeaf0b 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/ResultSetToListOfStringConverter.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/ResultSetToListOfStringConverter.java @@ -15,7 +15,7 @@ */ package org.springframework.data.cassandra.core.cql.converter; -import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -39,11 +39,7 @@ public class ResultSetToListOfStringConverter extends AbstractResultSetConverter */ @Override protected List doConvertSingleValue(Object object) { - - List list = new ArrayList<>(); - - list.add(object == null ? null : object.toString()); - return list; + return Collections.singletonList(object.toString()); } /* (non-Javadoc) diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/ResultSetToStringConverter.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/ResultSetToStringConverter.java index 0382f399d..650ed302a 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/ResultSetToStringConverter.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/ResultSetToStringConverter.java @@ -36,7 +36,7 @@ public class ResultSetToStringConverter extends AbstractResultSetConverter> { @Override public List convert(Row row) { - if (row == null) { - return null; - } - ColumnDefinitions cols = row.getColumnDefinitions(); return cols.asList().stream() // .map(Definition::getName).map(name -> row.isNull(name) ? null : row.getObject(name)) // diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/RowToMapConverter.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/RowToMapConverter.java index 1b0ebd2c8..261f88b82 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/RowToMapConverter.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/RowToMapConverter.java @@ -44,10 +44,6 @@ public enum RowToMapConverter implements Converter> { @Override public Map convert(Row row) { - if (row == null) { - return null; - } - ColumnDefinitions cols = row.getColumnDefinitions(); Map map = new HashMap<>(cols.size()); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/package-info.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/package-info.java index b5d266d70..b396729eb 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/package-info.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/converter/package-info.java @@ -1,4 +1,7 @@ /** * CQL specific converters. */ +@NonNullApi package org.springframework.data.cassandra.core.cql.converter; + +import org.springframework.lang.NonNullApi; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/AddColumnCqlGenerator.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/AddColumnCqlGenerator.java index e2126be2e..896d08961 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/AddColumnCqlGenerator.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/AddColumnCqlGenerator.java @@ -15,8 +15,6 @@ */ package org.springframework.data.cassandra.core.cql.generator; -import static org.springframework.data.cassandra.core.cql.CqlStringUtils.*; - import org.springframework.data.cassandra.core.cql.keyspace.AddColumnSpecification; /** @@ -39,7 +37,7 @@ public class AddColumnCqlGenerator extends ColumnChangeCqlGenerator { - public static String toCql(AlterKeyspaceSpecification specification) { - return new AlterKeyspaceCqlGenerator(specification).toCql(); - } - public AlterKeyspaceCqlGenerator(AlterKeyspaceSpecification specification) { super(specification); } + public static String toCql(AlterKeyspaceSpecification specification) { + return new AlterKeyspaceCqlGenerator(specification).toCql(); + } + @Override public StringBuilder toCql(StringBuilder cql) { - cql = noNull(cql); preambleCql(cql); optionsCql(cql); @@ -49,13 +46,12 @@ public class AlterKeyspaceCqlGenerator extends KeyspaceOptionsCqlGenerator options = spec().getOptions(); @@ -97,7 +93,5 @@ public class AlterKeyspaceCqlGenerator extends KeyspaceOptionsCqlGenerator { + /** + * Create a new {@literal {@link AlterTableCqlGenerator}. @param specification must not be {@literal null}. + */ + public AlterTableCqlGenerator(AlterTableSpecification specification) { + super(specification); + } + /** * Generates a CQL statement from the given {@code specification}. * @@ -48,18 +53,8 @@ public class AlterTableCqlGenerator extends TableOptionsCqlGenerator getCqlGeneratorFor(ColumnChangeSpecification change) { + private ColumnChangeCqlGenerator getCqlGeneratorFor(ColumnChangeSpecification change) { if (change instanceof AddColumnSpecification) { return new AddColumnCqlGenerator((AddColumnSpecification) change); @@ -121,14 +114,12 @@ public class AlterTableCqlGenerator extends TableOptionsCqlGenerator options = spec().getOptions(); - if (options == null || options.isEmpty()) { - return cql; + if (options.isEmpty()) { + return; } cql.append("WITH "); @@ -169,7 +160,5 @@ public class AlterTableCqlGenerator extends TableOptionsCqlGenerator { - public static String toCql(AlterUserTypeSpecification specification) { - return new AlterUserTypeCqlGenerator(specification).toCql(); - } - /** * Create a new {@link AlterUserTypeCqlGenerator} for a {@link AlterUserTypeSpecification}. * @@ -50,6 +44,10 @@ public class AlterUserTypeCqlGenerator extends UserTypeNameCqlGenerator { - public static String toCql(CreateIndexSpecification specification) { - return new CreateIndexCqlGenerator(specification).toCql(); - } - public CreateIndexCqlGenerator(CreateIndexSpecification specification) { super(specification); } + public static String toCql(CreateIndexSpecification specification) { + return new CreateIndexCqlGenerator(specification).toCql(); + } + @Override public StringBuilder toCql(StringBuilder cql) { - cql = noNull(cql); - cql.append("CREATE").append(spec().isCustom() ? " CUSTOM" : "").append(" INDEX") .append(spec().getIfNotExists() ? " IF NOT EXISTS" : ""); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/CreateKeyspaceCqlGenerator.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/CreateKeyspaceCqlGenerator.java index cb1cd5f46..1614f9d16 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/CreateKeyspaceCqlGenerator.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/CreateKeyspaceCqlGenerator.java @@ -15,8 +15,6 @@ */ package org.springframework.data.cassandra.core.cql.generator; -import static org.springframework.data.cassandra.core.cql.CqlStringUtils.*; - import java.util.Map; import org.springframework.data.cassandra.core.cql.keyspace.CreateKeyspaceSpecification; @@ -30,21 +28,19 @@ import org.springframework.data.cassandra.core.cql.keyspace.Option; * @author Matthew T. Adams * @author Alex Shvid */ -public class CreateKeyspaceCqlGenerator extends KeyspaceCqlGenerator { - - public static String toCql(CreateKeyspaceSpecification specification) { - return new CreateKeyspaceCqlGenerator(specification).toCql(); - } +public class CreateKeyspaceCqlGenerator extends KeyspaceOptionsCqlGenerator { public CreateKeyspaceCqlGenerator(CreateKeyspaceSpecification specification) { super(specification); } + public static String toCql(CreateKeyspaceSpecification specification) { + return new CreateKeyspaceCqlGenerator(specification).toCql(); + } + @Override public StringBuilder toCql(StringBuilder cql) { - cql = noNull(cql); - preambleCql(cql); optionsCql(cql); @@ -53,14 +49,13 @@ public class CreateKeyspaceCqlGenerator extends KeyspaceCqlGenerator { - - public static String toCql(CreateTableSpecification specification) { - return new CreateTableCqlGenerator(specification).toCql(); - } +public class CreateTableCqlGenerator extends TableOptionsCqlGenerator> { public CreateTableCqlGenerator(CreateTableSpecification specification) { super(specification); } + public static String toCql(CreateTableSpecification specification) { + return new CreateTableCqlGenerator(specification).toCql(); + } + + @Override + protected CreateTableSpecification spec() { + return (CreateTableSpecification) super.spec(); + } + @Override public StringBuilder toCql(StringBuilder cql) { - cql = noNull(cql); - preambleCql(cql); columnsAndOptionsCql(cql); @@ -55,15 +59,12 @@ public class CreateTableCqlGenerator extends TableCqlGenerator options = spec().getOptions(); - if (ordering != null || !options.isEmpty()) { + if (!options.isEmpty()) { // option preamble boolean first = true; cql.append(" WITH "); // end option preamble - if (ordering != null) { + if (StringUtils.hasText(ordering)) { cql.append(ordering); first = false; } + if (!options.isEmpty()) { for (String name : options.keySet()) { // append AND if we're not on first option @@ -153,17 +155,16 @@ public class CreateTableCqlGenerator extends TableCqlGenerator columns) { - StringBuilder ordering = null; + + StringBuilder ordering = new StringBuilder(); boolean first = true; for (ColumnSpecification col : columns) { if (col.getOrdering() != null) { // then ordering specified - if (ordering == null) { // then initialize ordering clause + if (StringUtils.isEmpty(ordering)) { // then initialize ordering clause ordering = new StringBuilder().append("CLUSTERING ORDER BY ("); } if (first) { @@ -174,9 +175,11 @@ public class CreateTableCqlGenerator extends TableCqlGenerator { - public static String toCql(CreateUserTypeSpecification specification) { - return new CreateUserTypeCqlGenerator(specification).toCql(); - } - /** * Create a new {@link CreateUserTypeCqlGenerator} for a given {@link CreateUserTypeSpecification}. * @@ -44,6 +38,10 @@ public class CreateUserTypeCqlGenerator extends UserTypeNameCqlGenerator { - public static String toCql(DropUserTypeSpecification specification) { - return new DropUserTypeCqlGenerator(specification).toCql(); - } - /** * Create a new {@link DropUserTypeCqlGenerator} for a given {@link DropUserTypeSpecification}. * @@ -42,13 +36,17 @@ public class DropUserTypeCqlGenerator extends UserTypeNameCqlGenerator> public abstract StringBuilder toCql(StringBuilder cql); - private IndexNameSpecification specification; + private final IndexNameSpecification specification; public IndexNameCqlGenerator(IndexNameSpecification specification) { - setSpecification(specification); - } - - protected void setSpecification(IndexNameSpecification specification) { Assert.notNull(specification, "IndexNameSpecification must not be null"); this.specification = specification; @@ -53,6 +49,6 @@ public abstract class IndexNameCqlGenerator> } public String toCql() { - return toCql(null).toString(); + return toCql(new StringBuilder()).toString(); } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/KeyspaceCqlGenerator.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/KeyspaceCqlGenerator.java deleted file mode 100644 index 25e4b7ffe..000000000 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/KeyspaceCqlGenerator.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013-2017 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 - * - * http://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.cql.generator; - -import org.springframework.data.cassandra.core.cql.keyspace.KeyspaceSpecification; - -/** - * Base class that contains behavior common to CQL generation for table operations. - * - * @author Matthew T. Adams - * @param subtype of this class for which this is a CQL generator. - */ -public abstract class KeyspaceCqlGenerator> - extends KeyspaceOptionsCqlGenerator> { - - public KeyspaceCqlGenerator(KeyspaceSpecification specification) { - super(specification); - } - - @SuppressWarnings("unchecked") - protected T spec() { - return (T) getSpecification(); - } -} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/KeyspaceNameCqlGenerator.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/KeyspaceNameCqlGenerator.java index bc182f34a..0d77c9f48 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/KeyspaceNameCqlGenerator.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/KeyspaceNameCqlGenerator.java @@ -28,13 +28,9 @@ public abstract class KeyspaceNameCqlGenerator specification; + private final KeyspaceActionSpecification specification; public KeyspaceNameCqlGenerator(KeyspaceActionSpecification specification) { - setSpecification(specification); - } - - protected void setSpecification(KeyspaceActionSpecification specification) { Assert.notNull(specification, "KeyspaceActionSpecification must not be null"); this.specification = specification; @@ -53,6 +49,6 @@ public abstract class KeyspaceNameCqlGenerator valueMap, StringBuilder cql) { - cql = noNull(cql); + void optionValueMap(Map valueMap, StringBuilder cql) { - if (valueMap == null || valueMap.isEmpty()) { - return cql; + if (valueMap.isEmpty()) { + return; } // else option value is a non-empty map @@ -73,6 +72,6 @@ public abstract class KeyspaceOptionsCqlGenerator> - extends TableOptionsCqlGenerator> { - - public TableCqlGenerator(TableSpecification specification) { - super(specification); - } - - @SuppressWarnings("unchecked") - protected T spec() { - return (T) getSpecification(); - } -} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/TableNameCqlGenerator.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/TableNameCqlGenerator.java index 49c1945be..98102b0e1 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/TableNameCqlGenerator.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/TableNameCqlGenerator.java @@ -24,22 +24,18 @@ import org.springframework.util.Assert; * @param subtype of TableNameSpecification. * @author Mark Paluch */ -public abstract class TableNameCqlGenerator> { +public abstract class TableNameCqlGenerator { - public abstract StringBuilder toCql(StringBuilder cql); + private TableNameSpecification specification; - private TableNameSpecification specification; - - public TableNameCqlGenerator(TableNameSpecification specification) { - setSpecification(specification); - } - - protected void setSpecification(TableNameSpecification specification) { + public TableNameCqlGenerator(TableNameSpecification specification) { Assert.notNull(specification, "TableNameSpecification must not be null"); this.specification = specification; } + public abstract StringBuilder toCql(StringBuilder cql); + @SuppressWarnings("unchecked") public T getSpecification() { return (T) specification; @@ -53,6 +49,6 @@ public abstract class TableNameCqlGenerator> } public String toCql() { - return toCql(null).toString(); + return toCql(new StringBuilder()).toString(); } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/TableOptionsCqlGenerator.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/TableOptionsCqlGenerator.java index 2e879a749..d8a8231cb 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/TableOptionsCqlGenerator.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/generator/TableOptionsCqlGenerator.java @@ -29,7 +29,7 @@ import org.springframework.data.cassandra.core.cql.keyspace.TableOptionsSpecific * @param T The subtype of this class for which this is a CQL generator. */ public abstract class TableOptionsCqlGenerator> - extends TableNameCqlGenerator> { + extends TableNameCqlGenerator { public TableOptionsCqlGenerator(TableOptionsSpecification specification) { super(specification); @@ -37,14 +37,13 @@ public abstract class TableOptionsCqlGenerator valueMap, StringBuilder cql) { - cql = noNull(cql); + void optionValueMap(Map valueMap, StringBuilder cql) { - if (valueMap == null || valueMap.isEmpty()) { - return cql; + if (valueMap.isEmpty()) { + return; } // else option value is a non-empty map @@ -73,6 +72,6 @@ public abstract class TableOptionsCqlGenerator> { - public abstract StringBuilder toCql(StringBuilder cql); - - private UserTypeNameSpecification specification; + private final UserTypeNameSpecification specification; /** * Create a new {@link UserTypeNameCqlGenerator}. @@ -39,21 +37,14 @@ public abstract class UserTypeNameCqlGenerator specification) { - setSpecification(specification); - } - - /** - * Sets the {@link UserTypeNameSpecification}. - * - * @param specification must not be {@literal null}. - */ - protected final void setSpecification(UserTypeNameSpecification specification) { Assert.notNull(specification, "UserTypeNameSpecification must not be null"); this.specification = specification; } + public abstract StringBuilder toCql(StringBuilder cql); + @SuppressWarnings("unchecked") public T getSpecification() { return (T) specification; @@ -67,6 +58,6 @@ public abstract class UserTypeNameCqlGenerator { - /** - * Entry point into the {@link AlterKeyspaceSpecification}'s fluent API to alter a keyspace. Convenient if imported - * statically. - */ - public static AlterKeyspaceSpecification alterKeyspace() { - return new AlterKeyspaceSpecification(); + private AlterKeyspaceSpecification(KeyspaceIdentifier name) { + super(name); } /** @@ -35,14 +34,11 @@ public class AlterKeyspaceSpecification extends KeyspaceOptionsSpecification { /** - * Entry point into the {@link AlterTableSpecification}'s fluent API to alter a table. Convenient if imported - * statically. + * The list of column changes. */ - public static AlterTableSpecification alterTable() { - return new AlterTableSpecification(); + private List changes = new ArrayList<>(); + + private AlterTableSpecification(CqlIdentifier name) { + super(name); } /** @@ -52,7 +53,7 @@ public class AlterTableSpecification extends TableOptionsSpecification changes = new ArrayList<>(); - /* * Adds a {@code DROP} to the list of column changes. * @@ -75,7 +71,7 @@ public class AlterTableSpecification extends TableOptionsSpecification changes = new ArrayList<>(); - /** - * Entry point into the {@link AlterUserTypeSpecification}'s fluent API to alter a type. Convenient if imported - * statically. - */ - public static AlterUserTypeSpecification alterType() { - return new AlterUserTypeSpecification(); - } - /** * Entry point into the {@link AlterUserTypeSpecification}'s fluent API to alter a type. Convenient if imported * statically. @@ -55,8 +47,12 @@ public class AlterUserTypeSpecification extends UserTypeNameSpecificationtrue, then sets the column's - * {@link #keyType} to {@link PrimaryKeyType#PARTITIONED}, else sets it to {@code null}. + * {@link #ordering} to {@literal null} and, if the given boolean is true, then sets the column's + * {@link #keyType} to {@link PrimaryKeyType#PARTITIONED}, else sets it to {@literal null}. * * @return this */ @@ -125,7 +128,7 @@ public class ColumnSpecification { /** * Toggles the identification of this column as a clustered key column. If the given boolean is {@code true}, then * sets the column's {@link #keyType} to {@link PrimaryKeyType#PARTITIONED} and {@link #ordering} to the given - * {@link Ordering} , else sets both {@link #keyType} and {@link #ordering} to {@code null}. + * {@link Ordering} , else sets both {@link #keyType} and {@link #ordering} to {@literal null}. * * @return this */ @@ -159,24 +162,27 @@ public class ColumnSpecification { return name; } + @Nullable public DataType getType() { return type; } + @Nullable public PrimaryKeyType getKeyType() { return keyType; } + @Nullable public Ordering getOrdering() { return ordering; } public String toCql() { - return toCql(null).toString(); + return toCql(new StringBuilder()).toString(); } public StringBuilder toCql(StringBuilder cql) { - return noNull(cql).append(name).append(" ").append(type); + return cql.append(name).append(" ").append(type); } /* (non-Javadoc) @@ -184,7 +190,7 @@ public class ColumnSpecification { */ @Override public String toString() { - return toCql(null).append(" /* keyType=").append(keyType).append(", ordering=").append(ordering).append(" */ ") - .toString(); + return toCql(new StringBuilder()).append(" /* keyType=").append(keyType).append(", ordering=").append(ordering) + .append(" */ ").toString(); } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/ColumnTypeChangeSpecification.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/ColumnTypeChangeSpecification.java index 653c27323..e31bd2ce7 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/ColumnTypeChangeSpecification.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/ColumnTypeChangeSpecification.java @@ -15,8 +15,6 @@ */ package org.springframework.data.cassandra.core.cql.keyspace; -import static org.springframework.data.cassandra.core.cql.CqlIdentifier.*; - import org.springframework.data.cassandra.core.cql.CqlIdentifier; import org.springframework.util.Assert; @@ -33,26 +31,16 @@ public abstract class ColumnTypeChangeSpecification extends ColumnChangeSpecific private final DataType type; /** - * Create a new {@link ColumnTypeChangeSpecification} for the given {@code name} and {@link type} - * - * @param name must not be empty or {@literal null}. - * @param type must not be {@literal null}. - */ - public ColumnTypeChangeSpecification(String name, DataType type) { - this(cqlId(name), type); - } - - /** - * Create a new {@link ColumnTypeChangeSpecification} for the given {@code name} and {@link type} + * Create a new {@link ColumnTypeChangeSpecification} for the given {@code name} and {@link DataType} * * @param name must not be {@literal null}. * @param type must not be {@literal null}. */ public ColumnTypeChangeSpecification(CqlIdentifier name, DataType type) { + super(name); Assert.notNull(type, "DataType must not be null"); - this.type = type; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/CreateIndexSpecification.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/CreateIndexSpecification.java index f01ae692d..43ff9ccac 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/CreateIndexSpecification.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/CreateIndexSpecification.java @@ -15,7 +15,7 @@ */ package org.springframework.data.cassandra.core.cql.keyspace; -import static org.springframework.data.cassandra.core.cql.CqlIdentifier.cqlId; +import static org.springframework.data.cassandra.core.cql.CqlIdentifier.*; import java.util.Collection; import java.util.Collections; @@ -23,6 +23,7 @@ import java.util.LinkedHashMap; import java.util.Map; import org.springframework.data.cassandra.core.cql.CqlIdentifier; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -40,13 +41,13 @@ public class CreateIndexSpecification extends IndexNameSpecification options = new LinkedHashMap<>(); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/CreateKeyspaceSpecification.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/CreateKeyspaceSpecification.java index 924db87d0..5b9bcf39b 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/CreateKeyspaceSpecification.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/CreateKeyspaceSpecification.java @@ -15,18 +15,20 @@ */ package org.springframework.data.cassandra.core.cql.keyspace; +import lombok.EqualsAndHashCode; + import org.springframework.data.cassandra.core.cql.KeyspaceIdentifier; import org.springframework.data.cassandra.core.cql.keyspace.KeyspaceOption.ReplicationStrategy; import org.springframework.data.cassandra.util.MapBuilder; -public class CreateKeyspaceSpecification extends KeyspaceSpecification { +@EqualsAndHashCode(callSuper = true) +public class CreateKeyspaceSpecification extends KeyspaceOptionsSpecification + implements KeyspaceDescriptor { - /** - * Entry point into the {@link CreateKeyspaceSpecification}'s fluent API to create a keyspace. Convenient if imported - * statically. - */ - public static CreateKeyspaceSpecification createKeyspace() { - return new CreateKeyspaceSpecification(); + private boolean ifNotExists = false; + + private CreateKeyspaceSpecification(KeyspaceIdentifier name) { + super(name); } /** @@ -34,7 +36,7 @@ public class CreateKeyspaceSpecification extends KeyspaceSpecification type; + private final Class type; - private boolean requiresValue; + private final boolean requiresValue; - private boolean escapesValue; + private final boolean escapesValue; - private boolean quotesValue; + private final boolean quotesValue; public DefaultOption(String name, Class type, boolean requiresValue, boolean escapesValue, boolean quotesValue) { - setName(name); - setType(type); + Assert.hasText(name, "Name must not be null or empty"); + Assert.notNull(type, "Type must not be null"); + + if (type.isInterface() && !(Map.class.isAssignableFrom(type) || Collection.class.isAssignableFrom(type))) { + throw new IllegalArgumentException("given type [" + type.getName() + "] must be a class, Map or Collection"); + } + + this.name = name; + this.type = type; this.requiresValue = requiresValue; this.escapesValue = escapesValue; @@ -53,24 +60,10 @@ public class DefaultOption implements Option { } - protected void setName(String name) { - - Assert.hasText(name, "Name must not be null or empty"); - this.name = name; - } - - protected void setType(Class type) { - if (type != null) { - if (type.isInterface() && !(Map.class.isAssignableFrom(type) || Collection.class.isAssignableFrom(type))) { - throw new IllegalArgumentException("given type [" + type.getName() + "] must be a class, Map or Collection"); - } - } - this.type = type; - } - @SuppressWarnings({ "unchecked", "rawtypes" }) public boolean isCoerceable(Object value) { - if (value == null || type == null) { + + if (getType().equals(Void.class)) { return true; } @@ -88,9 +81,7 @@ public class DefaultOption implements Option { String name = value instanceof Enum ? name = ((Enum) value).name() : value.toString(); Enum.valueOf((Class) type, name); return true; - } catch (NullPointerException x) { - return false; - } catch (IllegalArgumentException x) { + } catch (IllegalArgumentException | NullPointerException x) { return false; } } @@ -103,7 +94,7 @@ public class DefaultOption implements Option { } ctor.newInstance(value.toString()); return true; - } catch (InstantiationException e) {} catch (IllegalAccessException e) {} catch (IllegalArgumentException e) {} catch (InvocationTargetException e) {} catch (NoSuchMethodException e) {} catch (SecurityException e) {} + } catch (Exception e) {} return false; } @@ -125,7 +116,7 @@ public class DefaultOption implements Option { * @see org.springframework.data.cassandra.core.cql.keyspace.Option#takesValue() */ public boolean takesValue() { - return type != null; + return type != Void.class; } /* (non-Javadoc) @@ -152,7 +143,7 @@ public class DefaultOption implements Option { /* (non-Javadoc) * @see org.springframework.data.cassandra.core.cql.keyspace.Option#checkValue(java.lang.Object) */ - public void checkValue(Object value) { + public void checkValue(@Nullable Object value) { if (takesValue()) { if (value == null) { if (requiresValue) { @@ -166,7 +157,7 @@ public class DefaultOption implements Option { } // else value is not coerceable into the expected type throw new IllegalArgumentException( - "Option [" + getName() + "] takes value coerceable to type [" + getType().getName() + "]"); + "Option [" + getName() + "] takes value coerceable to type [" + getType() + "]"); } // else this option doesn't take a value if (value != null) { @@ -174,10 +165,12 @@ public class DefaultOption implements Option { } } - public String toString(Object value) { + public String toString(@Nullable Object value) { + if (value == null) { - return null; + return ""; } + checkValue(value); String string = value.toString(); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/DefaultTableDescriptor.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/DefaultTableDescriptor.java deleted file mode 100644 index 57ef43ded..000000000 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/DefaultTableDescriptor.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013-2017 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 - * - * http://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.cql.keyspace; - -/** - * Convenient default implementation of {@link TableDescriptor} as an extension of {@link TableSpecification} that - * doesn't require the use of generics. - * - * @author Matthew T. Adams - */ -public class DefaultTableDescriptor extends TableSpecification { - - /** - * Factory method to produce a new {@link DefaultTableDescriptor}. Convenient if imported statically. - */ - public static DefaultTableDescriptor table() { - return new DefaultTableDescriptor(); - } -} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/DropColumnSpecification.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/DropColumnSpecification.java index 76c65b80d..91a50c278 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/DropColumnSpecification.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/DropColumnSpecification.java @@ -25,17 +25,13 @@ import org.springframework.data.cassandra.core.cql.CqlIdentifier; public class DropColumnSpecification extends ColumnChangeSpecification { public static DropColumnSpecification dropColumn(String name) { - return new DropColumnSpecification(name); + return new DropColumnSpecification(CqlIdentifier.cqlId(name)); } public static DropColumnSpecification dropColumn(CqlIdentifier name) { return new DropColumnSpecification(name); } - public DropColumnSpecification(String name) { - super(name); - } - public DropColumnSpecification(CqlIdentifier name) { super(name); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/DropIndexSpecification.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/DropIndexSpecification.java index 00f7ef3c7..52cffffa5 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/DropIndexSpecification.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/DropIndexSpecification.java @@ -15,6 +15,8 @@ */ package org.springframework.data.cassandra.core.cql.keyspace; +import org.springframework.data.cassandra.core.cql.CqlIdentifier; + /** * Builder class that supports the construction of {@code DROP INDEX} specifications. * @@ -23,31 +25,23 @@ package org.springframework.data.cassandra.core.cql.keyspace; */ public class DropIndexSpecification extends IndexNameSpecification { - // private boolean ifExists; + private DropIndexSpecification(CqlIdentifier name) { + super(name); + } /** * Entry point into the {@link DropIndexSpecification}'s fluent API to drop a table. Convenient if imported * statically. */ - public static DropIndexSpecification dropIndex() { - return new DropIndexSpecification(); + public static DropIndexSpecification dropIndex(String name) { + return new DropIndexSpecification(CqlIdentifier.cqlId(name)); } - /* - * In CQL 3.1 this is supported so we can uncomment the exposure then. - * In the meantime, it will always be false and tests will pass. + /** + * Entry point into the {@link DropIndexSpecification}'s fluent API to drop a table. Convenient if imported + * statically. */ - - // public DropIndexSpecification ifExists() { - // return ifExists(true); - // } - // - // public DropIndexSpecification ifExists(boolean ifExists) { - // this.ifExists = ifExists; - // return this; - // } - // - // public boolean getIfExists() { - // return ifExists; - // } + public static DropIndexSpecification dropIndex(CqlIdentifier name) { + return new DropIndexSpecification(name); + } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/DropKeyspaceSpecification.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/DropKeyspaceSpecification.java index c0c864cc3..55aa827d0 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/DropKeyspaceSpecification.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/DropKeyspaceSpecification.java @@ -15,16 +15,17 @@ */ package org.springframework.data.cassandra.core.cql.keyspace; +import lombok.EqualsAndHashCode; + import org.springframework.data.cassandra.core.cql.KeyspaceIdentifier; +@EqualsAndHashCode(callSuper = true) public class DropKeyspaceSpecification extends KeyspaceActionSpecification { - /** - * Entry point into the {@link DropKeyspaceSpecification}'s fluent API to drop a keyspace. Convenient if imported - * statically. - */ - public static DropKeyspaceSpecification dropKeyspace() { - return new DropKeyspaceSpecification(); + private boolean ifExists; + + private DropKeyspaceSpecification(KeyspaceIdentifier name) { + super(name); } /** @@ -40,19 +41,7 @@ public class DropKeyspaceSpecification extends KeyspaceActionSpecification { +public class DropTableSpecification extends TableNameSpecification { - // private boolean ifExists; - - // Added in Cassandra 2.0. - - // public DropTableSpecification ifExists() { - // return ifExists(true); - // } - // - // public DropTableSpecification ifExists(boolean ifExists) { - // this.ifExists = ifExists; - // return this; - // } - // - // public boolean getIfExists() { - // return ifExists; - // } - - /** - * Entry point into the {@link DropTableSpecification}'s fluent API to drop a table. Convenient if imported - * statically. - */ - public static DropTableSpecification dropTable() { - return new DropTableSpecification(); + private DropTableSpecification(CqlIdentifier name) { + super(name); } /** @@ -56,7 +35,7 @@ public class DropTableSpecification extends TableNameSpecification /** * The name of the index. */ - private CqlIdentifier name; + private @Nullable CqlIdentifier name; + + protected IndexNameSpecification() {} + + protected IndexNameSpecification(CqlIdentifier name) { + + Assert.notNull(name, "CqlIdentifier must not be null"); + this.name = name; + } /** * Sets the index name. @@ -54,6 +63,7 @@ public abstract class IndexNameSpecification return (T) this; } + @Nullable public CqlIdentifier getName() { return this.name; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/KeyspaceActionSpecification.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/KeyspaceActionSpecification.java index 2b0ce95ae..f02c0cfaf 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/KeyspaceActionSpecification.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/KeyspaceActionSpecification.java @@ -15,7 +15,7 @@ */ package org.springframework.data.cassandra.core.cql.keyspace; -import static org.springframework.data.cassandra.core.cql.KeyspaceIdentifier.*; +import lombok.EqualsAndHashCode; import org.springframework.data.cassandra.core.cql.KeyspaceIdentifier; import org.springframework.util.Assert; @@ -27,68 +27,22 @@ import org.springframework.util.Assert; * @author David Webb * @param The subtype of the {@link KeyspaceActionSpecification} */ +@EqualsAndHashCode public abstract class KeyspaceActionSpecification> { /** * The name of the keyspace. */ - private KeyspaceIdentifier name; + private final KeyspaceIdentifier name; - /** - * Sets the keyspace name. - * - * @return this - */ - public T name(String name) { - return name(ksId(name)); - } - - /** - * Sets the keyspace name. - * - * @return this - */ - @SuppressWarnings("unchecked") - public T name(KeyspaceIdentifier name) { + protected KeyspaceActionSpecification(KeyspaceIdentifier name) { Assert.notNull(name, "KeyspaceIdentifier must not be null"); this.name = name; - return (T) this; } public KeyspaceIdentifier getName() { return name; } - - /** - * Equality incorporates the exact type to distinguish between instances based on this type. - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object o) { - - if (this == o) - return true; - if (!(o instanceof KeyspaceActionSpecification) || !getClass().equals(o.getClass())) - return false; - - KeyspaceActionSpecification that = (KeyspaceActionSpecification) o; - - return name != null ? name.equals(that.name) : that.name == null; - } - - /** - * Hash code incorporates the exact type to distinguish between instances based on this type. - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - - int result = name != null ? name.hashCode() : 0; - result = 31 * result + (getClass().hashCode()); - return result; - } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/KeyspaceOption.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/KeyspaceOption.java index 53463ad5d..b1881e462 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/KeyspaceOption.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/KeyspaceOption.java @@ -18,6 +18,7 @@ package org.springframework.data.cassandra.core.cql.keyspace; import java.util.Map; public enum KeyspaceOption implements Option { + REPLICATION("replication", Map.class, true, false, false), DURABLE_WRITES("durable_writes", Boolean.class, false, false, false); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/KeyspaceOptionsSpecification.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/KeyspaceOptionsSpecification.java index 22816c273..0ccd8a09b 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/KeyspaceOptionsSpecification.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/KeyspaceOptionsSpecification.java @@ -17,11 +17,15 @@ package org.springframework.data.cassandra.core.cql.keyspace; import static org.springframework.data.cassandra.core.cql.CqlStringUtils.*; +import lombok.EqualsAndHashCode; + import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; import org.springframework.data.cassandra.core.cql.CqlStringUtils; +import org.springframework.data.cassandra.core.cql.KeyspaceIdentifier; +import org.springframework.lang.Nullable; /** * Abstract builder class to support the construction of table specifications that have table options, that is, those @@ -36,15 +40,14 @@ import org.springframework.data.cassandra.core.cql.CqlStringUtils; * @author John McPeek * @param The subtype of the {@link KeyspaceOptionsSpecification}. */ +@EqualsAndHashCode(callSuper = true) public abstract class KeyspaceOptionsSpecification> extends KeyspaceActionSpecification> { protected Map options = new LinkedHashMap<>(); - @Override - @SuppressWarnings("unchecked") - public T name(String name) { - return (T) super.name(name); + protected KeyspaceOptionsSpecification(KeyspaceIdentifier name) { + super(name); } /** @@ -53,7 +56,7 @@ public abstract class KeyspaceOptionsSpecification - * Options that have {@code null} values are considered single string options where the name of the option is the + * Options that have {@literal null} values are considered single string options where the name of the option is the * string to be used. Otherwise, the result of {@link Object#toString()} is considered to be the value of the option * with the given name. The value, after conversion to string, may have embedded single quotes escaped according to * parameter {@code escape} and may be single-quoted according to parameter quote. * * @param name The name of the option - * @param value The value of the option. If {@code null}, the value is ignored and the option is considered to be + * @param value The value of the option. If {@literal null}, the value is ignored and the option is considered to be * composed of only the name, otherwise the value's {@link Object#toString()} value is used. * @param escape Whether to escape the value via {@link CqlStringUtils#escapeSingle(Object)}. Ignored if given value * is an instance of a {@link Map}. @@ -89,7 +92,8 @@ public abstract class KeyspaceOptionsSpecification extends KeyspaceOptionsSpecification> - implements KeyspaceDescriptor {} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/Option.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/Option.java index 3a43affd7..1b5c7919d 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/Option.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/Option.java @@ -15,6 +15,8 @@ */ package org.springframework.data.cassandra.core.cql.keyspace; +import org.springframework.lang.Nullable; + /** * Interface to represent option types. * @@ -66,10 +68,10 @@ public interface Option { * First ensures that the given value is coerceable into the type expected by this option, then returns the result of * {@link Object#toString()} called on the given value. If this option is escaping quotes ({@link #escapesValue()} is * {@code true}), then single quotes will be escaped, and if this option is quoting values ( {@link #quotesValue()} is - * {@code true}), then the value will be surrounded by single quotes. Given {@code null}, returns null. + * {@code true}), then the value will be surrounded by single quotes. Given {@literal null}, returns an empty string. * * @see #escapesValue() * @see #quotesValue() */ - String toString(Object value); + String toString(@Nullable Object value); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/RenameColumnSpecification.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/RenameColumnSpecification.java index f35fee17f..e3563f26b 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/RenameColumnSpecification.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/RenameColumnSpecification.java @@ -48,6 +48,7 @@ public class RenameColumnSpecification extends ColumnChangeSpecification { * @param to must not be {@literal null}. */ RenameColumnSpecification(CqlIdentifier from, CqlIdentifier to) { + super(from); Assert.notNull(to, "Target name must not be null"); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/TableNameSpecification.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/TableNameSpecification.java index c217b4026..539b1d0a3 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/TableNameSpecification.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/TableNameSpecification.java @@ -15,8 +15,6 @@ */ package org.springframework.data.cassandra.core.cql.keyspace; -import static org.springframework.data.cassandra.core.cql.CqlIdentifier.cqlId; - import org.springframework.data.cassandra.core.cql.CqlIdentifier; import org.springframework.util.Assert; @@ -24,32 +22,19 @@ import org.springframework.util.Assert; * Abstract builder class to support the construction of table specifications. * * @author Matthew T. Adams - * @param The subtype of the {@link TableNameSpecification} */ -public abstract class TableNameSpecification> { +public abstract class TableNameSpecification { /** * The name of the table. */ - private CqlIdentifier name; + private final CqlIdentifier name; - /** - * Sets the table name. - * - * @return this - */ - public T name(String name) { - return name(cqlId(name)); - } - - @SuppressWarnings("unchecked") - public T name(CqlIdentifier name) { + protected TableNameSpecification(CqlIdentifier name) { Assert.notNull(name, "CqlIdentifier must not be null"); this.name = name; - - return (T) this; } public CqlIdentifier getName() { diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/TableOption.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/TableOption.java index de56365aa..311f485e5 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/TableOption.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/TableOption.java @@ -36,7 +36,7 @@ public enum TableOption implements Option { /** * {@code COMPACT STORAGE} */ - COMPACT_STORAGE("COMPACT STORAGE", null, false, false, false), + COMPACT_STORAGE("COMPACT STORAGE", Void.class, false, false, false), /** * {@code compaction}. Value is a Map<CompactionOption,Object>. * @@ -46,7 +46,7 @@ public enum TableOption implements Option { /** * {@code compression}. Value is a Map<CompressionOption,Object>. * - * @see {@link CompressionOption} + * @see CompressionOption */ COMPRESSION("compression", Map.class, true, false, false), /** diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/TableOptionsSpecification.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/TableOptionsSpecification.java index 1dce824a9..5c06fdd7a 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/TableOptionsSpecification.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/TableOptionsSpecification.java @@ -23,6 +23,7 @@ import java.util.Map; import org.springframework.data.cassandra.core.cql.CqlIdentifier; import org.springframework.data.cassandra.core.cql.CqlStringUtils; +import org.springframework.lang.Nullable; /** * Abstract builder class to support the construction of table specifications that have table options, that is, those @@ -35,23 +36,15 @@ import org.springframework.data.cassandra.core.cql.CqlStringUtils; * are introduced without having to update the code immediately. * * @author Matthew T. Adams + * @author Mark Paluch * @param The subtype of the {@link TableOptionsSpecification}. */ -public abstract class TableOptionsSpecification> - extends TableNameSpecification> { +public abstract class TableOptionsSpecification> extends TableNameSpecification { - protected Map options = new LinkedHashMap<>(); + private final Map options = new LinkedHashMap<>(); - @Override - @SuppressWarnings("unchecked") - public T name(String name) { - return (T) super.name(name); - } - - @Override - @SuppressWarnings("unchecked") - public T name(CqlIdentifier name) { - return (T) super.name(name); + protected TableOptionsSpecification(CqlIdentifier name) { + super(name); } /** @@ -60,7 +53,7 @@ public abstract class TableOptionsSpecification - * Options that have {@code null} values are considered single string options where the name of the option is the + * Options that have {@literal null} values are considered single string options where the name of the option is the * string to be used. Otherwise, the result of {@link Object#toString()} is considered to be the value of the option * with the given name. The value, after conversion to string, may have embedded single quotes escaped according to * parameter {@code escape} and may be single-quoted according to parameter quote. * * @param name The name of the option - * @param value The value of the option. If {@code null}, the value is ignored and the option is considered to be + * @param value The value of the option. If {@literal null}, the value is ignored and the option is considered to be * composed of only the name, otherwise the value's {@link Object#toString()} value is used. * @param escape Whether to escape the value via {@link CqlStringUtils#escapeSingle(Object)}. Ignored if given value * is an instance of a {@link Map}. @@ -96,7 +89,7 @@ public abstract class TableOptionsSpecification extends TableOptionsSpecification nonKeyColumns = new ArrayList<>(); + protected TableSpecification(CqlIdentifier name) { + super(name); + } + /** * Adds the given non-key column to the table. Must be specified after all primary key columns. * @@ -226,7 +230,7 @@ public class TableSpecification extends TableOptionsSpecification { diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/UserTypeNameSpecification.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/UserTypeNameSpecification.java index d6c53a5fa..f1691d179 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/UserTypeNameSpecification.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/UserTypeNameSpecification.java @@ -29,32 +29,13 @@ import org.springframework.util.Assert; */ public abstract class UserTypeNameSpecification> { - private CqlIdentifier name; + private final CqlIdentifier name; - /** - * Sets the type name. - * - * @param name must not be empty or {@literal null}. - * @return this - */ - public T name(String name) { - return name(CqlIdentifier.cqlId(name)); - } - - /** - * Sets the type name. - * - * @param name must not be {@literal null}. - * @return this - */ - @SuppressWarnings("unchecked") - public T name(CqlIdentifier name) { + protected UserTypeNameSpecification(CqlIdentifier name) { Assert.notNull(name, "Name must not be null"); this.name = name; - - return (T) this; } /** diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/UserTypeSpecification.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/UserTypeSpecification.java index 9ed85818e..fefff907b 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/UserTypeSpecification.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/UserTypeSpecification.java @@ -38,6 +38,10 @@ public class UserTypeSpecification> extends U private final List fields = new ArrayList<>(); + protected UserTypeSpecification(CqlIdentifier name) { + super(name); + } + /** * Adds the given field to the type. * @@ -59,7 +63,7 @@ public class UserTypeSpecification> extends U @SuppressWarnings("unchecked") public T field(CqlIdentifier name, DataType type) { - fields.add(new FieldSpecification().name(name).type(type)); + fields.add(FieldSpecification.of(name, type)); return (T) this; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/package-info.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/package-info.java index a0458112c..f97a5ebce 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/package-info.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/package-info.java @@ -1,4 +1,7 @@ /** * Keyspace object action specifications such as {@code CREATE TABLE}, {@code DROP INDEX}. */ +@NonNullApi package org.springframework.data.cassandra.core.cql.keyspace; + +import org.springframework.lang.NonNullApi; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/package-info.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/package-info.java index 888ebc3cd..68dc08402 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/package-info.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/package-info.java @@ -1,4 +1,7 @@ /** * CQL core support. */ +@NonNullApi package org.springframework.data.cassandra.core.cql; + +import org.springframework.lang.NonNullApi; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/session/lookup/AbstractRoutingSessionFactory.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/session/lookup/AbstractRoutingSessionFactory.java index 7d3f466c3..a1b6b2444 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/session/lookup/AbstractRoutingSessionFactory.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/session/lookup/AbstractRoutingSessionFactory.java @@ -20,6 +20,7 @@ import java.util.Map; import org.springframework.beans.factory.InitializingBean; import org.springframework.data.cassandra.SessionFactory; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import com.datastax.driver.core.Session; @@ -38,17 +39,17 @@ import com.datastax.driver.core.Session; */ public abstract class AbstractRoutingSessionFactory implements SessionFactory, InitializingBean { - private Map targetSessionFactories; + private @Nullable Map targetSessionFactories; - private Object defaultTargetSessionFactory; + private @Nullable Object defaultTargetSessionFactory; private boolean lenientFallback = true; private SessionFactoryLookup sessionFactoryLookup = new MapSessionFactoryLookup(); - private Map resolvedSessionFactories; + private @Nullable Map resolvedSessionFactories; - private SessionFactory resolvedDefaultSessionFactory; + private @Nullable SessionFactory resolvedDefaultSessionFactory; /** * Specify the map of target session factories, with the lookup key as key. @@ -61,6 +62,9 @@ public abstract class AbstractRoutingSessionFactory implements SessionFactory, I * {@link #determineCurrentLookupKey()}. */ public void setTargetSessionFactories(Map targetSessionFactories) { + + Assert.notNull(targetSessionFactories, "Target SessionFactories must not be null"); + this.targetSessionFactories = targetSessionFactories; } @@ -74,6 +78,9 @@ public abstract class AbstractRoutingSessionFactory implements SessionFactory, I * match the {@link #determineCurrentLookupKey()} current lookup key. */ public void setDefaultTargetSessionFactory(Object defaultTargetSessionFactory) { + + Assert.notNull(defaultTargetSessionFactory, "Default target SessionFactory must not be null"); + this.defaultTargetSessionFactory = defaultTargetSessionFactory; } @@ -85,7 +92,7 @@ public abstract class AbstractRoutingSessionFactory implements SessionFactory, I * {@link SessionFactory} map - simply falling back to the default {@link SessionFactory} in that case. *

* Switch this flag to {@literal false} if you would prefer the fallback to only apply if the lookup key was - * {@code null}. Lookup keys without a {@link SessionFactory} entry will then lead to an + * {@literal null}. Lookup keys without a {@link SessionFactory} entry will then lead to an * {@link IllegalStateException}. * * @param lenientFallback {@literal true} to accepting lookup keys without a corresponding entry in the target. @@ -107,7 +114,7 @@ public abstract class AbstractRoutingSessionFactory implements SessionFactory, I * @param sessionFactoryLookup the {@link SessionFactoryLookup}. Defaults to {@link MapSessionFactoryLookup} if * {@literal null}. */ - public void setSessionFactoryLookup(SessionFactoryLookup sessionFactoryLookup) { + public void setSessionFactoryLookup(@Nullable SessionFactoryLookup sessionFactoryLookup) { this.sessionFactoryLookup = (sessionFactoryLookup != null ? sessionFactoryLookup : new MapSessionFactoryLookup()); } @@ -174,10 +181,10 @@ public abstract class AbstractRoutingSessionFactory implements SessionFactory, I } else if (sessionFactory instanceof String) { return this.sessionFactoryLookup.getSessionFactory((String) sessionFactory); } else { - throw new IllegalArgumentException(String - .format( - "Illegal session factory value. Only [org.springframework.data.cassandra.core.cql.session.SessionFactory]" - + " and String supported: %s", sessionFactory)); + throw new IllegalArgumentException(String.format( + "Illegal session factory value. Only [org.springframework.data.cassandra.core.cql.session.SessionFactory]" + + " and String supported: %s", + sessionFactory)); } } @@ -214,5 +221,6 @@ public abstract class AbstractRoutingSessionFactory implements SessionFactory, I * * @return the current lookup key. The returned key needs to match the stored lookup key type. */ + @Nullable protected abstract Object determineCurrentLookupKey(); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/session/lookup/BeanFactorySessionFactoryLookup.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/session/lookup/BeanFactorySessionFactoryLookup.java index 50ea066c0..5b92e1018 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/session/lookup/BeanFactorySessionFactoryLookup.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/session/lookup/BeanFactorySessionFactoryLookup.java @@ -19,6 +19,7 @@ import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.data.cassandra.SessionFactory; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -32,7 +33,7 @@ import org.springframework.util.Assert; */ public class BeanFactorySessionFactoryLookup implements SessionFactoryLookup, BeanFactoryAware { - private BeanFactory beanFactory; + private @Nullable BeanFactory beanFactory; /** * Create a new instance of {@link BeanFactorySessionFactoryLookup}. diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/session/lookup/MapSessionFactoryLookup.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/session/lookup/MapSessionFactoryLookup.java index a631aaa12..d2a5dd1c7 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/session/lookup/MapSessionFactoryLookup.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/session/lookup/MapSessionFactoryLookup.java @@ -20,6 +20,7 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.springframework.data.cassandra.SessionFactory; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -65,11 +66,11 @@ public class MapSessionFactoryLookup implements SessionFactoryLookup { * Set the {@link Map} of {@link SessionFactory session factories}; the keys are {@link String Strings}, the values * are actual {@link SessionFactory} instances. *

- * If the supplied {@link Map} is {@code null}, then this method call effectively has no effect. + * If the supplied {@link Map} is {@literal null}, then this method call effectively has no effect. * * @param sessionFactories {@link Map} of {@link SessionFactory session factories}. */ - public void setSessionFactories(Map sessionFactories) { + public void setSessionFactories(@Nullable Map sessionFactories) { if (sessionFactories != null) { this.sessionFactories.putAll(sessionFactories); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/session/lookup/SessionFactoryLookup.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/session/lookup/SessionFactoryLookup.java index 83403a6eb..919d7d614 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/session/lookup/SessionFactoryLookup.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/session/lookup/SessionFactoryLookup.java @@ -35,7 +35,7 @@ public interface SessionFactoryLookup { * their backing store. * * @param sessionFactoryName the name of the {@link SessionFactory}. - * @return the {@link SessionFactory} (never {@code null}). + * @return the {@link SessionFactory} (never {@literal null}). * @throws SessionFactoryLookupFailureException if the lookup failed. */ SessionFactory getSessionFactory(String sessionFactoryName) throws SessionFactoryLookupFailureException; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/session/lookup/package-info.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/session/lookup/package-info.java index 63632332f..1fb3f11e3 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/session/lookup/package-info.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/session/lookup/package-info.java @@ -1,6 +1,7 @@ /** * Provides a strategy for looking up {@link org.springframework.data.cassandra.SessionFactory}. - * - * @author Mark Paluch */ +@NonNullApi package org.springframework.data.cassandra.core.cql.session.lookup; + +import org.springframework.lang.NonNullApi; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/session/package-info.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/session/package-info.java index 926b07f30..a23644ba3 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/session/package-info.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/session/package-info.java @@ -1,7 +1,8 @@ /** * Provides utility classes for simple {@link com.datastax.driver.core.Session} access and various session * implementations. - * - * @author Mark Paluch */ +@NonNullApi package org.springframework.data.cassandra.core.cql.session; + +import org.springframework.lang.NonNullApi; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/support/CachedPreparedStatementCreator.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/support/CachedPreparedStatementCreator.java index 16e511448..6e4244282 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/support/CachedPreparedStatementCreator.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/support/CachedPreparedStatementCreator.java @@ -47,7 +47,7 @@ public class CachedPreparedStatementCreator implements PreparedStatementCreator * Create a new {@link CachedPreparedStatementCreator}. * * @param cache must not be {@literal null}. - * @param statement may be {@literal null} of {@code cql} is provided. + * @param statement must not be {@literal null}. */ protected CachedPreparedStatementCreator(PreparedStatementCache cache, RegularStatement statement) { diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/support/package-info.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/support/package-info.java new file mode 100644 index 000000000..5e96407c3 --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/support/package-info.java @@ -0,0 +1,7 @@ +/** + * Support classes for the CQL framework. Provides prepared statement caching. + */ +@NonNullApi +package org.springframework.data.cassandra.core.cql.support; + +import org.springframework.lang.NonNullApi; 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 92368f81d..525bb371f 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 @@ -32,6 +32,7 @@ import org.springframework.data.mapping.MappingException; import org.springframework.data.mapping.model.BasicPersistentEntity; 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; @@ -52,9 +53,7 @@ public class BasicCassandraPersistentEntity extends BasicPersistentEntity forceQuote = Optional.empty(); @@ -92,10 +91,6 @@ public class BasicCassandraPersistentEntity extends BasicPersistentEntity extends BasicPersistentEntity String.format("Cannot determine default name for %s", this)); + + return cqlId(name, forceQuote); } /* (non-Javadoc) @@ -140,9 +139,7 @@ public class BasicCassandraPersistentEntity extends BasicPersistentEntity extends BasicPersistentEntity extends BasicPersistentEntity implements CassandraPersistentProperty, ApplicationContextAware { - private final UserTypeResolver userTypeResolver; + private final @Nullable UserTypeResolver userTypeResolver; - private StandardEvaluationContext spelContext; + private @Nullable StandardEvaluationContext spelContext; /** * Whether this property has been explicitly instructed to force quote column names. @@ -77,7 +78,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP /** * An unmodifiable list of this property's column names. */ - private CqlIdentifier columnName; + private @Nullable CqlIdentifier columnName; /** * Create a new {@link BasicCassandraPersistentProperty}. @@ -101,7 +102,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP * @param userTypeResolver resolver for user-defined types. */ public BasicCassandraPersistentProperty(Property property, CassandraPersistentEntity owner, - SimpleTypeHolder simpleTypeHolder, UserTypeResolver userTypeResolver) { + SimpleTypeHolder simpleTypeHolder, @Nullable UserTypeResolver userTypeResolver) { super(property, owner, simpleTypeHolder); @@ -140,12 +141,15 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP this.columnName = determineColumnName(); } + Assert.state(this.columnName != null, () -> String.format("Cannot determine column name for %s", this)); + return this.columnName; } /* (non-Javadoc) * @see org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty#getPrimaryKeyOrdering() */ + @Nullable @Override public Ordering getPrimaryKeyOrdering() { @@ -171,6 +175,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP return dataType; } + @Nullable private DataType findDataType() { CassandraType cassandraType = findAnnotation(CassandraType.class); @@ -213,20 +218,20 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP switch (type) { case MAP: ensureTypeArguments(annotation.typeArguments().length, 2); - return DataType.map(getDataTypeFor(annotation.typeArguments()[0]), - getDataTypeFor(annotation.typeArguments()[1])); + return DataType.map(CassandraSimpleTypeHolder.getDataTypeFor(annotation.typeArguments()[0]), + CassandraSimpleTypeHolder.getDataTypeFor(annotation.typeArguments()[1])); case LIST: ensureTypeArguments(annotation.typeArguments().length, 1); if (annotation.typeArguments()[0] == Name.UDT) { return DataType.list(getUserType(annotation)); } - return DataType.list(getDataTypeFor(annotation.typeArguments()[0])); + return DataType.list(CassandraSimpleTypeHolder.getDataTypeFor(annotation.typeArguments()[0])); case SET: ensureTypeArguments(annotation.typeArguments().length, 1); if (annotation.typeArguments()[0] == Name.UDT) { return DataType.set(getUserType(annotation)); } - return DataType.set(getDataTypeFor(annotation.typeArguments()[0])); + return DataType.set(CassandraSimpleTypeHolder.getDataTypeFor(annotation.typeArguments()[0])); case UDT: return getUserType(annotation); default: @@ -242,6 +247,8 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP getType(), getOwner().getName())); } + Assert.state(this.userTypeResolver != null, "UserTypeResolver is null"); + CqlIdentifier identifier = CqlIdentifier.cqlId(annotation.userTypeName()); UserType userType = this.userTypeResolver.resolveType(identifier); @@ -253,26 +260,13 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP return userType; } - private DataType getDataTypeFor(DataType.Name dataTypeName) { - - DataType dataType = CassandraSimpleTypeHolder.getDataTypeFor(dataTypeName); - - if (dataType == null) { - throw new InvalidDataAccessApiUsageException(String.format( - "Only primitive types are allowed inside Collections for property [%1$s] of type [%2$s] in entity [%3$s]", - getName(), getType(), getOwner().getName())); - } - - return dataType; - } - private DataType getDataTypeFor(Class javaType) { DataType dataType = CassandraSimpleTypeHolder.getDataTypeFor(javaType); if (dataType == null) { throw new InvalidDataAccessApiUsageException(String.format( - "Only primitive types are allowed inside Collections for property [%1$s] of type ['%2$s'] in entity [%3$s]", + "Only primitive types are allowed inside Collections for property [%1$s] of type ['%2$s'] in entity [%3$s]", getName(), getType(), getOwner().getName())); } @@ -281,9 +275,9 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP private void ensureTypeArguments(int args, int expected) { if (args != expected) { - throw new InvalidDataAccessApiUsageException(String.format( - "Expected [%1$s] typed arguments for property ['%2$s'] of type ['%3$s'] in entity [%4$s]", - expected, getName(), getType(), getOwner().getName())); + throw new InvalidDataAccessApiUsageException( + String.format("Expected [%1$s] typed arguments for property ['%2$s'] of type ['%3$s'] in entity [%4$s]", + expected, getName(), getType(), getOwner().getName())); } } @@ -325,6 +319,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP return (annotation != null && PrimaryKeyType.CLUSTERED.equals(annotation.type())); } + @Nullable private CqlIdentifier determineColumnName() { if (isCompositePrimaryKey()) { // then the id type has @PrimaryKeyClass @@ -367,7 +362,8 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP return createColumnName(defaultName, overriddenName, forceQuote); } - private CqlIdentifier createColumnName(String defaultName, String overriddenName, boolean forceQuote) { + @Nullable + private CqlIdentifier createColumnName(String defaultName, @Nullable String overriddenName, boolean forceQuote) { String name = defaultName; @@ -375,7 +371,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP name = (this.spelContext != null ? SpelUtils.evaluate(overriddenName, this.spelContext) : overriddenName); } - return cqlId(name, forceQuote); + return name == null ? null : cqlId(name, forceQuote); } /* (non-Javadoc) @@ -402,10 +398,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP if (changed) { CqlIdentifier columnName = getColumnName(); - - if (columnName != null) { - setColumnName(cqlId(columnName.getUnquoted(), forceQuote)); - } + setColumnName(cqlId(columnName.getUnquoted(), forceQuote)); } } @@ -422,7 +415,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP */ @Override protected Association createAssociation() { - return new Association<>(this, null); + return new Association<>(this, this); } /* (non-Javadoc) @@ -439,12 +432,11 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP @Override public AnnotatedType findAnnotatedType(Class annotationType) { - return Optionals.toStream(Optional.ofNullable(getField()).map(Field::getAnnotatedType), - Optional.ofNullable(getGetter()).map(Method::getAnnotatedReturnType), - Optional.ofNullable(getSetter()).map(it -> it.getParameters()[0].getAnnotatedType())) - .filter(it -> hasAnnotation(it, annotationType, getTypeInformation())) - .findFirst() - .orElse(null); + return Optionals + .toStream(Optional.ofNullable(getField()).map(Field::getAnnotatedType), + Optional.ofNullable(getGetter()).map(Method::getAnnotatedReturnType), + Optional.ofNullable(getSetter()).map(it -> it.getParameters()[0].getAnnotatedType())) + .filter(it -> hasAnnotation(it, annotationType, getTypeInformation())).findFirst().orElse(null); } private static boolean hasAnnotation(AnnotatedType type, Class annotationType, diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/BasicMapId.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/BasicMapId.java index d0d2a31bd..7a828acee 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/BasicMapId.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/BasicMapId.java @@ -20,6 +20,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -84,7 +85,7 @@ public class BasicMapId implements MapId { * @see org.springframework.data.cassandra.core.mapping.MapId#with(java.lang.String, java.io.Object) */ @Override - public BasicMapId with(String name, Object value) { + public BasicMapId with(String name, @Nullable Object value) { put(name, value); return this; } 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 80308e5af..e3cb2aeb7 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 @@ -51,6 +51,7 @@ import org.springframework.data.mapping.model.Property; import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.util.Optionals; import org.springframework.data.util.TypeInformation; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; @@ -78,11 +79,11 @@ public class CassandraMappingContext private Mapping mapping = new Mapping(); - private UserTypeResolver userTypeResolver; + private @Nullable UserTypeResolver userTypeResolver; - private ApplicationContext context; + private @Nullable ApplicationContext context; - private ClassLoader beanClassLoader; + private @Nullable ClassLoader beanClassLoader; // useful caches private final Map>> entitySetsByTableName = new HashMap<>(); @@ -110,21 +111,19 @@ public class CassandraMappingContext private void processMappingOverrides() { - this.mapping.getEntityMappings().stream() - .filter(Objects::nonNull) - .forEach(entityMapping -> { + this.mapping.getEntityMappings().stream().filter(Objects::nonNull).forEach(entityMapping -> { - Class entityClass = getEntityClass(entityMapping.getEntityClassName()); - CassandraPersistentEntity entity = getRequiredPersistentEntity(entityClass); + Class entityClass = getEntityClass(entityMapping.getEntityClassName()); + CassandraPersistentEntity entity = getRequiredPersistentEntity(entityClass); - String entityTableName = entityMapping.getTableName(); + String entityTableName = entityMapping.getTableName(); - if (StringUtils.hasText(entityTableName)) { - entity.setTableName(cqlId(entityTableName, Boolean.valueOf(entityMapping.getForceQuote()))); - } + if (StringUtils.hasText(entityTableName)) { + entity.setTableName(cqlId(entityTableName, Boolean.valueOf(entityMapping.getForceQuote()))); + } - processMappingOverrides(entity, entityMapping); - }); + processMappingOverrides(entity, entityMapping); + }); } private Class getEntityClass(String entityClassName) { @@ -138,8 +137,8 @@ public class CassandraMappingContext private static void processMappingOverrides(CassandraPersistentEntity entity, EntityMapping entityMapping) { - entityMapping.getPropertyMappings().forEach((key, propertyMapping) -> - processMappingOverride(entity, propertyMapping)); + entityMapping.getPropertyMappings() + .forEach((key, propertyMapping) -> processMappingOverride(entity, propertyMapping)); } private static void processMappingOverride(CassandraPersistentEntity entity, PropertyMapping mapping) { @@ -292,6 +291,8 @@ public class CassandraMappingContext BasicCassandraPersistentEntity entity; if (userDefinedType != null) { + Assert.state(this.userTypeResolver != null, "UserTypeResolver must not be null"); + entity = new CassandraUserTypePersistentEntity<>(typeInformation, this.verifier, this.userTypeResolver); } else { @@ -351,12 +352,9 @@ public class CassandraMappingContext private boolean hasReferencedUserType(CqlIdentifier identifier) { - return getPersistentEntities().stream() - .flatMap(entity -> StreamSupport.stream(entity.spliterator(), false)) + 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::cqlId) + .map(CassandraType::userTypeName).filter(StringUtils::hasText).map(CqlIdentifier::cqlId) .anyMatch(identifier::equals); } @@ -373,7 +371,7 @@ public class CassandraMappingContext Assert.notNull(entity, "CassandraPersistentEntity must not be null"); - CreateTableSpecification specification = createTable().name(entity.getTableName()); + CreateTableSpecification specification = createTable(entity.getTableName()); for (CassandraPersistentProperty property : entity) { @@ -506,10 +504,8 @@ public class CassandraMappingContext } return this.customConversions.getCustomWriteTarget(property.getType()) - .map(CassandraSimpleTypeHolder::getDataTypeFor) - .orElseGet(() -> this.customConversions.getCustomWriteTarget(property.getActualType()) - .filter(it -> !property.isMapLike()) - .map(it -> { + .map(CassandraSimpleTypeHolder::getDataTypeFor).orElseGet(() -> this.customConversions + .getCustomWriteTarget(property.getActualType()).filter(it -> !property.isMapLike()).map(it -> { if (property.isCollectionLike()) { @@ -545,6 +541,7 @@ public class CassandraMappingContext return entity != null && entity.isUserDefinedType() ? dataTypeProvider.getDataType(entity) : getDataType(type); } + @Nullable private DataType getUserDataType(CassandraPersistentProperty property, DataTypeProvider dataTypeProvider, CassandraPersistentEntity persistentEntity) { @@ -580,8 +577,7 @@ public class CassandraMappingContext */ public DataType getDataType(Class type) { - return this.customConversions.getCustomWriteTarget(type) - .map(CassandraSimpleTypeHolder::getDataTypeFor) + return this.customConversions.getCustomWriteTarget(type).map(CassandraSimpleTypeHolder::getDataTypeFor) .orElseGet(() -> getDataTypeFor(type)); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraPersistentEntity.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraPersistentEntity.java index 122f8f2f0..79622521e 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraPersistentEntity.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraPersistentEntity.java @@ -15,9 +15,9 @@ */ package org.springframework.data.cassandra.core.mapping; -import org.springframework.context.ApplicationContextAware; import org.springframework.data.cassandra.core.cql.CqlIdentifier; import org.springframework.data.mapping.PersistentEntity; +import org.springframework.lang.Nullable; import com.datastax.driver.core.UserType; @@ -28,8 +28,7 @@ import com.datastax.driver.core.UserType; * @author Matthew T. Adams * @author Mark Paluch */ -public interface CassandraPersistentEntity - extends PersistentEntity, ApplicationContextAware { +public interface CassandraPersistentEntity extends PersistentEntity { /** * Returns whether this entity represents a composite primary key. @@ -67,5 +66,6 @@ public interface CassandraPersistentEntity * @since 1.5 * @see UserDefinedType */ + @Nullable UserType getUserType(); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraPersistentProperty.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraPersistentProperty.java index 880432a23..9adedac87 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraPersistentProperty.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraPersistentProperty.java @@ -23,6 +23,7 @@ import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.cassandra.core.cql.CqlIdentifier; import org.springframework.data.cassandra.core.cql.Ordering; import org.springframework.data.mapping.PersistentProperty; +import org.springframework.lang.Nullable; import com.datastax.driver.core.DataType; @@ -47,6 +48,7 @@ public interface CassandraPersistentProperty * The ordering (ascending or descending) for the column. Valid only for primary key columns; returns null for * non-primary key columns. */ + @Nullable Ordering getPrimaryKeyOrdering(); /** @@ -114,5 +116,6 @@ public interface CassandraPersistentProperty * @return the annotated type or {@literal null}. * @since 2.0 */ + @Nullable AnnotatedType findAnnotatedType(Class annotationType); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraSimpleTypeHolder.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraSimpleTypeHolder.java index ba99ab294..e3a88f7d3 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraSimpleTypeHolder.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraSimpleTypeHolder.java @@ -24,6 +24,7 @@ import java.util.UUID; import java.util.stream.Collectors; import org.springframework.data.mapping.model.SimpleTypeHolder; +import org.springframework.lang.Nullable; import com.datastax.driver.core.CodecRegistry; import com.datastax.driver.core.DataType; @@ -90,9 +91,7 @@ public class CassandraSimpleTypeHolder extends SimpleTypeHolder { Map nameToDataType = new HashMap<>(16); - DataType.allPrimitiveTypes().forEach(dataType -> { - nameToDataType.put(dataType.getName(), dataType); - }); + DataType.allPrimitiveTypes().forEach(dataType -> nameToDataType.put(dataType.getName(), dataType)); return nameToDataType; } @@ -159,7 +158,8 @@ public class CassandraSimpleTypeHolder extends SimpleTypeHolder { * @param javaClass must not be {@literal null}. * @return */ + @Nullable public static DataType getDataTypeFor(Class javaClass) { - return (javaClass.isEnum() ? DataType.varchar() : classToDataType.get(javaClass)); + return (javaClass.isEnum() ? DataType.varchar() : classToDataType.get(javaClass)); } } 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 0f091d6ce..4592158a9 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 @@ -18,6 +18,7 @@ package org.springframework.data.cassandra.core.mapping; import org.springframework.data.cassandra.core.cql.CqlIdentifier; import org.springframework.data.mapping.MappingException; import org.springframework.data.util.TypeInformation; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import com.datastax.driver.core.UserType; @@ -36,7 +37,7 @@ public class CassandraUserTypePersistentEntity extends BasicCassandraPersiste private final Object lock = new Object(); - private volatile UserType userType; + private volatile @Nullable UserType userType; /** * Create a new {@link CassandraUserTypePersistentEntity}. diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/EntityMapping.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/EntityMapping.java index 3b071b860..e9eb9a235 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/EntityMapping.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/EntityMapping.java @@ -19,6 +19,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -38,7 +39,7 @@ public class EntityMapping { /** * The name of the entity's class. */ - private String entityClassName; + private @Nullable String entityClassName; /** * Whether to force the table name to be quoted. @@ -60,6 +61,7 @@ public class EntityMapping { setForceQuote(forceQuote); } + @Nullable public String getEntityClassName() { return entityClassName; } @@ -84,7 +86,7 @@ public class EntityMapping { return Collections.unmodifiableMap(propertyMappings); } - public void setPropertyMappings(Map propertyMappings) { + public void setPropertyMappings(@Nullable Map propertyMappings) { this.propertyMappings = (propertyMappings != null ? new HashMap<>(propertyMappings) : Collections.emptyMap()); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/IdInterfaceException.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/IdInterfaceException.java index 381e0a0cd..89ff77cf3 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/IdInterfaceException.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/IdInterfaceException.java @@ -18,6 +18,7 @@ package org.springframework.data.cassandra.core.mapping; import java.lang.reflect.Method; import org.springframework.data.mapping.MappingException; +import org.springframework.lang.Nullable; /** * Exception thrown on incorrect mapping of an Id interface. @@ -30,13 +31,14 @@ public class IdInterfaceException extends MappingException { private static final long serialVersionUID = -1635695314254522703L; private final String idInterfaceName; - private final String method; - public IdInterfaceException(Class idInterface, Method method, String message) { + private final @Nullable String method; + + public IdInterfaceException(Class idInterface, @Nullable Method method, String message) { this(idInterface.getClass().getName(), method == null ? null : method.toString(), message); } - public IdInterfaceException(String idInterfaceName, String method, String message) { + public IdInterfaceException(String idInterfaceName, @Nullable String method, String message) { super(message); this.idInterfaceName = idInterfaceName; this.method = method; @@ -46,6 +48,7 @@ public class IdInterfaceException extends MappingException { return idInterfaceName; } + @Nullable public String getMethod() { return method; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/MapId.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/MapId.java index 54bb36892..d0c3e7815 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/MapId.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/MapId.java @@ -17,6 +17,8 @@ package org.springframework.data.cassandra.core.mapping; import java.util.Map; +import org.springframework.lang.Nullable; + /** * Interface that represents the id of a persistent entity, where the keys correspond to the entity's JavaBean * properties. @@ -33,5 +35,5 @@ public interface MapId extends Map { * @param value The property value. * @return {@code this} */ - MapId with(String name, Object value); + MapId with(String name, @Nullable Object value); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/MapIdFactory.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/MapIdFactory.java index 022a58d6a..6b9db942b 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/MapIdFactory.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/MapIdFactory.java @@ -59,6 +59,7 @@ public class MapIdFactory { * @see IdInterfaceValidator#validate(Class) */ public static T id(Class idInterface, ClassLoader loader) { + if (MapId.class.equals(idInterface)) { return (T) new BasicMapId(); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/MapIdProxyDelegate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/MapIdProxyDelegate.java index 30311c657..e6906cbf7 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/MapIdProxyDelegate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/MapIdProxyDelegate.java @@ -21,6 +21,7 @@ import java.util.Arrays; import java.util.Map; import java.util.stream.Collectors; +import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; /** @@ -45,12 +46,14 @@ class MapIdProxyDelegate implements InvocationHandler { private MapId delegate = new BasicMapId(); private Class idInterface; - public MapIdProxyDelegate(Class idInterface) { + MapIdProxyDelegate(Class idInterface) { this.idInterface = idInterface; } + @Nullable @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (isMapIdMethod(method)) { return method.invoke(delegate, args); } @@ -69,11 +72,12 @@ class MapIdProxyDelegate implements InvocationHandler { return invokeGetter(method); } - public boolean isMapIdMethod(Method method) { + private boolean isMapIdMethod(Method method) { return MAP_ID_SIGNATURES.containsKey(new Signature(method, true)); } - public Object invokeGetter(Method method) { + private Object invokeGetter(Method method) { + String name = method.getName(); if (name.startsWith("get")) { if (name.length() == 3) { @@ -86,7 +90,8 @@ class MapIdProxyDelegate implements InvocationHandler { return delegate.get(name); } - public void invokeSetter(Method method, Object value) { + private void invokeSetter(Method method, @Nullable Object value) { + String name = method.getName(); int minLength = 1; boolean isSet = name.startsWith("set"); @@ -111,73 +116,74 @@ class MapIdProxyDelegate implements InvocationHandler { delegate.put(name, value); } -} -class Signature { - String name; - Class[] argTypes; - Class returnType; + static class Signature { + private String name; + private @Nullable Class[] argTypes; + private @Nullable Class returnType; - Signature(Method method, boolean includeReturnType) { - this(method.getName(), method.getParameterTypes(), includeReturnType ? method.getReturnType() : null); - } + Signature(Method method, boolean includeReturnType) { + this(method.getName(), method.getParameterTypes(), includeReturnType ? method.getReturnType() : null); + } - Signature(String name, Class[] argTypes, Class returnType) { - this.name = name; - this.argTypes = argTypes; - this.returnType = returnType; - } + Signature(String name, Class[] argTypes, @Nullable Class returnType) { - @Override - public String toString() { - return String.format("%s %s(%s)", returnType, name, Arrays.toString(argTypes)); - } + this.name = name; + this.argTypes = argTypes; + this.returnType = returnType; + } - @Override - public boolean equals(Object that) { - if (that == null) { - return false; + @Override + public String toString() { + return String.format("%s %s(%s)", returnType, name, Arrays.toString(argTypes)); } - if (this == that) { - return true; - } - if (!(that instanceof Signature)) { - return false; - } - Signature that_ = (Signature) that; - if (!this.name.equals(that_.name)) { - return false; - } - if ((this.argTypes == null && that_.argTypes != null) || (this.argTypes != null && that_.argTypes == null)) { - return false; - } - if (this.argTypes != null) { - if (this.argTypes.length != that_.argTypes.length) { + + @Override + public boolean equals(Object that) { + if (that == null) { return false; } - for (int i = 0; i < this.argTypes.length; i++) { - if (!this.argTypes[i].equals(that_.argTypes[i])) { + if (this == that) { + return true; + } + if (!(that instanceof Signature)) { + return false; + } + Signature that_ = (Signature) that; + if (!this.name.equals(that_.name)) { + return false; + } + if ((this.argTypes == null && that_.argTypes != null) || (this.argTypes != null && that_.argTypes == null)) { + return false; + } + if (this.argTypes != null) { + if (this.argTypes.length != that_.argTypes.length) { return false; } + for (int i = 0; i < this.argTypes.length; i++) { + if (!this.argTypes[i].equals(that_.argTypes[i])) { + return false; + } + } } + if (this.returnType == null) { + return that_.returnType == null; + } + return this.returnType.equals(that_.returnType); } - if (this.returnType == null) { - return that_.returnType == null; - } - return this.returnType.equals(that_.returnType); - } - @Override - public int hashCode() { - int hash = 37 ^ name.hashCode(); - if (argTypes != null) { - for (Class c : argTypes) { - hash ^= c.hashCode(); + @Override + public int hashCode() { + int hash = 37 ^ name.hashCode(); + if (argTypes != null) { + for (Class c : argTypes) { + hash ^= c.hashCode(); + } } + if (returnType != null) { + hash ^= returnType.hashCode(); + } + return hash; } - if (returnType != null) { - hash ^= returnType.hashCode(); - } - return hash; } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/Mapping.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/Mapping.java index c4f42ba92..48965dd6d 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/Mapping.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/Mapping.java @@ -19,6 +19,8 @@ import java.util.Collections; import java.util.HashSet; import java.util.Set; +import org.springframework.lang.Nullable; + public class Mapping { private Set entityMappings = new HashSet<>(); @@ -27,7 +29,7 @@ public class Mapping { return Collections.unmodifiableSet(entityMappings); } - public void setEntityMappings(Set mappings) { + public void setEntityMappings(@Nullable Set mappings) { if (mappings == null) { entityMappings.clear(); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/PropertyMapping.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/PropertyMapping.java index 6128e9064..afd8083ed 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/PropertyMapping.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/PropertyMapping.java @@ -15,6 +15,7 @@ */ package org.springframework.data.cassandra.core.mapping; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -26,14 +27,17 @@ import org.springframework.util.ObjectUtils; */ public class PropertyMapping { - private String columnName; + private @Nullable String columnName; - private String forceQuote; + private @Nullable String forceQuote; private String propertyName; public PropertyMapping(String propertyName) { - setPropertyName(propertyName); + + Assert.notNull(propertyName, "Property name must not be null"); + + this.propertyName = propertyName; } public PropertyMapping(String propertyName, String columnName) { @@ -41,11 +45,15 @@ public class PropertyMapping { } public PropertyMapping(String propertyName, String columnName, String forceQuote) { - setPropertyName(propertyName); + + Assert.notNull(propertyName, "Property name must not be null"); + this.propertyName = propertyName; + setColumnName(columnName); setForceQuote(forceQuote); } + @Nullable public String getColumnName() { return columnName; } @@ -56,6 +64,7 @@ public class PropertyMapping { this.columnName = columnName; } + @Nullable public String getForceQuote() { return forceQuote; } @@ -68,12 +77,6 @@ public class PropertyMapping { return propertyName; } - public void setPropertyName(String propertyName) { - - Assert.notNull(propertyName, "Property name must not be null"); - this.propertyName = propertyName; - } - /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/SimpleUserTypeResolver.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/SimpleUserTypeResolver.java index 4fa4e86b5..e80f0eb36 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/SimpleUserTypeResolver.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/SimpleUserTypeResolver.java @@ -16,6 +16,7 @@ package org.springframework.data.cassandra.core.mapping; import org.springframework.data.cassandra.core.cql.CqlIdentifier; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import com.datastax.driver.core.Cluster; @@ -52,6 +53,7 @@ public class SimpleUserTypeResolver implements UserTypeResolver { /* (non-Javadoc) * @see org.springframework.data.cassandra.core.mapping.UserTypeResolver#resolveType(org.springframework.data.cassandra.core.cql.CqlIdentifier) */ + @Nullable @Override public UserType resolveType(CqlIdentifier typeName) { diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/UserTypeResolver.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/UserTypeResolver.java index 7bdddaf5d..ec5849ad2 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/UserTypeResolver.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/UserTypeResolver.java @@ -16,6 +16,7 @@ package org.springframework.data.cassandra.core.mapping; import org.springframework.data.cassandra.core.cql.CqlIdentifier; +import org.springframework.lang.Nullable; import com.datastax.driver.core.UserType; @@ -34,5 +35,6 @@ public interface UserTypeResolver { * @param typeName must not be {@literal null}. * @return the type or {@literal null}, if not found. */ + @Nullable UserType resolveType(CqlIdentifier typeName); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/package-info.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/package-info.java index e4495da63..39114460e 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/package-info.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/package-info.java @@ -1,4 +1,7 @@ /** * Infrastructure for the Apache Cassandra row-to-object mapping subsystem. */ +@NonNullApi package org.springframework.data.cassandra.core.mapping; + +import org.springframework.lang.NonNullApi; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/package-info.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/package-info.java index 63b7e7a95..b6bf72456 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/package-info.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/package-info.java @@ -1,4 +1,7 @@ /** * Apache Cassandra core support. */ +@NonNullApi package org.springframework.data.cassandra.core; + +import org.springframework.lang.NonNullApi; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/Columns.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/Columns.java index 13d4ddb33..96c90d194 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/Columns.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/Columns.java @@ -185,7 +185,7 @@ public class Columns implements Iterable { * Returns a new {@link Columns} consisting of the {@link ColumnName}s of the current {@link Columns} combined with * the given ones. Existing {@link ColumnName}s are overwritten if specified within {@code columns}. * - * @param columns can be {@literal null}. + * @param columns must not be {@literal null}. * @return a new {@link Columns} with the merged result of the configured and given {@link Columns}. */ public Columns and(Columns columns) { diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/Criteria.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/Criteria.java index 897851ecf..e00cd3b47 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/Criteria.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/Criteria.java @@ -21,6 +21,7 @@ import java.util.Arrays; import java.util.Collection; import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -34,7 +35,7 @@ public class Criteria implements CriteriaDefinition { private final ColumnName columnName; - private Predicate predicate; + private @Nullable Predicate predicate; private Criteria(ColumnName columnName, Predicate predicate) { @@ -82,10 +83,10 @@ public class Criteria implements CriteriaDefinition { /** * Create a criterion using equality. * - * @param value the value to match against. + * @param value the value to match against, may be {@literal null}. * @return {@literal this} {@link Criteria} object. */ - public CriteriaDefinition is(Object value) { + public CriteriaDefinition is(@Nullable Object value) { this.predicate = new Predicate(Operators.EQ, value); return this; @@ -231,6 +232,7 @@ public class Criteria implements CriteriaDefinition { /** * @return the {@link Predicate}. */ + @SuppressWarnings({ "ConstantConditions", "NullableProblems" }) // Predicate not accessible when in null state. public Predicate getPredicate() { return predicate; } @@ -256,8 +258,7 @@ public class Criteria implements CriteriaDefinition { protected boolean simpleCriteriaEquals(CriteriaDefinition left, CriteriaDefinition right) { - boolean keyEqual = left.getColumnName() == null ? right.getColumnName() == null - : left.getColumnName().equals(right.getColumnName()); + boolean keyEqual = left.getColumnName().equals(right.getColumnName()); boolean criteriaEqual = left.getPredicate().equals(right.getPredicate()); return keyEqual && criteriaEqual; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/CriteriaDefinition.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/CriteriaDefinition.java index 6a4902c48..334bd6f4b 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/CriteriaDefinition.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/CriteriaDefinition.java @@ -17,6 +17,7 @@ package org.springframework.data.cassandra.core.query; import lombok.EqualsAndHashCode; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -51,7 +52,7 @@ public interface CriteriaDefinition { private final Operator operator; - private final Object value; + private final @Nullable Object value; /** * Create a new {@link Predicate} given {@code operator} and {@code value}. @@ -59,7 +60,7 @@ public interface CriteriaDefinition { * @param operator must not be {@literal null}. * @param value the match value. */ - public Predicate(Operator operator, Object value) { + public Predicate(Operator operator, @Nullable Object value) { Assert.notNull(operator, "Operator must not be null"); @@ -77,6 +78,7 @@ public interface CriteriaDefinition { /** * @return the match value. */ + @Nullable public Object getValue() { return value; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/SerializationUtils.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/SerializationUtils.java index a12b5633a..8015c7c5c 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/SerializationUtils.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/SerializationUtils.java @@ -22,6 +22,7 @@ import java.util.Set; import org.springframework.core.convert.converter.Converter; import org.springframework.data.cassandra.core.query.CriteriaDefinition.Operator; +import org.springframework.lang.Nullable; import com.datastax.driver.core.CodecRegistry; import com.datastax.driver.core.TypeCodec; @@ -44,10 +45,11 @@ abstract class SerializationUtils { * but falling back to the given object's {@link Object#toString()} method if it's not serializable. Useful for * printing raw {@link Criteria}s containing complex values before actually converting them into Mongo native types. * - * @param criteria - * @return + * @param criteria may be {@literal null}. + * @return may be {@literal null}. */ - public static String serializeToCqlSafely(CriteriaDefinition criteria) { + @Nullable + public static String serializeToCqlSafely(@Nullable CriteriaDefinition criteria) { if (criteria == null) { return null; @@ -65,10 +67,11 @@ abstract class SerializationUtils { * but falling back to the given object's {@link Object#toString()} method if it's not serializable. Useful for * printing raw {@link Criteria}s containing complex values before actually converting them into Mongo native types. * - * @param value value to serialize to CQL. - * @return the value as a serialized CQL {@link String}. + * @param value value to serialize to CQL, may be {@literal null}. + * @return the value as a serialized CQL {@link String}, may be {@literal null}. */ - public static String serializeToCqlSafely(Object value) { + @Nullable + public static String serializeToCqlSafely(@Nullable Object value) { if (value == null) { return null; @@ -89,7 +92,7 @@ abstract class SerializationUtils { } } - private static String serialize(Object value) { + private static String serialize(@Nullable Object value) { if (value == null) { return "null"; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/Update.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/Update.java index 752df716c..79a5334f0 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/Update.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/Update.java @@ -24,6 +24,7 @@ import java.util.LinkedHashMap; import java.util.Map; import org.springframework.data.cassandra.core.query.Update.AddToOp.Mode; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -65,7 +66,8 @@ public class Update { Assert.notNull(assignmentOps, "Update operations must not be null"); Map updateOperations = assignmentOps instanceof Collection - ? new LinkedHashMap<>(((Collection) assignmentOps).size()) : new LinkedHashMap<>(); + ? new LinkedHashMap<>(((Collection) assignmentOps).size()) + : new LinkedHashMap<>(); assignmentOps.forEach(assignmentOp -> updateOperations.put(assignmentOp.getColumnName(), assignmentOp)); @@ -85,11 +87,11 @@ public class Update { * Set the {@code columnName} to {@code value}. * * @param columnName must not be {@literal null}. - * @param value value to set on column with name. + * @param value value to set on column with name, may be {@literal null}. * @return a new {@link Update} object containing the merge result of the existing assignments and the current * assignment. */ - public Update set(String columnName, Object value) { + public Update set(String columnName, @Nullable Object value) { return add(new SetOp(ColumnName.from(columnName), value)); } @@ -550,14 +552,15 @@ public class Update { */ public static class SetOp extends AssignmentOp { - private final Object value; + private final @Nullable Object value; - public SetOp(ColumnName columnName, Object value) { + public SetOp(ColumnName columnName, @Nullable Object value) { super(columnName); this.value = value; } + @Nullable public Object getValue() { return value; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/package-info.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/package-info.java new file mode 100644 index 000000000..df963afe8 --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/package-info.java @@ -0,0 +1,7 @@ +/** + * Apache Cassandra specific query and update support. + */ +@NonNullApi +package org.springframework.data.cassandra.core.query; + +import org.springframework.lang.NonNullApi; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/package-info.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/package-info.java index 0779e28bb..154bb0875 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/package-info.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/package-info.java @@ -1,4 +1,7 @@ /** * Spring Data's Cassandra abstraction. */ +@NonNullApi package org.springframework.data.cassandra; + +import org.springframework.lang.NonNullApi; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/Query.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/Query.java index ef1fd3269..b42addad0 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/Query.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/Query.java @@ -48,5 +48,4 @@ public @interface Query { * @since 2.0 */ boolean allowFiltering() default false; - } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/cdi/CassandraRepositoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/cdi/CassandraRepositoryBean.java index ba184393f..a2976bb62 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/cdi/CassandraRepositoryBean.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/cdi/CassandraRepositoryBean.java @@ -27,6 +27,7 @@ import org.springframework.data.cassandra.core.CassandraOperations; import org.springframework.data.cassandra.repository.support.CassandraRepositoryFactory; import org.springframework.data.repository.cdi.CdiRepositoryBean; import org.springframework.data.repository.config.CustomRepositoryImplementationDetector; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -49,8 +50,8 @@ public class CassandraRepositoryBean extends CdiRepositoryBean { * implementations {@link CustomRepositoryImplementationDetector}, can be {@literal null}. */ public CassandraRepositoryBean(Bean operations, Set qualifiers, - Class repositoryType, BeanManager beanManager, CustomRepositoryImplementationDetector detector) { - super(qualifiers, repositoryType, beanManager, Optional.of(detector)); + Class repositoryType, BeanManager beanManager, @Nullable CustomRepositoryImplementationDetector detector) { + super(qualifiers, repositoryType, beanManager, Optional.ofNullable(detector)); Assert.notNull(operations, "Cannot create repository with 'null' for CassandraOperations."); this.cassandraOperationsBean = operations; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/cdi/CassandraRepositoryExtension.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/cdi/CassandraRepositoryExtension.java index 703ac0d57..7f4295e1f 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/cdi/CassandraRepositoryExtension.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/cdi/CassandraRepositoryExtension.java @@ -66,6 +66,7 @@ public class CassandraRepositoryExtension extends CdiRepositoryExtensionSupport * @param beanManager The BeanManager instance. */ void afterBeanDiscovery(@Observes AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager) { + for (Map.Entry, Set> entry : getRepositoryTypes()) { Class repositoryType = entry.getKey(); @@ -95,5 +96,4 @@ public class CassandraRepositoryExtension extends CdiRepositoryExtensionSupport return new CassandraRepositoryBean<>(cassandraOperationsBean, qualifiers, repositoryType, beanManager, getCustomImplementationDetector()); } - } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/cdi/package-info.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/cdi/package-info.java index e4e61b1a9..5eb9bef58 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/cdi/package-info.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/cdi/package-info.java @@ -1,4 +1,7 @@ /** * CDI support for Apache Cassandra specific repository implementation. */ +@NonNullApi package org.springframework.data.cassandra.repository.cdi; + +import org.springframework.lang.NonNullApi; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/config/CassandraRepositoryNamespaceHandler.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/config/CassandraRepositoryNamespaceHandler.java index 42051494a..be319aae8 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/config/CassandraRepositoryNamespaceHandler.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/config/CassandraRepositoryNamespaceHandler.java @@ -16,13 +16,13 @@ package org.springframework.data.cassandra.repository.config; import org.springframework.data.cassandra.config.CassandraNamespaceHandler; -import org.springframework.data.cassandra.repository.config.CassandraRepositoryConfigurationExtension; import org.springframework.data.repository.config.RepositoryBeanDefinitionParser; /** * Namespace handler for spring-data-cassandra. * * @author Oliver Gierke + * @author Mark Paluch */ class CassandraRepositoryNamespaceHandler extends CassandraNamespaceHandler { @@ -32,7 +32,7 @@ class CassandraRepositoryNamespaceHandler extends CassandraNamespaceHandler { */ @Override public void init() { - + super.init(); registerBeanDefinitionParser("repositories", diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/config/EnableCassandraRepositories.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/config/EnableCassandraRepositories.java index 0a975e28a..6462e428c 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/config/EnableCassandraRepositories.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/config/EnableCassandraRepositories.java @@ -82,39 +82,30 @@ public @interface EnableCassandraRepositories { * Returns the postfix to be used when looking up custom repository implementations. Defaults to {@literal Impl}. So * for a repository named {@code UserRepository} the corresponding implementation class will be looked up scanning for * {@code UserRepositoryImpl}. - * - * @return */ String repositoryImplementationPostfix() default "Impl"; /** * Configures the location of where to find the Spring Data named queries properties file. Will default to * {@code META-INF/cassandra-named-queries.properties}. - * - * @return */ String namedQueriesLocation() default ""; /** * Returns the key of the {@link QueryLookupStrategy} to be used for lookup queries for query methods. Defaults to * {@link Key#CREATE_IF_NOT_FOUND}. - * - * @return */ Key queryLookupStrategy() default Key.CREATE_IF_NOT_FOUND; /** * Returns the {@link FactoryBean} class to be used for each repository instance. Defaults to * {@link CassandraRepositoryFactoryBean}. - * - * @return */ Class repositoryFactoryBeanClass() default CassandraRepositoryFactoryBean.class; /** * Configure the repository base class to be used to create repository proxies for this particular configuration. * - * @return * @since 1.3 */ Class repositoryBaseClass() default DefaultRepositoryBaseClass.class; @@ -122,8 +113,6 @@ public @interface EnableCassandraRepositories { /** * Configures the name of the {@link CassandraTemplate} bean to be used with the repositories detected. Defaults to * {@link DefaultBeanNames#DATA_TEMPLATE} - * - * @return */ String cassandraTemplateRef() default "cassandraTemplate"; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/config/EnableReactiveCassandraRepositories.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/config/EnableReactiveCassandraRepositories.java index bf5275cad..4c31bc1eb 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/config/EnableReactiveCassandraRepositories.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/config/EnableReactiveCassandraRepositories.java @@ -80,47 +80,35 @@ public @interface EnableReactiveCassandraRepositories { * Returns the postfix to be used when looking up custom repository implementations. Defaults to {@literal Impl}. So * for a repository named {@code UserRepository} the corresponding implementation class will be looked up scanning for * {@code UserRepositoryImpl}. - * - * @return */ String repositoryImplementationPostfix() default "Impl"; /** * Configures the location of where to find the Spring Data named queries properties file. Will default to * {@code META-INF/cassandra-named-queries.properties}. - * - * @return */ String namedQueriesLocation() default ""; /** * Returns the key of the {@link QueryLookupStrategy} to be used for lookup queries for query methods. Defaults to * {@link Key#CREATE_IF_NOT_FOUND}. - * - * @return */ Key queryLookupStrategy() default Key.CREATE_IF_NOT_FOUND; /** * Returns the {@link FactoryBean} class to be used for each repository instance. Defaults to * {@link ReactiveCassandraRepositoryFactoryBean}. - * - * @return */ Class repositoryFactoryBeanClass() default ReactiveCassandraRepositoryFactoryBean.class; /** * Configure the repository base class to be used to create repository proxies for this particular configuration. - * - * @return */ Class repositoryBaseClass() default DefaultRepositoryBaseClass.class; /** * Configures the name of the {@link org.springframework.data.cassandra.core.ReactiveCassandraTemplate} bean to be * used with the repositories detected. - * - * @return */ String reactiveCassandraTemplateRef() default "reactiveCassandraTemplate"; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/config/package-info.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/config/package-info.java index d4f69df5c..5ada97c02 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/config/package-info.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/config/package-info.java @@ -1,4 +1,7 @@ /** * Support infrastructure for the configuration of Apache Cassandra specific repositories. */ +@NonNullApi package org.springframework.data.cassandra.repository.config; + +import org.springframework.lang.NonNullApi; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/package-info.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/package-info.java index 746fd0703..0ba7c1c98 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/package-info.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/package-info.java @@ -1,4 +1,7 @@ /** * Apache Cassandra specific repository implementation. */ +@NonNullApi package org.springframework.data.cassandra.repository; + +import org.springframework.lang.NonNullApi; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/AbstractCassandraQuery.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/AbstractCassandraQuery.java index 2ff9a7cc3..cc4a0664e 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/AbstractCassandraQuery.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/AbstractCassandraQuery.java @@ -44,6 +44,7 @@ import org.springframework.data.repository.query.ParameterAccessor; import org.springframework.data.repository.query.RepositoryQuery; import org.springframework.data.repository.query.ResultProcessor; import org.springframework.data.repository.query.ReturnedType; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -124,6 +125,7 @@ public abstract class AbstractCassandraQuery implements RepositoryQuery { /* (non-Javadoc) * @see org.springframework.data.repository.query.RepositoryQuery#execute(java.lang.Object[]) */ + @Nullable @Override public Object execute(Object[] parameters) { diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraParameterAccessor.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraParameterAccessor.java index 6274bdfcc..7e97fcada 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraParameterAccessor.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraParameterAccessor.java @@ -17,6 +17,7 @@ package org.springframework.data.cassandra.repository.query; import org.springframework.data.cassandra.core.mapping.CassandraType; import org.springframework.data.repository.query.ParameterAccessor; +import org.springframework.lang.Nullable; import com.datastax.driver.core.DataType; @@ -50,6 +51,7 @@ public interface CassandraParameterAccessor extends ParameterAccessor { * @see org.springframework.data.cassandra.core.mapping.CassandraSimpleTypeHolder * @see org.springframework.data.cassandra.core.mapping.CassandraType */ + @Nullable CassandraType findCassandraType(int index); /** diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraParameters.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraParameters.java index 9efd716f2..a3c2abe01 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraParameters.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraParameters.java @@ -29,7 +29,7 @@ import org.springframework.data.repository.query.Parameter; import org.springframework.data.repository.query.Parameters; import org.springframework.data.repository.util.QueryExecutionConverters; import org.springframework.data.repository.util.ReactiveWrappers; -import org.springframework.util.Assert; +import org.springframework.lang.Nullable; /** * Custom extension of {@link Parameters} discovering additional properties of query method parameters. @@ -75,7 +75,7 @@ public class CassandraParameters extends Parameters parameterType; protected CassandraParameter(MethodParameter parameter) { @@ -85,14 +85,7 @@ public class CassandraParameters extends Parameters T getAnnotation(Class annotationClass) { return methodParameter.getParameterAnnotation(annotationClass); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraParametersParameterAccessor.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraParametersParameterAccessor.java index 7aba40b7f..9d949ed5f 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraParametersParameterAccessor.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraParametersParameterAccessor.java @@ -22,6 +22,7 @@ import org.springframework.data.cassandra.core.mapping.CassandraSimpleTypeHolder import org.springframework.data.cassandra.core.mapping.CassandraType; import org.springframework.data.repository.query.ParameterAccessor; import org.springframework.data.repository.query.ParametersParameterAccessor; +import org.springframework.lang.Nullable; import com.datastax.driver.core.DataType; @@ -54,6 +55,7 @@ public class CassandraParametersParameterAccessor extends ParametersParameterAcc * (non-Javadoc) * @see org.springframework.data.cassandra.repository.query.CassandraParameterAccessor#findCassandraType(int) */ + @Nullable public CassandraType findCassandraType(int index) { return getParameters().getParameter(index).getCassandraType(); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraQueryCreator.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraQueryCreator.java index 6cc475880..09c3aad39 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraQueryCreator.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraQueryCreator.java @@ -104,6 +104,8 @@ class CassandraQueryCreator extends AbstractQueryCreator type); /** @@ -132,9 +134,13 @@ interface CassandraQueryExecution { /* (non-Javadoc) * @see org.springframework.data.cassandra.repository.query.CassandraQueryExecution#execute(java.lang.String, java.lang.Class) */ + @Nullable @Override public Object execute(Statement statement, Class type) { - return converter.convert(delegate.execute(statement, type)); + + Object result = delegate.execute(statement, type); + + return result != null ? converter.convert(result) : null; } } @@ -154,7 +160,7 @@ interface CassandraQueryExecution { * @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object) */ @Override - public Object convert(Object source) { + public Object convert(@Nullable Object source) { ReturnedType returnedType = processor.getReturnedType(); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraQueryMethod.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraQueryMethod.java index b04454030..7ef27b58c 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraQueryMethod.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/CassandraQueryMethod.java @@ -29,6 +29,7 @@ import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.repository.query.QueryMethod; import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.TypeInformation; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; @@ -51,7 +52,7 @@ public class CassandraQueryMethod extends QueryMethod { private final Optional query; - private CassandraEntityMetadata entityMetadata; + private @Nullable CassandraEntityMetadata entityMetadata; /** * Create a new {@link CassandraQueryMethod} from the given {@link Method}. @@ -148,16 +149,29 @@ public class CassandraQueryMethod extends QueryMethod { * Returns the query string declared in a {@link Query} annotation or {@literal null} if neither the annotation found * nor the attribute was specified. * - * @return + * @return the query string or {@literal null} if no query string present. */ + @Nullable public String getAnnotatedQuery() { return query.map(Query::value).orElse(null); } /** - * Returns the {@link Query} annotation that is applied to the method or {@code null} if none available. + * Returns the required query string declared in a {@link Query} annotation or throws {@link IllegalStateException} if + * neither the annotation found nor the attribute was specified. * - * @return + * @return the query string. + * @throws IllegalStateException in case query method has no annotated query. + */ + public String getRequiredAnnotatedQuery() { + return query.map(Query::value) + .orElseThrow(() -> new IllegalStateException("Query method " + this + " has no annotated query")); + } + + /** + * Returns the {@link Query} annotation that is applied to the method or {@literal null} if none available. + * + * @return the optional query annotation. */ Optional getQueryAnnotation() { return query; @@ -179,6 +193,8 @@ public class CassandraQueryMethod extends QueryMethod { * @return true is the method returns a {@link ResultSet}. */ public boolean isResultSetQuery() { - return ResultSet.class.isAssignableFrom(getReturnType().getActualType().getType()); + + TypeInformation actualType = getReturnType().getActualType(); + return actualType != null && ResultSet.class.isAssignableFrom(actualType.getType()); } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ConvertingParameterAccessor.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ConvertingParameterAccessor.java index 0a5b5ae5b..e385ea931 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ConvertingParameterAccessor.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ConvertingParameterAccessor.java @@ -28,6 +28,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.TypeInformation; +import org.springframework.lang.Nullable; import com.datastax.driver.core.CodecRegistry; import com.datastax.driver.core.DataType; @@ -100,10 +101,7 @@ class ConvertingParameterAccessor implements CassandraParameterAccessor { */ @Override public DataType getDataType(int index) { - - DataType dataType = delegate.getDataType(index); - - return (dataType != null ? dataType : converter.getMappingContext().getDataType(getParameterType(index))); + return delegate.getDataType(index); } /* (non-Javadoc) @@ -138,7 +136,8 @@ class ConvertingParameterAccessor implements CassandraParameterAccessor { } @SuppressWarnings("unchecked") - private Object potentiallyConvert(int index, Object bindableValue) { + @Nullable + private Object potentiallyConvert(int index, @Nullable Object bindableValue) { if (bindableValue == null) { return null; @@ -148,14 +147,15 @@ class ConvertingParameterAccessor implements CassandraParameterAccessor { } @SuppressWarnings("unchecked") - private Object potentiallyConvert(int index, Object bindableValue, CassandraPersistentProperty property) { + @Nullable + private Object potentiallyConvert(int index, @Nullable Object bindableValue, CassandraPersistentProperty property) { return (bindableValue == null ? null : converter.convertToColumnType(bindableValue, findTypeInformation(index, bindableValue, property))); } private TypeInformation findTypeInformation(int index, Object bindableValue, - CassandraPersistentProperty property) { + @Nullable CassandraPersistentProperty property) { if (delegate.findCassandraType(index) != null) { TypeCodec typeCodec = CodecRegistry.DEFAULT_INSTANCE.codecFor(getDataType(index, property)); @@ -182,7 +182,7 @@ class ConvertingParameterAccessor implements CassandraParameterAccessor { * @param property {@link CassandraPersistentProperty}. * @return the {@link DataType} */ - DataType getDataType(int index, CassandraPersistentProperty property) { + DataType getDataType(int index, @Nullable CassandraPersistentProperty property) { CassandraType cassandraType = delegate.findCassandraType(index); @@ -268,6 +268,7 @@ class ConvertingParameterAccessor implements CassandraParameterAccessor { * (non-Javadoc) * @see java.util.Iterator#next() */ + @Nullable public Object next() { return potentiallyConvert(index++, delegate.next()); } @@ -283,6 +284,7 @@ class ConvertingParameterAccessor implements CassandraParameterAccessor { /* (non-Javadoc) * @see org.springframework.data.cassandra.repository.query.ConvertingParameterAccessor.PotentiallyConvertingIterator#nextConverted(org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty) */ + @Nullable @Override public Object nextConverted(CassandraPersistentProperty property) { return potentiallyConvert(index++, delegate.next(), property); @@ -301,7 +303,7 @@ class ConvertingParameterAccessor implements CassandraParameterAccessor { * * @return the converted object, may be {@literal null}. */ + @Nullable Object nextConverted(CassandraPersistentProperty property); - } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/DtoInstantiatingConverter.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/DtoInstantiatingConverter.java index 75da7ae54..e1944b9d4 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/DtoInstantiatingConverter.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/DtoInstantiatingConverter.java @@ -28,6 +28,7 @@ import org.springframework.data.mapping.PreferredConstructor.Parameter; import org.springframework.data.mapping.SimplePropertyHandler; import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.model.ParameterValueProvider; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -82,14 +83,14 @@ class DtoInstantiatingConverter implements Converter { Object dto = instantiator.createInstance(targetEntity, new ParameterValueProvider() { @Override + @Nullable public Object getParameterValue(Parameter parameter) { - // TODO: Fix generics - if (parameter != null) { - return sourceAccessor.getProperty(sourceEntity.getRequiredPersistentProperty(parameter.getName())); + if (parameter.getName() == null) { + throw new IllegalArgumentException(String.format("Parameter %s does not have a name", parameter)); } - return null; + return sourceAccessor.getProperty(sourceEntity.getRequiredPersistentProperty(parameter.getName())); } }); @@ -99,7 +100,7 @@ class DtoInstantiatingConverter implements Converter { targetEntity.doWithProperties((SimplePropertyHandler) property -> { - if (!constructor.isConstructorParameter(property)) { + if (constructor != null && !constructor.isConstructorParameter(property)) { return; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ExpressionEvaluatingParameterBinder.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ExpressionEvaluatingParameterBinder.java index 49658d290..b2ab2c7b1 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ExpressionEvaluatingParameterBinder.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ExpressionEvaluatingParameterBinder.java @@ -24,6 +24,7 @@ import org.springframework.data.repository.query.Parameter; import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; @@ -46,7 +47,7 @@ class ExpressionEvaluatingParameterBinder { * @param expressionParser must not be {@literal null}. * @param evaluationContextProvider must not be {@literal null}. */ - public ExpressionEvaluatingParameterBinder(SpelExpressionParser expressionParser, + ExpressionEvaluatingParameterBinder(SpelExpressionParser expressionParser, EvaluationContextProvider evaluationContextProvider) { Assert.notNull(expressionParser, "ExpressionParser must not be null"); @@ -88,6 +89,7 @@ class ExpressionEvaluatingParameterBinder { * @param binding must not be {@literal null}. * @return the value used for the given {@link ParameterBinding}. */ + @Nullable private Object getParameterValueForBinding(CassandraParameterAccessor parameterAccessor, CassandraParameters parameters, ParameterBinding binding) { @@ -120,6 +122,7 @@ class ExpressionEvaluatingParameterBinder { * @param parameterValues must not be {@literal null}. * @return the value of the {@code expressionString} evaluation. */ + @Nullable private Object evaluateExpression(String expressionString, CassandraParameters parameters, Object[] parameterValues) { EvaluationContext evaluationContext = evaluationContextProvider.getEvaluationContext(parameters, parameterValues); @@ -162,7 +165,7 @@ class ExpressionEvaluatingParameterBinder { * * @return never {@literal null}. */ - public List getBindings() { + List getBindings() { return Collections.unmodifiableList(bindings); } @@ -171,7 +174,7 @@ class ExpressionEvaluatingParameterBinder { * * @return the {@link CassandraParameters} associated with the {@link CassandraQueryMethod}. */ - public CassandraParameters getParameters() { + CassandraParameters getParameters() { return queryMethod.getParameters(); } @@ -180,7 +183,7 @@ class ExpressionEvaluatingParameterBinder { * * @return the {@link CassandraQueryMethod} used in the expression evaluation context. */ - public CassandraQueryMethod getQueryMethod() { + CassandraQueryMethod getQueryMethod() { return queryMethod; } } @@ -194,49 +197,52 @@ class ExpressionEvaluatingParameterBinder { private final boolean quoted; private final int parameterIndex; - private final String expression; - private final String parameterName; + private final @Nullable String expression; + private final @Nullable String parameterName; - private ParameterBinding(int parameterIndex, boolean quoted, String expression, String parameterName) { + private ParameterBinding(int parameterIndex, boolean quoted, @Nullable String expression, + @Nullable String parameterName) { this.parameterIndex = parameterIndex; this.quoted = quoted; this.expression = expression; this.parameterName = parameterName; } - public static ParameterBinding expression(String expression, boolean quoted) { + static ParameterBinding expression(String expression, boolean quoted) { return new ParameterBinding(-1, quoted, expression, null); } - public static ParameterBinding indexed(int parameterIndex) { + static ParameterBinding indexed(int parameterIndex) { return new ParameterBinding(parameterIndex, false, null, null); } - public static ParameterBinding named(String name) { + static ParameterBinding named(String name) { return new ParameterBinding(-1, false, null, name); } - public boolean isNamed() { + boolean isNamed() { return (parameterName != null); } - public int getParameterIndex() { + int getParameterIndex() { return parameterIndex; } - public String getParameter() { + String getParameter() { return ("?" + (isExpression() ? "expr" : "") + parameterIndex); } - public String getExpression() { + @Nullable + String getExpression() { return expression; } - public boolean isExpression() { + boolean isExpression() { return (this.expression != null); } - public String getParameterName() { + @Nullable + String getParameterName() { return parameterName; } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ReactiveCassandraParameterAccessor.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ReactiveCassandraParameterAccessor.java index fe7dad3a0..0c85507fd 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ReactiveCassandraParameterAccessor.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ReactiveCassandraParameterAccessor.java @@ -38,7 +38,8 @@ class ReactiveCassandraParameterAccessor extends CassandraParametersParameterAcc private final List> subscriptions; - public ReactiveCassandraParameterAccessor(CassandraQueryMethod method, Object[] values) { + @SuppressWarnings("ConstantConditions") + ReactiveCassandraParameterAccessor(CassandraQueryMethod method, Object[] values) { super(method, values); @@ -62,7 +63,7 @@ class ReactiveCassandraParameterAccessor extends CassandraParametersParameterAcc /* (non-Javadoc) * @see org.springframework.data.repository.query.ParametersParameterAccessor#getValue(int) */ - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "ConstantConditions" }) @Override protected T getValue(int index) { return (subscriptions.get(index) != null ? (T) subscriptions.get(index).block() : super.getValue(index)); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ReactiveCassandraQueryExecution.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ReactiveCassandraQueryExecution.java index d4327227c..bcb90ce1e 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ReactiveCassandraQueryExecution.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ReactiveCassandraQueryExecution.java @@ -97,6 +97,7 @@ interface ReactiveCassandraQueryExecution { * (non-Javadoc) * @see org.springframework.data.cassandra.repository.query.ReactiveCassandraQueryExecution#execute(java.lang.String, java.lang.Class) */ + @SuppressWarnings("ConstantConditions") @Override public Object execute(Statement statement, Class type) { return converter.convert(delegate.execute(statement, type)); @@ -128,7 +129,7 @@ interface ReactiveCassandraQueryExecution { return source; } - if (source != null && returnedType.isInstance(source)) { + if (returnedType.isInstance(source)) { return source; } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ReactiveStringBasedCassandraQuery.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ReactiveStringBasedCassandraQuery.java index 5a288e21d..35a83dfd2 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ReactiveStringBasedCassandraQuery.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ReactiveStringBasedCassandraQuery.java @@ -56,7 +56,7 @@ public class ReactiveStringBasedCassandraQuery extends AbstractReactiveCassandra ReactiveCassandraOperations operations, SpelExpressionParser expressionParser, EvaluationContextProvider evaluationContextProvider) { - this(queryMethod.getAnnotatedQuery(), queryMethod, operations, expressionParser, evaluationContextProvider); + this(queryMethod.getRequiredAnnotatedQuery(), queryMethod, operations, expressionParser, evaluationContextProvider); } /** diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/SimpleCassandraEntityMetadata.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/SimpleCassandraEntityMetadata.java index 7e26f0cdd..c0762589c 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/SimpleCassandraEntityMetadata.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/SimpleCassandraEntityMetadata.java @@ -38,7 +38,7 @@ class SimpleCassandraEntityMetadata implements CassandraEntityMetadata { * @param type must not be {@literal null}. * @param entity must not be {@literal null} or empty. */ - public SimpleCassandraEntityMetadata(Class type, CassandraPersistentEntity entity) { + SimpleCassandraEntityMetadata(Class type, CassandraPersistentEntity entity) { Assert.notNull(type, "Type must not be null"); Assert.notNull(entity, "Collection entity must not be null or empty"); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/StringBasedCassandraQuery.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/StringBasedCassandraQuery.java index 4771892df..33dc874a1 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/StringBasedCassandraQuery.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/StringBasedCassandraQuery.java @@ -54,7 +54,7 @@ public class StringBasedCassandraQuery extends AbstractCassandraQuery { public StringBasedCassandraQuery(CassandraQueryMethod queryMethod, CassandraOperations operations, SpelExpressionParser expressionParser, EvaluationContextProvider evaluationContextProvider) { - this(queryMethod.getAnnotatedQuery(), queryMethod, operations, expressionParser, evaluationContextProvider); + this(queryMethod.getRequiredAnnotatedQuery(), queryMethod, operations, expressionParser, evaluationContextProvider); } /** diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/StringBasedQuery.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/StringBasedQuery.java index 616ae7781..381262cad 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/StringBasedQuery.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/StringBasedQuery.java @@ -23,6 +23,7 @@ import java.util.regex.Pattern; import org.springframework.data.cassandra.repository.query.ExpressionEvaluatingParameterBinder.BindingContext; import org.springframework.data.cassandra.repository.query.ExpressionEvaluatingParameterBinder.ParameterBinding; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -50,7 +51,7 @@ class StringBasedQuery { * @param query must not be empty. * @param parameterBinder must not be {@literal null}. */ - public StringBasedQuery(String query, ExpressionEvaluatingParameterBinder parameterBinder) { + StringBasedQuery(String query, ExpressionEvaluatingParameterBinder parameterBinder) { Assert.hasText(query, "Query must not be empty"); Assert.notNull(parameterBinder, "ExpressionEvaluatingParameterBinder must not be null"); @@ -62,8 +63,7 @@ class StringBasedQuery { } - /* (non-Javadoc) */ - protected ExpressionEvaluatingParameterBinder getParameterBinder() { + private ExpressionEvaluatingParameterBinder getParameterBinder() { return this.parameterBinder; } @@ -79,7 +79,7 @@ class StringBasedQuery { * @param queryMethod must not be {@literal null}. * @return the bound String query containing formatted parameters. */ - public SimpleStatement bindQuery(CassandraParameterAccessor parameterAccessor, CassandraQueryMethod queryMethod) { + SimpleStatement bindQuery(CassandraParameterAccessor parameterAccessor, CassandraQueryMethod queryMethod) { Assert.notNull(parameterAccessor, "CassandraParameterAccessor must not be null"); Assert.notNull(queryMethod, "CassandraQueryMethod must not be null"); @@ -236,6 +236,7 @@ class StringBasedQuery { return result.append(input.subSequence(currentPosition, input.length())).toString(); } + @Nullable private static Matcher findNextBindingOrExpression(String input, int position) { List matchers = new ArrayList<>(); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/UnsupportedCassandraQueryOperatorException.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/UnsupportedCassandraQueryOperatorException.java deleted file mode 100644 index ef2475f13..000000000 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/UnsupportedCassandraQueryOperatorException.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.springframework.data.cassandra.repository.query; - -import org.springframework.dao.InvalidDataAccessApiUsageException; - -public class UnsupportedCassandraQueryOperatorException extends InvalidDataAccessApiUsageException { - - public UnsupportedCassandraQueryOperatorException(String msg) { - super(msg); - // TODO Auto-generated constructor stub - } - - public UnsupportedCassandraQueryOperatorException(String msg, Throwable cause) { - super(msg, cause); - // TODO Auto-generated constructor stub - } - -} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/package-info.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/package-info.java index f56efb649..af4c4c3ba 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/package-info.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/package-info.java @@ -1,4 +1,7 @@ /** * Query derivation mechanism for Apache Cassandra specific repositories. */ +@NonNullApi package org.springframework.data.cassandra.repository.query; + +import org.springframework.lang.NonNullApi; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/CassandraRepositoryFactory.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/CassandraRepositoryFactory.java index 7940dcb33..663eb6a62 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/CassandraRepositoryFactory.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/CassandraRepositoryFactory.java @@ -37,6 +37,7 @@ import org.springframework.data.repository.query.QueryLookupStrategy; import org.springframework.data.repository.query.QueryLookupStrategy.Key; import org.springframework.data.repository.query.RepositoryQuery; import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -105,7 +106,7 @@ public class CassandraRepositoryFactory extends RepositoryFactorySupport { * @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getQueryLookupStrategy(Key, EvaluationContextProvider) */ @Override - protected Optional getQueryLookupStrategy(Key key, + protected Optional getQueryLookupStrategy(@Nullable Key key, EvaluationContextProvider evaluationContextProvider) { return Optional.of(new CassandraQueryLookupStrategy(operations, evaluationContextProvider, mappingContext)); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/CassandraRepositoryFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/CassandraRepositoryFactoryBean.java index 13a4384a7..c7de34a4b 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/CassandraRepositoryFactoryBean.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/CassandraRepositoryFactoryBean.java @@ -15,11 +15,13 @@ */ package org.springframework.data.cassandra.repository.support; +import org.springframework.data.cassandra.core.CassandraOperations; import org.springframework.data.cassandra.core.CassandraTemplate; import org.springframework.data.cassandra.repository.CassandraRepository; import org.springframework.data.repository.Repository; import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport; import org.springframework.data.repository.core.support.RepositoryFactorySupport; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -33,7 +35,7 @@ import org.springframework.util.Assert; public class CassandraRepositoryFactoryBean, S, ID> extends RepositoryFactoryBeanSupport { - private CassandraTemplate cassandraTemplate; + private @Nullable CassandraOperations cassandraOperations; /** * Create a new {@link CassandraRepositoryFactoryBean} for the given repository interface. @@ -46,7 +48,10 @@ public class CassandraRepositoryFactoryBean, S, ID> @Override protected RepositoryFactorySupport createRepositoryFactory() { - return new CassandraRepositoryFactory(cassandraTemplate); + + Assert.state(cassandraOperations != null, "CassandraOperations must not be null"); + + return new CassandraRepositoryFactory(cassandraOperations); } /** @@ -56,7 +61,8 @@ public class CassandraRepositoryFactoryBean, S, ID> * on Apache Cassandra. */ public void setCassandraTemplate(CassandraTemplate cassandraTemplate) { - this.cassandraTemplate = cassandraTemplate; + + this.cassandraOperations = cassandraTemplate; setMappingContext(cassandraTemplate.getConverter().getMappingContext()); } @@ -68,6 +74,6 @@ public class CassandraRepositoryFactoryBean, S, ID> super.afterPropertiesSet(); - Assert.notNull(cassandraTemplate, "CassandraTemplate must not be null!"); + Assert.notNull(cassandraOperations, "CassandraOperations must not be null!"); } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/MappingCassandraEntityInformation.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/MappingCassandraEntityInformation.java index f38b79fa9..826acd0ff 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/MappingCassandraEntityInformation.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/MappingCassandraEntityInformation.java @@ -22,6 +22,7 @@ import org.springframework.data.cassandra.core.mapping.CassandraPersistentProper import org.springframework.data.cassandra.core.mapping.MapId; import org.springframework.data.cassandra.repository.query.CassandraEntityInformation; import org.springframework.data.repository.core.support.AbstractEntityInformation; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -57,16 +58,15 @@ public class MappingCassandraEntityInformation extends AbstractEntityInfo */ @SuppressWarnings("unchecked") @Override + @Nullable public ID getId(T entity) { Assert.notNull(entity, "Entity must not be null"); CassandraPersistentProperty idProperty = entityMetadata.getIdProperty(); - if (idProperty != null) { - return (ID) entityMetadata.getIdentifierAccessor(entity).getIdentifier(); - } - return (ID) converter.getId(entity, entityMetadata); + return idProperty != null ? (ID) entityMetadata.getIdentifierAccessor(entity).getIdentifier() + : (ID) converter.getId(entity, entityMetadata); } /* (non-Javadoc) @@ -77,7 +77,7 @@ public class MappingCassandraEntityInformation extends AbstractEntityInfo public Class getIdType() { if (entityMetadata.getIdProperty() != null) { - return (Class) entityMetadata.getIdProperty().getType(); + return (Class) entityMetadata.getRequiredIdProperty().getType(); } return (Class) MapId.class; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/ReactiveCassandraRepositoryFactory.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/ReactiveCassandraRepositoryFactory.java index ba8fce999..18fcee77f 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/ReactiveCassandraRepositoryFactory.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/ReactiveCassandraRepositoryFactory.java @@ -36,6 +36,7 @@ import org.springframework.data.repository.query.QueryLookupStrategy; import org.springframework.data.repository.query.QueryLookupStrategy.Key; import org.springframework.data.repository.query.RepositoryQuery; import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -88,7 +89,7 @@ public class ReactiveCassandraRepositoryFactory extends ReactiveRepositoryFactor * @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getQueryLookupStrategy(org.springframework.data.repository.query.QueryLookupStrategy.Key, org.springframework.data.repository.query.EvaluationContextProvider) */ @Override - protected Optional getQueryLookupStrategy(Key key, + protected Optional getQueryLookupStrategy(@Nullable Key key, EvaluationContextProvider evaluationContextProvider) { return Optional.of(new CassandraQueryLookupStrategy(operations, evaluationContextProvider, mappingContext)); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/ReactiveCassandraRepositoryFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/ReactiveCassandraRepositoryFactoryBean.java index 53cb3c7e8..3a3d7b210 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/ReactiveCassandraRepositoryFactoryBean.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/ReactiveCassandraRepositoryFactoryBean.java @@ -20,6 +20,7 @@ import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.repository.Repository; import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport; import org.springframework.data.repository.core.support.RepositoryFactorySupport; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -29,14 +30,14 @@ import org.springframework.util.Assert; * @author Mark Paluch * @since 2.0 * @see org.springframework.data.repository.reactive.ReactiveSortingRepository - * @see org.springframework.data.repository.reactive.RxJava1SortingRepository + * @see org.springframework.data.repository.reactive.RxJava2SortingRepository */ public class ReactiveCassandraRepositoryFactoryBean, S, ID> extends RepositoryFactoryBeanSupport { private boolean mappingContextConfigured = false; - private ReactiveCassandraOperations operations; + private @Nullable ReactiveCassandraOperations operations; /** * Create a new {@link ReactiveCassandraRepositoryFactoryBean} for the given repository interface. @@ -73,6 +74,9 @@ public class ReactiveCassandraRepositoryFactoryBean, */ @Override protected final RepositoryFactorySupport createRepositoryFactory() { + + Assert.state(operations != null, "ReactiveCassandraOperations must not be null"); + return getFactoryInstance(operations); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/package-info.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/package-info.java index 8c0a91ed0..f59e986f2 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/package-info.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/package-info.java @@ -1,4 +1,7 @@ /** * Support infrastructure for query derivation of Apache Cassandra specific repositories. */ +@NonNullApi package org.springframework.data.cassandra.repository.support; + +import org.springframework.lang.NonNullApi; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/util/MapBuilder.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/util/MapBuilder.java index cea42c691..bfc82b6a8 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/util/MapBuilder.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/util/MapBuilder.java @@ -21,6 +21,7 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -34,7 +35,7 @@ import org.springframework.util.Assert; */ public class MapBuilder implements Map { - private Map map; + private final Map map; /** * Create a new {@link MapBuilder}. @@ -131,6 +132,7 @@ public class MapBuilder implements Map { * @see java.util.Map#get(java.lang.Object) */ @Override + @Nullable public V get(Object key) { return map.get(key); } @@ -147,6 +149,7 @@ public class MapBuilder implements Map { * @see java.util.Map#remove(java.lang.Object) */ @Override + @Nullable public V remove(Object key) { return map.remove(key); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/util/SpelUtils.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/util/SpelUtils.java index f371a7915..5cd0a75e3 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/util/SpelUtils.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/util/SpelUtils.java @@ -1,3 +1,18 @@ +/* + * Copyright 2017 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 + * + * http://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.util; import org.springframework.expression.EvaluationContext; @@ -5,7 +20,13 @@ import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.ParserContext; import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.lang.Nullable; +/** + * Evaluates a SpEL expression. + * + * @author Mark Paluch + */ public class SpelUtils { public static final SpelExpressionParser DEFAULT_PARSER = new SpelExpressionParser(); @@ -13,6 +34,7 @@ public class SpelUtils { /** * Evaluates the given value against the given context as a string. */ + @Nullable public static String evaluate(CharSequence value, EvaluationContext context) { return evaluate(value, context, DEFAULT_PARSER); } @@ -20,6 +42,7 @@ public class SpelUtils { /** * Evaluates the given value against the given context as a string using the given parser. */ + @Nullable public static String evaluate(CharSequence value, EvaluationContext context, ExpressionParser parser) { return evaluate(value, context, String.class, parser); } @@ -27,6 +50,7 @@ public class SpelUtils { /** * Evaluates the given value against the given context as an object of the given class. */ + @Nullable public static T evaluate(CharSequence value, EvaluationContext context, Class clazz) { return evaluate(value, context, clazz, DEFAULT_PARSER); } @@ -34,7 +58,9 @@ public class SpelUtils { /** * Evaluates the given value against the given context as an object of the given class using the given parser. */ + @Nullable public static T evaluate(CharSequence value, EvaluationContext context, Class clazz, ExpressionParser parser) { + Expression expression = parser.parseExpression(value.toString(), ParserContext.TEMPLATE_EXPRESSION); return expression.getValue(context, clazz); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/util/package-info.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/util/package-info.java new file mode 100644 index 000000000..3da2bd2e0 --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/util/package-info.java @@ -0,0 +1,7 @@ +/** + * Map and SpEL utility infrastructure. + */ +@NonNullApi +package org.springframework.data.cassandra.util; + +import org.springframework.lang.NonNullApi; diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/config/AbstractClusterConfigurationUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/config/AbstractClusterConfigurationUnitTests.java index 76a512c77..1ac93ba69 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/config/AbstractClusterConfigurationUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/config/AbstractClusterConfigurationUnitTests.java @@ -214,8 +214,8 @@ public class AbstractClusterConfigurationUnitTests { @Test // DATACASS-226 public void shouldSetKeyspaceCreations() { - final List specification = Collections - .singletonList(CreateKeyspaceSpecification.createKeyspace()); + List specification = Collections + .singletonList(CreateKeyspaceSpecification.createKeyspace("foo")); AbstractClusterConfiguration clusterConfiguration = new AbstractClusterConfiguration() { @Override protected List getKeyspaceCreations() { @@ -229,8 +229,8 @@ public class AbstractClusterConfigurationUnitTests { @Test // DATACASS-226 public void shouldSetKeyspaceDrops() { - final List specification = Collections - .singletonList(DropKeyspaceSpecification.dropKeyspace()); + List specification = Collections + .singletonList(DropKeyspaceSpecification.dropKeyspace("foo")); AbstractClusterConfiguration clusterConfiguration = new AbstractClusterConfiguration() { @Override protected List getKeyspaceDrops() { @@ -244,7 +244,7 @@ public class AbstractClusterConfigurationUnitTests { @Test // DATACASS-226 public void shouldSetStartupScripts() { - final List scripts = Collections.singletonList("USE BLUE_METH; CREATE TABLE..."); + List scripts = Collections.singletonList("USE BLUE_METH; CREATE TABLE..."); AbstractClusterConfiguration clusterConfiguration = new AbstractClusterConfiguration() { @Override protected List getStartupScripts() { @@ -258,7 +258,7 @@ public class AbstractClusterConfigurationUnitTests { @Test // DATACASS-226 public void shouldSetShutdownScripts() { - final List scripts = Collections.singletonList("USE BLUE_METH; DROP TABLE..."); + List scripts = Collections.singletonList("USE BLUE_METH; DROP TABLE..."); AbstractClusterConfiguration clusterConfiguration = new AbstractClusterConfiguration() { @Override protected List getShutdownScripts() { diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/config/KeyspaceCreatingJavaConfigIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/config/KeyspaceCreatingJavaConfigIntegrationTests.java index 0902cb933..93af5bc89 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/config/KeyspaceCreatingJavaConfigIntegrationTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/config/KeyspaceCreatingJavaConfigIntegrationTests.java @@ -72,7 +72,7 @@ public class KeyspaceCreatingJavaConfigIntegrationTests extends AbstractKeyspace protected List getKeyspaceCreations() { ArrayList list = new ArrayList<>(); - CreateKeyspaceSpecification specification = CreateKeyspaceSpecification.createKeyspace().name(getKeyspaceName()); + CreateKeyspaceSpecification specification = CreateKeyspaceSpecification.createKeyspace(getKeyspaceName()); specification.with(KeyspaceOption.REPLICATION, KeyspaceAttributes.newSimpleReplication(1L)); list.add(specification); diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/InsertOptionsUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/InsertOptionsUnitTests.java index 736909e85..fb06f5b36 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/InsertOptionsUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/InsertOptionsUnitTests.java @@ -17,6 +17,8 @@ package org.springframework.data.cassandra.core; import static org.assertj.core.api.Assertions.*; +import java.time.Duration; + import org.junit.Test; /** @@ -34,7 +36,7 @@ public class InsertOptionsUnitTests { .withIfNotExists() // .build(); - assertThat(insertOptions.getTtl()).isEqualTo(10); + assertThat(insertOptions.getTtl()).isEqualTo(Duration.ofSeconds(10)); assertThat(insertOptions.isIfNotExists()).isTrue(); } } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/UpdateOptionsUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/UpdateOptionsUnitTests.java index 0f99ca4ed..9a0a9a1d1 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/UpdateOptionsUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/UpdateOptionsUnitTests.java @@ -15,7 +15,9 @@ */ package org.springframework.data.cassandra.core; -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.*; + +import java.time.Duration; import org.junit.Test; @@ -34,7 +36,7 @@ public class UpdateOptionsUnitTests { .withIfExists() // .build(); - assertThat(updateOptions.getTtl()).isEqualTo(10); + assertThat(updateOptions.getTtl()).isEqualTo(Duration.ofSeconds(10)); assertThat(updateOptions.isIfExists()).isTrue(); } } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/convert/ColumnReaderUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/convert/ColumnReaderUnitTests.java index f39138132..8b04eaf4e 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/convert/ColumnReaderUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/convert/ColumnReaderUnitTests.java @@ -53,7 +53,7 @@ public class ColumnReaderUnitTests { } @Test - public void throwsIllegalArgumentExceptionIfColumnDoesNotExistByName() throws Exception { + public void throwsIllegalArgumentExceptionIfColumnDoesNotExistByName() { when(columnDefinitions.getIndexOf(NON_EXISTENT_COLUMN)).thenReturn(-1); @@ -66,12 +66,12 @@ public class ColumnReaderUnitTests { } @Test - public void throwsIllegalArgumentExceptionIfColumnDoesNotExistByCqlIdentifier() throws Exception { + public void throwsIllegalArgumentExceptionIfColumnDoesNotExistByCqlIdentifier() { when(columnDefinitions.getIndexOf(NON_EXISTENT_COLUMN)).thenReturn(-1); try { - underTest.get(new CqlIdentifier(NON_EXISTENT_COLUMN)); + underTest.get(CqlIdentifier.cqlId(NON_EXISTENT_COLUMN)); fail("Expected illegal argument exception"); } catch (IllegalArgumentException e) { assertThat(e.getMessage()).isEqualTo("Column does not exist in Cassandra table: " + NON_EXISTENT_COLUMN); @@ -79,12 +79,12 @@ public class ColumnReaderUnitTests { } @Test - public void throwsIllegalArgumentExceptionIfColumnDoesNotExistByCqlIdentifierAndType() throws Exception { + public void throwsIllegalArgumentExceptionIfColumnDoesNotExistByCqlIdentifierAndType() { when(columnDefinitions.getIndexOf(NON_EXISTENT_COLUMN)).thenReturn(-1); try { - underTest.get(new CqlIdentifier(NON_EXISTENT_COLUMN), String.class); + underTest.get(CqlIdentifier.cqlId(NON_EXISTENT_COLUMN), String.class); fail("Expected illegal argument exception"); } catch (IllegalArgumentException e) { assertThat(e.getMessage()).isEqualTo("Column does not exist in Cassandra table: " + NON_EXISTENT_COLUMN); diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/CassandraAccessorUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/CassandraAccessorUnitTests.java index fe1db4b74..e3495b3d6 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/CassandraAccessorUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/CassandraAccessorUnitTests.java @@ -39,10 +39,9 @@ public class CassandraAccessorUnitTests { private CassandraAccessor cassandraAccessor; - @Mock private CassandraExceptionTranslator mockExceptionTranslator; - @Rule public ExpectedException exception = ExpectedException.none(); + @Mock private CassandraExceptionTranslator mockExceptionTranslator; @Mock private Session mockSession; @Before @@ -79,11 +78,6 @@ public class CassandraAccessorUnitTests { } } - @Test // DATACASS-286 - public void getUninitializedExceptionTranslatorReturnsDefault() { - assertThat(cassandraAccessor.getExceptionTranslator()).isEqualTo(cassandraAccessor.exceptionTranslator); - } - @Test // DATACASS-286 public void setAndGetSession() { diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/QueryOptionsUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/QueryOptionsUnitTests.java index 9f9730c00..6da5bf81d 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/QueryOptionsUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/QueryOptionsUnitTests.java @@ -17,6 +17,7 @@ package org.springframework.data.cassandra.core.cql; import static org.assertj.core.api.Assertions.*; +import java.time.Duration; import java.util.concurrent.TimeUnit; import org.junit.Test; @@ -48,7 +49,7 @@ public class QueryOptionsUnitTests { assertThat(queryOptions.getClass()).isEqualTo(QueryOptions.class); assertThat(queryOptions.getRetryPolicy()).isEqualTo(FallthroughRetryPolicy.INSTANCE); assertThat(queryOptions.getConsistencyLevel()).isEqualTo(ConsistencyLevel.ANY); - assertThat(queryOptions.getReadTimeout()).isEqualTo(1000); + assertThat(queryOptions.getReadTimeout()).isEqualTo(Duration.ofSeconds(1)); assertThat(queryOptions.getFetchSize()).isEqualTo(10); assertThat(queryOptions.getTracing()).isTrue(); } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/QueryOptionsUtilUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/QueryOptionsUtilUnitTests.java index 145ab4ac7..b2ea6f19a 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/QueryOptionsUtilUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/QueryOptionsUtilUnitTests.java @@ -71,9 +71,8 @@ public class QueryOptionsUtilUnitTests { @Test // DATACASS-202 public void addPreparedStatementOptionsShouldAddOurQueryOptions() { - QueryOptions queryOptions = QueryOptions.builder().retryPolicy(FallthroughRetryPolicy.INSTANCE).build(); - - queryOptions.setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM); + QueryOptions queryOptions = QueryOptions.builder().retryPolicy(FallthroughRetryPolicy.INSTANCE) + .consistencyLevel(ConsistencyLevel.LOCAL_QUORUM).build(); QueryOptionsUtil.addPreparedStatementOptions(mockPreparedStatement, queryOptions); @@ -97,9 +96,8 @@ public class QueryOptionsUtilUnitTests { @Test // DATACASS-202 public void addStatementQueryOptionsShouldAddOurQueryOptions() { - QueryOptions queryOptions = QueryOptions.builder().retryPolicy(FallthroughRetryPolicy.INSTANCE).build(); - - queryOptions.setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM); + QueryOptions queryOptions = QueryOptions.builder().retryPolicy(FallthroughRetryPolicy.INSTANCE) + .consistencyLevel(ConsistencyLevel.LOCAL_QUORUM).build(); QueryOptionsUtil.addQueryOptions(mockStatement, queryOptions); diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/WriteOptionsUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/WriteOptionsUnitTests.java index a0d1c0555..aaaa5d789 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/WriteOptionsUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/WriteOptionsUnitTests.java @@ -17,6 +17,7 @@ package org.springframework.data.cassandra.core.cql; import static org.assertj.core.api.Assertions.*; +import java.time.Duration; import java.util.concurrent.TimeUnit; import org.junit.Test; @@ -43,10 +44,10 @@ public class WriteOptionsUnitTests { .withTracing()// .build(); // - assertThat(writeOptions.getTtl()).isEqualTo(123); + assertThat(writeOptions.getTtl()).isEqualTo(Duration.ofSeconds(123)); assertThat(writeOptions.getRetryPolicy()).isEqualTo(FallthroughRetryPolicy.INSTANCE); assertThat(writeOptions.getConsistencyLevel()).isEqualTo(ConsistencyLevel.ANY); - assertThat(writeOptions.getReadTimeout()).isEqualTo(1); + assertThat(writeOptions.getReadTimeout()).isEqualTo(Duration.ofMillis(1)); assertThat(writeOptions.getFetchSize()).isEqualTo(10); assertThat(writeOptions.getTracing()).isTrue(); } @@ -56,7 +57,7 @@ public class WriteOptionsUnitTests { WriteOptions writeOptions = WriteOptions.builder().readTimeout(1, TimeUnit.MINUTES).build(); - assertThat(writeOptions.getReadTimeout()).isEqualTo(60L * 1000L); + assertThat(writeOptions.getReadTimeout()).isEqualTo(Duration.ofSeconds(60)); assertThat(writeOptions.getFetchSize()).isNull(); assertThat(writeOptions.getTracing()).isNull(); } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/AbstractTableOperationCqlGeneratorTest.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/AbstractTableOperationCqlGeneratorTest.java index c6e98cf74..9645df816 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/AbstractTableOperationCqlGeneratorTest.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/AbstractTableOperationCqlGeneratorTest.java @@ -26,7 +26,7 @@ import org.springframework.data.cassandra.core.cql.keyspace.TableNameSpecificati * @param The type of the {@link TableNameSpecification} * @param The type of the {@link TableNameCqlGenerator} */ -public abstract class AbstractTableOperationCqlGeneratorTest, G extends TableNameCqlGenerator> { +public abstract class AbstractTableOperationCqlGeneratorTest> { public abstract S specification(); diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/AlterKeyspaceCqlGeneratorUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/AlterKeyspaceCqlGeneratorUnitTests.java index 46503f8a3..9a67c4415 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/AlterKeyspaceCqlGeneratorUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/AlterKeyspaceCqlGeneratorUnitTests.java @@ -74,7 +74,7 @@ public class AlterKeyspaceCqlGeneratorUnitTests { replicationMap.put(new DefaultOption("dc1", Long.class, false, false, true), 2); replicationMap.put(new DefaultOption("dc2", Long.class, false, false, true), 3); - return AlterKeyspaceSpecification.alterKeyspace().name(name).with(KeyspaceOption.REPLICATION, replicationMap) + return AlterKeyspaceSpecification.alterKeyspace(name).with(KeyspaceOption.REPLICATION, replicationMap) .with(KeyspaceOption.DURABLE_WRITES, durableWrites); } @@ -107,7 +107,7 @@ public class AlterKeyspaceCqlGeneratorUnitTests { replicationMap.put(new DefaultOption("dc1", Long.class, false, false, true), 2); replicationMap.put(new DefaultOption("dc2", Long.class, false, false, true), 3); - return AlterKeyspaceSpecification.alterKeyspace().name(name).with(KeyspaceOption.REPLICATION, replicationMap); + return AlterKeyspaceSpecification.alterKeyspace(name).with(KeyspaceOption.REPLICATION, replicationMap); } @Override diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/AlterUserTypeCqlGeneratorIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/AlterUserTypeCqlGeneratorIntegrationTests.java index 507c03c3d..fcb054628 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/AlterUserTypeCqlGeneratorIntegrationTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/AlterUserTypeCqlGeneratorIntegrationTests.java @@ -88,11 +88,11 @@ public class AlterUserTypeCqlGeneratorIntegrationTests extends AbstractKeyspaceC @Test(expected = IllegalArgumentException.class) // DATACASS-172 public void generationFailsIfNameIsNotSet() { - toCql(AlterUserTypeSpecification.alterType()); + toCql(AlterUserTypeSpecification.alterType(null)); } @Test(expected = IllegalArgumentException.class) // DATACASS-172 public void generationFailsWithoutFields() { - toCql(AlterUserTypeSpecification.alterType().name("hello")); + toCql(AlterUserTypeSpecification.alterType("hello")); } } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/AlterUserTypeCqlGeneratorUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/AlterUserTypeCqlGeneratorUnitTests.java index c97053fe4..dba1013ee 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/AlterUserTypeCqlGeneratorUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/AlterUserTypeCqlGeneratorUnitTests.java @@ -67,13 +67,9 @@ public class AlterUserTypeCqlGeneratorUnitTests { assertThat(toCql(spec)).isEqualTo("ALTER TYPE address RENAME zip TO zap AND city TO county;"); } - @Test(expected = IllegalArgumentException.class) // DATACASS-172 - public void generationFailsIfNameIsNotSet() { - toCql(AlterUserTypeSpecification.alterType()); - } @Test(expected = IllegalArgumentException.class) // DATACASS-172 public void generationFailsWithoutFields() { - toCql(AlterUserTypeSpecification.alterType().name("hello")); + toCql(AlterUserTypeSpecification.alterType("hello")); } } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/CreateKeyspaceCqlGeneratorUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/CreateKeyspaceCqlGeneratorUnitTests.java index 9ce4b4bad..5dc6f83fa 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/CreateKeyspaceCqlGeneratorUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/CreateKeyspaceCqlGeneratorUnitTests.java @@ -81,7 +81,7 @@ public class CreateKeyspaceCqlGeneratorUnitTests { public CreateKeyspaceSpecification specification() { keyspace = name; - return CreateKeyspaceSpecification.createKeyspace().name(keyspace) + return CreateKeyspaceSpecification.createKeyspace(keyspace) .with(KeyspaceOption.REPLICATION, replicationMap).with(KeyspaceOption.DURABLE_WRITES, durableWrites); } @@ -106,7 +106,7 @@ public class CreateKeyspaceCqlGeneratorUnitTests { public CreateKeyspaceSpecification specification() { keyspace = name; - return CreateKeyspaceSpecification.createKeyspace().name(keyspace); + return CreateKeyspaceSpecification.createKeyspace(keyspace); } @Test @@ -134,7 +134,7 @@ public class CreateKeyspaceCqlGeneratorUnitTests { replicationMap.put(new DefaultOption("dc1", Long.class, false, false, true), 2); replicationMap.put(new DefaultOption("dc2", Long.class, false, false, true), 3); - return CreateKeyspaceSpecification.createKeyspace().name(keyspace) + return CreateKeyspaceSpecification.createKeyspace(keyspace) .with(KeyspaceOption.REPLICATION, replicationMap).with(KeyspaceOption.DURABLE_WRITES, durableWrites); } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/CreateTableCqlGeneratorUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/CreateTableCqlGeneratorUnitTests.java index e085471f0..4e19635d0 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/CreateTableCqlGeneratorUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/CreateTableCqlGeneratorUnitTests.java @@ -128,7 +128,7 @@ public class CreateTableCqlGeneratorUnitTests { @Override public CreateTableSpecification specification() { - return CreateTableSpecification.createTable().name(name).partitionKeyColumn(partitionKey0, partitionKeyType0) + return CreateTableSpecification.createTable(name).partitionKeyColumn(partitionKey0, partitionKeyType0) .column(column1, columnType1); } @@ -154,7 +154,7 @@ public class CreateTableCqlGeneratorUnitTests { @Override public CreateTableSpecification specification() { - return CreateTableSpecification.createTable().name(name).partitionKeyColumn(partKey0, partKeyType0) + return CreateTableSpecification.createTable(name).partitionKeyColumn(partKey0, partKeyType0) .partitionKeyColumn(partKey1, partKeyType1).column(column0, columnType0); } @@ -188,7 +188,7 @@ public class CreateTableCqlGeneratorUnitTests { @Override public CreateTableSpecification specification() { - return CreateTableSpecification.createTable().name(name).partitionKeyColumn(partitionKey0, partitionKeyType0) + return CreateTableSpecification.createTable(name).partitionKeyColumn(partitionKey0, partitionKeyType0) .partitionKeyColumn(partitionKey1, partitionKeyType1).column(column1, columnType1) .with(TableOption.READ_REPAIR_CHANCE, readRepairChance); } @@ -243,7 +243,7 @@ public class CreateTableCqlGeneratorUnitTests { cachingMap.put(CachingOption.KEYS, KeyCachingOption.ALL); cachingMap.put(CachingOption.ROWS_PER_PARTITION, "NONE"); - return CreateTableSpecification.createTable().name(name).partitionKeyColumn(partitionKey0, partitionKeyType0) + return CreateTableSpecification.createTable(name).partitionKeyColumn(partitionKey0, partitionKeyType0) .partitionKeyColumn(partitionKey1, partitionKeyType1).column(column1, columnType1) .with(TableOption.COMPACT_STORAGE).with(TableOption.READ_REPAIR_CHANCE, readRepairChance) .with(TableOption.COMPACTION, compactionMap).with(TableOption.COMPRESSION, compressionMap) @@ -306,7 +306,7 @@ public class CreateTableCqlGeneratorUnitTests { @Override public CreateTableSpecification specification() { - return CreateTableSpecification.createTable().name(tableName).partitionKeyColumn(cqlId("pk"), DataType.text()); + return CreateTableSpecification.createTable(tableName).partitionKeyColumn(cqlId("pk"), DataType.text()); } /** diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/CreateUserTypeCqlGeneratorIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/CreateUserTypeCqlGeneratorIntegrationTests.java index 5c438de37..9a054365a 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/CreateUserTypeCqlGeneratorIntegrationTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/CreateUserTypeCqlGeneratorIntegrationTests.java @@ -60,8 +60,7 @@ public class CreateUserTypeCqlGeneratorIntegrationTests extends AbstractKeyspace public void createUserTypeIfNotExists() { CreateUserTypeSpecification spec = CreateUserTypeSpecification // - .createType() // - .name("address").ifNotExists().field("zip", DataType.ascii()) // + .createType("address").ifNotExists().field("zip", DataType.ascii()) // .field("city", DataType.varchar()); session.execute(toCql(spec)); @@ -75,8 +74,7 @@ public class CreateUserTypeCqlGeneratorIntegrationTests extends AbstractKeyspace public void createNestedUserType() { CreateUserTypeSpecification addressSpec = CreateUserTypeSpecification // - .createType() // - .name("address").ifNotExists().field("zip", DataType.ascii()) // + .createType("address").ifNotExists().field("zip", DataType.ascii()) // .field("city", DataType.varchar()); session.execute(toCql(addressSpec)); @@ -85,8 +83,7 @@ public class CreateUserTypeCqlGeneratorIntegrationTests extends AbstractKeyspace UserType address = keyspace.getUserType("address"); CreateUserTypeSpecification personSpec = CreateUserTypeSpecification // - .createType() // - .name("person").ifNotExists().field("address", address.copy(true)) // + .createType("person").ifNotExists().field("address", address.copy(true)) // .field("city", DataType.varchar()); session.execute(toCql(personSpec)); diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/CreateUserTypeCqlGeneratorUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/CreateUserTypeCqlGeneratorUnitTests.java index 54284b628..8e98387ae 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/CreateUserTypeCqlGeneratorUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/CreateUserTypeCqlGeneratorUnitTests.java @@ -55,20 +55,14 @@ public class CreateUserTypeCqlGeneratorUnitTests { public void createUserTypeIfNotExists() { CreateUserTypeSpecification spec = CreateUserTypeSpecification // - .createType() // - .name("address").ifNotExists().field("zip", DataType.ascii()) // + .createType("address").ifNotExists().field("zip", DataType.ascii()) // .field("city", DataType.varchar()); assertThat(toCql(spec)).isEqualTo("CREATE TYPE IF NOT EXISTS address (zip ascii, city varchar);"); } - @Test(expected = IllegalArgumentException.class) // DATACASS-172 - public void generationFailsIfNameIsNotSet() { - toCql(CreateUserTypeSpecification.createType()); - } - @Test(expected = IllegalArgumentException.class) // DATACASS-172 public void generationFailsWithoutFields() { - toCql(CreateUserTypeSpecification.createType().name("hello")); + toCql(CreateUserTypeSpecification.createType("hello")); } } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/DropIndexCqlGeneratorUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/DropIndexCqlGeneratorUnitTests.java index 6a211d028..491b9fdb6 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/DropIndexCqlGeneratorUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/DropIndexCqlGeneratorUnitTests.java @@ -46,7 +46,7 @@ public class DropIndexCqlGeneratorUnitTests { public String name = "myindex"; public DropIndexSpecification specification() { - return DropIndexSpecification.dropIndex().name(name); + return DropIndexSpecification.dropIndex(name); } public DropIndexCqlGenerator generator() { @@ -67,7 +67,7 @@ public class DropIndexCqlGeneratorUnitTests { public String name = "myindex"; public DropIndexSpecification specification() { - return DropIndexSpecification.dropIndex().name(name) + return DropIndexSpecification.dropIndex(name) // .ifExists() ; } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/DropKeyspaceCqlGeneratorUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/DropKeyspaceCqlGeneratorUnitTests.java index b95e720ca..bc0a3be84 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/DropKeyspaceCqlGeneratorUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/DropKeyspaceCqlGeneratorUnitTests.java @@ -49,7 +49,7 @@ public class DropKeyspaceCqlGeneratorUnitTests { @Override public DropKeyspaceSpecification specification() { - return DropKeyspaceSpecification.dropKeyspace().name(name); + return DropKeyspaceSpecification.dropKeyspace(name); } @Override diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/DropTableCqlGeneratorUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/DropTableCqlGeneratorUnitTests.java index 2bcd54b48..6dcbd536c 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/DropTableCqlGeneratorUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/DropTableCqlGeneratorUnitTests.java @@ -46,7 +46,7 @@ public class DropTableCqlGeneratorUnitTests { public String name = "mytable"; public DropTableSpecification specification() { - return DropTableSpecification.dropTable().name(name); + return DropTableSpecification.dropTable(name); } public DropTableCqlGenerator generator() { diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/TableLifecycleIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/TableLifecycleIntegrationTests.java index 54bc61d68..3d9b26577 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/TableLifecycleIntegrationTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/generator/TableLifecycleIntegrationTests.java @@ -65,7 +65,7 @@ public class TableLifecycleIntegrationTests extends AbstractKeyspaceCreatingInte @Override public DropTableSpecification specification() { - return DropTableSpecification.dropTable().name(createTableTest.specification.getName()); + return DropTableSpecification.dropTable(createTableTest.specification.getName()); } @Override diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/keyspace/OptionUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/keyspace/OptionUnitTests.java index 2fb605191..690f076a0 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/keyspace/OptionUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/keyspace/OptionUnitTests.java @@ -41,19 +41,19 @@ public class OptionUnitTests { @Test public void testOptionWithNullType() { - new DefaultOption("opt", null, true, true, true); - new DefaultOption("opt", null, false, true, true); + new DefaultOption("opt", Void.class, true, true, true); + new DefaultOption("opt", Void.class, false, true, true); } @Test public void testOptionWithNullTypeIsCoerceable() { - Option op = new DefaultOption("opt", null, true, true, true); + Option op = new DefaultOption("opt", Void.class, true, true, true); assertThat(op.isCoerceable("")).isTrue(); - assertThat(op.isCoerceable(null)).isTrue(); } @Test public void testOptionValueCoercion() { + String name = "my_option"; Class type = String.class; boolean requires = true; @@ -77,7 +77,6 @@ public class OptionUnitTests { assertThat(op.toString(value)).isEqualTo(expected); } assertThat(op.isCoerceable("x")).isFalse(); - assertThat(op.isCoerceable(null)).isTrue(); type = Long.class; escapes = false; @@ -90,28 +89,25 @@ public class OptionUnitTests { assertThat(op.toString(value)).isEqualTo(expected); } assertThat(op.isCoerceable("x")).isFalse(); - assertThat(op.isCoerceable(null)).isTrue(); type = Double.class; escapes = false; quotes = false; op = new DefaultOption(name, type, requires, escapes, quotes); - String[] expecteds = new String[] { "1", "1.0", "1.0", "1", "1.0", null }; - Object[] values = new Object[] { 1, 1.0F, 1.0D, "1", "1.0", null }; + String[] expecteds = new String[] { "1", "1.0", "1.0", "1", "1.0" }; + Object[] values = new Object[] { 1, 1.0F, 1.0D, "1", "1.0" }; for (int i = 0; i < values.length; i++) { assertThat(op.isCoerceable(values[i])).isTrue(); assertThat(op.toString(values[i])).isEqualTo(expecteds[i]); } assertThat(op.isCoerceable("x")).isFalse(); - assertThat(op.isCoerceable(null)).isTrue(); type = RetentionPolicy.class; escapes = false; quotes = false; op = new DefaultOption(name, type, requires, escapes, quotes); - assertThat(op.isCoerceable(null)).isTrue(); assertThat(op.isCoerceable(RetentionPolicy.CLASS)).isTrue(); assertThat(op.isCoerceable("CLASS")).isTrue(); assertThat(op.isCoerceable("x")).isFalse(); diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/QueryDerivationIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/QueryDerivationIntegrationTests.java index e9cc7a174..5da36b8e8 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/QueryDerivationIntegrationTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/QueryDerivationIntegrationTests.java @@ -15,8 +15,8 @@ */ package org.springframework.data.cassandra.repository; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assume.assumeTrue; +import static org.assertj.core.api.Assertions.*; +import static org.junit.Assume.*; import java.time.LocalDate; import java.util.Arrays; @@ -25,10 +25,10 @@ import java.util.Collections; import java.util.List; import java.util.Set; +import org.assertj.core.api.Assertions; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.context.annotation.Configuration; @@ -51,8 +51,6 @@ import org.springframework.data.util.Version; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.assertj.core.api.Assertions; - import com.datastax.driver.core.Session; /** @@ -121,7 +119,7 @@ public class QueryDerivationIntegrationTests extends AbstractSpringDataEmbeddedC @Test // DATACASS-7 public void shouldFindByLastnameAndDynamicSort() { - List result = personRepository.findByLastname("White", new Sort("firstname")); + List result = personRepository.findByLastname("White", Sort.by("firstname")); assertThat(result).contains(flynn, skyler, walter); } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/cdi/CassandraOperationsProducer.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/cdi/CassandraOperationsProducer.java index bd78e1a06..483afffc9 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/cdi/CassandraOperationsProducer.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/cdi/CassandraOperationsProducer.java @@ -72,7 +72,7 @@ class CassandraOperationsProducer { CassandraAdminTemplate cassandraTemplate = new CassandraAdminTemplate(cluster.connect(), cassandraConverter); - CreateKeyspaceSpecification createKeyspaceSpecification = new CreateKeyspaceSpecification(KEYSPACE_NAME) + CreateKeyspaceSpecification createKeyspaceSpecification = CreateKeyspaceSpecification.createKeyspace(KEYSPACE_NAME) .ifNotExists(); cassandraTemplate.getCqlOperations().execute(CreateKeyspaceCqlGenerator.toCql(createKeyspaceSpecification)); cassandraTemplate.getCqlOperations().execute("USE " + KEYSPACE_NAME); diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/conversion/ParameterConversionTestSupport.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/conversion/ParameterConversionTestSupport.java index 0d6f16f5b..8f24e241b 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/conversion/ParameterConversionTestSupport.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/conversion/ParameterConversionTestSupport.java @@ -65,7 +65,7 @@ abstract class ParameterConversionTestSupport extends AbstractSpringDataEmbedded } @Override - public CassandraSessionFactoryBean session() throws ClassNotFoundException { + public CassandraSessionFactoryBean session() { Cluster cluster = cluster().getObject(); Session session = cluster.connect(getKeyspaceName()); diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/forcequote/compositeprimarykey/CompositeKeyCrudIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/forcequote/compositeprimarykey/CompositeKeyCrudIntegrationTests.java index c6e7fa8a1..0314bbf18 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/forcequote/compositeprimarykey/CompositeKeyCrudIntegrationTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/forcequote/compositeprimarykey/CompositeKeyCrudIntegrationTests.java @@ -78,8 +78,7 @@ public class CompositeKeyCrudIntegrationTests extends AbstractKeyspaceCreatingIn assertThat(correlationEntities).hasSize(2); - QueryOptions queryOptions = new QueryOptions(); - queryOptions.setConsistencyLevel(ConsistencyLevel.ONE); + QueryOptions queryOptions = QueryOptions.builder().consistencyLevel(ConsistencyLevel.ONE).build(); operations.delete(correlationEntity1, queryOptions); operations.delete(correlationEntity2, queryOptions); diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/ConvertingParameterAccessorUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/ConvertingParameterAccessorUnitTests.java index 8cff5135e..3ef469d6f 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/ConvertingParameterAccessorUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/ConvertingParameterAccessorUnitTests.java @@ -118,16 +118,6 @@ public class ConvertingParameterAccessorUnitTests { assertThat(list.get(0)).isInstanceOf(com.datastax.driver.core.LocalDate.class); } - @Test // DATACASS-7 - @SuppressWarnings({ "rawtypes", "unchecked" }) - public void shouldProvideTypeBasedOnValue() { - - when(mockParameterAccessor.getDataType(0)).thenReturn(null); - when(mockParameterAccessor.getParameterType(0)).thenReturn((Class) LocalDate.class); - - assertThat(convertingParameterAccessor.getDataType(0)).isEqualTo(DataType.date()); - } - @Test // DATACASS-7 @SuppressWarnings({ "rawtypes", "unchecked" }) public void shouldProvideTypeBasedOnPropertyType() { diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/IntegrationTestConfig.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/IntegrationTestConfig.java index 09a88c3ff..109d85545 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/IntegrationTestConfig.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/IntegrationTestConfig.java @@ -77,11 +77,11 @@ public class IntegrationTestConfig extends AbstractReactiveCassandraConfiguratio @Override protected List getKeyspaceCreations() { - return Collections.singletonList(createKeyspace().name(getKeyspaceName()).withSimpleReplication()); + return Collections.singletonList(createKeyspace(getKeyspaceName()).withSimpleReplication()); } @Override protected List getKeyspaceDrops() { - return Collections.singletonList(DropKeyspaceSpecification.dropKeyspace().name(getKeyspaceName())); + return Collections.singletonList(DropKeyspaceSpecification.dropKeyspace(getKeyspaceName())); } }