diff --git a/src/main/java/org/springframework/data/redis/connection/FutureResult.java b/src/main/java/org/springframework/data/redis/connection/FutureResult.java index 0b52c22f6..aff993b52 100644 --- a/src/main/java/org/springframework/data/redis/connection/FutureResult.java +++ b/src/main/java/org/springframework/data/redis/connection/FutureResult.java @@ -26,7 +26,8 @@ import org.springframework.lang.Nullable; * @author Jennifer Hickey * @author Christoph Strobl * @author Mark Paluch - * @param The data type of the object that holds the future result (usually of type Future) + * @param The data type of the object that holds the future result (usually type of the + * {@link java.util.concurrent.Future} or response wrapper). */ public abstract class FutureResult { @@ -36,7 +37,7 @@ public abstract class FutureResult { private boolean status = false; @SuppressWarnings("rawtypes") // - protected @Nullable Converter converter; + protected Converter converter; /** * Create new {@link FutureResult} for given object actually holding the result itself. @@ -70,7 +71,6 @@ public abstract class FutureResult { * @param defaultConversionResult must not be {@literal null}. * @since 2.1 */ - @SuppressWarnings("rawtypes") public FutureResult(T resultHolder, @Nullable Converter converter, Supplier defaultConversionResult) { this.resultHolder = resultHolder; @@ -99,7 +99,7 @@ public abstract class FutureResult { public Object convert(@Nullable Object result) { if (result == null) { - return computeDefaultResult(result); + return computeDefaultResult(null); } return computeDefaultResult(converter.convert(result)); @@ -140,8 +140,8 @@ public abstract class FutureResult { /** * Indicate whether or not the actual result needs to be {@link #convert(Object) converted} before handing over. * - * @return + * @return {@literal true} if result conversion is required. * @since 2.1 */ - public abstract boolean seeksConversion(); + public abstract boolean conversionRequired(); } diff --git a/src/main/java/org/springframework/data/redis/connection/convert/TransactionResultConverter.java b/src/main/java/org/springframework/data/redis/connection/convert/TransactionResultConverter.java index 574e16106..efecb94d6 100644 --- a/src/main/java/org/springframework/data/redis/connection/convert/TransactionResultConverter.java +++ b/src/main/java/org/springframework/data/redis/connection/convert/TransactionResultConverter.java @@ -16,7 +16,6 @@ package org.springframework.data.redis.connection.convert; import java.util.ArrayList; -import java.util.LinkedList; import java.util.List; import java.util.Queue; @@ -31,13 +30,13 @@ import org.springframework.data.redis.connection.FutureResult; * * @author Jennifer Hickey * @author Christoph Strobl + * @author Mark Paluch * @param The type of {@link FutureResult} of the individual tx operations */ public class TransactionResultConverter implements Converter, List> { - private Queue> txResults = new LinkedList<>(); - - private Converter exceptionConverter; + private final Queue> txResults; + private final Converter exceptionConverter; public TransactionResultConverter(Queue> txResults, Converter exceptionConverter) { @@ -71,7 +70,7 @@ public class TransactionResultConverter implements Converter, Li : new RedisSystemException("Error reading future result.", source); } if (!(futureResult.isStatus())) { - convertedResults.add(futureResult.seeksConversion() ? futureResult.convert(result) : result); + convertedResults.add(futureResult.conversionRequired() ? futureResult.convert(result) : result); } } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java index 94bda731e..add3c4f32 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java @@ -389,7 +389,7 @@ public class JedisConnection extends AbstractRedisConnection { Object data = result.get(); if (!result.isStatus()) { - results.add(result.seeksConversion() ? result.convert(data) : data); + results.add(result.conversionRequired() ? result.convert(data) : data); } } catch (JedisDataException e) { DataAccessException dataAccessException = convertJedisAccessException(e); @@ -554,16 +554,16 @@ public class JedisConnection extends AbstractRedisConnection { return JedisResultBuilder.forResponse(response).build(); } - JedisResult newJedisResult(Response response, Converter converter) { + JedisResult newJedisResult(Response response, Converter converter) { - return JedisResultBuilder.forResponse(response).mappedWith(converter) + return JedisResultBuilder. forResponse(response).mappedWith(converter) .convertPipelineAndTxResults(convertPipelineAndTxResults).build(); } - JedisResult newJedisResult(Response response, Converter converter, Supplier defaultValue) { + JedisResult newJedisResult(Response response, Converter converter, Supplier defaultValue) { - return JedisResultBuilder.forResponse(response).mappedWith(converter) - .convertPipelineAndTxResults(convertPipelineAndTxResults).defaultNullTo(defaultValue).build(); + return JedisResultBuilder. forResponse(response).mappedWith(converter) + .convertPipelineAndTxResults(convertPipelineAndTxResults).mapNullTo(defaultValue).build(); } JedisStatusResult newStatusResult(Response response) { diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisResult.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisResult.java index 2f35f2f43..cc0d092cf 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisResult.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisResult.java @@ -30,21 +30,23 @@ import org.springframework.lang.Nullable; * @author Jennifer Hickey * @author Christoph Strobl * @author Mark Paluch + * @param The data type of the object that holds the future result (usually of type Future). + * @param The data type of the result type. * @since 2.1 */ -class JedisResult extends FutureResult> { +class JedisResult extends FutureResult> { private final boolean convertPipelineAndTxResults; - JedisResult(Response resultHolder) { + JedisResult(Response resultHolder) { this(resultHolder, false, null); } - JedisResult(Response resultHolder, boolean convertPipelineAndTxResults, @Nullable Converter converter) { - this(resultHolder, null, convertPipelineAndTxResults, converter); + JedisResult(Response resultHolder, boolean convertPipelineAndTxResults, @Nullable Converter converter) { + this(resultHolder, () -> null, convertPipelineAndTxResults, converter); } - JedisResult(Response resultHolder, Supplier defaultReturnValue, boolean convertPipelineAndTxResults, + JedisResult(Response resultHolder, Supplier defaultReturnValue, boolean convertPipelineAndTxResults, @Nullable Converter converter) { super(resultHolder, converter, defaultReturnValue); @@ -58,25 +60,26 @@ class JedisResult extends FutureResult> { */ @Nullable @Override + @SuppressWarnings("unchecked") public T get() { return (T) getResultHolder().get(); } /* * (non-Javadoc) - * @see org.springframework.data.redis.connection.FutureResult#seeksConversion() - * @return + * @see org.springframework.data.redis.connection.FutureResult#conversionRequired() */ - public boolean seeksConversion() { - return convertPipelineAndTxResults && converter != null; + public boolean conversionRequired() { + return convertPipelineAndTxResults; } /** * Jedis specific {@link FutureResult} implementation of a throw away status result. */ - static class JedisStatusResult extends JedisResult { + static class JedisStatusResult extends JedisResult { - JedisStatusResult(Response resultHolder, Converter converter) { + @SuppressWarnings("unchecked") + JedisStatusResult(Response resultHolder, Converter converter) { super(resultHolder, false, converter); setStatus(true); @@ -87,54 +90,77 @@ class JedisResult extends FutureResult> { * Builder for constructing {@link JedisResult}. * * @param - * @param + * @param * @since 2.1 */ - static class JedisResultBuilder { + static class JedisResultBuilder { private final Response response; - private Converter converter; + private Converter converter; private boolean convertPipelineAndTxResults = false; - private Supplier nullValueDefault = () -> null; + private Supplier nullValueDefault = () -> null; + @SuppressWarnings("unchecked") JedisResultBuilder(Response response) { this.response = response; - this.converter = (source) -> source; + this.converter = (source) -> (R) source; } - static JedisResultBuilder forResponse(Response response) { + /** + * Create a new {@link JedisResultBuilder} given {@link Response}. + * + * @param response must not be {@literal null}. + * @param native response type. + * @param resulting response type. + * @return the new {@link JedisResultBuilder}. + */ + static JedisResultBuilder forResponse(Response response) { return new JedisResultBuilder<>(response); } - JedisResultBuilder mappedWith(Converter converter) { + /** + * Configure a {@link Converter} to convert between {@code T} and {@code R} types. + * + * @param converter must not be {@literal null}. + * @return {@code this} builder. + */ + JedisResultBuilder mappedWith(Converter converter) { this.converter = converter; - return (JedisResultBuilder) this; + return this; } - JedisResultBuilder defaultNullTo(S value) { - return (defaultNullTo(() -> value)); + /** + * Configure a {@link Supplier} to map {@literal null} responses to a different value. + * + * @param supplier must not be {@literal null}. + * @return {@code this} builder. + */ + JedisResultBuilder mapNullTo(Supplier supplier) { + + this.nullValueDefault = supplier; + return this; } - JedisResultBuilder defaultNullTo(Supplier value) { - - this.nullValueDefault = value; - return (JedisResultBuilder) this; - } - - JedisResultBuilder convertPipelineAndTxResults(boolean flag) { + JedisResultBuilder convertPipelineAndTxResults(boolean flag) { convertPipelineAndTxResults = flag; return this; } - JedisResult build() { - return new JedisResult(response, nullValueDefault, convertPipelineAndTxResults, converter); + /** + * @return a new {@link JedisResult} wrapper with configuration applied from this builder. + */ + JedisResult build() { + return new JedisResult<>(response, nullValueDefault, convertPipelineAndTxResults, converter); } + /** + * @return a new {@link JedisStatusResult} wrapper for status results with configuration applied from this builder. + */ JedisStatusResult buildStatusResult() { - return new JedisStatusResult(response, converter); + return new JedisStatusResult<>(response, converter); } } } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java index a16257237..ab5d7ed2c 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java @@ -66,9 +66,6 @@ import org.springframework.data.redis.connection.*; import org.springframework.data.redis.connection.convert.TransactionResultConverter; import org.springframework.data.redis.connection.lettuce.LettuceConnectionProvider.TargetAware; import org.springframework.data.redis.connection.lettuce.LettuceResult.LettuceResultBuilder; -import org.springframework.data.redis.connection.lettuce.LettuceResult.LettuceStatusResult; -import org.springframework.data.redis.connection.lettuce.LettuceResult.LettuceTxResult; -import org.springframework.data.redis.connection.lettuce.LettuceResult.LettuceTxStatusResult; import org.springframework.data.redis.core.RedisCommand; import org.springframework.data.redis.core.ScanOptions; import org.springframework.lang.Nullable; @@ -119,35 +116,41 @@ public class LettuceConnection extends AbstractRedisConnection { return newLettuceResult(resultHolder, (val) -> val); } - LettuceResult newLettuceResult(Future resultHolder, Converter converter) { + @SuppressWarnings("unchecked") + LettuceResult newLettuceResult(Future resultHolder, Converter converter) { - return LettuceResultBuilder.forResponse(resultHolder).mappedWith(converter) + return LettuceResultBuilder.forResponse(resultHolder).mappedWith((Converter) converter) .convertPipelineAndTxResults(convertPipelineAndTxResults).build(); } - LettuceResult newLettuceResult(Future resultHolder, Converter converter, Supplier defaultValue) { + @SuppressWarnings("unchecked") + LettuceResult newLettuceResult(Future resultHolder, Converter converter, + Supplier defaultValue) { - return LettuceResultBuilder.forResponse(resultHolder).mappedWith(converter) + return LettuceResultBuilder.forResponse(resultHolder).mappedWith((Converter) converter) .convertPipelineAndTxResults(convertPipelineAndTxResults).defaultNullTo(defaultValue).build(); } - LettuceStatusResult newLettuceStatusResult(Future resultHolder) { - return new LettuceStatusResult(resultHolder); + LettuceResult newLettuceStatusResult(Future resultHolder) { + return LettuceResultBuilder. forResponse(resultHolder).buildStatusResult(); } - LettuceTxResult newLettuceTxResult(Object resultHolder) { + LettuceTxResult newLettuceTxResult(T resultHolder) { return newLettuceTxResult(resultHolder, (val) -> val); } - LettuceTxResult newLettuceTxResult(Object resultHolder, Converter converter) { + @SuppressWarnings("unchecked") + LettuceTxResult newLettuceTxResult(T resultHolder, Converter converter) { - return LettuceResultBuilder.forResponse(resultHolder).mappedWith(converter) + return LettuceResultBuilder.forResponse(resultHolder).mappedWith((Converter) converter) .convertPipelineAndTxResults(convertPipelineAndTxResults).buildTxResult(); } - LettuceTxResult newLettuceTxResult(Object resultHolder, Converter converter, Supplier defaultValue) { + @SuppressWarnings("unchecked") + LettuceTxResult newLettuceTxResult(T resultHolder, Converter converter, + Supplier defaultValue) { - return LettuceResultBuilder.forResponse(resultHolder).mappedWith(converter) + return LettuceResultBuilder.forResponse(resultHolder).mappedWith((Converter) converter) .convertPipelineAndTxResults(convertPipelineAndTxResults).defaultNullTo(defaultValue).buildTxResult(); } @@ -397,6 +400,7 @@ public class LettuceConnection extends AbstractRedisConnection { Assert.hasText(command, "a valid command needs to be specified"); try { + String name = command.trim().toUpperCase(); CommandType commandType = CommandType.valueOf(name); @@ -412,17 +416,20 @@ public class LettuceConnection extends AbstractRedisConnection { CommandOutput expectedOutput = commandOutputTypeHint != null ? commandOutputTypeHint : typeHints.getTypeHint(commandType); Command cmd = new Command(commandType, expectedOutput, cmdArg); + if (isPipelined()) { pipeline(newLettuceResult(connectionImpl.dispatch(cmd.getType(), cmd.getOutput(), cmd.getArgs()))); return null; - } else if (isQueueing()) { + } + + if (isQueueing()) { transaction(newLettuceTxResult(connectionImpl.dispatch(cmd.getType(), cmd.getOutput(), cmd.getArgs()))); return null; - } else { - return await(connectionImpl.dispatch(cmd.getType(), cmd.getOutput(), cmd.getArgs())); } + + return await(connectionImpl.dispatch(cmd.getType(), cmd.getOutput(), cmd.getArgs())); } catch (RedisException ex) { throw convertLettuceAccessException(ex); } @@ -488,61 +495,62 @@ public class LettuceConnection extends AbstractRedisConnection { @Override public List closePipeline() { - if (isPipelined) { - isPipelined = false; - List> futures = new ArrayList<>(); - for (LettuceResult result : ppline) { - futures.add(result.getResultHolder()); - } + if (!isPipelined) { - try { - boolean done = LettuceFutures.awaitAll(timeout, TimeUnit.MILLISECONDS, - futures.toArray(new RedisFuture[futures.size()])); + return Collections.emptyList(); + } + isPipelined = false; + List> futures = new ArrayList<>(ppline.size()); + for (LettuceResult result : ppline) { + futures.add(result.getResultHolder()); + } - List results = new ArrayList<>(futures.size()); + try { + boolean done = LettuceFutures.awaitAll(timeout, TimeUnit.MILLISECONDS, + futures.toArray(new RedisFuture[futures.size()])); - Exception problem = null; + List results = new ArrayList<>(futures.size()); - if (done) { - for (LettuceResult result : ppline) { + Exception problem = null; - if (result.getResultHolder().getOutput().hasError()) { + if (done) { + for (LettuceResult result : ppline) { - Exception err = new InvalidDataAccessApiUsageException(result.getResultHolder().getOutput().getError()); - // remember only the first error + if (result.getResultHolder().getOutput().hasError()) { + + Exception err = new InvalidDataAccessApiUsageException(result.getResultHolder().getOutput().getError()); + // remember only the first error + if (problem == null) { + problem = err; + } + results.add(err); + } else if (!result.isStatus()) { + + try { + results.add(result.conversionRequired() ? result.convert(result.get()) : result.get()); + } catch (DataAccessException e) { if (problem == null) { - problem = err; - } - results.add(err); - } else if (!result.isStatus()) { - - try { - results.add(result.seeksConversion() ? result.convert(result.get()) : result.get()); - } catch (DataAccessException e) { - if (problem == null) { - problem = e; - } - results.add(e); + problem = e; } + results.add(e); } } } - ppline.clear(); - - if (problem != null) { - throw new RedisPipelineException(problem, results); - } - if (done) { - return results; - } - - throw new RedisPipelineException(new QueryTimeoutException("Redis command timed out")); - } catch (Exception e) { - throw new RedisPipelineException(e); } - } + ppline.clear(); - return Collections.emptyList(); + if (problem != null) { + throw new RedisPipelineException(problem, results); + } + + if (done) { + return results; + } + + throw new RedisPipelineException(new QueryTimeoutException("Redis command timed out")); + } catch (Exception e) { + throw new RedisPipelineException(e); + } } /* @@ -558,7 +566,7 @@ public class LettuceConnection extends AbstractRedisConnection { return null; } if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().echo(message))); + transaction(new LettuceTxResult<>(getConnection().echo(message))); return null; } return getConnection().echo(message); @@ -575,7 +583,7 @@ public class LettuceConnection extends AbstractRedisConnection { return null; } if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().ping())); + transaction(new LettuceTxResult<>(getConnection().ping())); return null; } return getConnection().ping(); @@ -589,10 +597,10 @@ public class LettuceConnection extends AbstractRedisConnection { isMulti = false; try { if (isPipelined()) { - pipeline(new LettuceStatusResult(((RedisAsyncCommands) getAsyncDedicatedConnection()).discard())); + pipeline(newLettuceStatusResult(getAsyncDedicatedRedisCommands().discard())); return; } - ((RedisCommands) getDedicatedConnection()).discard(); + getDedicatedRedisCommands().discard(); } catch (Exception ex) { throw convertLettuceAccessException(ex); } finally { @@ -608,7 +616,7 @@ public class LettuceConnection extends AbstractRedisConnection { try { if (isPipelined()) { - RedisFuture exec = ((RedisAsyncCommands) getAsyncDedicatedConnection()).exec(); + RedisFuture exec = getAsyncDedicatedRedisCommands().exec(); LettuceTransactionResultConverter resultConverter = new LettuceTransactionResultConverter( new LinkedList<>(txResults), LettuceConverters.exceptionConverter()); @@ -618,7 +626,7 @@ public class LettuceConnection extends AbstractRedisConnection { return null; } - TransactionResult transactionResult = ((RedisCommands) getDedicatedConnection()).exec(); + TransactionResult transactionResult = (getDedicatedRedisCommands()).exec(); List results = LettuceConverters.transactionResultUnwrapper().convert(transactionResult); return convertPipelineAndTxResults ? new LettuceTransactionResultConverter(txResults, LettuceConverters.exceptionConverter()).convert(results) @@ -641,7 +649,7 @@ public class LettuceConnection extends AbstractRedisConnection { ((RedisAsyncCommands) getAsyncDedicatedConnection()).multi(); return; } - ((RedisCommands) getDedicatedConnection()).multi(); + (getDedicatedRedisCommands()).multi(); } catch (Exception ex) { throw convertLettuceAccessException(ex); } @@ -661,7 +669,7 @@ public class LettuceConnection extends AbstractRedisConnection { this.dbIndex = dbIndex; if (isQueueing()) { - transaction(new LettuceTxStatusResult(((RedisCommands) getAsyncConnection()).select(dbIndex))); + transaction(newLettuceStatusResult(((RedisCommands)getAsyncConnection()).select(dbIndex))); return; } ((RedisCommands) getConnection()).select(dbIndex); @@ -674,14 +682,14 @@ public class LettuceConnection extends AbstractRedisConnection { public void unwatch() { try { if (isPipelined()) { - pipeline(new LettuceStatusResult(((RedisAsyncCommands) getAsyncDedicatedConnection()).unwatch())); + pipeline(newLettuceStatusResult(((RedisAsyncCommands) getAsyncDedicatedConnection()).unwatch())); return; } if (isQueueing()) { - transaction(new LettuceTxStatusResult(((RedisAsyncCommands) getDedicatedConnection()).unwatch())); + transaction(newLettuceStatusResult(getDedicatedRedisCommands().unwatch())); return; } - ((RedisCommands) getDedicatedConnection()).unwatch(); + getDedicatedRedisCommands().unwatch(); } catch (Exception ex) { throw convertLettuceAccessException(ex); } @@ -694,14 +702,14 @@ public class LettuceConnection extends AbstractRedisConnection { } try { if (isPipelined()) { - pipeline(new LettuceStatusResult(((RedisAsyncCommands) getAsyncDedicatedConnection()).watch((Object[]) keys))); + pipeline(newLettuceStatusResult(getAsyncDedicatedRedisCommands().watch(keys))); return; } if (isQueueing()) { - transaction(new LettuceTxStatusResult(((RedisAsyncCommands) getDedicatedConnection()).watch((Object[]) keys))); + transaction(new LettuceTxStatusResult(getDedicatedRedisCommands().watch(keys))); return; } - ((RedisCommands) getDedicatedConnection()).watch((Object[]) keys); + getDedicatedRedisCommands().watch(keys); } catch (Exception ex) { throw convertLettuceAccessException(ex); } @@ -854,6 +862,11 @@ public class LettuceConnection extends AbstractRedisConnection { return getDedicatedConnection(); } + @SuppressWarnings("unchecked") + private RedisAsyncCommands getAsyncDedicatedRedisCommands() { + return (RedisAsyncCommands) getAsyncDedicatedConnection(); + } + protected RedisClusterAsyncCommands getAsyncDedicatedConnection() { if (asyncDedicatedConn == null) { @@ -876,6 +889,11 @@ public class LettuceConnection extends AbstractRedisConnection { String.format("%s is not a supported connection type.", asyncDedicatedConn.getClass().getName())); } + @SuppressWarnings("unchecked") + private RedisCommands getDedicatedRedisCommands() { + return (RedisCommands) getDedicatedConnection(); + } + RedisClusterCommands getDedicatedConnection() { if (asyncDedicatedConn == null) { @@ -898,6 +916,7 @@ public class LettuceConnection extends AbstractRedisConnection { String.format("%s is not a supported connection type.", asyncDedicatedConn.getClass().getName())); } + @SuppressWarnings("unchecked") protected StatefulConnection doGetAsyncDedicatedConnection() { return connectionProvider.getConnection(StatefulConnection.class); } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceKeyCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceKeyCommands.java index fb3a90cb5..674ae9f16 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceKeyCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceKeyCommands.java @@ -66,7 +66,7 @@ class LettuceKeyCommands implements RedisKeyCommands { return null; } if (isQueueing()) { - transaction(connection.newLettuceTxResult(getAsyncConnection().exists(new byte[][] { key }), + transaction(connection.newLettuceTxResult(getConnection().exists(new byte[][] { key }), LettuceConverters.longToBooleanConverter())); return null; } @@ -93,7 +93,7 @@ class LettuceKeyCommands implements RedisKeyCommands { return null; } if (isQueueing()) { - transaction(connection.newLettuceTxResult(getAsyncConnection().exists(keys))); + transaction(connection.newLettuceTxResult(getConnection().exists(keys))); return null; } return getConnection().exists(keys); diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceResult.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceResult.java index 3bdea5a11..4e175d7a4 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceResult.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceResult.java @@ -34,19 +34,20 @@ import org.springframework.lang.Nullable; * @since 2.1 */ @SuppressWarnings("rawtypes") -class LettuceResult extends FutureResult> { +class LettuceResult extends FutureResult> { private final boolean convertPipelineAndTxResults; - LettuceResult(Future resultHolder) { + LettuceResult(Future resultHolder) { this(resultHolder, false, val -> val); } - LettuceResult(Future resultHolder, boolean convertPipelineAndTxResults, @Nullable Converter converter) { + LettuceResult(Future resultHolder, boolean convertPipelineAndTxResults, @Nullable Converter converter) { this(resultHolder, () -> null, convertPipelineAndTxResults, converter); } - LettuceResult(Future resultHolder, Supplier defaultReturnValue, boolean convertPipelineAndTxResults, + @SuppressWarnings("unchecked") + LettuceResult(Future resultHolder, Supplier defaultReturnValue, boolean convertPipelineAndTxResults, @Nullable Converter converter) { super((RedisCommand) resultHolder, converter, defaultReturnValue); @@ -56,59 +57,52 @@ class LettuceResult extends FutureResult> { /* * (non-Javadoc) * @see org.springframework.data.redis.connection.FutureResult#get() - * @return */ @Nullable - @SuppressWarnings("unchecked") @Override + @SuppressWarnings("unchecked") public T get() { return (T) getResultHolder().getOutput().get(); } /* * (non-Javadoc) - * @see org.springframework.data.redis.connection.FutureResult#seeksConversion() - * @return + * @see org.springframework.data.redis.connection.FutureResult#conversionRequired() */ @Override - public boolean seeksConversion() { - return convertPipelineAndTxResults && converter != null; + public boolean conversionRequired() { + return convertPipelineAndTxResults; } /** * Lettuce specific {@link FutureResult} implementation of a throw away status result. */ - static class LettuceStatusResult extends LettuceResult { + static class LettuceStatusResult extends LettuceResult { - @SuppressWarnings("rawtypes") - LettuceStatusResult(Future resultHolder) { + @SuppressWarnings("unchecked") + LettuceStatusResult(Future resultHolder) { super(resultHolder); setStatus(true); } - - LettuceStatusResult(Future resultHolder, boolean convertPipelineAndTxResults, Converter converter) { - super(resultHolder, convertPipelineAndTxResults, converter); - setStatus(true); - } } /** * Lettuce specific {@link FutureResult} implementation of a transaction result. */ - static class LettuceTxResult extends FutureResult { + static class LettuceTxResult extends FutureResult { private final boolean convertPipelineAndTxResults; LettuceTxResult(T resultHolder) { - this(resultHolder, false, val -> val); + this(resultHolder, false, val -> (R) val); } - LettuceTxResult(T resultHolder, boolean convertPipelineAndTxResults, Converter converter) { + LettuceTxResult(T resultHolder, boolean convertPipelineAndTxResults, Converter converter) { this(resultHolder, () -> null, convertPipelineAndTxResults, converter); } LettuceTxResult(T resultHolder, Supplier defaultReturnValue, boolean convertPipelineAndTxResults, - Converter converter) { + Converter converter) { super(resultHolder, converter, defaultReturnValue); this.convertPipelineAndTxResults = convertPipelineAndTxResults; } @@ -121,15 +115,14 @@ class LettuceResult extends FutureResult> { @Override public boolean seeksConversion() { - return convertPipelineAndTxResults && converter != null; + return convertPipelineAndTxResults; } - } /** * Lettuce specific {@link FutureResult} implementation of a throw away status result. */ - static class LettuceTxStatusResult extends LettuceTxResult { + static class LettuceTxStatusResult extends LettuceTxResult { LettuceTxStatusResult(Object resultHolder) { super(resultHolder); @@ -141,63 +134,76 @@ class LettuceResult extends FutureResult> { * Builder for constructing {@link LettuceResult}. * * @param - * @param + * @param * @since 2.1 */ - static class LettuceResultBuilder { + static class LettuceResultBuilder { - private final Object response; - private Converter converter; + private final Future response; + private Converter converter; private boolean convertPipelineAndTxResults = false; - private Supplier nullValueDefault = () -> null; + private Supplier nullValueDefault = () -> null; - LettuceResultBuilder(Object response) { + LettuceResultBuilder(Future response) { this.response = response; - this.converter = (source) -> source; + this.converter = (source) -> (R) source; } - static LettuceResultBuilder forResponse(Future response) { + /** + * Create a new {@link LettuceResultBuilder} given {@link Future}. + * + * @param response must not be {@literal null}. + * @param native response type. + * @param resulting response type. + * @return the new {@link LettuceResultBuilder}. + */ + static LettuceResultBuilder forResponse(Future response) { return new LettuceResultBuilder<>(response); } - static LettuceResultBuilder forResponse(T response) { - return new LettuceResultBuilder<>(response); - } - - LettuceResultBuilder mappedWith(Converter converter) { + /** + * Configure a {@link Converter} to convert between {@code T} and {@code R} types. + * + * @param converter must not be {@literal null}. + * @return {@code this} builder. + */ + LettuceResultBuilder mappedWith(Converter converter) { this.converter = converter; - return (LettuceResultBuilder) this; + return (LettuceResultBuilder) this; } - LettuceResultBuilder defaultNullTo(S value) { - return (defaultNullTo(() -> value)); + /** + * Configure a {@link Supplier} to map {@literal null} responses to a different value. + * + * @param supplier must not be {@literal null}. + * @return {@code this} builder. + */ + LettuceResultBuilder defaultNullTo(Supplier supplier) { + + this.nullValueDefault = supplier; + return this; } - LettuceResultBuilder defaultNullTo(Supplier value) { - - this.nullValueDefault = value; - return (LettuceResultBuilder) this; - } - - LettuceResultBuilder convertPipelineAndTxResults(boolean flag) { + LettuceResultBuilder convertPipelineAndTxResults(boolean flag) { convertPipelineAndTxResults = flag; return this; } - LettuceResult build() { - return new LettuceResult((Future) response, nullValueDefault, convertPipelineAndTxResults, converter); + /** + * @return a new {@link LettuceResult} wrapper with configuration applied from this builder. + */ + LettuceResult build() { + return new LettuceResult<>(response, nullValueDefault, convertPipelineAndTxResults, converter); } - LettuceTxResult buildTxResult() { - - return new LettuceTxResult(response, nullValueDefault, convertPipelineAndTxResults, converter); - } - - LettuceResult buildStatusResult() { - return new LettuceStatusResult((Future) response); + /** + * @return a new {@link LettuceResult} wrapper for status results with configuration applied from this builder. + */ + LettuceResult buildStatusResult() { + return new LettuceStatusResult<>(response); } } } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceServerCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceServerCommands.java index 92a6cd27a..31e5352c4 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceServerCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceServerCommands.java @@ -453,7 +453,7 @@ class LettuceServerCommands implements RedisServerCommands { throw new UnsupportedOperationException("Cannot be called in pipeline mode."); } if (isQueueing()) { - transaction(connection.newLettuceTxResult(getAsyncConnection().clientList(), + transaction(connection.newLettuceTxResult(getConnection().clientList(), LettuceConverters.stringToRedisClientListConverter())); return null; } @@ -551,11 +551,11 @@ class LettuceServerCommands implements RedisServerCommands { return connection.isQueueing(); } - private void pipeline(LettuceResult result) { + private void pipeline(LettuceResult result) { connection.pipeline(result); } - private void transaction(LettuceTxResult result) { + private void transaction(LettuceTxResult result) { connection.transaction(result); }