diff --git a/Jenkinsfile b/Jenkinsfile index a4820853f1..b95fd94e19 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -9,7 +9,7 @@ pipeline { triggers { pollSCM 'H/10 * * * *' - upstream(upstreamProjects: "spring-data-keyvalue/main", threshold: hudson.model.Result.SUCCESS) + upstream(upstreamProjects: "spring-data-keyvalue/4.0.x", threshold: hudson.model.Result.SUCCESS) } options { diff --git a/pom.xml b/pom.xml index d5df70171f..af617ef8f0 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> - <version>3.5.0-SNAPSHOT</version> + <version>4.0.0-SNAPSHOT</version> <name>Spring Data Redis</name> <description>Spring Data module for Redis</description> @@ -14,13 +14,12 @@ <parent> <groupId>org.springframework.data.build</groupId> <artifactId>spring-data-parent</artifactId> - <version>3.5.0-SNAPSHOT</version> + <version>4.0.0-SNAPSHOT</version> </parent> <properties> - <springdata.keyvalue>3.5.0-SNAPSHOT</springdata.keyvalue> - <springdata.commons>3.5.0-SNAPSHOT</springdata.commons> - <awaitility>4.0.2</awaitility> + <springdata.keyvalue>4.0.0-SNAPSHOT</springdata.keyvalue> + <springdata.commons>4.0.0-SNAPSHOT</springdata.commons> <beanutils>1.9.4</beanutils> <xstream>1.4.21</xstream> <pool>2.11.1</pool> diff --git a/src/main/antora/modules/ROOT/pages/observability.adoc b/src/main/antora/modules/ROOT/pages/observability.adoc index e3a43ae122..a663d514fa 100644 --- a/src/main/antora/modules/ROOT/pages/observability.adoc +++ b/src/main/antora/modules/ROOT/pages/observability.adoc @@ -2,7 +2,7 @@ = Observability Getting insights from an application component about its operations, timing and relation to application code is crucial to understand latency. -Spring Data Redis ships with a Micrometer integration through the Lettuce driver to collect observations during Redis interaction. +Lettuce ships with a Micrometer integration to collect observations during Redis interaction. Once the integration is set up, Micrometer will create meters and spans (for distributed tracing) for each Redis command. To enable the integration, apply the following configuration to `LettuceClientConfiguration`: @@ -16,7 +16,7 @@ class ObservabilityConfiguration { public ClientResources clientResources(ObservationRegistry observationRegistry) { return ClientResources.builder() - .tracing(new MicrometerTracingAdapter(observationRegistry, "my-redis-cache")) + .tracing(new MicrometerTracing(observationRegistry, "my-redis-cache")) .build(); } @@ -31,77 +31,7 @@ class ObservabilityConfiguration { } ---- -See also https://opentelemetry.io/docs/reference/specification/trace/semantic_conventions/database/#redis[OpenTelemetry Semantic Conventions] for further reference. +See also for further reference: +* https://redis.github.io/lettuce/advanced-usage/#micrometer[Lettuce Tracing] +* https://opentelemetry.io/docs/reference/specification/trace/semantic_conventions/database/#redis[OpenTelemetry Semantic Conventions] . -[[observability-metrics]] -== Observability - Metrics - -Below you can find a list of all metrics declared by this project. - -[[observability-metrics-redis-command-observation]] -== Redis Command Observation - -____ -Timer created around a Redis command execution. -____ - -**Metric name** `spring.data.redis`. **Type** `timer` and **base unit** `seconds`. - -Fully qualified name of the enclosing class `org.springframework.data.redis.connection.lettuce.observability.RedisObservation`. - - - -.Low cardinality Keys -[cols="a,a"] -|=== -|Name | Description -|`db.operation`|Redis command value. -|`db.redis.database_index`|Redis database index. -|`db.system`|Database system. -|`db.user`|Redis user. -|`net.peer.name`|Name of the database host. -|`net.peer.port`|Logical remote port number. -|`net.sock.peer.addr`|Mongo peer address. -|`net.sock.peer.port`|Mongo peer port. -|`net.transport`|Network transport. -|=== - -.High cardinality Keys -[cols="a,a"] -|=== -|Name | Description -|`db.statement`|Redis statement. -|`spring.data.redis.command.error`|Redis error response. -|=== - -[[observability-spans]] -== Observability - Spans - -Below you can find a list of all spans declared by this project. - -[[observability-spans-redis-command-observation]] -== Redis Command Observation Span - -> Timer created around a Redis command execution. - -**Span name** `spring.data.redis`. - -Fully qualified name of the enclosing class `org.springframework.data.redis.connection.lettuce.observability.RedisObservation`. - - - -.Tag Keys -|=== -|Name | Description -|`db.operation`|Redis command value. -|`db.redis.database_index`|Redis database index. -|`db.statement`|Redis statement. -|`db.system`|Database system. -|`db.user`|Redis user. -|`net.peer.name`|Name of the database host. -|`net.peer.port`|Logical remote port number. -|`net.sock.peer.addr`|Mongo peer address. -|`net.sock.peer.port`|Mongo peer port. -|`net.transport`|Network transport. -|`spring.data.redis.command.error`|Redis error response. -|=== diff --git a/src/main/antora/modules/ROOT/pages/redis/pubsub.adoc b/src/main/antora/modules/ROOT/pages/redis/pubsub.adoc index 6539ca127c..031425a4ed 100644 --- a/src/main/antora/modules/ROOT/pages/redis/pubsub.adoc +++ b/src/main/antora/modules/ROOT/pages/redis/pubsub.adoc @@ -162,7 +162,7 @@ XML:: ---- ====== -NOTE: The listener topic can be either a channel (for example, `topic="chatroom"`) or a pattern (for example, `topic="*room"`) +NOTE: The listener topic can be either a channel (for example, `topic="chatroom"` respective `Topic.channel("chatroom")`) or a pattern (for example, `topic="*room"` respective `Topic.pattern("*room")`). The preceding example uses the Redis namespace to declare the message listener container and automatically register the POJOs as listeners. The full-blown beans definition follows: diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/observability/DefaultLettuceObservationConvention.java b/src/main/java/org/springframework/data/redis/connection/lettuce/observability/DefaultLettuceObservationConvention.java deleted file mode 100644 index ca4fdc65e5..0000000000 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/observability/DefaultLettuceObservationConvention.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2022-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.redis.connection.lettuce.observability; - -import io.lettuce.core.protocol.RedisCommand; -import io.lettuce.core.tracing.Tracing.Endpoint; -import io.micrometer.common.KeyValues; - -import java.net.InetSocketAddress; -import java.util.Locale; - -import org.springframework.data.redis.connection.lettuce.observability.RedisObservation.HighCardinalityCommandKeyNames; -import org.springframework.data.redis.connection.lettuce.observability.RedisObservation.LowCardinalityCommandKeyNames; - -/** - * Default {@link LettuceObservationConvention} implementation. - * - * @author Mark Paluch - * @since 3.0 - * @deprecated since 3.4 for removal with the next major revision. Use Lettuce's Micrometer integration through - * {@link io.lettuce.core.tracing.MicrometerTracing}. - */ -@Deprecated(since = "3.4", forRemoval = true) -record DefaultLettuceObservationConvention( - boolean includeCommandArgsInSpanTags) implements LettuceObservationConvention { - - @Override - public KeyValues getLowCardinalityKeyValues(LettuceObservationContext context) { - - Endpoint ep = context.getRequiredEndpoint(); - KeyValues keyValues = KeyValues.of(LowCardinalityCommandKeyNames.DATABASE_SYSTEM.withValue("redis"), // - LowCardinalityCommandKeyNames.REDIS_COMMAND.withValue(context.getRequiredCommand().getType().toString())); - - if (ep instanceof SocketAddressEndpoint endpoint) { - - if (endpoint.socketAddress() instanceof InetSocketAddress inet) { - keyValues = keyValues - .and(KeyValues.of(LowCardinalityCommandKeyNames.NET_SOCK_PEER_ADDR.withValue(inet.getHostString()), - LowCardinalityCommandKeyNames.NET_SOCK_PEER_PORT.withValue("" + inet.getPort()), - LowCardinalityCommandKeyNames.NET_TRANSPORT.withValue("IP.TCP"))); - } else { - keyValues = keyValues - .and(KeyValues.of(LowCardinalityCommandKeyNames.NET_PEER_NAME.withValue(endpoint.toString()), - LowCardinalityCommandKeyNames.NET_TRANSPORT.withValue("Unix"))); - } - } - - return keyValues; - } - - @Override - public KeyValues getHighCardinalityKeyValues(LettuceObservationContext context) { - - RedisCommand<?, ?, ?> command = context.getRequiredCommand(); - - if (includeCommandArgsInSpanTags) { - - if (command.getArgs() != null) { - return KeyValues.of(HighCardinalityCommandKeyNames.STATEMENT - .withValue(command.getType().toString() + " " + command.getArgs().toCommandString())); - } - } - - return KeyValues.empty(); - } - - @Override - public String getContextualName(LettuceObservationContext context) { - return context.getRequiredCommand().getType().toString().toLowerCase(Locale.ROOT); - } -} diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/observability/LettuceObservationContext.java b/src/main/java/org/springframework/data/redis/connection/lettuce/observability/LettuceObservationContext.java deleted file mode 100644 index eb1321f511..0000000000 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/observability/LettuceObservationContext.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2022-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.redis.connection.lettuce.observability; - -import io.lettuce.core.protocol.RedisCommand; -import io.lettuce.core.tracing.Tracing.Endpoint; -import io.micrometer.observation.Observation; -import io.micrometer.observation.transport.Kind; -import io.micrometer.observation.transport.SenderContext; - -import org.springframework.lang.Nullable; - -/** - * Micrometer {@link Observation.Context} holding Lettuce contextual details. - * - * @author Mark Paluch - * @since 3.0 - * @deprecated since 3.4 for removal with the next major revision. Use Lettuce's Micrometer integration through - * {@link io.lettuce.core.tracing.MicrometerTracing}. - */ -@Deprecated(since = "3.4", forRemoval = true) -public class LettuceObservationContext extends SenderContext<Object> { - - private volatile @Nullable RedisCommand<?, ?, ?> command; - - private volatile @Nullable Endpoint endpoint; - - public LettuceObservationContext(String serviceName) { - super((carrier, key, value) -> {}, Kind.CLIENT); - setRemoteServiceName(serviceName); - } - - public RedisCommand<?, ?, ?> getRequiredCommand() { - - RedisCommand<?, ?, ?> local = command; - - if (local == null) { - throw new IllegalArgumentException("LettuceObservationContext is not associated with a Command"); - } - - return local; - } - - public void setCommand(RedisCommand<?, ?, ?> command) { - this.command = command; - } - - public Endpoint getRequiredEndpoint() { - - Endpoint local = endpoint; - - if (local == null) { - throw new IllegalArgumentException("LettuceObservationContext is not associated with a Endpoint"); - } - - return local; - } - - public void setEndpoint(Endpoint endpoint) { - this.endpoint = endpoint; - } -} diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/observability/LettuceObservationConvention.java b/src/main/java/org/springframework/data/redis/connection/lettuce/observability/LettuceObservationConvention.java deleted file mode 100644 index ea01647152..0000000000 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/observability/LettuceObservationConvention.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2022-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.redis.connection.lettuce.observability; - -import io.micrometer.observation.Observation; -import io.micrometer.observation.ObservationConvention; - -/** - * {@link ObservationConvention} for {@link LettuceObservationContext}. - * - * @author Mark Paluch - * @since 3.0 - * @deprecated since 3.4 for removal with the next major revision. Use Lettuce's Micrometer integration through - * {@link io.lettuce.core.tracing.MicrometerTracing}. - */ -@Deprecated(since = "3.4", forRemoval = true) -interface LettuceObservationConvention extends ObservationConvention<LettuceObservationContext> { - - @Override - default boolean supportsContext(Observation.Context context) { - return context instanceof LettuceObservationContext; - } - -} diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/observability/MicrometerTracingAdapter.java b/src/main/java/org/springframework/data/redis/connection/lettuce/observability/MicrometerTracingAdapter.java deleted file mode 100644 index bbf3d28fe6..0000000000 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/observability/MicrometerTracingAdapter.java +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright 2022-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.redis.connection.lettuce.observability; - -import io.lettuce.core.protocol.CompleteableCommand; -import io.lettuce.core.protocol.RedisCommand; -import io.lettuce.core.tracing.TraceContext; -import io.lettuce.core.tracing.TraceContextProvider; -import io.lettuce.core.tracing.Tracer; -import io.lettuce.core.tracing.Tracer.Span; -import io.lettuce.core.tracing.TracerProvider; -import io.lettuce.core.tracing.Tracing; -import io.micrometer.observation.Observation; -import io.micrometer.observation.ObservationRegistry; -import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor; -import reactor.core.publisher.Mono; - -import java.net.SocketAddress; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.data.redis.connection.lettuce.observability.RedisObservation.HighCardinalityCommandKeyNames; -import org.springframework.lang.Nullable; - -/** - * {@link Tracing} adapter using Micrometer's {@link Observation}. This adapter integrates with Micrometer to propagate - * observations into timers, distributed traces and any other registered handlers. Observations include a set of tags - * capturing Redis runtime information. - * <h3>Capturing full statements</h3> This adapter can capture full statements when enabling - * {@code includeCommandArgsInSpanTags}. You should carefully consider the impact of this setting as all command - * arguments will be captured in traces including these that may contain sensitive details. - * - * @author Mark Paluch - * @author Yanming Zhou - * @since 3.0 - * @deprecated since 3.4 for removal with the next major revision. Use Lettuce's Micrometer integration through - * {@link io.lettuce.core.tracing.MicrometerTracing}. - */ -@Deprecated(since = "3.4", forRemoval = true) -public class MicrometerTracingAdapter implements Tracing { - - private static final Log log = LogFactory.getLog(MicrometerTracingAdapter.class); - - private final ObservationRegistry observationRegistry; - private final String serviceName; - private final boolean includeCommandArgsInSpanTags; - - private final LettuceObservationConvention observationConvention; - - /** - * Create a new {@link MicrometerTracingAdapter} instance. - * - * @param observationRegistry must not be {@literal null}. - * @param serviceName service name to be used. - */ - public MicrometerTracingAdapter(ObservationRegistry observationRegistry, String serviceName) { - this(observationRegistry, serviceName, false); - } - - /** - * Create a new {@link MicrometerTracingAdapter} instance. - * - * @param observationRegistry must not be {@literal null}. - * @param serviceName service name to be used. - * @param includeCommandArgsInSpanTags whether to attach the full command into the trace. Use this flag with caution - * as sensitive arguments will be captured in the observation spans and metric tags. - */ - public MicrometerTracingAdapter(ObservationRegistry observationRegistry, String serviceName, - boolean includeCommandArgsInSpanTags) { - - this.observationRegistry = observationRegistry; - this.serviceName = serviceName; - this.observationConvention = new DefaultLettuceObservationConvention(includeCommandArgsInSpanTags); - this.includeCommandArgsInSpanTags = includeCommandArgsInSpanTags; - } - - @Override - public TracerProvider getTracerProvider() { - return () -> new MicrometerTracer(observationRegistry); - } - - @Override - public TraceContextProvider initialTraceContextProvider() { - return new MicrometerTraceContextProvider(observationRegistry); - } - - @Override - public boolean isEnabled() { - return true; - } - - @Override - public boolean includeCommandArgsInSpanTags() { - return includeCommandArgsInSpanTags; - } - - @Override - public Endpoint createEndpoint(SocketAddress socketAddress) { - return new SocketAddressEndpoint(socketAddress); - } - - /** - * {@link Tracer} implementation based on Micrometer's {@link ObservationRegistry}. - */ - public class MicrometerTracer extends Tracer { - - private final ObservationRegistry observationRegistry; - - public MicrometerTracer(ObservationRegistry observationRegistry) { - this.observationRegistry = observationRegistry; - } - - @Override - public Tracer.Span nextSpan() { - return this.postProcessSpan(createObservation(null)); - } - - @Override - public Tracer.Span nextSpan(TraceContext traceContext) { - return postProcessSpan(createObservation(traceContext)); - } - - private Observation createObservation(@Nullable TraceContext parentContext) { - - return RedisObservation.REDIS_COMMAND_OBSERVATION.observation(observationRegistry, () -> { - - LettuceObservationContext context = new LettuceObservationContext(serviceName); - - if (parentContext instanceof MicrometerTraceContext traceContext) { - context.setParentObservation(traceContext.observation()); - } - return context; - }); - } - - private Tracer.Span postProcessSpan(Observation observation) { - - return !observation.isNoop() ? new MicrometerSpan(observation.observationConvention(observationConvention)) - : NoOpSpan.INSTANCE; - } - } - - /** - * No-op {@link Span} implementation. - */ - static class NoOpSpan extends Tracer.Span { - - static final NoOpSpan INSTANCE = new NoOpSpan(); - - public NoOpSpan() {} - - @Override - public Tracer.Span start(RedisCommand<?, ?, ?> command) { - return this; - } - - @Override - public Tracer.Span name(String name) { - return this; - } - - @Override - public Tracer.Span annotate(String value) { - return this; - } - - @Override - public Tracer.Span tag(String key, String value) { - return this; - } - - @Override - public Tracer.Span error(Throwable throwable) { - return this; - } - - @Override - public Tracer.Span remoteEndpoint(Tracing.Endpoint endpoint) { - return this; - } - - @Override - public void finish() {} - } - - /** - * Micrometer {@link Observation}-based {@link Span} implementation. - */ - static class MicrometerSpan extends Tracer.Span { - - private final Observation observation; - - private @Nullable RedisCommand<?, ?, ?> command; - - public MicrometerSpan(Observation observation) { - this.observation = observation; - } - - @Override - public Span start(RedisCommand<?, ?, ?> command) { - - ((LettuceObservationContext) observation.getContext()).setCommand(command); - - this.command = command; - - if (log.isDebugEnabled()) { - log.debug("Starting Observation for Command %s".formatted(command)); - } - - if (command instanceof CompleteableCommand<?> completeableCommand) { - - completeableCommand.onComplete((o, throwable) -> { - - if (command.getOutput() != null) { - - String error = command.getOutput().getError(); - if (error != null) { - observation.highCardinalityKeyValue(HighCardinalityCommandKeyNames.ERROR.withValue(error)); - } else if (throwable != null) { - error(throwable); - } - } - - finish(); - }); - } else { - throw new IllegalArgumentException("Command " + command - + " must implement CompleteableCommand to attach Span completion to command completion"); - } - - observation.start(); - return this; - } - - @Override - public Span name(String name) { - return this; - } - - @Override - public Span annotate(String annotation) { - return this; - } - - @Override - public Span tag(String key, String value) { - observation.highCardinalityKeyValue(key, value); - return this; - } - - @Override - public Span error(Throwable throwable) { - - if (log.isDebugEnabled()) { - log.debug("Attaching error to Observation for Command %s".formatted(command)); - } - - observation.error(throwable); - return this; - } - - @Override - public Span remoteEndpoint(Endpoint endpoint) { - - ((LettuceObservationContext) observation.getContext()).setEndpoint(endpoint); - return this; - } - - @Override - public void finish() { - - if (log.isDebugEnabled()) { - log.debug("Stopping Observation for Command %s".formatted(command)); - } - - observation.stop(); - } - } - - /** - * {@link TraceContextProvider} using {@link ObservationRegistry}. - */ - record MicrometerTraceContextProvider(ObservationRegistry registry) implements TraceContextProvider { - - @Override - @Nullable - public TraceContext getTraceContext() { - - Observation observation = registry.getCurrentObservation(); - - if (observation == null) { - return null; - } - - return new MicrometerTraceContext(observation); - } - - @Override - public Mono<TraceContext> getTraceContextLater() { - - return Mono.deferContextual(Mono::justOrEmpty).filter((it) -> { - return it.hasKey(TraceContext.class) || it.hasKey(Observation.class) - || it.hasKey(ObservationThreadLocalAccessor.KEY); - }).map((it) -> { - - if (it.hasKey(Observation.class)) { - return new MicrometerTraceContext(it.get(Observation.class)); - } - - if (it.hasKey(TraceContext.class)) { - return it.get(TraceContext.class); - } - - return new MicrometerTraceContext(it.get(ObservationThreadLocalAccessor.KEY)); - }); - } - } - - /** - * {@link TraceContext} implementation using {@link Observation}. - * - * @param observation - */ - record MicrometerTraceContext(Observation observation) implements TraceContext { - - } -} diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/observability/RedisObservation.java b/src/main/java/org/springframework/data/redis/connection/lettuce/observability/RedisObservation.java deleted file mode 100644 index 989f2cece8..0000000000 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/observability/RedisObservation.java +++ /dev/null @@ -1,175 +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.redis.connection.lettuce.observability; - -import io.micrometer.common.docs.KeyName; -import io.micrometer.observation.docs.ObservationDocumentation; - -/** - * A Redis-based {@link io.micrometer.observation.Observation}. - * - * @author Mark Paluch - * @since 3.0 - * @deprecated since 3.4 for removal with the next major revision. Use Lettuce's Micrometer integration through - * {@link io.lettuce.core.tracing.MicrometerTracing}. - */ -@Deprecated(since = "3.4", forRemoval = true) -public enum RedisObservation implements ObservationDocumentation { - - /** - * Timer created around a Redis command execution. - */ - REDIS_COMMAND_OBSERVATION { - - @Override - public String getName() { - return "spring.data.redis"; - } - - @Override - public KeyName[] getLowCardinalityKeyNames() { - return LowCardinalityCommandKeyNames.values(); - } - - @Override - public KeyName[] getHighCardinalityKeyNames() { - return HighCardinalityCommandKeyNames.values(); - } - }; - - /** - * Enums related to low cardinality key names for Redis commands. - */ - enum LowCardinalityCommandKeyNames implements KeyName { - - /** - * Database system. - */ - DATABASE_SYSTEM { - @Override - public String asString() { - return "db.system"; - } - }, - - /** - * Network transport. - */ - NET_TRANSPORT { - @Override - public String asString() { - return "net.transport"; - } - }, - - /** - * Name of the database host. - */ - NET_PEER_NAME { - @Override - public String asString() { - return "net.peer.name"; - } - }, - - /** - * Logical remote port number. - */ - NET_PEER_PORT { - @Override - public String asString() { - return "net.peer.port"; - } - }, - - /** - * Mongo peer address. - */ - NET_SOCK_PEER_ADDR { - @Override - public String asString() { - return "net.sock.peer.addr"; - } - }, - - /** - * Mongo peer port. - */ - NET_SOCK_PEER_PORT { - @Override - public String asString() { - return "net.sock.peer.port"; - } - }, - - /** - * Redis user. - */ - DB_USER { - @Override - public String asString() { - return "db.user"; - } - }, - - /** - * Redis database index. - */ - DB_INDEX { - @Override - public String asString() { - return "db.redis.database_index"; - } - }, - - /** - * Redis command value. - */ - REDIS_COMMAND { - @Override - public String asString() { - return "db.operation"; - } - } - - } - - /** - * Enums related to high cardinality key names for Redis commands. - */ - enum HighCardinalityCommandKeyNames implements KeyName { - - /** - * Redis statement. - */ - STATEMENT { - @Override - public String asString() { - return "db.statement"; - } - }, - - /** - * Redis error response. - */ - ERROR { - @Override - public String asString() { - return "spring.data.redis.command.error"; - } - } - } -} diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/observability/SocketAddressEndpoint.java b/src/main/java/org/springframework/data/redis/connection/lettuce/observability/SocketAddressEndpoint.java deleted file mode 100644 index fdaf1c27e1..0000000000 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/observability/SocketAddressEndpoint.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2022-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.redis.connection.lettuce.observability; - -import io.lettuce.core.tracing.Tracing.Endpoint; - -import java.net.InetSocketAddress; -import java.net.SocketAddress; - -/** - * @author Mark Paluch - * @deprecated since 3.4 for removal with the next major revision. Use Lettuce's Micrometer integration through - * {@link io.lettuce.core.tracing.MicrometerTracing}. - */ -@Deprecated(since = "3.4", forRemoval = true) -record SocketAddressEndpoint(SocketAddress socketAddress) implements Endpoint { - - @Override - public String toString() { - - if (socketAddress instanceof InetSocketAddress inet) { - return inet.getHostString() + ":" + inet.getPort(); - } - - return socketAddress.toString(); - } -} diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/observability/package-info.java b/src/main/java/org/springframework/data/redis/connection/lettuce/observability/package-info.java deleted file mode 100644 index e3231ef4c3..0000000000 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/observability/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -/** - * Integration of Micrometer Tracing for Lettuce Observability. - */ -@org.springframework.lang.NonNullApi -@org.springframework.lang.NonNullFields -package org.springframework.data.redis.connection.lettuce.observability; diff --git a/src/main/java/org/springframework/data/redis/core/RedisKeyValueAdapter.java b/src/main/java/org/springframework/data/redis/core/RedisKeyValueAdapter.java index ea74c8fc5c..6c49e739d8 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisKeyValueAdapter.java +++ b/src/main/java/org/springframework/data/redis/core/RedisKeyValueAdapter.java @@ -346,12 +346,12 @@ public <T> T delete(Object id, String keyspace, Class<T> type) { } @Override - public List<?> getAllOf(String keyspace) { + public List<Object> getAllOf(String keyspace) { return getAllOf(keyspace, Object.class, -1, -1); } @Override - public <T> Iterable<T> getAllOf(String keyspace, Class<T> type) { + public <T> List<T> getAllOf(String keyspace, Class<T> type) { return getAllOf(keyspace, type, -1, -1); } diff --git a/src/main/java/org/springframework/data/redis/listener/Topic.java b/src/main/java/org/springframework/data/redis/listener/Topic.java index 0aad48207a..bec4cd3c32 100644 --- a/src/main/java/org/springframework/data/redis/listener/Topic.java +++ b/src/main/java/org/springframework/data/redis/listener/Topic.java @@ -19,13 +19,37 @@ * Topic for a Redis message. Acts a high-level abstraction on top of Redis low-level channels or patterns. * * @author Costin Leau + * @author Mark Paluch */ public interface Topic { + /** + * Create a new {@link ChannelTopic} for channel subscriptions. + * + * @param channelName {@link String name} of the Redis channel; must not be {@literal null}. + * @return the {@link ChannelTopic} for the given {@code channelName}. + * @since 3.5 + */ + static ChannelTopic channel(String channelName) { + return ChannelTopic.of(channelName); + } + + /** + * Create a new {@link PatternTopic} for channel subscriptions based on a {@code pattern}. + * + * @param pattern {@link String pattern} used to match channels; must not be {@literal null} or empty. + * @return the {@link PatternTopic} for the given {@code pattern}. + * @since 3.5 + */ + static PatternTopic pattern(String pattern) { + return PatternTopic.of(pattern); + } + /** * Returns the topic (as a String). * * @return the topic */ String getTopic(); + } diff --git a/src/main/java/org/springframework/data/redis/repository/query/RedisPartTreeQuery.java b/src/main/java/org/springframework/data/redis/repository/query/RedisPartTreeQuery.java index 5582f36cc4..4b69f8f23d 100644 --- a/src/main/java/org/springframework/data/redis/repository/query/RedisPartTreeQuery.java +++ b/src/main/java/org/springframework/data/redis/repository/query/RedisPartTreeQuery.java @@ -35,9 +35,9 @@ import org.springframework.data.repository.query.ParameterAccessor; import org.springframework.data.repository.query.ParametersParameterAccessor; import org.springframework.data.repository.query.QueryMethod; -import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider; import org.springframework.data.repository.query.ResultProcessor; import org.springframework.data.repository.query.ReturnedType; +import org.springframework.data.repository.query.ValueExpressionDelegate; import org.springframework.data.repository.query.parser.AbstractQueryCreator; import org.springframework.data.util.ReflectionUtils; import org.springframework.data.util.Streamable; @@ -54,9 +54,9 @@ public class RedisPartTreeQuery extends KeyValuePartTreeQuery { private final RedisKeyValueAdapter adapter; - public RedisPartTreeQuery(QueryMethod queryMethod, QueryMethodEvaluationContextProvider evaluationContextProvider, + public RedisPartTreeQuery(QueryMethod queryMethod, ValueExpressionDelegate valueExpressionDelegate, KeyValueOperations template, Class<? extends AbstractQueryCreator<?, ?>> queryCreator) { - super(queryMethod, evaluationContextProvider, template, queryCreator); + super(queryMethod, valueExpressionDelegate, template, queryCreator); this.adapter = (RedisKeyValueAdapter) template.getKeyValueAdapter(); } diff --git a/src/main/resources/notice.txt b/src/main/resources/notice.txt index 880bae215e..9b80042f87 100644 --- a/src/main/resources/notice.txt +++ b/src/main/resources/notice.txt @@ -1,4 +1,4 @@ -Spring Data Redis 3.5 M2 (2025.0.0) +Spring Data Redis 4.0 M2 (2025.1.0) Copyright (c) [2010-2019] Pivotal Software, Inc. This product is licensed to you under the Apache License, Version 2.0 (the "License"). @@ -9,54 +9,3 @@ separate copyright notices and license terms. Your use of the source code for the these subcomponents is subject to the terms and conditions of the subcomponent's license, as noted in the LICENSE file. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/java/org/springframework/data/redis/listener/ReactiveRedisMessageListenerContainerIntegrationTests.java b/src/test/java/org/springframework/data/redis/listener/ReactiveRedisMessageListenerContainerIntegrationTests.java index e990cea5f2..4b59bc872d 100644 --- a/src/test/java/org/springframework/data/redis/listener/ReactiveRedisMessageListenerContainerIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/listener/ReactiveRedisMessageListenerContainerIntegrationTests.java @@ -23,12 +23,9 @@ import java.nio.ByteBuffer; import java.time.Duration; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.List; -import java.util.Queue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.CompletableFuture; import java.util.concurrent.LinkedBlockingDeque; @@ -110,7 +107,7 @@ void shouldReceiveChannelMessages() { ReactiveRedisMessageListenerContainer container = new ReactiveRedisMessageListenerContainer(connectionFactory); - container.receiveLater(ChannelTopic.of(CHANNEL1)) // + container.receiveLater(Topic.channel(CHANNEL1)) // .doOnNext(it -> doPublish(CHANNEL1.getBytes(), MESSAGE.getBytes())) // .flatMapMany(Function.identity()) // .as(StepVerifier::create) // @@ -153,7 +150,7 @@ public void onChannelUnsubscribed(byte[] channel, long count) { } }; - container.receive(Collections.singletonList(ChannelTopic.of(CHANNEL1)), listener) // + container.receive(Collections.singletonList(Topic.channel(CHANNEL1)), listener) // .as(StepVerifier::create) // .then(awaitSubscription(container::getActiveSubscriptions)) .then(() -> doPublish(CHANNEL1.getBytes(), MESSAGE.getBytes())) // @@ -220,7 +217,7 @@ public void onPatternUnsubscribed(byte[] pattern, long count) { } }; - container.receive(Collections.singletonList(PatternTopic.of(PATTERN1)), listener) // + container.receive(Collections.singletonList(Topic.pattern(PATTERN1)), listener) // .cast(PatternMessage.class) // .as(StepVerifier::create) // .then(awaitSubscription(container::getActiveSubscriptions)) @@ -314,10 +311,10 @@ void multipleListenShouldTrackSubscriptions() throws Exception { ReactiveRedisMessageListenerContainer container = new ReactiveRedisMessageListenerContainer(connectionFactory); - Flux<? extends ReactiveSubscription.Message<String, String>> c1 = container.receiveLater(ChannelTopic.of(CHANNEL1)) + Flux<? extends ReactiveSubscription.Message<String, String>> c1 = container.receiveLater(Topic.channel(CHANNEL1)) .block(); Flux<? extends ReactiveSubscription.Message<String, String>> c1p1 = container - .receiveLater(Arrays.asList(ChannelTopic.of(CHANNEL1), PatternTopic.of(PATTERN1)), + .receiveLater(Arrays.asList(Topic.channel(CHANNEL1), PatternTopic.of(PATTERN1)), SerializationPair.fromSerializer(RedisSerializer.string()), SerializationPair.fromSerializer(RedisSerializer.string())) .block(); diff --git a/src/test/java/org/springframework/data/redis/listener/ReactiveRedisMessageListenerContainerUnitTests.java b/src/test/java/org/springframework/data/redis/listener/ReactiveRedisMessageListenerContainerUnitTests.java index f5e99bff47..f22ff8e560 100644 --- a/src/test/java/org/springframework/data/redis/listener/ReactiveRedisMessageListenerContainerUnitTests.java +++ b/src/test/java/org/springframework/data/redis/listener/ReactiveRedisMessageListenerContainerUnitTests.java @@ -79,7 +79,7 @@ void shouldSubscribeToPattern() { container = createContainer(); - container.receive(PatternTopic.of("foo*")).as(StepVerifier::create).thenAwait().thenCancel().verify(); + container.receive(Topic.pattern("foo*")).as(StepVerifier::create).thenAwait().thenCancel().verify(); verify(subscriptionMock).pSubscribe(getByteBuffer("foo*")); } @@ -90,7 +90,7 @@ void shouldSubscribeToMultiplePatterns() { when(subscriptionMock.receive()).thenReturn(Flux.never()); container = createContainer(); - container.receive(PatternTopic.of("foo*"), PatternTopic.of("bar*")).as(StepVerifier::create).thenRequest(1) + container.receive(Topic.pattern("foo*"), Topic.pattern("bar*")).as(StepVerifier::create).thenRequest(1) .thenAwait().thenCancel().verify(); verify(subscriptionMock).pSubscribe(getByteBuffer("foo*"), getByteBuffer("bar*")); @@ -102,7 +102,7 @@ void shouldSubscribeToChannel() { when(subscriptionMock.receive()).thenReturn(Flux.never()); container = createContainer(); - container.receive(ChannelTopic.of("foo")).as(StepVerifier::create).thenAwait().thenCancel().verify(); + container.receive(Topic.channel("foo")).as(StepVerifier::create).thenAwait().thenCancel().verify(); verify(subscriptionMock).subscribe(getByteBuffer("foo")); } @@ -113,7 +113,7 @@ void shouldSubscribeToMultipleChannels() { when(subscriptionMock.receive()).thenReturn(Flux.never()); container = createContainer(); - container.receive(ChannelTopic.of("foo"), ChannelTopic.of("bar")).as(StepVerifier::create).thenAwait().thenCancel() + container.receive(Topic.channel("foo"), Topic.channel("bar")).as(StepVerifier::create).thenAwait().thenCancel() .verify(); verify(subscriptionMock).subscribe(getByteBuffer("foo"), getByteBuffer("bar")); @@ -127,7 +127,7 @@ void shouldEmitChannelMessage() { when(subscriptionMock.receive()).thenReturn(sink.asFlux()); container = createContainer(); - Flux<Message<String, String>> messageStream = container.receive(ChannelTopic.of("foo")); + Flux<Message<String, String>> messageStream = container.receive(Topic.channel("foo")); messageStream.as(StepVerifier::create).then(() -> { sink.tryEmitNext(createChannelMessage("foo", "message")); @@ -146,7 +146,7 @@ void shouldEmitPatternMessage() { when(subscriptionMock.receive()).thenReturn(sink.asFlux()); container = createContainer(); - Flux<PatternMessage<String, String, String>> messageStream = container.receive(PatternTopic.of("foo*")); + Flux<PatternMessage<String, String, String>> messageStream = container.receive(Topic.pattern("foo*")); messageStream.as(StepVerifier::create).then(() -> { sink.tryEmitNext(createPatternMessage("foo*", "foo", "message")); @@ -171,7 +171,7 @@ void shouldRegisterSubscription() { when(subscriptionMock.receive()).thenReturn(sink.asFlux()); container = createContainer(); - Flux<Message<String, String>> messageStream = container.receive(ChannelTopic.of("foo*")); + Flux<Message<String, String>> messageStream = container.receive(Topic.channel("foo*")); Disposable subscription = messageStream.subscribe(); @@ -193,7 +193,7 @@ void shouldRegisterSubscriptionMultipleSubscribers() { when(subscriptionMock.receive()).thenReturn(sink.asFlux()); container = createContainer(); - Flux<Message<String, String>> messageStream = container.receive(new ChannelTopic("foo*")); + Flux<Message<String, String>> messageStream = container.receive(Topic.channel("foo*")); Disposable first = messageStream.subscribe(); Disposable second = messageStream.subscribe(); @@ -216,7 +216,7 @@ void shouldUnsubscribeOnCancel() { when(subscriptionMock.receive()).thenReturn(sink.asFlux()); container = createContainer(); - Flux<PatternMessage<String, String, String>> messageStream = container.receive(PatternTopic.of("foo*")); + Flux<PatternMessage<String, String, String>> messageStream = container.receive(Topic.pattern("foo*")); messageStream.as(StepVerifier::create).then(() -> { @@ -240,7 +240,7 @@ void shouldTerminateSubscriptionsOnShutdown() { })); container = createContainer(); - Flux<PatternMessage<String, String, String>> messageStream = container.receive(PatternTopic.of("foo*")); + Flux<PatternMessage<String, String, String>> messageStream = container.receive(Topic.pattern("foo*")); messageStream.as(StepVerifier::create).then(() -> { container.destroy(); @@ -255,7 +255,7 @@ void shouldCleanupDownstream() { when(subscriptionMock.receive()).thenReturn(sink.asFlux()); container = createContainer(); - Flux<PatternMessage<String, String, String>> messageStream = container.receive(PatternTopic.of("foo*")); + Flux<PatternMessage<String, String, String>> messageStream = container.receive(Topic.pattern("foo*")); messageStream.as(StepVerifier::create).then(() -> { assertThat(sink.currentSubscriberCount()).isGreaterThan(0); diff --git a/src/test/java/org/springframework/data/redis/repository/configuration/RedisRepositoryConfigurationExtensionUnitTests.java b/src/test/java/org/springframework/data/redis/repository/configuration/RedisRepositoryConfigurationExtensionUnitTests.java index b515de2ac4..afc66411de 100644 --- a/src/test/java/org/springframework/data/redis/repository/configuration/RedisRepositoryConfigurationExtensionUnitTests.java +++ b/src/test/java/org/springframework/data/redis/repository/configuration/RedisRepositoryConfigurationExtensionUnitTests.java @@ -28,6 +28,7 @@ import org.springframework.core.env.StandardEnvironment; import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.StandardAnnotationMetadata; import org.springframework.data.annotation.Id; import org.springframework.data.keyvalue.repository.KeyValueRepository; @@ -46,12 +47,12 @@ */ class RedisRepositoryConfigurationExtensionUnitTests { - private StandardAnnotationMetadata metadata = new StandardAnnotationMetadata(Config.class, true); + private AnnotationMetadata metadata = AnnotationMetadata.introspect(Config.class); private ResourceLoader loader = new PathMatchingResourcePatternResolver(); private Environment environment = new StandardEnvironment(); private BeanDefinitionRegistry registry = new DefaultListableBeanFactory(); private RepositoryConfigurationSource configurationSource = new AnnotationRepositoryConfigurationSource(metadata, - EnableRedisRepositories.class, loader, environment, registry); + EnableRedisRepositories.class, loader, environment, registry, null); private RedisRepositoryConfigurationExtension extension = new RedisRepositoryConfigurationExtension(); @@ -75,46 +76,46 @@ void isNotStrictMatchIfDomainTypeIsNotAnnotatedWithDocument() { @Test // DATAREDIS-491 void picksUpEnableKeyspaceEventsOnStartupCorrectly() { - metadata = new StandardAnnotationMetadata(Config.class, true); - BeanDefinitionRegistry beanDefintionRegistry = getBeanDefinitionRegistry(); + metadata = AnnotationMetadata.introspect(Config.class); + BeanDefinitionRegistry bdr = getBeanDefinitionRegistry(); - assertThat(getEnableKeyspaceEvents(beanDefintionRegistry)).isEqualTo((Object) EnableKeyspaceEvents.ON_STARTUP); + assertThat(getEnableKeyspaceEvents(bdr)).isEqualTo((Object) EnableKeyspaceEvents.ON_STARTUP); } @Test // DATAREDIS-491 void picksUpEnableKeyspaceEventsDefaultCorrectly() { - metadata = new StandardAnnotationMetadata(ConfigWithKeyspaceEventsDisabled.class, true); - BeanDefinitionRegistry beanDefintionRegistry = getBeanDefinitionRegistry(); + metadata = AnnotationMetadata.introspect(ConfigWithKeyspaceEventsDisabled.class); + BeanDefinitionRegistry bdr = getBeanDefinitionRegistry(); - assertThat(getEnableKeyspaceEvents(beanDefintionRegistry)).isEqualTo((Object) EnableKeyspaceEvents.OFF); + assertThat(getEnableKeyspaceEvents(bdr)).isEqualTo((Object) EnableKeyspaceEvents.OFF); } @Test // DATAREDIS-505 void picksUpDefaultKeyspaceNotificationsConfigParameterCorrectly() { metadata = new StandardAnnotationMetadata(Config.class, true); - BeanDefinitionRegistry beanDefintionRegistry = getBeanDefinitionRegistry(); + BeanDefinitionRegistry bdr = getBeanDefinitionRegistry(); - assertThat(getKeyspaceNotificationsConfigParameter(beanDefintionRegistry)).isEqualTo((Object) "Ex"); + assertThat(getKeyspaceNotificationsConfigParameter(bdr)).isEqualTo((Object) "Ex"); } @Test // DATAREDIS-505 void picksUpCustomKeyspaceNotificationsConfigParameterCorrectly() { metadata = new StandardAnnotationMetadata(ConfigWithKeyspaceEventsEnabledAndCustomEventConfig.class, true); - BeanDefinitionRegistry beanDefintionRegistry = getBeanDefinitionRegistry(); + BeanDefinitionRegistry bdr = getBeanDefinitionRegistry(); - assertThat(getKeyspaceNotificationsConfigParameter(beanDefintionRegistry)).isEqualTo((Object) "KEA"); + assertThat(getKeyspaceNotificationsConfigParameter(bdr)).isEqualTo((Object) "KEA"); } @Test // DATAREDIS-1049 void explicitlyEmptyKeyspaceNotificationsConfigParameterShouldBeCapturedCorrectly() { metadata = new StandardAnnotationMetadata(ConfigWithEmptyConfigParameter.class, true); - BeanDefinitionRegistry beanDefintionRegistry = getBeanDefinitionRegistry(); + BeanDefinitionRegistry bdr = getBeanDefinitionRegistry(); - assertThat(getKeyspaceNotificationsConfigParameter(beanDefintionRegistry)).isEqualTo(""); + assertThat(getKeyspaceNotificationsConfigParameter(bdr)).isEqualTo(""); } private static void assertDoesNotHaveRepo(Class<?> repositoryInterface, @@ -147,7 +148,7 @@ private BeanDefinitionRegistry getBeanDefinitionRegistry() { BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry(); RepositoryConfigurationSource configurationSource = new AnnotationRepositoryConfigurationSource(metadata, - EnableRedisRepositories.class, loader, environment, registry); + EnableRedisRepositories.class, loader, environment, registry, null); RedisRepositoryConfigurationExtension extension = new RedisRepositoryConfigurationExtension(); @@ -156,13 +157,13 @@ private BeanDefinitionRegistry getBeanDefinitionRegistry() { return registry; } - private Object getEnableKeyspaceEvents(BeanDefinitionRegistry beanDefintionRegistry) { - return beanDefintionRegistry.getBeanDefinition("redisKeyValueAdapter").getPropertyValues() + private Object getEnableKeyspaceEvents(BeanDefinitionRegistry bdr) { + return bdr.getBeanDefinition("redisKeyValueAdapter").getPropertyValues() .getPropertyValue("enableKeyspaceEvents").getValue(); } - private Object getKeyspaceNotificationsConfigParameter(BeanDefinitionRegistry beanDefintionRegistry) { - return beanDefintionRegistry.getBeanDefinition("redisKeyValueAdapter").getPropertyValues() + private Object getKeyspaceNotificationsConfigParameter(BeanDefinitionRegistry bdr) { + return bdr.getBeanDefinition("redisKeyValueAdapter").getPropertyValues() .getPropertyValue("keyspaceNotificationsConfigParameter").getValue(); } diff --git a/src/test/kotlin/org/springframework/data/redis/core/ReactiveRedisOperationsExtensionsUnitTests.kt b/src/test/kotlin/org/springframework/data/redis/core/ReactiveRedisOperationsExtensionsUnitTests.kt index 62a6c968f3..90563f411f 100644 --- a/src/test/kotlin/org/springframework/data/redis/core/ReactiveRedisOperationsExtensionsUnitTests.kt +++ b/src/test/kotlin/org/springframework/data/redis/core/ReactiveRedisOperationsExtensionsUnitTests.kt @@ -26,7 +26,7 @@ import org.junit.jupiter.api.Test import org.springframework.data.redis.connection.DataType import org.springframework.data.redis.connection.ReactiveSubscription import org.springframework.data.redis.core.script.RedisScript -import org.springframework.data.redis.listener.ChannelTopic +import org.springframework.data.redis.listener.Topic import org.springframework.data.redis.serializer.RedisElementReader import org.springframework.data.redis.serializer.RedisElementWriter import reactor.core.publisher.Flux @@ -167,8 +167,8 @@ class ReactiveRedisOperationsExtensionsUnitTests { @Test // DATAREDIS-1033 fun listenTo() { - val topic1 = ChannelTopic.of("foo") - val topic2 = ChannelTopic.of("bar") + val topic1 = Topic.channel("foo") + val topic2 = Topic.channel("bar") val message = ReactiveSubscription.ChannelMessage("a", "b") val operations = mockk<ReactiveRedisOperations<String, String>>() every { operations.listenTo(any(), any()) } returns Flux.just(message)