From 5dc484e9d19fe228726caf7485e02433acfd1a03 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 8 Jan 2025 10:41:27 +0100 Subject: [PATCH] Remove `ListenableFuture` support. Closes #1548 --- .../cassandra/core/cql/AsyncResultStream.java | 7 +- .../core/cql/legacy/AsyncCqlOperations.java | 743 ------------ .../core/cql/legacy/AsyncCqlTemplate.java | 701 ----------- .../legacy/AsyncPreparedStatementCreator.java | 65 -- .../cql/legacy/AsyncResultSetExtractor.java | 64 - .../core/cql/legacy/AsyncResultStream.java | 238 ---- .../AsyncRowMapperResultSetExtractor.java | 69 -- .../core/cql/legacy/AsyncSessionCallback.java | 62 - ...ionTranslatingListenableFutureAdapter.java | 129 -- .../core/cql/legacy/package-info.java | 7 - .../core/cql/util/CassandraFutureAdapter.java | 126 -- .../core/legacy/AsyncCassandraOperations.java | 394 ------- .../core/legacy/AsyncCassandraTemplate.java | 1033 ----------------- .../legacy/EntityLifecycleEventDelegate.java | 64 - .../core/legacy/EntityOperations.java | 360 ------ .../core/legacy/EntityQueryUtils.java | 184 --- .../core/legacy/EntityWriteResult.java | 38 - .../legacy/PreparedStatementDelegate.java | 291 ----- .../cassandra/core/legacy/WriteResult.java | 30 - .../cassandra/core/legacy/package-info.java | 7 - ...efaultBridgedReactiveSessionUnitTests.java | 10 +- .../AsyncCqlTemplateIntegrationTests.java | 185 --- .../cql/legacy/AsyncCqlTemplateUnitTests.java | 865 -------------- .../legacy/AsyncResultStreamUnitTests.java | 142 --- ...syncCassandraTemplateIntegrationTests.java | 380 ------ .../AsyncCassandraTemplateUnitTests.java | 605 ---------- .../ROOT/pages/cassandra/cql-template.adoc | 2 +- .../ROOT/pages/cassandra/template.adoc | 2 +- 28 files changed, 9 insertions(+), 6794 deletions(-) delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncCqlOperations.java delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncCqlTemplate.java delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncPreparedStatementCreator.java delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncResultSetExtractor.java delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncResultStream.java delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncRowMapperResultSetExtractor.java delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncSessionCallback.java delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/ExceptionTranslatingListenableFutureAdapter.java delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/package-info.java delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/util/CassandraFutureAdapter.java delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/legacy/AsyncCassandraOperations.java delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/legacy/AsyncCassandraTemplate.java delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/legacy/EntityLifecycleEventDelegate.java delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/legacy/EntityOperations.java delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/legacy/EntityQueryUtils.java delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/legacy/EntityWriteResult.java delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/legacy/PreparedStatementDelegate.java delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/legacy/WriteResult.java delete mode 100644 spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/legacy/package-info.java delete mode 100644 spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/legacy/AsyncCqlTemplateIntegrationTests.java delete mode 100644 spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/legacy/AsyncCqlTemplateUnitTests.java delete mode 100644 spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/legacy/AsyncResultStreamUnitTests.java delete mode 100644 spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/legacy/AsyncCassandraTemplateIntegrationTests.java delete mode 100644 spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/legacy/AsyncCassandraTemplateUnitTests.java diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/AsyncResultStream.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/AsyncResultStream.java index 5866ddef9..418d37c99 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/AsyncResultStream.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/AsyncResultStream.java @@ -22,7 +22,6 @@ import java.util.stream.Collector; import org.springframework.util.Assert; -import org.springframework.util.concurrent.ListenableFuture; import com.datastax.oss.driver.api.core.cql.AsyncResultSet; import com.datastax.oss.driver.api.core.cql.Row; @@ -75,7 +74,7 @@ AsyncResultStream map(RowMapper mapper) { /** * Performs a mutable reduction operation on the elements of this stream using a {@link Collector} resulting in a - * {@link ListenableFuture}. + * {@link CompletableFuture}. *

* This is a terminal operation. * @@ -97,7 +96,7 @@ CompletableFuture collect(Collector collector) { } /** - * Performs an action for each element of this stream. This method returns a {@link ListenableFuture} that completes + * Performs an action for each element of this stream. This method returns a {@link CompletableFuture} that completes * without a value ({@code null}) once all elements have been processed. *

* This is a terminal operation. @@ -177,7 +176,7 @@ void forEachAsync(CompletableFuture target, AsyncResultSet resultSet) { class CollectState { private final AtomicInteger rowNumber = new AtomicInteger(); - private volatile A intermediate; + private final A intermediate; private final Collector collector; CollectState(Collector collector) { diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncCqlOperations.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncCqlOperations.java deleted file mode 100644 index 578cd7149..000000000 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncCqlOperations.java +++ /dev/null @@ -1,743 +0,0 @@ -/* - * Copyright 2016-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.cassandra.core.cql.legacy; - -import java.util.List; -import java.util.Map; - -import org.springframework.dao.DataAccessException; -import org.springframework.dao.IncorrectResultSizeDataAccessException; -import org.springframework.data.cassandra.core.cql.ColumnMapRowMapper; -import org.springframework.data.cassandra.core.cql.CqlOperations; -import org.springframework.data.cassandra.core.cql.CqlTemplate; -import org.springframework.data.cassandra.core.cql.PreparedStatementBinder; -import org.springframework.data.cassandra.core.cql.PreparedStatementCallback; -import org.springframework.data.cassandra.core.cql.RowCallbackHandler; -import org.springframework.data.cassandra.core.cql.RowMapper; -import org.springframework.data.cassandra.core.cql.SingleColumnRowMapper; -import org.springframework.lang.Nullable; -import org.springframework.util.concurrent.ListenableFuture; - -import com.datastax.oss.driver.api.core.cql.AsyncResultSet; -import com.datastax.oss.driver.api.core.cql.PreparedStatement; -import com.datastax.oss.driver.api.core.cql.ResultSet; -import com.datastax.oss.driver.api.core.cql.Statement; - -/** - * Interface specifying a basic set of CQL asynchronously executed operations. Exposes similar methods as - * {@link CqlTemplate}, but returns result handles or accepts callbacks as opposed to concrete results. Implemented by - * {@link AsyncCqlTemplate}. Not often used directly, but a useful option to enhance testability, as it can easily be - * mocked or stubbed. - * - * @author Mark Paluch - * @author John Blum - * @since 4.0 - * @see AsyncCqlTemplate - * @see CqlOperations - * @deprecated since 4.0, use the {@link java.util.concurrent.CompletableFuture}-based variant - * {@link org.springframework.data.cassandra.core.cql.AsyncCqlOperations}. - */ -@Deprecated(since = "4.0", forRemoval = true) -@SuppressWarnings("removal") -public interface AsyncCqlOperations { - - // ------------------------------------------------------------------------- - // Methods dealing with a plain com.datastax.oss.driver.api.core.CqlSession - // ------------------------------------------------------------------------- - - /** - * Execute a CQL data access operation, implemented as callback action working on a - * {@link com.datastax.oss.driver.api.core.CqlSession}. This allows for implementing arbitrary data access operations, - * within Spring's managed CQL environment: that is, converting CQL - * {@link com.datastax.oss.driver.api.core.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. - * - * @param action the callback object that specifies the action. - * @return a result object returned by the action, or {@literal null}. - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture execute(AsyncSessionCallback action) throws DataAccessException; - - // ------------------------------------------------------------------------- - // Methods dealing with static CQL - // ------------------------------------------------------------------------- - - /** - * Issue a single CQL execute, typically a DDL statement, insert, update or delete statement. - * - * @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. - */ - ListenableFuture execute(String cql) throws DataAccessException; - - /** - * 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 {@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. - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture execute(String cql, Object... args) throws DataAccessException; - - /** - * Issue an statement using a {@link PreparedStatementBinder} to set bind parameters, with given CQL. Simpler than - * 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 {@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 executing the query. - */ - ListenableFuture execute(String cql, @Nullable PreparedStatementBinder psb) throws DataAccessException; - - /** - * Execute a CQL data access operation, implemented as callback action working on a CQL {@link PreparedStatement}. - * This allows for implementing arbitrary data access operations on a single Statement, within Spring's managed CQL - * environment: that is, participating in Spring-managed transactions and converting CQL - * {@link com.datastax.oss.driver.api.core.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. - * - * @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 executing the query. - */ - ListenableFuture execute(String cql, PreparedStatementCallback action) throws DataAccessException; - - /** - * Execute a query given static CQL, reading the {@link ResultSet} with a {@link AsyncResultSetExtractor}. - *

- * 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 {@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 AsyncResultSetExtractor. - * @throws DataAccessException if there is any problem executing the query. - * @see #query(String, AsyncResultSetExtractor, Object...) - */ - ListenableFuture query(String cql, AsyncResultSetExtractor resultSetExtractor) throws DataAccessException; - - /** - * Execute a query given static CQL, reading the {@link ResultSet} on a per-row basis with a - * {@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 {@literal null} as argument array. - * - * @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[]) - */ - ListenableFuture query(String cql, RowCallbackHandler rowCallbackHandler) throws DataAccessException; - - /** - * Execute a query given static CQL, mapping each row to a Java object via a {@link RowMapper}. - *

- * 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 {@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. - * @see #query(String, RowMapper, Object[]) - */ - ListenableFuture> query(String cql, RowMapper rowMapper) throws DataAccessException; - - /** - * 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 AsyncResultSetExtractor}. - * - * @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). - * @return an arbitrary result object, as returned by the {@link AsyncResultSetExtractor} - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture query(String cql, AsyncResultSetExtractor resultSetExtractor, Object... args) - throws DataAccessException; - - /** - * 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 {@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) - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture query(String cql, RowCallbackHandler rowCallbackHandler, Object... args) - throws DataAccessException; - - /** - * 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 {@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) - * @return the result {@link List}, containing mapped objects - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture> query(String cql, RowMapper rowMapper, Object... args) throws DataAccessException; - - /** - * Query using a prepared statement, reading the {@link ResultSet} with a {@link AsyncResultSetExtractor}. - * - * @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 AsyncResultSetExtractor}. - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture query(String cql, @Nullable PreparedStatementBinder psb, - AsyncResultSetExtractor resultSetExtractor) 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, reading the {@link ResultSet} on a per-row basis with a - * {@link RowCallbackHandler}. - * - * @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, @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 {@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, @Nullable PreparedStatementBinder psb, RowMapper rowMapper) - throws DataAccessException; - - /** - * Execute a query for a result {@link List}, given static CQL. - *

- * Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a - * {@link PreparedStatement}, use the overloaded {@code queryForList} method with {@literal null} as argument array. - *

- * The results will be mapped to a {@link List} (one item for each row) of {@link Map}s (one entry for each column - * 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 {@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[]) - */ - ListenableFuture>> queryForList(String cql) throws DataAccessException; - - /** - * Query given CQL to create a prepared statement from CQL and a list of arguments to bind to the query, expecting a - * result {@link List}. - *

- * The results will be mapped to a {@link List} (one item for each row) of {@link Map}s (one entry for each column, - * 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 {@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 - * @throws DataAccessException if there is any problem executing the query. - * @see #queryForList(String) - */ - ListenableFuture>> queryForList(String cql, Object... args) throws DataAccessException; - - /** - * Execute a query for a result {@link List}, given static CQL. - *

- * Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a - * {@link PreparedStatement}, use the overloaded {@code queryForList} method with {@literal null} as argument array. - *

- * 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 {@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. - * @throws DataAccessException if there is any problem executing the query. - * @see #queryForList(String, Class, Object[]) - * @see SingleColumnRowMapper - */ - ListenableFuture> queryForList(String cql, Class elementType) throws DataAccessException; - - /** - * Query given CQL to create a prepared statement from CQL and a list of arguments to bind to the query, expecting a - * result {@link List}. - *

- * 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 {@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 - * CQL type). - * @return a {@link List} of objects that match the specified element type. - * @throws DataAccessException if there is any problem executing the query. - * @see #queryForList(String, Class) - * @see SingleColumnRowMapper - */ - ListenableFuture> queryForList(String cql, Class elementType, Object... args) - throws DataAccessException; - - /** - * Execute a query for a result Map, given static CQL. - *

- * Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a - * {@link PreparedStatement}, use the overloaded {@link #queryForMap(String, Object...)} method with {@literal null} - * as argument array. - *

- * 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 {@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. - * @see #queryForMap(String, Object[]) - * @see ColumnMapRowMapper - */ - ListenableFuture> queryForMap(String cql) throws DataAccessException; - - /** - * Query given CQL to create a prepared statement from CQL and a list of arguments to bind to the query, expecting a - * result Map. The queryForMap() methods defined by this interface are appropriate when you don't have a domain model. - * Otherwise, consider using one of the queryForObject() methods. - *

- * 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 {@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). - * @throws IncorrectResultSizeDataAccessException if the query does not return exactly one row - * @throws DataAccessException if there is any problem executing the query. - * @see #queryForMap(String) - * @see ColumnMapRowMapper - */ - ListenableFuture> queryForMap(String cql, Object... args) throws DataAccessException; - - /** - * Execute a query for a result object, given static CQL. - *

- * Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a - * {@link PreparedStatement}, use the overloaded {@link #queryForObject(String, Class, Object...)} method with - * {@literal null} as argument array. - *

- * 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 {@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 {@literal null} in case of CQL NULL. - * @throws IncorrectResultSizeDataAccessException if the query does not return exactly one row, or does not return - * exactly one column in that row. - * @throws DataAccessException if there is any problem executing the query. - * @see #queryForObject(String, Class, Object[]) - */ - ListenableFuture queryForObject(String cql, Class requiredType) throws DataAccessException; - - /** - * Query given CQL to create a prepared statement from CQL and a list of arguments to bind to the query, expecting a - * result object. - *

- * 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 {@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) - * @return the result object of the required type, or {@literal null} in case of CQL NULL. - * @throws IncorrectResultSizeDataAccessException if the query does not return exactly one row, or does not return - * exactly one column in that row. - * @throws DataAccessException if there is any problem executing the query. - * @see #queryForObject(String, Class) - */ - ListenableFuture queryForObject(String cql, Class requiredType, Object... args) throws DataAccessException; - - /** - * Execute a query given static CQL, mapping a single result row to a Java object via a {@link RowMapper}. - *

- * Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a - * {@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 {@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. - * @throws DataAccessException if there is any problem executing the query. - * @see #queryForObject(String, RowMapper, Object[]) - */ - ListenableFuture queryForObject(String cql, RowMapper rowMapper) throws DataAccessException; - - /** - * 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 {@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) - * @return the single mapped object - * @throws IncorrectResultSizeDataAccessException if the query does not return exactly one row. - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture queryForObject(String cql, RowMapper rowMapper, Object... args) throws DataAccessException; - - /** - * Execute a query for a ResultSet, given static CQL. - *

- * Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a - * {@link PreparedStatement}, use the overloaded {@code queryForResultSet} method with {@literal null} as argument - * array. - *

- * The results will be mapped to an {@link ResultSet}. - * - * @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[]) - */ - ListenableFuture queryForResultSet(String cql) throws DataAccessException; - - /** - * Query given CQL to create a prepared statement from CQL and a list of arguments to bind to the query, expecting a - * ResultSet. - *

- * The results will be mapped to an {@link ResultSet}. - * - * @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. - * @throws DataAccessException if there is any problem executing the query. - * @see #queryForResultSet(String) - */ - ListenableFuture queryForResultSet(String cql, Object... args) throws DataAccessException; - - // ------------------------------------------------------------------------- - // Methods dealing with com.datastax.oss.driver.api.core.cql.Statement - // ------------------------------------------------------------------------- - - /** - * Issue a single CQL execute, typically a DDL statement, insert, update or delete statement. - * - * @param statement static CQL {@link Statement}, must not be {@literal null}. - * @return boolean value whether the statement was applied. - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture execute(Statement statement) throws DataAccessException; - - /** - * Execute a query given static CQL, reading the {@link ResultSet} with a {@link AsyncResultSetExtractor}. - *

- * 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 statement static CQL {@link Statement}, must not be {@literal null}. - * @param resultSetExtractor object that will extract all rows of results, must not be {@literal null}. - * @return an arbitrary result object, as returned by the AsyncResultSetExtractor. - * @throws DataAccessException if there is any problem executing the query. - * @see #query(String, AsyncResultSetExtractor, Object...) - */ - ListenableFuture query(Statement statement, AsyncResultSetExtractor resultSetExtractor) - throws DataAccessException; - - /** - * Execute a query given static CQL, reading the {@link ResultSet} on a per-row basis with a - * {@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 {@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}. - * @throws DataAccessException if there is any problem executing the query. - * @see #query(String, RowCallbackHandler, Object[]) - */ - ListenableFuture query(Statement statement, RowCallbackHandler rowCallbackHandler) - throws DataAccessException; - - /** - * Execute a query given static CQL, mapping each row to a Java object via a {@link RowMapper}. - *

- * 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 statement static CQL {@link Statement}, must not be {@literal null}. - * @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. - * @see #query(String, RowMapper, Object[]) - */ - ListenableFuture> query(Statement statement, RowMapper rowMapper) throws DataAccessException; - - /** - * Execute a query for a result {@link List}, given static CQL. - *

- * Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a - * {@link PreparedStatement}, use the overloaded {@code queryForList} method with {@literal null} as argument array. - *

- * The results will be mapped to a {@link List} (one item for each row) of {@link Map}s (one entry for each column - * 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 {@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[]) - */ - ListenableFuture>> queryForList(Statement statement) throws DataAccessException; - - /** - * Execute a query for a result {@link List}, given static CQL. - *

- * Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a - * {@link PreparedStatement}, use the overloaded {@code queryForList} method with {@literal null} as argument array. - *

- * 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 statement static CQL {@link Statement}, must not be {@literal null}. - * @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. - * @throws DataAccessException if there is any problem executing the query. - * @see #queryForList(String, Class, Object[]) - * @see SingleColumnRowMapper - */ - ListenableFuture> queryForList(Statement statement, Class elementType) throws DataAccessException; - - /** - * Execute a query for a result Map, given static CQL. - *

- * Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a - * {@link PreparedStatement}, use the overloaded {@link #queryForMap(String, Object...)} method with {@literal null} - * as argument array. - *

- * 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 statement static CQL {@link Statement}, must not be {@literal null}. - * @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. - * @see #queryForMap(String, Object[]) - * @see ColumnMapRowMapper - */ - ListenableFuture> queryForMap(Statement statement) throws DataAccessException; - - /** - * Execute a query for a result object, given static CQL. - *

- * Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a - * {@link PreparedStatement}, use the overloaded {@link #queryForObject(String, Class, Object...)} method with - * {@literal null} as argument array. - *

- * 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 statement static CQL {@link Statement}, must not be {@literal null}. - * @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 {@literal null} in case of CQL NULL. - * @throws IncorrectResultSizeDataAccessException if the query does not return exactly one row, or does not return - * exactly one column in that row. - * @throws DataAccessException if there is any problem executing the query. - * @see #queryForObject(String, Class, Object[]) - */ - ListenableFuture queryForObject(Statement statement, Class requiredType) throws DataAccessException; - - /** - * Execute a query given static CQL, mapping a single result row to a Java object via a {@link RowMapper}. - *

- * Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a - * {@link PreparedStatement}, use the overloaded {@link #queryForObject(String, RowMapper, Object...)} method with - * {@literal null} as argument array. - * - * @param statement static CQL {@link Statement}, must not be {@literal null}. - * @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. - * @throws DataAccessException if there is any problem executing the query. - * @see #queryForObject(String, RowMapper, Object[]) - */ - ListenableFuture queryForObject(Statement statement, RowMapper rowMapper) throws DataAccessException; - - /** - * Execute a query for a ResultSet, given static CQL. - *

- * Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a - * {@link PreparedStatement}, use the overloaded {@code queryForResultSet} method with {@literal null} as argument - * array. - *

- * The results will be mapped to an {@link ResultSet}. - * - * @param statement static CQL {@link Statement}, must not be {@literal null}. - * @return a {@link ResultSet} representation. - * @throws DataAccessException if there is any problem executing the query. - * @see #queryForResultSet(String, Object[]) - */ - ListenableFuture queryForResultSet(Statement statement) throws DataAccessException; - - // ------------------------------------------------------------------------- - // Methods dealing with com.datastax.oss.driver.api.core.cql.PreparedStatement - // ------------------------------------------------------------------------- - - /** - * Issue a single CQL execute operation (such as an insert, update or delete statement) using a - * {@link AsyncPreparedStatementCreator} to provide CQL and any required parameters. - * - * @param preparedStatementCreator object that provides CQL and any necessary parameters, must not be {@literal null}. - * @return boolean value whether the statement was applied. - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture execute(AsyncPreparedStatementCreator preparedStatementCreator) throws DataAccessException; - - /** - * Execute a CQL data access operation, implemented as callback action working on a CQL {@link PreparedStatement}. - * This allows for implementing arbitrary data access operations on a single {@link PreparedStatement}, within - * Spring's managed CQL environment: that is, participating in Spring-managed transactions and converting CQL - * {@link com.datastax.oss.driver.api.core.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. - * - * @param preparedStatementCreator object that can create a {@link PreparedStatement} given a - * {@link com.datastax.oss.driver.api.core.CqlSession}, 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 executing the query. - */ - ListenableFuture execute(AsyncPreparedStatementCreator preparedStatementCreator, - PreparedStatementCallback action) throws DataAccessException; - - /** - * Query using a prepared statement, reading the {@link ResultSet} with a {@link AsyncResultSetExtractor}. - * - * @param preparedStatementCreator object that can create a {@link PreparedStatement} given a - * {@link com.datastax.oss.driver.api.core.CqlSession}, must not be {@literal null}. - * @param resultSetExtractor object that will extract results, must not be {@literal null}. - * @return an arbitrary result object, as returned by the {@link AsyncResultSetExtractor} - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture query(AsyncPreparedStatementCreator preparedStatementCreator, - AsyncResultSetExtractor resultSetExtractor) throws DataAccessException; - - /** - * Query using a prepared statement, reading the {@link ResultSet} on a per-row basis with a - * {@link RowCallbackHandler}. - * - * @param preparedStatementCreator object that can create a {@link PreparedStatement} given a - * {@link com.datastax.oss.driver.api.core.CqlSession}, must not be {@literal null}. - * @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, - RowCallbackHandler rowCallbackHandler) throws DataAccessException; - - /** - * Query using a prepared statement, mapping each row to a Java object via a {@link RowMapper}. - * - * @param preparedStatementCreator object that can create a {@link PreparedStatement} given a - * {@link com.datastax.oss.driver.api.core.CqlSession}, must not be {@literal null}. - * @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, RowMapper rowMapper) - throws DataAccessException; - - /** - * Query using a prepared statement and a {@link PreparedStatementBinder} implementation that knows how to bind values - * to the query, reading the {@link ResultSet} with a {@link AsyncResultSetExtractor}. - * - * @param preparedStatementCreator object that can create a {@link PreparedStatement} given a - * {@link com.datastax.oss.driver.api.core.CqlSession}, must not be {@literal null}. - * @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 AsyncResultSetExtractor}. - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture query(AsyncPreparedStatementCreator preparedStatementCreator, - @Nullable PreparedStatementBinder psb, AsyncResultSetExtractor resultSetExtractor) throws DataAccessException; - - /** - * Query using a prepared statement and a {@link PreparedStatementBinder} implementation that knows how to bind values - * to the query, reading the {@link ResultSet} on a per-row basis with a {@link RowCallbackHandler}. - * - * @param preparedStatementCreator object that can create a {@link PreparedStatement} given a - * {@link com.datastax.oss.driver.api.core.CqlSession}, must not be {@literal null}. - * @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, - @Nullable PreparedStatementBinder psb, RowCallbackHandler rowCallbackHandler) throws DataAccessException; - - /** - * Query using a prepared statement 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 preparedStatementCreator object that can create a {@link PreparedStatement} given a - * {@link com.datastax.oss.driver.api.core.CqlSession}, must not be {@literal null}. - * @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, - @Nullable PreparedStatementBinder psb, RowMapper rowMapper) throws DataAccessException; -} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncCqlTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncCqlTemplate.java deleted file mode 100644 index f65a054ad..000000000 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncCqlTemplate.java +++ /dev/null @@ -1,701 +0,0 @@ -/* - * Copyright 2016-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.cassandra.core.cql.legacy; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.ExecutionException; -import java.util.function.Function; - -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.data.cassandra.core.cql.CassandraAccessor; -import org.springframework.data.cassandra.core.cql.CqlProvider; -import org.springframework.data.cassandra.core.cql.PreparedStatementBinder; -import org.springframework.data.cassandra.core.cql.PreparedStatementCallback; -import org.springframework.data.cassandra.core.cql.PreparedStatementCreator; -import org.springframework.data.cassandra.core.cql.ResultSetExtractor; -import org.springframework.data.cassandra.core.cql.RowCallbackHandler; -import org.springframework.data.cassandra.core.cql.RowMapper; -import org.springframework.data.cassandra.core.cql.RowMapperResultSetExtractor; -import org.springframework.data.cassandra.core.cql.util.CassandraFutureAdapter; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; -import org.springframework.util.concurrent.ListenableFuture; -import org.springframework.util.concurrent.SettableListenableFuture; - -import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.core.DriverException; -import com.datastax.oss.driver.api.core.cql.AsyncResultSet; -import com.datastax.oss.driver.api.core.cql.PreparedStatement; -import com.datastax.oss.driver.api.core.cql.ResultSet; -import com.datastax.oss.driver.api.core.cql.SimpleStatement; -import com.datastax.oss.driver.api.core.cql.Statement; - -/** - * This is the central class in the CQL core package for asynchronous Cassandra data access. It simplifies the - * use of CQL and helps to avoid common errors. It executes core CQL workflow, leaving application code to provide CQL - * and extract results. This class executes CQL queries or updates, initiating iteration over {@link ResultSet}s and - * catching {@link DriverException} exceptions and translating them to the generic, more informative exception hierarchy - * defined in the {@code org.springframework.dao} package. - *

- * Code using this class need only implement callback interfaces, giving them a clearly defined contract. The - * {@link PreparedStatementCreator} callback interface creates a prepared statement given a Connection, providing CQL - * and any necessary parameters. The {@link AsyncResultSetExtractor} interface extracts values from a {@link ResultSet}. - * See also {@link PreparedStatementBinder} and {@link RowMapper} for two popular alternative callback interfaces. - *

- * Can be used within a service implementation via direct instantiation with a {@link CqlSession} reference, or get - * prepared in an application context and given to services as bean reference. Note: The {@link CqlSession} should - * always be configured as a bean in the application context, in the first case given to the service directly, in the - * second case to the prepared template. - *

- * Because this class is parameterizable by the callback interfaces and the {@link PersistenceExceptionTranslator} - * interface, there should be no need to subclass it. - *

- * All CQL operations performed by this class are logged at debug level, using - * "org.springframework.data.cassandra.core.cqlTemplate" as log category. - *

- * NOTE: An instance of this class is thread-safe once configured. - * - * @author Mark Paluch - * @author John Blum - * @since 4.0 - * @see ListenableFuture - * @see PreparedStatementCreator - * @see PreparedStatementBinder - * @see PreparedStatementCallback - * @see AsyncResultSetExtractor - * @see RowCallbackHandler - * @see RowMapper - * @see PersistenceExceptionTranslator - * @deprecated since 4.0, use the {@link java.util.concurrent.CompletableFuture}-based variant - * {@link org.springframework.data.cassandra.core.cql.AsyncCqlTemplate}. - */ -@Deprecated(since = "4.0", forRemoval = true) -@SuppressWarnings("removal") -public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOperations { - - /** - * Create a new, uninitialized {@link AsyncCqlTemplate}. Note: The {@link SessionFactory} has to be set before using - * the instance. - * - * @see #setSessionFactory(SessionFactory) - */ - public AsyncCqlTemplate() {} - - /** - * Create a new {@link AsyncCqlTemplate} with the given {@link CqlSession}. - * - * @param session the active Cassandra {@link CqlSession}, must not be {@literal null}. - * @throws IllegalStateException if {@link CqlSession} is {@literal null}. - */ - public AsyncCqlTemplate(CqlSession session) { - - Assert.notNull(session, "Session must not be null"); - - setSession(session); - } - - /** - * Constructs a new {@link AsyncCqlTemplate} with the given {@link SessionFactory}. - * - * @param sessionFactory the active Cassandra {@link SessionFactory}. - * @since 2.0 - * @see SessionFactory - */ - public AsyncCqlTemplate(SessionFactory sessionFactory) { - - Assert.notNull(sessionFactory, "SessionFactory must not be null"); - - setSessionFactory(sessionFactory); - } - - // ------------------------------------------------------------------------- - // Methods dealing with a plain com.datastax.oss.driver.api.core.CqlSession - // ------------------------------------------------------------------------- - - @Override - public ListenableFuture execute(AsyncSessionCallback action) throws DataAccessException { - - Assert.notNull(action, "Callback object must not be null"); - - try { - return action.doInSession(getCurrentSession()); - } catch (DriverException e) { - throw translateException("SessionCallback", toCql(action), e); - } - } - - // ------------------------------------------------------------------------- - // Methods dealing with static CQL - // ------------------------------------------------------------------------- - - @Override - public ListenableFuture execute(String cql) throws DataAccessException { - - Assert.hasText(cql, "CQL must not be empty"); - - return new MappingListenableFutureAdapter<>(queryForResultSet(cql), AsyncResultSet::wasApplied); - } - - @Override - public ListenableFuture query(String cql, AsyncResultSetExtractor resultSetExtractor) - throws DataAccessException { - - Assert.hasText(cql, "CQL must not be empty"); - Assert.notNull(resultSetExtractor, "AsyncResultSetExtractor must not be null"); - - try { - if (logger.isDebugEnabled()) { - logger.debug(String.format("Executing CQL statement [%s]", cql)); - } - - CompletionStage results = getCurrentSession().executeAsync(applyStatementSettings(newStatement(cql))) - .thenApply(resultSetExtractor::extractData) // - .thenCompose(ListenableFuture::completable); - - return new CassandraFutureAdapter<>(results, ex -> translateExceptionIfPossible("Query", cql, ex)); - } catch (DriverException e) { - throw translateException("Query", cql, e); - } - } - - @Override - public ListenableFuture query(String cql, RowCallbackHandler rowCallbackHandler) throws DataAccessException { - - ListenableFuture results = query(cql, newAsyncResultSetExtractor(rowCallbackHandler)); - - return new MappingListenableFutureAdapter<>(results, o -> null); - - } - - @Override - public ListenableFuture> query(String cql, RowMapper rowMapper) throws DataAccessException { - return query(cql, newAsyncResultSetExtractor(rowMapper)); - } - - @Override - public ListenableFuture>> queryForList(String cql) throws DataAccessException { - return query(cql, newAsyncResultSetExtractor(newColumnMapRowMapper())); - } - - @Override - public ListenableFuture> queryForList(String cql, Class elementType) throws DataAccessException { - return query(cql, newAsyncResultSetExtractor(newSingleColumnRowMapper(elementType))); - } - - @Override - public ListenableFuture> queryForMap(String cql) throws DataAccessException { - return queryForObject(cql, newColumnMapRowMapper()); - } - - @Override - public ListenableFuture queryForObject(String cql, Class requiredType) throws DataAccessException { - return queryForObject(cql, newSingleColumnRowMapper(requiredType)); - } - - @Override - public ListenableFuture queryForObject(String cql, RowMapper rowMapper) throws DataAccessException { - - ListenableFuture> results = query(cql, newAsyncResultSetExtractor(rowMapper)); - - return new ExceptionTranslatingListenableFutureAdapter<>( - new MappingListenableFutureAdapter<>(results, DataAccessUtils::nullableSingleResult), getExceptionTranslator()); - } - - @Override - public ListenableFuture queryForResultSet(String cql) throws DataAccessException { - return query(cql, AsyncCqlTemplate::toResultSet); - } - - // ------------------------------------------------------------------------- - // Methods dealing with com.datastax.oss.driver.api.core.cql.Statement - // ------------------------------------------------------------------------- - - @Override - public ListenableFuture execute(Statement statement) throws DataAccessException { - - Assert.notNull(statement, "CQL Statement must not be null"); - - return new MappingListenableFutureAdapter<>(queryForResultSet(statement), AsyncResultSet::wasApplied); - } - - @Override - public ListenableFuture query(Statement statement, AsyncResultSetExtractor resultSetExtractor) - throws DataAccessException { - - Assert.notNull(statement, "CQL Statement must not be null"); - Assert.notNull(resultSetExtractor, "AsyncResultSetExtractor must not be null"); - - try { - if (logger.isDebugEnabled()) { - logger.debug(String.format("Executing statement [%s]", toCql(statement))); - } - - CompletionStage results = getCurrentSession() // - .executeAsync(applyStatementSettings(statement)) // - .thenApply(resultSetExtractor::extractData) // - .thenCompose(ListenableFuture::completable); - - return new CassandraFutureAdapter<>(results, ex -> translateExceptionIfPossible("Query", toCql(statement), ex)); - } catch (DriverException e) { - throw translateException("Query", toCql(statement), e); - } - } - - @Override - public ListenableFuture query(Statement statement, RowCallbackHandler rowCallbackHandler) - throws DataAccessException { - - ListenableFuture result = query(statement, newAsyncResultSetExtractor(rowCallbackHandler)); - - return new ExceptionTranslatingListenableFutureAdapter<>(new MappingListenableFutureAdapter<>(result, o -> null), - getExceptionTranslator()); - } - - @Override - public ListenableFuture> query(Statement statement, RowMapper rowMapper) - throws DataAccessException { - return query(statement, newAsyncResultSetExtractor(rowMapper)); - } - - @Override - public ListenableFuture>> queryForList(Statement statement) throws DataAccessException { - return query(statement, newAsyncResultSetExtractor(newColumnMapRowMapper())); - } - - @Override - public ListenableFuture> queryForList(Statement statement, Class elementType) - throws DataAccessException { - return query(statement, newAsyncResultSetExtractor(newSingleColumnRowMapper(elementType))); - } - - @Override - public ListenableFuture> queryForMap(Statement statement) throws DataAccessException { - return queryForObject(statement, newColumnMapRowMapper()); - } - - @Override - public ListenableFuture queryForObject(Statement statement, Class requiredType) - throws DataAccessException { - return queryForObject(statement, newSingleColumnRowMapper(requiredType)); - } - - @Override - public ListenableFuture queryForObject(Statement statement, RowMapper rowMapper) - throws DataAccessException { - - ListenableFuture> results = query(statement, newAsyncResultSetExtractor(rowMapper)); - - return new ExceptionTranslatingListenableFutureAdapter<>( - new MappingListenableFutureAdapter<>(results, DataAccessUtils::nullableSingleResult), getExceptionTranslator()); - } - - @Override - public ListenableFuture queryForResultSet(Statement statement) throws DataAccessException { - return query(statement, AsyncCqlTemplate::toResultSet); - } - - // ------------------------------------------------------------------------- - // Methods dealing with com.datastax.driver.core.PreparedStatement - // ------------------------------------------------------------------------- - - @Override - public ListenableFuture execute(AsyncPreparedStatementCreator preparedStatementCreator) - throws DataAccessException { - - return new MappingListenableFutureAdapter<>(query(preparedStatementCreator, AsyncCqlTemplate::toResultSet), - AsyncResultSet::wasApplied); - } - - @Override - public ListenableFuture execute(String cql, Object... args) throws DataAccessException { - return execute(cql, newPreparedStatementBinder(args)); - } - - @Override - public ListenableFuture execute(String cql, @Nullable PreparedStatementBinder psb) - throws DataAccessException { - - return new MappingListenableFutureAdapter<>( - query(newAsyncPreparedStatementCreator(cql), psb, AsyncCqlTemplate::toResultSet), AsyncResultSet::wasApplied); - } - - @Override - public ListenableFuture execute(String cql, PreparedStatementCallback action) throws DataAccessException { - return execute(newAsyncPreparedStatementCreator(cql), action); - } - - @Override - public ListenableFuture execute(AsyncPreparedStatementCreator preparedStatementCreator, - PreparedStatementCallback action) throws DataAccessException { - - 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(String.format("Preparing statement [%s] using %s", toCql(preparedStatementCreator), - preparedStatementCreator)); - } - - CqlSession currentSession = getCurrentSession(); - return new ExceptionTranslatingListenableFutureAdapter<>(new MappingListenableFutureAdapter<>( - preparedStatementCreator.createPreparedStatement(currentSession), preparedStatement -> { - try { - return action.doInPreparedStatement(currentSession, preparedStatement); - } catch (DriverException e) { - throw translateException(exceptionTranslator, e); - } - }), getExceptionTranslator()); - - } catch (DriverException e) { - throw translateException(exceptionTranslator, e); - } - } - - @Override - public ListenableFuture query(AsyncPreparedStatementCreator preparedStatementCreator, - AsyncResultSetExtractor resultSetExtractor) throws DataAccessException { - - return query(preparedStatementCreator, null, resultSetExtractor); - } - - @Override - public ListenableFuture query(AsyncPreparedStatementCreator preparedStatementCreator, - RowCallbackHandler rowCallbackHandler) throws DataAccessException { - - ListenableFuture results = query(preparedStatementCreator, null, newAsyncResultSetExtractor(rowCallbackHandler)); - - return new ExceptionTranslatingListenableFutureAdapter<>(new MappingListenableFutureAdapter<>(results, o -> null), - getExceptionTranslator()); - } - - @Override - public ListenableFuture> query(AsyncPreparedStatementCreator preparedStatementCreator, - RowMapper rowMapper) throws DataAccessException { - - return query(preparedStatementCreator, null, newAsyncResultSetExtractor(rowMapper)); - } - - @Override - public ListenableFuture query(AsyncPreparedStatementCreator preparedStatementCreator, - @Nullable PreparedStatementBinder psb, AsyncResultSetExtractor resultSetExtractor) throws DataAccessException { - - Assert.notNull(preparedStatementCreator, "AsyncPreparedStatementCreator must not be null"); - Assert.notNull(resultSetExtractor, "AsyncResultSetExtractor object must not be null"); - - PersistenceExceptionTranslator exceptionTranslator = ex -> translateExceptionIfPossible("Query", - toCql(preparedStatementCreator), ex); - - try { - - if (logger.isDebugEnabled()) { - logger.debug(String.format("Preparing statement [%s] using %s", toCql(preparedStatementCreator), - preparedStatementCreator)); - } - - CqlSession session = getCurrentSession(); - - ListenableFuture> statementFuture = new MappingListenableFutureAdapter<>( - preparedStatementCreator.createPreparedStatement(session), preparedStatement -> { - if (logger.isDebugEnabled()) { - logger.debug(String.format("Executing prepared statement [%s]", toCql(preparedStatement))); - } - - return applyStatementSettings(psb != null ? psb.bindValues(preparedStatement) : preparedStatement.bind()); - }); - - CompletableFuture result = statementFuture.completable() // - .thenCompose(session::executeAsync) // - .thenApply(resultSetExtractor::extractData) // - .thenCompose(ListenableFuture::completable); - - return new CassandraFutureAdapter<>(result, exceptionTranslator); - } catch (DriverException e) { - throw translateException(exceptionTranslator, e); - } - } - - @Override - public ListenableFuture query(AsyncPreparedStatementCreator preparedStatementCreator, - @Nullable PreparedStatementBinder psb, RowCallbackHandler rowCallbackHandler) throws DataAccessException { - - ListenableFuture results = query(preparedStatementCreator, psb, newAsyncResultSetExtractor(rowCallbackHandler)); - - return new ExceptionTranslatingListenableFutureAdapter<>(new MappingListenableFutureAdapter<>(results, o -> null), - getExceptionTranslator()); - } - - @Override - public ListenableFuture> query(AsyncPreparedStatementCreator preparedStatementCreator, - @Nullable PreparedStatementBinder psb, RowMapper rowMapper) throws DataAccessException { - return query(preparedStatementCreator, psb, newAsyncResultSetExtractor(rowMapper)); - } - - @Override - public ListenableFuture query(String cql, AsyncResultSetExtractor resultSetExtractor, Object... args) - throws DataAccessException { - return query(newAsyncPreparedStatementCreator(cql), newPreparedStatementBinder(args), resultSetExtractor); - } - - @Override - public ListenableFuture query(String cql, RowCallbackHandler rowCallbackHandler, Object... args) - throws DataAccessException { - - ListenableFuture results = query(newAsyncPreparedStatementCreator(cql), newPreparedStatementBinder(args), - newAsyncResultSetExtractor(rowCallbackHandler)); - - return new ExceptionTranslatingListenableFutureAdapter<>(new MappingListenableFutureAdapter<>(results, o -> null), - getExceptionTranslator()); - } - - @Override - public ListenableFuture> query(String cql, RowMapper rowMapper, Object... args) - throws DataAccessException { - return query(newAsyncPreparedStatementCreator(cql), newPreparedStatementBinder(args), - newAsyncResultSetExtractor(rowMapper)); - } - - @Override - public ListenableFuture query(String cql, @Nullable PreparedStatementBinder psb, - AsyncResultSetExtractor resultSetExtractor) throws DataAccessException { - - return query(newAsyncPreparedStatementCreator(cql), psb, resultSetExtractor); - } - - @Override - public ListenableFuture query(String cql, @Nullable PreparedStatementBinder psb, - RowCallbackHandler rowCallbackHandler) throws DataAccessException { - - ListenableFuture results = query(newAsyncPreparedStatementCreator(cql), psb, - newAsyncResultSetExtractor(rowCallbackHandler)); - - return new ExceptionTranslatingListenableFutureAdapter<>(new MappingListenableFutureAdapter<>(results, o -> null), - getExceptionTranslator()); - } - - @Override - public ListenableFuture> query(String cql, @Nullable PreparedStatementBinder psb, RowMapper rowMapper) - throws DataAccessException { - - return query(newAsyncPreparedStatementCreator(cql), psb, newAsyncResultSetExtractor(rowMapper)); - } - - @Override - public ListenableFuture>> queryForList(String cql, Object... args) - throws DataAccessException { - - return query(newAsyncPreparedStatementCreator(cql), newPreparedStatementBinder(args), - newAsyncResultSetExtractor(newColumnMapRowMapper())); - } - - @Override - public ListenableFuture> queryForList(String cql, Class elementType, Object... args) - throws DataAccessException { - - return query(newAsyncPreparedStatementCreator(cql), newPreparedStatementBinder(args), - newAsyncResultSetExtractor(newSingleColumnRowMapper(elementType))); - } - - @Override - public ListenableFuture> queryForMap(String cql, Object... args) throws DataAccessException { - return queryForObject(cql, newColumnMapRowMapper(), args); - } - - @Override - public ListenableFuture queryForObject(String cql, Class requiredType, Object... args) - throws DataAccessException { - - return queryForObject(cql, newSingleColumnRowMapper(requiredType), args); - } - - @Override - public ListenableFuture queryForObject(String cql, RowMapper rowMapper, Object... args) - throws DataAccessException { - - ListenableFuture> results = query(newAsyncPreparedStatementCreator(cql), newPreparedStatementBinder(args), - newAsyncResultSetExtractor(rowMapper)); - - return new ExceptionTranslatingListenableFutureAdapter<>( - new MappingListenableFutureAdapter<>(results, DataAccessUtils::nullableSingleResult), getExceptionTranslator()); - } - - @Override - public ListenableFuture queryForResultSet(String cql, Object... args) throws DataAccessException { - return query(cql, AsyncCqlTemplate::toResultSet, args); - } - - // ------------------------------------------------------------------------- - // Implementation hooks and helper methods - // ------------------------------------------------------------------------- - - /** - * 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 {@literal null}) - * @param ex the offending {@code RuntimeException}. - * @return the exception translation {@link Function} - * @see CqlProvider - */ - protected DataAccessException translateException(String task, @Nullable String cql, DriverException ex) { - return translate(task, cql, ex); - } - - /** - * 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 {@literal null}) - * @param ex the offending {@code RuntimeException}. - * @return the translated {@link DataAccessException} or {@literal null} if translation not possible. - * @see CqlProvider - */ - @Nullable - protected DataAccessException translateExceptionIfPossible(String task, @Nullable String cql, RuntimeException ex) { - return translate(task, cql, ex); - } - - /** - * Create a new CQL-based {@link AsyncPreparedStatementCreator} using the CQL passed in. By default, we'll create an - * {@link SimpleAsyncPreparedStatementCreator}. This method allows for the creation to be overridden by subclasses. - * - * @param cql static CQL to execute, must not be empty or {@literal null}. - * @return the new {@link AsyncPreparedStatementCreator} to use - */ - protected AsyncPreparedStatementCreator newAsyncPreparedStatementCreator(String cql) { - return new SimpleAsyncPreparedStatementCreator( - (SimpleStatement) applyStatementSettings(SimpleStatement.newInstance(cql)), - ex -> translateExceptionIfPossible("PrepareStatement", cql, ex)); - } - - /** - * Constructs a new instance of the {@link ResultSetExtractor} adapting the given {@link RowCallbackHandler}. - * - * @param rowCallbackHandler {@link RowCallbackHandler} to adapt as a {@link ResultSetExtractor}. - * @return a {@link ResultSetExtractor} implementation adapting an instance of the {@link RowCallbackHandler}. - * @see AsyncRowCallbackHandlerResultSetExtractor - * @see ResultSetExtractor - * @see RowCallbackHandler - */ - protected AsyncRowCallbackHandlerResultSetExtractor newAsyncResultSetExtractor( - RowCallbackHandler rowCallbackHandler) { - return new AsyncRowCallbackHandlerResultSetExtractor(rowCallbackHandler); - } - - /** - * Constructs a new instance of the {@link ResultSetExtractor} adapting the given {@link RowMapper}. - * - * @param rowMapper {@link RowMapper} to adapt as a {@link ResultSetExtractor}. - * @return a {@link ResultSetExtractor} implementation adapting an instance of the {@link RowMapper}. - * @see ResultSetExtractor - * @see RowMapper - * @see RowMapperResultSetExtractor - */ - protected AsyncRowMapperResultSetExtractor newAsyncResultSetExtractor(RowMapper rowMapper) { - return new AsyncRowMapperResultSetExtractor<>(rowMapper); - } - - private CqlSession getCurrentSession() { - - SessionFactory sessionFactory = getSessionFactory(); - - Assert.state(sessionFactory != null, "SessionFactory is null"); - - return sessionFactory.getSession(); - } - - private static ListenableFuture toResultSet(AsyncResultSet resultSet) { - - SettableListenableFuture future = new SettableListenableFuture<>(); - future.set(resultSet); - - return future; - } - - 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 { - - private final PersistenceExceptionTranslator exceptionTranslator; - - private final SimpleStatement statement; - - private SimpleAsyncPreparedStatementCreator(SimpleStatement statement, - PersistenceExceptionTranslator exceptionTranslator) { - - this.statement = statement; - this.exceptionTranslator = exceptionTranslator; - } - - @Override - public ListenableFuture createPreparedStatement(CqlSession session) throws DriverException { - return new CassandraFutureAdapter<>(session.prepareAsync(this.statement), exceptionTranslator); - } - - @Override - public String getCql() { - return this.statement.getQuery(); - } - } - - /** - * Adapter to enable use of a {@link RowCallbackHandler} inside a {@link ResultSetExtractor}. - */ - protected static class AsyncRowCallbackHandlerResultSetExtractor implements AsyncResultSetExtractor { - - private final RowCallbackHandler rowCallbackHandler; - - protected AsyncRowCallbackHandlerResultSetExtractor(RowCallbackHandler rowCallbackHandler) { - this.rowCallbackHandler = rowCallbackHandler; - } - - @Override - @Nullable - public ListenableFuture extractData(AsyncResultSet resultSet) { - return AsyncResultStream.from(resultSet).forEach(rowCallbackHandler::processRow); - } - } - - private static class MappingListenableFutureAdapter - extends org.springframework.util.concurrent.ListenableFutureAdapter { - - private final Function mapper; - - private MappingListenableFutureAdapter(ListenableFuture adaptee, Function mapper) { - super(adaptee); - this.mapper = mapper; - } - - @Override - protected T adapt(S adapteeResult) throws ExecutionException { - return mapper.apply(adapteeResult); - } - } - -} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncPreparedStatementCreator.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncPreparedStatementCreator.java deleted file mode 100644 index 86774faf4..000000000 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncPreparedStatementCreator.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2016-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.cassandra.core.cql.legacy; - -import org.springframework.data.cassandra.core.cql.AsyncCqlTemplate; -import org.springframework.data.cassandra.core.cql.CqlProvider; -import org.springframework.data.cassandra.core.cql.CqlTemplate; -import org.springframework.data.cassandra.core.cql.PreparedStatementCallback; -import org.springframework.util.concurrent.ListenableFuture; - -import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.core.DriverException; -import com.datastax.oss.driver.api.core.cql.PreparedStatement; - -/** - * One of the two central callback interfaces used by the - * {@link org.springframework.data.cassandra.core.cql.legacy.AsyncCqlTemplate} class. This interface prepares a CQL - * statement returning a {@link ListenableFuture} given a {@link CqlSession}, provided by the {@link CqlTemplate} class. - *

- * Implementations may either create new prepared statements or reuse cached instances. Implementations do not need to - * concern themselves with {@link DriverException}s that may be thrown from operations they attempt. The - * {@link org.springframework.data.cassandra.core.cql.AsyncCqlTemplate} class will catch and handle - * {@link DriverException}s appropriately. - *

- * Classes implementing this interface should also implement the {@link CqlProvider} interface if it is able to provide - * the CQL it uses for {@link PreparedStatement} creation. This allows for better contextual information in case of - * exceptions. - * - * @author Mark Paluch - * @since 4.0 - * @see org.springframework.data.cassandra.core.cql.legacy.AsyncCqlTemplate#execute(AsyncPreparedStatementCreator, - * PreparedStatementCallback) - * @see CqlProvider - * @deprecated since 4.0, use the {@link java.util.concurrent.CompletableFuture}-based variant. - */ -@Deprecated(since = "4.0", forRemoval = true) -@FunctionalInterface -@SuppressWarnings("removal") -public interface AsyncPreparedStatementCreator { - - /** - * Create a statement in this session. Allows implementations to use {@link PreparedStatement}s. The - * {@link CqlTemplate} will attempt to cache the {@link PreparedStatement}s for future use without the overhead of - * re-preparing on the entire cluster. - * - * @param session Session to use to create statement, must not be {@literal null}. - * @return a prepared statement. - * @throws DriverException there is no need to catch DriverException that may be thrown in the implementation of this - * method. The {@link AsyncCqlTemplate} class will handle them. - */ - ListenableFuture createPreparedStatement(CqlSession session) throws DriverException; -} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncResultSetExtractor.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncResultSetExtractor.java deleted file mode 100644 index 7642dc6bf..000000000 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncResultSetExtractor.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2013-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.cassandra.core.cql.legacy; - -import org.springframework.dao.DataAccessException; -import org.springframework.data.cassandra.core.cql.AsyncCqlTemplate; -import org.springframework.data.cassandra.core.cql.RowCallbackHandler; -import org.springframework.data.cassandra.core.cql.RowMapper; -import org.springframework.lang.Nullable; -import org.springframework.util.concurrent.ListenableFuture; - -import com.datastax.oss.driver.api.core.DriverException; -import com.datastax.oss.driver.api.core.cql.AsyncResultSet; - -/** - * Callback interface used by {@link org.springframework.data.cassandra.core.cql.legacy.AsyncCqlTemplate}'s query - * methods. Implementations of this interface perform the actual work of extracting results from a - * {@link AsyncResultSet}, but don't need to worry about exception handling. {@link DriverException}s will be caught and - * handled by the calling {@link org.springframework.data.cassandra.core.cql.legacy.AsyncCqlTemplate}. - *

- * This interface is mainly used within the CQL framework itself. A {@link RowMapper} is usually a simpler choice for - * {@link AsyncResultSet} processing, mapping one result object per row instead of one result object for the entire - * {@link AsyncResultSet}. - *

- * Note: In contrast to a {@link RowCallbackHandler}, a {@link AsyncResultSetExtractor} object is typically stateless - * and thus reusable, as long as it doesn't access stateful resources or keep result state within the object. - * - * @author Mark Paluch - * @since 4.0 - * @see AsyncCqlTemplate - * @see RowMapper - * @deprecated since 4.0, use the {@link java.util.concurrent.CompletableFuture}-based variant. - */ -@Deprecated(since = "4.0", forRemoval = true) -@FunctionalInterface -@SuppressWarnings("removal") -public interface AsyncResultSetExtractor { - - /** - * Implementations must implement this method to process the entire {@link AsyncResultSet}. - * - * @param resultSet {@link AsyncResultSet} to extract data from. - * @return an arbitrary result object, or {@literal null} if none (the extractor will typically be stateful in the - * latter case). - * @throws DriverException if a {@link DriverException} is encountered getting column values or navigating (that is, - * there's no need to catch {@link DriverException}) - * @throws DataAccessException in case of custom exceptions - */ - @Nullable - ListenableFuture extractData(AsyncResultSet resultSet) throws DriverException, DataAccessException; -} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncResultStream.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncResultStream.java deleted file mode 100644 index 579e3b635..000000000 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncResultStream.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright 2019-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.cassandra.core.cql.legacy; - -import java.util.concurrent.CompletionStage; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; -import java.util.stream.Collector; - -import org.springframework.data.cassandra.core.cql.RowMapper; -import org.springframework.util.Assert; -import org.springframework.util.concurrent.ListenableFuture; -import org.springframework.util.concurrent.SettableListenableFuture; - -import com.datastax.oss.driver.api.core.cql.AsyncResultSet; -import com.datastax.oss.driver.api.core.cql.Row; - -/** - * Asynchronous supplied sequence of elements supporting sequential operations over a {@link AsyncResultSet a result - * set}. An asynchronous stream represents a pipeline of operations to process a {@link AsyncResultSet}. - * - * @author Mark Paluch - * @since 4.0 - */ -@Deprecated(since = "4.0", forRemoval = true) -@SuppressWarnings("removal") -class AsyncResultStream { - - private final AsyncResultSet resultSet; - - private final RowMapper mapper; - - private AsyncResultStream(AsyncResultSet resultSet, RowMapper mapper) { - this.resultSet = resultSet; - this.mapper = mapper; - } - - /** - * Creates a {@link AsyncResultStream} given {@link AsyncResultSet}. - * - * @param resultSet the result set to process. - * @return a new {@link AsyncResultStream} instance. - */ - static AsyncResultStream from(AsyncResultSet resultSet) { - - Assert.notNull(resultSet, "AsyncResultSet must not be null"); - - return new AsyncResultStream<>(resultSet, (row, rowNum) -> row); - } - - /** - * Returns a stream consisting of the results of applying the given function to the elements of this stream. - *

- * This is an intermediate operation. - * - * @param The element type of the new stream - * @param mapper a non-interfering, stateless {@link RowMapper}. - */ - AsyncResultStream map(RowMapper mapper) { - - Assert.notNull(mapper, "RowMapper must not be null"); - - return new AsyncResultStream<>(resultSet, mapper); - } - - /** - * Performs a mutable reduction operation on the elements of this stream using a {@link Collector} resulting in a - * {@link ListenableFuture}. - *

- * This is a terminal operation. - * - * @param the type of the result - * @param the intermediate accumulation type of the {@link Collector} - * @param collector the {@link Collector} describing the reduction - * @return the result of the reduction - */ - ListenableFuture collect(Collector collector) { - - Assert.notNull(collector, "Collector must not be null"); - - SettableListenableFuture future = new SettableListenableFuture<>(); - CollectState collectState = new CollectState<>(collector); - - collectState.collectAsync(future, this.resultSet); - - return future; - } - - /** - * Performs an action for each element of this stream. This method returns a {@link ListenableFuture} that completes - * without a value ({@code null}) once all elements have been processed. - *

- * This is a terminal operation. - *

- * If the action accesses shared state, it is responsible for providing the required synchronization. - * - * @param action a non-interfering action to perform on the elements. - */ - ListenableFuture forEach(Consumer action) { - - Assert.notNull(action, "Action must not be null"); - - SettableListenableFuture future = new SettableListenableFuture<>(); - ForwardLoopState loopState = new ForwardLoopState(action); - - loopState.forEachAsync(future, this.resultSet); - - return future; - } - - /** - * State object for forward-looping using {@code forEach}. - */ - class ForwardLoopState { - - private final AtomicInteger rowNumber = new AtomicInteger(); - private final Consumer consumer; - - ForwardLoopState(Consumer consumer) { - this.consumer = consumer; - } - - void peekRow(Iterable rows) { - rows.forEach(row -> consumer.accept(mapper.mapRow(row, rowNumber.incrementAndGet()))); - } - - /** - * Recursive async iteration. - * - * @param target - * @param resultSet - */ - void forEachAsync(SettableListenableFuture target, AsyncResultSet resultSet) { - - if (target.isCancelled()) { - return; - } - - try { - peekRow(resultSet.currentPage()); - } catch (RuntimeException e) { - target.setException(e); - return; - } - - if (!resultSet.hasMorePages()) { - target.set(null); - } else { - - CompletionStage nextPage = resultSet.fetchNextPage(); - - nextPage.whenComplete((nextResultSet, throwable) -> { - - if (throwable != null) { - target.setException(throwable); - } else { - forEachAsync(target, nextResultSet); - } - }); - } - } - } - - /** - * State object for collecting rows using {@code collect}. - */ - class CollectState { - - private final AtomicInteger rowNumber = new AtomicInteger(); - private volatile A intermediate; - private final Collector collector; - - CollectState(Collector collector) { - this.collector = collector; - this.intermediate = collector.supplier().get(); - } - - void collectPage(Iterable rows) { - - for (Row row : rows) { - collector.accumulator().accept(intermediate, mapper.mapRow(row, rowNumber.incrementAndGet())); - } - } - - R finish() { - return collector.finisher().apply(intermediate); - } - - /** - * Recursive collection. - * - * @param target - * @param resultSet - */ - void collectAsync(SettableListenableFuture target, AsyncResultSet resultSet) { - - if (target.isCancelled()) { - return; - } - - try { - collectPage(resultSet.currentPage()); - } catch (RuntimeException e) { - target.setException(e); - return; - } - - if (!resultSet.hasMorePages()) { - target.set(finish()); - } else { - - CompletionStage nextPage = resultSet.fetchNextPage(); - - nextPage.whenComplete((nextResultSet, throwable) -> { - - if (throwable != null) { - target.setException(throwable); - } else { - collectAsync(target, nextResultSet); - } - }); - } - } - } -} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncRowMapperResultSetExtractor.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncRowMapperResultSetExtractor.java deleted file mode 100644 index 463b2e603..000000000 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncRowMapperResultSetExtractor.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2016-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.cassandra.core.cql.legacy; - -import java.util.List; -import java.util.stream.Collectors; - -import org.springframework.dao.DataAccessException; -import org.springframework.data.cassandra.core.cql.AsyncCqlTemplate; -import org.springframework.data.cassandra.core.cql.ResultSetExtractor; -import org.springframework.data.cassandra.core.cql.RowMapper; -import org.springframework.util.Assert; -import org.springframework.util.concurrent.ListenableFuture; - -import com.datastax.oss.driver.api.core.DriverException; -import com.datastax.oss.driver.api.core.cql.AsyncResultSet; - -/** - * Adapter implementation of the {@link ResultSetExtractor} interface that delegates to a {@link RowMapper} which is - * supposed to create an object for each row. Each object is added to the results List of this - * {@link ResultSetExtractor}. - *

- * Useful for the typical case of one object per row in the database table. The number of entries in the results will - * match the number of rows. - *

- * Note that a {@link RowMapper} object is typically stateless and thus reusable. - * - * @author Mark Paluch - * @since 4.0 - * @see RowMapper - * @see AsyncCqlTemplate - * @deprecated since 4.0, use the {@link java.util.concurrent.CompletableFuture}-based variant. - */ -@Deprecated(since = "4.0", forRemoval = true) -@SuppressWarnings("removal") -public class AsyncRowMapperResultSetExtractor implements AsyncResultSetExtractor> { - - private final RowMapper rowMapper; - - /** - * Create a new {@link AsyncRowMapperResultSetExtractor}. - * - * @param rowMapper the {@link RowMapper} which creates an object for each row, must not be {@literal null}. - */ - public AsyncRowMapperResultSetExtractor(RowMapper rowMapper) { - - Assert.notNull(rowMapper, "RowMapper is must not be null"); - - this.rowMapper = rowMapper; - } - - @Override - public ListenableFuture> extractData(AsyncResultSet resultSet) throws DriverException, DataAccessException { - return AsyncResultStream.from(resultSet).map(rowMapper).collect(Collectors.toList()); - } -} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncSessionCallback.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncSessionCallback.java deleted file mode 100644 index 99e91686b..000000000 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/AsyncSessionCallback.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2016-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.cassandra.core.cql.legacy; - -import org.springframework.dao.DataAccessException; -import org.springframework.util.concurrent.ListenableFuture; - -import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.core.DriverException; - -/** - * Generic callback interface for code that operates asynchronously on a Cassandra {@link CqlSession}. Allows to execute - * any number of operations on a single session, using any type and number of statements. - *

- * This is particularly useful for delegating to existing data access code that expects a {@link CqlSession} to work on - * and throws {@link DriverException}. For newly written code, it is strongly recommended to use - * {@link AsyncCqlTemplate}'s more specific operations, for example a {@code query} or {@code update} variant. - * - * @author David Webb - * @author Mark Paluch - * @since 4.0 - * @see AsyncCqlTemplate#execute(AsyncSessionCallback) - * @see AsyncCqlTemplate#query - * @see AsyncCqlTemplate#execute(String) - * @deprecated since 4.0, use the {@link java.util.concurrent.CompletableFuture}-based variant. - */ -@Deprecated(since = "4.0", forRemoval = true) -@FunctionalInterface -@SuppressWarnings("removal") -public interface AsyncSessionCallback { - - /** - * Gets called by {@link AsyncCqlTemplate#execute} with an active Cassandra {@link CqlSession}. Does not need to care - * about activating or closing the {@link CqlSession}. - *

- * Allows for returning a result object created within the callback, i.e. a domain object or a collection of domain - * objects. Note that there's special support for single step actions: see {@link AsyncCqlTemplate#queryForObject} - * etc. A thrown {@link RuntimeException} is treated as application exception: it gets propagated to the caller of the - * template. - * - * @param session active Cassandra Session, must not be {@literal null}. - * @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) - * @see AsyncCqlTemplate#queryForResultSet(String) - */ - ListenableFuture doInSession(CqlSession session) throws DriverException, DataAccessException; -} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/ExceptionTranslatingListenableFutureAdapter.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/ExceptionTranslatingListenableFutureAdapter.java deleted file mode 100644 index f60824193..000000000 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/ExceptionTranslatingListenableFutureAdapter.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2016-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.cassandra.core.cql.legacy; - -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -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; -import org.springframework.util.concurrent.ListenableFutureCallback; -import org.springframework.util.concurrent.SettableListenableFuture; -import org.springframework.util.concurrent.SuccessCallback; - -/** - * Adapter class to {@link ListenableFuture} {@link ExecutionException} by applying a - * {@link PersistenceExceptionTranslator}. - * - * @author Mark Paluch - * @since 4.0 - */ -@Deprecated(since = "4.0", forRemoval = true) -@SuppressWarnings("removal") -class ExceptionTranslatingListenableFutureAdapter implements ListenableFuture { - - private final ListenableFuture adaptee; - - private final ListenableFuture future; - - /** - * Create a new {@link ExceptionTranslatingListenableFutureAdapter} given a {@link ListenableFuture} and a - * {@link PersistenceExceptionTranslator}. - * - * @param adaptee must not be {@literal null}. - * @param persistenceExceptionTranslator must not be {@literal null}. - */ - ExceptionTranslatingListenableFutureAdapter(ListenableFuture adaptee, - PersistenceExceptionTranslator persistenceExceptionTranslator) { - - Assert.notNull(adaptee, "ListenableFuture must not be null"); - Assert.notNull(persistenceExceptionTranslator, "PersistenceExceptionTranslator must not be null"); - - this.adaptee = adaptee; - this.future = adaptListenableFuture(adaptee, persistenceExceptionTranslator); - } - - private static ListenableFuture adaptListenableFuture(ListenableFuture listenableFuture, - PersistenceExceptionTranslator exceptionTranslator) { - - SettableListenableFuture settableFuture = new SettableListenableFuture<>(); - - listenableFuture.addCallback(new ListenableFutureCallback() { - - @Override - public void onSuccess(@Nullable T result) { - settableFuture.set(result); - } - - @Override - public void onFailure(Throwable ex) { - if (ex instanceof RuntimeException) { - DataAccessException dataAccessException = exceptionTranslator - .translateExceptionIfPossible((RuntimeException) ex); - - if (dataAccessException != null) { - settableFuture.setException(dataAccessException); - return; - } - } - - settableFuture.setException(ex); - } - }); - - return settableFuture; - } - - @Override - public void addCallback(ListenableFutureCallback callback) { - future.addCallback(callback); - } - - @Override - public void addCallback(SuccessCallback successCallback, FailureCallback failureCallback) { - future.addCallback(successCallback, failureCallback); - } - - @Override - public boolean cancel(boolean mayInterruptIfRunning) { - return adaptee.cancel(mayInterruptIfRunning); - } - - @Override - public boolean isCancelled() { - return adaptee.isCancelled(); - } - - @Override - public boolean isDone() { - return future.isDone(); - } - - @Override - public T get() throws InterruptedException, ExecutionException { - return future.get(); - } - - @Override - public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { - return future.get(timeout, unit); - } -} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/package-info.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/package-info.java deleted file mode 100644 index 71e3795f4..000000000 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/legacy/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * CQL legacy core asynchronous support for easier migration. - */ -@NonNullApi -package org.springframework.data.cassandra.core.cql.legacy; - -import org.springframework.lang.NonNullApi; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/util/CassandraFutureAdapter.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/util/CassandraFutureAdapter.java deleted file mode 100644 index 0844ef890..000000000 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/util/CassandraFutureAdapter.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2019-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.cassandra.core.cql.util; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import org.springframework.dao.support.PersistenceExceptionTranslator; -import org.springframework.util.concurrent.FailureCallback; -import org.springframework.util.concurrent.ListenableFuture; -import org.springframework.util.concurrent.ListenableFutureCallback; -import org.springframework.util.concurrent.ListenableFutureCallbackRegistry; -import org.springframework.util.concurrent.SuccessCallback; - -/** - * Adapts a {@link CompletableFuture} or {@link CompletionStage} into a Spring {@link ListenableFuture} applying - * {@link PersistenceExceptionTranslator}. - * - * @since 3.0 - * @param the result type returned by this Future's {@code get} method - * @deprecated since 3.0, use {@link CompletableFuture} directly. - */ -@Deprecated -public class CassandraFutureAdapter implements ListenableFuture { - - private final CompletableFuture completableFuture; - private final CompletableFuture translated; - - private final ListenableFutureCallbackRegistry callbacks = new ListenableFutureCallbackRegistry<>(); - - /** - * Create a new adapter for the given {@link CompletionStage}. - */ - public CassandraFutureAdapter(CompletionStage completionStage, PersistenceExceptionTranslator exceptionMapper) { - this(completionStage.toCompletableFuture(), exceptionMapper); - } - - /** - * Create a new adapter for the given {@link CompletableFuture}. - */ - public CassandraFutureAdapter(CompletableFuture completableFuture, - PersistenceExceptionTranslator exceptionMapper) { - this.completableFuture = completableFuture; - this.translated = new CompletableFuture<>(); - this.completableFuture.whenComplete((result, ex) -> { - if (ex != null) { - - Throwable exceptionToUse = ex; - if (exceptionToUse instanceof CompletionException) { - exceptionToUse = exceptionToUse.getCause(); - } - - if (exceptionToUse instanceof RuntimeException) { - RuntimeException translated = exceptionMapper.translateExceptionIfPossible((RuntimeException) exceptionToUse); - this.callbacks.failure(translated != null ? translated : ex); - this.translated.completeExceptionally(translated != null ? translated : ex); - } else { - this.callbacks.failure(ex); - this.translated.completeExceptionally(ex); - } - } else { - this.callbacks.success(result); - this.translated.complete(result); - } - }); - } - - @Override - public void addCallback(ListenableFutureCallback callback) { - this.callbacks.addCallback(callback); - } - - @Override - public void addCallback(SuccessCallback successCallback, FailureCallback failureCallback) { - this.callbacks.addSuccessCallback(successCallback); - this.callbacks.addFailureCallback(failureCallback); - } - - @Override - public CompletableFuture completable() { - return this.completableFuture; - } - - @Override - public boolean cancel(boolean mayInterruptIfRunning) { - return this.completableFuture.cancel(mayInterruptIfRunning); - } - - @Override - public boolean isCancelled() { - return this.completableFuture.isCancelled(); - } - - @Override - public boolean isDone() { - return this.completableFuture.isDone(); - } - - @Override - public T get() throws InterruptedException, ExecutionException { - return this.translated.get(); - } - - @Override - public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { - return this.translated.get(timeout, unit); - } - -} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/legacy/AsyncCassandraOperations.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/legacy/AsyncCassandraOperations.java deleted file mode 100644 index 73e905bbe..000000000 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/legacy/AsyncCassandraOperations.java +++ /dev/null @@ -1,394 +0,0 @@ -/* - * Copyright 2016-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License") - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.cassandra.core.legacy; - -import java.util.List; -import java.util.function.Consumer; - -import org.springframework.dao.DataAccessException; -import org.springframework.data.cassandra.core.DeleteOptions; -import org.springframework.data.cassandra.core.EntityWriteResult; -import org.springframework.data.cassandra.core.InsertOptions; -import org.springframework.data.cassandra.core.UpdateOptions; -import org.springframework.data.cassandra.core.WriteResult; -import org.springframework.data.cassandra.core.convert.CassandraConverter; -import org.springframework.data.cassandra.core.cql.QueryOptions; -import org.springframework.data.cassandra.core.cql.WriteOptions; -import org.springframework.data.cassandra.core.cql.legacy.AsyncCqlOperations; -import org.springframework.data.cassandra.core.query.CassandraPageRequest; -import org.springframework.data.cassandra.core.query.Query; -import org.springframework.data.cassandra.core.query.Update; -import org.springframework.data.domain.Slice; -import org.springframework.util.concurrent.ListenableFuture; - -import com.datastax.oss.driver.api.core.cql.AsyncResultSet; -import com.datastax.oss.driver.api.core.cql.Statement; - -/** - * Interface specifying a basic set of asynchronous Cassandra operations. Implemented by {@link AsyncCassandraTemplate}. - * Not often used directly, but a useful option to enhance testability, as it can easily be mocked or stubbed. - * - * @author Mark Paluch - * @author John Blum - * @since 4.0 - * @see AsyncCassandraTemplate - * @see AsyncCqlOperations - * @see Statement - * @see InsertOptions - * @see UpdateOptions - * @deprecated since 4.0, use the {@link java.util.concurrent.CompletableFuture}-based variant - * {@link org.springframework.data.cassandra.core.AsyncCassandraTemplate}. - */ -@Deprecated(since = "4.0", forRemoval = true) -@SuppressWarnings("removal") -public interface AsyncCassandraOperations { - - /** - * Expose the underlying {@link AsyncCqlOperations} to allow asynchronous CQL operations. - * - * @return the underlying {@link AsyncCqlOperations}. - * @see AsyncCqlOperations - */ - AsyncCqlOperations getAsyncCqlOperations(); - - /** - * Returns the underlying {@link CassandraConverter}. - * - * @return the underlying {@link CassandraConverter}. - */ - CassandraConverter getConverter(); - - // ------------------------------------------------------------------------- - // Methods dealing with static CQL - // ------------------------------------------------------------------------- - - /** - * Execute a {@code SELECT} query and convert the resulting items to a {@link List} of entities. - * - * @param cql must not be {@literal null}. - * @param entityClass The entity type must not be {@literal null}. - * @return the converted results - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture> select(String cql, Class entityClass) throws DataAccessException; - - /** - * Execute a {@code SELECT} query and convert the resulting items notifying {@link Consumer} for each entity. - * - * @param cql must not be {@literal null}. - * @param entityConsumer object that will be notified on each entity, one object at a time, must not be - * {@literal null}. - * @param entityClass The entity type must not be {@literal null}. - * @return the completion handle - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture select(String cql, Consumer entityConsumer, Class entityClass) - throws DataAccessException; - - /** - * Execute a {@code SELECT} query and convert the resulting item to an entity. - * - * @param cql must not be {@literal null}. - * @param entityClass The entity type must not be {@literal null}. - * @return the converted object or {@literal null}. - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture selectOne(String cql, Class entityClass) throws DataAccessException; - - // ------------------------------------------------------------------------- - // Methods dealing with com.datastax.oss.driver.api.core.cql.Statement - // ------------------------------------------------------------------------- - - /** - * Execute the given Cassandra {@link Statement}. Any errors that result from executing this command will be converted - * into Spring's DAO exception hierarchy. - * - * @param statement a Cassandra {@link Statement}, must not be {@literal null}. - * @return the {@link AsyncResultSet}. - * @throws DataAccessException if there is any problem executing the query. - * @since 3.2 - */ - ListenableFuture execute(Statement statement) throws DataAccessException; - - /** - * Execute a {@code SELECT} query and convert the resulting items to a {@link List} of entities. - * - * @param statement must not be {@literal null}. - * @param entityClass The entity type must not be {@literal null}. - * @return the converted results - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture> select(Statement statement, Class entityClass) throws DataAccessException; - - /** - * Execute a {@code SELECT} query with paging and convert the result set to a {@link Slice} of entities. A sliced - * query translates the effective {@link Statement#getFetchSize() fetch size} to the page size. - * - * @param statement the CQL statement, must not be {@literal null}. - * @param entityClass The entity type must not be {@literal null}. - * @return the converted results - * @throws DataAccessException if there is any problem executing the query. - * @see CassandraPageRequest - */ - ListenableFuture> slice(Statement statement, Class entityClass) throws DataAccessException; - - /** - * Execute a {@code SELECT} query and convert the resulting items notifying {@link Consumer} for each entity. - * - * @param statement must not be {@literal null}. - * @param entityConsumer object that will be notified on each entity, one object at a time, must not be - * {@literal null}. - * @param entityClass The entity type must not be {@literal null}. - * @return the completion handle - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture select(Statement statement, Consumer entityConsumer, Class entityClass) - throws DataAccessException; - - /** - * Execute a {@code SELECT} query and convert the resulting item to an entity. - * - * @param statement must not be {@literal null}. - * @param entityClass The entity type must not be {@literal null}. - * @return the converted object or {@literal null}. - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture selectOne(Statement statement, Class entityClass) throws DataAccessException; - - // ------------------------------------------------------------------------- - // Methods dealing with org.springframework.data.cassandra.core.query.Query - // ------------------------------------------------------------------------- - - /** - * Execute a {@code SELECT} query and convert the resulting items to a {@link List} of entities. - * - * @param query must not be {@literal null}. - * @param entityClass The entity type must not be {@literal null}. - * @return the converted results - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture> select(Query query, Class entityClass) throws DataAccessException; - - /** - * Execute a {@code SELECT} query with paging and convert the result set to a {@link Slice} of entities. - * - * @param query the query object used to create a CQL statement, must not be {@literal null}. - * @param entityClass The entity type must not be {@literal null}. - * @return the converted results - * @throws DataAccessException if there is any problem executing the query. - * @see CassandraPageRequest - */ - ListenableFuture> slice(Query query, Class entityClass) throws DataAccessException; - - /** - * Execute a {@code SELECT} query and convert the resulting items notifying {@link Consumer} for each entity. - * - * @param query must not be {@literal null}. - * @param entityConsumer object that will be notified on each entity, one object at a time, must not be - * {@literal null}. - * @param entityClass The entity type must not be {@literal null}. - * @return the completion handle - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture select(Query query, Consumer entityConsumer, Class entityClass) - throws DataAccessException; - - /** - * Execute a {@code SELECT} query and convert the resulting item to an entity. - * - * @param query must not be {@literal null}. - * @param entityClass The entity type must not be {@literal null}. - * @return the converted object or {@literal null}. - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture selectOne(Query query, Class entityClass) throws DataAccessException; - - /** - * Update the queried entities and return {@literal true} if the update was applied. - * - * @param query must not be {@literal null}. - * @param update must not be {@literal null}. - * @param entityClass The entity type must not be {@literal null}. - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture update(Query query, Update update, Class entityClass) throws DataAccessException; - - /** - * Remove entities (rows)/columns from the table by {@link Query}. - * - * @param query must not be {@literal null}. - * @param entityClass The entity type must not be {@literal null}. - * @return {@literal true} if the deletion was applied. - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture delete(Query query, Class entityClass) throws DataAccessException; - - // ------------------------------------------------------------------------- - // Methods dealing with entities - // ------------------------------------------------------------------------- - - /** - * Returns the number of rows for the given entity class. - * - * @param entityClass {@link Class type} of the entity; must not be {@literal null}. - * @return the number of existing entities. - * @throws DataAccessException if any problem occurs while executing the query. - */ - ListenableFuture count(Class entityClass) throws DataAccessException; - - /** - * Returns the number of rows for the given entity class applying {@link Query}. This overridden method allows users - * to further refine the selection criteria using a {@link Query} predicate to determine how many entities of the - * given {@link Class type} match the criteria. - * - * @param query user-provided count {@link Query} to execute; must not be {@literal null}. - * @param entityClass {@link Class type} of the entity; must not be {@literal null}. - * @return the number of existing entities. - * @throws DataAccessException if any problem occurs while executing the query. - * @since 2.1 - */ - ListenableFuture count(Query query, Class entityClass) throws DataAccessException; - - /** - * Determine whether a row of {@code entityClass} with the given {@code id} exists. - * - * @param id Id value. For single primary keys it's the plain value. For composite primary keys either, it's an - * instance of either {@link org.springframework.data.cassandra.core.mapping.PrimaryKeyClass} or - * {@link org.springframework.data.cassandra.core.mapping.MapId}. Must not be {@literal null}. - * @param entityClass {@link Class type} of the entity; must not be {@literal null}. - * @return {@literal true} if the object exists. - * @throws DataAccessException if any problem occurs while executing the query. - */ - ListenableFuture exists(Object id, Class entityClass) throws DataAccessException; - - /** - * Determine whether the result for {@code entityClass} {@link Query} yields at least one row. - * - * @param query user-provided exists {@link Query} to execute; must not be {@literal null}. - * @param entityClass {@link Class type} of the entity; must not be {@literal null}. - * @return {@literal true} if the object exists. - * @throws DataAccessException if any problem occurs while executing the query. - * @since 2.1 - */ - ListenableFuture exists(Query query, Class entityClass) throws DataAccessException; - - /** - * Execute the Select by {@code id} for the given {@code entityClass}. - * - * @param id the Id value. For single primary keys it's the plain value. For composite primary keys either the - * {@link org.springframework.data.cassandra.core.mapping.PrimaryKeyClass} or - * {@link org.springframework.data.cassandra.core.mapping.MapId}. Must not be {@literal null}. - * @param entityClass The entity type must not be {@literal null}. - * @return the converted object or {@literal null}. - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture selectOneById(Object id, Class entityClass) throws DataAccessException; - - /** - * Insert the given entity and return the entity if the insert was applied. - * - * @param entity The entity to insert, must not be {@literal null}. - * @return the inserted entity. - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture insert(T entity) throws DataAccessException; - - /** - * 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 must not be {@literal null}. - * @return the {@link EntityWriteResult} for this operation. - * @throws DataAccessException if there is any problem executing the query. - * @see InsertOptions#empty() - */ - ListenableFuture> insert(T entity, InsertOptions options) throws DataAccessException; - - /** - * Update the given entity and return the entity if the update was applied. - * - * @param entity The entity to update, must not be {@literal null}. - * @return the updated entity. - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture update(T entity) throws DataAccessException; - - /** - * 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 must not be {@literal null}. - * @return the {@link EntityWriteResult} for this operation. - * @throws DataAccessException if there is any problem executing the query. - * @see UpdateOptions#empty() - */ - ListenableFuture> update(T entity, UpdateOptions options) throws DataAccessException; - - /** - * Delete the given entity and return the entity if the delete statement was applied. - * - * @param entity must not be {@literal null}. - * @return the deleted entity. - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture delete(T entity) throws DataAccessException; - - /** - * Delete the given entity applying {@link QueryOptions} and return the entity if the delete statement was applied. - * - * @param entity must not 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; - - /** - * Delete the given entity applying {@link DeleteOptions} and return the entity if the delete statement was applied. - * - * @param entity must not 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 DeleteOptions#empty() - * @since 2.2 - */ - default ListenableFuture delete(Object entity, DeleteOptions options) throws DataAccessException { - return delete(entity, (QueryOptions) options); - } - - /** - * Remove the given object from the table by id. - * - * @param id the Id value. For single primary keys it's the plain value. For composite primary keys either the - * {@link org.springframework.data.cassandra.core.mapping.PrimaryKeyClass} or - * {@link org.springframework.data.cassandra.core.mapping.MapId}. Must not be {@literal null}. - * @param entityClass The entity type must not be {@literal null}. - * @return {@literal true} if the deletion was applied. - * @throws DataAccessException if there is any problem executing the query. - */ - ListenableFuture deleteById(Object id, Class entityClass) throws DataAccessException; - - /** - * Execute a {@code TRUNCATE} query to remove all entities of a given class. - * - * @param entityClass The entity type must not be {@literal null}. - * @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/legacy/AsyncCassandraTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/legacy/AsyncCassandraTemplate.java deleted file mode 100644 index 0c0637639..000000000 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/legacy/AsyncCassandraTemplate.java +++ /dev/null @@ -1,1033 +0,0 @@ -/* - * Copyright 2016-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.cassandra.core.legacy; - -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CompletionStage; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.beans.BeansException; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.context.ApplicationEventPublisherAware; -import org.springframework.dao.DataAccessException; -import org.springframework.dao.OptimisticLockingFailureException; -import org.springframework.dao.support.DataAccessUtils; -import org.springframework.dao.support.PersistenceExceptionTranslator; -import org.springframework.data.cassandra.SessionFactory; -import org.springframework.data.cassandra.core.EntityWriteResult; -import org.springframework.data.cassandra.core.InsertOptions; -import org.springframework.data.cassandra.core.StatementFactory; -import org.springframework.data.cassandra.core.UpdateOptions; -import org.springframework.data.cassandra.core.WriteResult; -import org.springframework.data.cassandra.core.convert.CassandraConverter; -import org.springframework.data.cassandra.core.convert.MappingCassandraConverter; -import org.springframework.data.cassandra.core.cql.CassandraAccessor; -import org.springframework.data.cassandra.core.cql.CqlExceptionTranslator; -import org.springframework.data.cassandra.core.cql.CqlProvider; -import org.springframework.data.cassandra.core.cql.PreparedStatementBinder; -import org.springframework.data.cassandra.core.cql.QueryExtractorDelegate; -import org.springframework.data.cassandra.core.cql.QueryOptions; -import org.springframework.data.cassandra.core.cql.RowCallbackHandler; -import org.springframework.data.cassandra.core.cql.RowMapper; -import org.springframework.data.cassandra.core.cql.SingleColumnRowMapper; -import org.springframework.data.cassandra.core.cql.WriteOptions; -import org.springframework.data.cassandra.core.cql.legacy.AsyncCqlOperations; -import org.springframework.data.cassandra.core.cql.legacy.AsyncCqlTemplate; -import org.springframework.data.cassandra.core.cql.legacy.AsyncPreparedStatementCreator; -import org.springframework.data.cassandra.core.cql.legacy.AsyncResultSetExtractor; -import org.springframework.data.cassandra.core.cql.legacy.AsyncSessionCallback; -import org.springframework.data.cassandra.core.cql.session.DefaultSessionFactory; -import org.springframework.data.cassandra.core.cql.util.CassandraFutureAdapter; -import org.springframework.data.cassandra.core.cql.util.StatementBuilder; -import org.springframework.data.cassandra.core.legacy.EntityOperations.AdaptibleEntity; -import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity; -import org.springframework.data.cassandra.core.mapping.SimpleUserTypeResolver; -import org.springframework.data.cassandra.core.mapping.event.AfterConvertEvent; -import org.springframework.data.cassandra.core.mapping.event.AfterDeleteEvent; -import org.springframework.data.cassandra.core.mapping.event.AfterLoadEvent; -import org.springframework.data.cassandra.core.mapping.event.AfterSaveEvent; -import org.springframework.data.cassandra.core.mapping.event.BeforeConvertCallback; -import org.springframework.data.cassandra.core.mapping.event.BeforeDeleteEvent; -import org.springframework.data.cassandra.core.mapping.event.BeforeSaveCallback; -import org.springframework.data.cassandra.core.mapping.event.BeforeSaveEvent; -import org.springframework.data.cassandra.core.mapping.event.CassandraMappingEvent; -import org.springframework.data.cassandra.core.query.Query; -import org.springframework.data.domain.Slice; -import org.springframework.data.mapping.callback.EntityCallbacks; -import org.springframework.data.projection.EntityProjection; -import org.springframework.data.projection.ProjectionFactory; -import org.springframework.data.projection.SpelAwareProxyProjectionFactory; -import org.springframework.data.util.Streamable; -import org.springframework.lang.Nullable; -import org.springframework.scheduling.annotation.AsyncResult; -import org.springframework.util.Assert; -import org.springframework.util.concurrent.ListenableFuture; - -import com.datastax.oss.driver.api.core.CqlIdentifier; -import com.datastax.oss.driver.api.core.CqlSession; -import com.datastax.oss.driver.api.core.DriverException; -import com.datastax.oss.driver.api.core.config.DefaultDriverOption; -import com.datastax.oss.driver.api.core.cql.AsyncResultSet; -import com.datastax.oss.driver.api.core.cql.BoundStatement; -import com.datastax.oss.driver.api.core.cql.PreparedStatement; -import com.datastax.oss.driver.api.core.cql.ResultSet; -import com.datastax.oss.driver.api.core.cql.Row; -import com.datastax.oss.driver.api.core.cql.SimpleStatement; -import com.datastax.oss.driver.api.core.cql.Statement; -import com.datastax.oss.driver.api.querybuilder.QueryBuilder; -import com.datastax.oss.driver.api.querybuilder.delete.Delete; -import com.datastax.oss.driver.api.querybuilder.insert.Insert; -import com.datastax.oss.driver.api.querybuilder.insert.RegularInsert; -import com.datastax.oss.driver.api.querybuilder.select.Select; -import com.datastax.oss.driver.api.querybuilder.truncate.Truncate; -import com.datastax.oss.driver.api.querybuilder.update.Update; - -/** - * Primary implementation of {@link AsyncCassandraOperations}. It simplifies the use of asynchronous Cassandra usage and - * helps to avoid common errors. It executes core Cassandra workflow. This class executes CQL queries or updates, - * initiating iteration over {@link ResultSet} and catching Cassandra exceptions and translating them to the generic, - * more informative exception hierarchy defined in the {@code org.springframework.dao} package. - *

- * Can be used within a service implementation via direct instantiation with a {@link CqlSession} reference, or get - * prepared in an application context and given to services as bean reference. - *

- * This class supports the use of prepared statements when enabling {@link #setUsePreparedStatements(boolean)}. All - * statements created by methods of this class (such as {@link #select(Query, Class)} or - * {@link #update(Query, org.springframework.data.cassandra.core.query.Update, Class)} will be executed as prepared - * statements. Also, statements accepted by methods (such as {@link #select(String, Class)} or - * {@link #select(Statement, Class) and others}) will be prepared prior to execution. Note that {@link Statement} - * objects passed to methods must be {@link SimpleStatement} so that these can be prepared. - *

- * Note: The {@link CqlSession} should always be configured as a bean in the application context, in the first case - * given to the service directly, in the second case to the prepared template. - * - * @author Mark Paluch - * @author John Blum - * @see org.springframework.data.cassandra.core.AsyncCassandraOperations - * @since 4.0 - * @deprecated since 4.0, use the {@link java.util.concurrent.CompletableFuture}-based variant - * {@link org.springframework.data.cassandra.core.AsyncCassandraTemplate}. - */ -@Deprecated(since = "4.0", forRemoval = true) -@SuppressWarnings("removal") -public class AsyncCassandraTemplate - implements AsyncCassandraOperations, ApplicationEventPublisherAware, ApplicationContextAware { - - private final Log log = LogFactory.getLog(getClass()); - - private final AsyncCqlOperations cqlOperations; - - private final CassandraConverter converter; - - private final CqlExceptionTranslator exceptionTranslator; - - private final EntityOperations entityOperations; - - private final StatementFactory statementFactory; - - private final EntityLifecycleEventDelegate eventDelegate; - - private @Nullable EntityCallbacks entityCallbacks; - - private boolean usePreparedStatements = true; - - /** - * Creates an instance of {@link AsyncCassandraTemplate} initialized with the given {@link CqlSession} and a default - * {@link MappingCassandraConverter}. - * - * @param session {@link CqlSession} used to interact with Cassandra; must not be {@literal null}. - * @see CassandraConverter - * @see CqlSession - */ - public AsyncCassandraTemplate(CqlSession session) { - this(session, newConverter(session)); - } - - /** - * Creates an instance of {@link AsyncCassandraTemplate} initialized with the given {@link CqlSession} and - * {@link CassandraConverter}. - * - * @param session {@link CqlSession} used to interact with Cassandra; must not be {@literal null}. - * @param converter {@link CassandraConverter} used to convert between Java and Cassandra types; must not be - * {@literal null}. - * @see CassandraConverter - * @see CqlSession - */ - public AsyncCassandraTemplate(CqlSession session, CassandraConverter converter) { - this(new DefaultSessionFactory(session), converter); - } - - /** - * Creates an instance of {@link AsyncCassandraTemplate} initialized with the given {@link SessionFactory} and - * {@link CassandraConverter}. - * - * @param sessionFactory {@link SessionFactory} used to interact with Cassandra; must not be {@literal null}. - * @param converter {@link CassandraConverter} used to convert between Java and Cassandra types; must not be - * {@literal null}. - * @see CassandraConverter - * @see CqlSession - */ - public AsyncCassandraTemplate(SessionFactory sessionFactory, CassandraConverter converter) { - this(new AsyncCqlTemplate(sessionFactory), converter); - } - - /** - * Creates an instance of {@link AsyncCassandraTemplate} initialized with the given {@link AsyncCqlTemplate} and - * {@link CassandraConverter}. - * - * @param asyncCqlTemplate {@link AsyncCqlTemplate} used to interact with Cassandra; must not be {@literal null}. - * @param converter {@link CassandraConverter} used to convert between Java and Cassandra types; must not be - * {@literal null}. - * @see CassandraConverter - * @see CqlSession - */ - public AsyncCassandraTemplate(AsyncCqlTemplate asyncCqlTemplate, CassandraConverter converter) { - - Assert.notNull(asyncCqlTemplate, "AsyncCqlTemplate must not be null"); - Assert.notNull(converter, "CassandraConverter must not be null"); - - this.converter = converter; - this.cqlOperations = asyncCqlTemplate; - this.entityOperations = new EntityOperations(converter); - this.exceptionTranslator = asyncCqlTemplate.getExceptionTranslator(); - this.statementFactory = new StatementFactory(converter); - this.eventDelegate = new EntityLifecycleEventDelegate(); - } - - @Override - public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { - this.eventDelegate.setPublisher(applicationEventPublisher); - } - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - - if (entityCallbacks == null) { - setEntityCallbacks(EntityCallbacks.create(applicationContext)); - } - } - - /** - * Configure {@link EntityCallbacks} to pre-/post-process entities during persistence operations. - * - * @param entityCallbacks - */ - public void setEntityCallbacks(@Nullable EntityCallbacks entityCallbacks) { - this.entityCallbacks = entityCallbacks; - } - - /** - * Configure whether lifecycle events such as {@link AfterLoadEvent}, {@link BeforeSaveEvent}, etc. should be - * published or whether emission should be suppressed. Enabled by default. - * - * @param enabled {@code true} to enable entity lifecycle events; {@code false} to disable entity lifecycle events. - * @since 4.0 - * @see CassandraMappingEvent - */ - public void setEntityLifecycleEventsEnabled(boolean enabled) { - this.eventDelegate.setEventsEnabled(enabled); - } - - @Override - public AsyncCqlOperations getAsyncCqlOperations() { - return this.cqlOperations; - } - - @Override - public CassandraConverter getConverter() { - return this.converter; - } - - /** - * Returns the {@link StatementFactory} used by this template to construct and run Cassandra CQL statements. - * - * @return the {@link StatementFactory} used by this template to construct and run Cassandra CQL statements. - * @see StatementFactory - * @since 2.1 - */ - public StatementFactory getStatementFactory() { - return this.statementFactory; - } - - /** - * Returns whether this instance is configured to use {@link PreparedStatement prepared statements}. If enabled - * (default), then all persistence methods (such as {@link #select}, {@link #update}, and others) will make use of - * prepared statements. Note that methods accepting a {@link Statement} must be called with {@link SimpleStatement} - * instances to participate in statement preparation. - * - * @return {@literal true} if prepared statements usage is enabled; {@literal false} otherwise. - * @since 3.2 - */ - public boolean isUsePreparedStatements() { - return usePreparedStatements; - } - - /** - * Enable/disable {@link PreparedStatement prepared statements} usage. If enabled (default), then all persistence - * methods (such as {@link #select}, {@link #update}, and others) will make use of prepared statements. Note that - * methods accepting a {@link Statement} must be called with {@link SimpleStatement} instances to participate in - * statement preparation. - * - * @param usePreparedStatements whether to use prepared statements. - * @since 3.2 - */ - public void setUsePreparedStatements(boolean usePreparedStatements) { - this.usePreparedStatements = usePreparedStatements; - } - - /** - * Returns the {@link EntityOperations} used to perform data access operations on an entity inside a Cassandra data - * source. - * - * @return the configured {@link EntityOperations} for this template. - * @see org.springframework.data.cassandra.core.EntityOperations - */ - protected EntityOperations getEntityOperations() { - return this.entityOperations; - } - - /** - * Returns a reference to the configured {@link ProjectionFactory} used by this template to process CQL query - * projections. - * - * @return a reference to the configured {@link ProjectionFactory} used by this template to process CQL query - * projections. - * @see org.springframework.data.projection.SpelAwareProxyProjectionFactory - * @since 2.1 - * @deprecated since 3.4, use {@link CassandraConverter#getProjectionFactory()} instead. - */ - @Deprecated - protected SpelAwareProxyProjectionFactory getProjectionFactory() { - return (SpelAwareProxyProjectionFactory) getConverter().getProjectionFactory(); - } - - private CassandraPersistentEntity getRequiredPersistentEntity(Class entityType) { - return getEntityOperations().getRequiredPersistentEntity(entityType); - } - - private CqlIdentifier getTableName(Class entityClass) { - return getEntityOperations().getTableName(entityClass); - } - - // ------------------------------------------------------------------------- - // Methods dealing with static CQL - // ------------------------------------------------------------------------- - - @Override - public ListenableFuture> select(String cql, Class entityClass) { - - Assert.hasText(cql, "CQL must not be empty"); - - return select(SimpleStatement.newInstance(cql), entityClass); - } - - @Override - public ListenableFuture select(String cql, Consumer entityConsumer, Class entityClass) - throws DataAccessException { - - Assert.hasText(cql, "CQL must not be empty"); - Assert.notNull(entityConsumer, "Entity Consumer must not be null"); - Assert.notNull(entityClass, "Entity type must not be null"); - - return select(SimpleStatement.newInstance(cql), entityConsumer, entityClass); - } - - @Override - public ListenableFuture selectOne(String cql, Class entityClass) { - - Assert.hasText(cql, "CQL must not be empty"); - Assert.notNull(entityClass, "Entity type must not be null"); - - return selectOne(SimpleStatement.newInstance(cql), entityClass); - } - - // ------------------------------------------------------------------------- - // Methods dealing with com.datastax.oss.driver.api.core.cql.Statement - // ------------------------------------------------------------------------- - - @Override - public ListenableFuture execute(Statement statement) throws DataAccessException { - - Assert.notNull(statement, "Statement must not be null"); - - return doQueryForResultSet(statement); - } - - @Override - public ListenableFuture> select(Statement statement, Class entityClass) { - - Assert.notNull(statement, "Statement must not be null"); - Assert.notNull(entityClass, "Entity type must not be null"); - - Function mapper = getMapper(entityClass, entityClass, EntityQueryUtils.getTableName(statement)); - - return doQuery(statement, (row, rowNum) -> mapper.apply(row)); - } - - @Override - public ListenableFuture select(Statement statement, Consumer entityConsumer, Class entityClass) - throws DataAccessException { - - Assert.notNull(statement, "Statement must not be null"); - Assert.notNull(entityConsumer, "Entity Consumer must not be empty"); - Assert.notNull(entityClass, "Entity type must not be null"); - - Function mapper = getMapper(entityClass, entityClass, EntityQueryUtils.getTableName(statement)); - - return doQuery(statement, row -> { - entityConsumer.accept(mapper.apply(row)); - }); - } - - @Override - public ListenableFuture selectOne(Statement statement, Class entityClass) { - return new MappingListenableFutureAdapter<>(select(statement, entityClass), - list -> list.isEmpty() ? null : list.get(0)); - } - - @Override - public ListenableFuture> slice(Statement statement, Class entityClass) { - - Assert.notNull(statement, "Statement must not be null"); - Assert.notNull(entityClass, "Entity type must not be null"); - - ListenableFuture resultSet = doQueryForResultSet(statement); - - Function mapper = getMapper(entityClass, entityClass, EntityQueryUtils.getTableName(statement)); - - return new MappingListenableFutureAdapter<>(resultSet, - rs -> EntityQueryUtils.readSlice(rs, (row, rowNum) -> mapper.apply(row), 0, getEffectivePageSize(statement))); - } - - // ------------------------------------------------------------------------- - // Methods dealing with org.springframework.data.cassandra.core.query.Query - // ------------------------------------------------------------------------- - - @Override - public ListenableFuture> select(Query query, Class entityClass) throws DataAccessException { - - Assert.notNull(query, "Query must not be null"); - Assert.notNull(entityClass, "Entity type must not be null"); - - return select(getStatementFactory().select(query, getRequiredPersistentEntity(entityClass)).build(), entityClass); - } - - @Override - public ListenableFuture select(Query query, Consumer entityConsumer, Class entityClass) - throws DataAccessException { - - Assert.notNull(query, "Query must not be null"); - Assert.notNull(entityConsumer, "Entity Consumer must not be empty"); - Assert.notNull(entityClass, "Entity type must not be null"); - - return select(getStatementFactory().select(query, getRequiredPersistentEntity(entityClass)).build(), entityConsumer, - entityClass); - } - - @Override - public ListenableFuture selectOne(Query query, Class entityClass) throws DataAccessException { - - Assert.notNull(query, "Query must not be null"); - Assert.notNull(entityClass, "Entity type must not be null"); - - return selectOne(getStatementFactory().select(query, getRequiredPersistentEntity(entityClass)).build(), - entityClass); - } - - @Override - public ListenableFuture> slice(Query query, Class entityClass) throws DataAccessException { - - Assert.notNull(query, "Query must not be null"); - Assert.notNull(entityClass, "Entity type must not be null"); - - return slice(getStatementFactory().select(query, getRequiredPersistentEntity(entityClass)).build(), entityClass); - } - - @Override - public ListenableFuture update(Query query, org.springframework.data.cassandra.core.query.Update update, - Class entityClass) throws DataAccessException { - - Assert.notNull(query, "Query must not be null"); - Assert.notNull(update, "Update must not be null"); - Assert.notNull(entityClass, "Entity type must not be null"); - - return doExecute(getStatementFactory().update(query, update, getRequiredPersistentEntity(entityClass)).build(), - AsyncResultSet::wasApplied); - } - - @Override - public ListenableFuture delete(Query query, Class entityClass) throws DataAccessException { - - Assert.notNull(query, "Query must not be null"); - Assert.notNull(entityClass, "Entity type must not be null"); - - return doDelete(query, entityClass, getTableName(entityClass)); - } - - private ListenableFuture doDelete(Query query, Class entityClass, CqlIdentifier tableName) { - - StatementBuilder builder = getStatementFactory().delete(query, getRequiredPersistentEntity(entityClass), - tableName); - SimpleStatement delete = builder.build(); - - maybeEmitEvent(() -> new BeforeDeleteEvent<>(delete, entityClass, tableName)); - - ListenableFuture future = doExecute(delete, AsyncResultSet::wasApplied); - - future.addCallback(success -> maybeEmitEvent(() -> new AfterDeleteEvent<>(delete, entityClass, tableName)), - e -> {}); - - return future; - } - - // ------------------------------------------------------------------------- - // Methods dealing with entities - // ------------------------------------------------------------------------- - - @Override - public ListenableFuture count(Class entityClass) { - - Assert.notNull(entityClass, "Entity type must not be null"); - - return doCount(Query.empty(), entityClass, getTableName(entityClass)); - } - - @Override - public ListenableFuture count(Query query, Class entityClass) throws DataAccessException { - - Assert.notNull(query, "Query must not be null"); - Assert.notNull(entityClass, "Entity type must not be null"); - - return doCount(query, entityClass, getTableName(entityClass)); - } - - ListenableFuture doCount(Query query, Class entityClass, CqlIdentifier tableName) { - - StatementBuilder countStatement = getStatementFactory() - .count(query, getRequiredPersistentEntity(entityClass), tableName); - - SimpleStatement statement = countStatement.build(); - - ListenableFuture result = doExecute(statement, it -> { - - SingleColumnRowMapper mapper = SingleColumnRowMapper.newInstance(Long.class); - - Row row = DataAccessUtils.nullableSingleResult(Streamable.of(it.currentPage()).toList()); - return mapper.mapRow(row, 0); - }); - - return new MappingListenableFutureAdapter<>(result, it -> it != null ? it : 0L); - } - - @Override - public ListenableFuture exists(Object id, Class entityClass) { - - Assert.notNull(id, "Id must not be null"); - Assert.notNull(entityClass, "Entity type must not be null"); - - CassandraPersistentEntity entity = getRequiredPersistentEntity(entityClass); - - StatementBuilder select = getStatementFactory() - .selectOneById(id, entity, entity.getTableName()); - - return doExecute(select.build(), resultSet -> resultSet.one() != null); - } - - @Override - public ListenableFuture exists(Query query, Class entityClass) throws DataAccessException { - - Assert.notNull(query, "Query must not be null"); - Assert.notNull(entityClass, "Entity type must not be null"); - - StatementBuilder select = getStatementFactory() - .select(query.limit(1), getRequiredPersistentEntity(entityClass), getTableName(entityClass)); - - return doExecute(select.build(), resultSet -> resultSet.one() != null); - } - - @Override - public ListenableFuture selectOneById(Object id, Class entityClass) { - - Assert.notNull(id, "Id must not be null"); - Assert.notNull(entityClass, "Entity type must not be null"); - - CassandraPersistentEntity entity = getRequiredPersistentEntity(entityClass); - CqlIdentifier tableName = entity.getTableName(); - StatementBuilder