From f4443dd03953d632991a03fba257ce6317180aad Mon Sep 17 00:00:00 2001 From: Lina Butler Date: Tue, 3 Mar 2026 01:17:08 -0800 Subject: [PATCH] Support Redis URIs. This commit adds a new kind of `redis.node.type`, `uri`, which takes a Lettuce Redis URI [^1]. The existing connection types expect `host:port` pairs, not absolute URIs, and take additional options as separate fields. Since Redis URIs can specify all these options as query params, the new `uri` type takes just the URI. Closes #60. [^1]: https://redis.github.io/lettuce/user-guide/connecting-redis --- README.md | 13 ++++- .../redis/uri/StringURIFactory.java | 27 ++++++++++ .../io.dropwizard.redis.uri.RedisURIFactory | 1 + .../redis/uri/StringURIFactoryTest.java | 52 +++++++++++++++++++ .../resources/yaml/uri/string-redis-uri.yaml | 3 ++ 5 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 src/main/java/io/dropwizard/redis/uri/StringURIFactory.java create mode 100644 src/test/java/io/dropwizard/redis/uri/StringURIFactoryTest.java create mode 100644 src/test/resources/yaml/uri/string-redis-uri.yaml diff --git a/README.md b/README.md index f72b25d..d17054d 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ public void run(ExampleConfiguration config, Environment environment) { } ``` - +Finally, set the configuration values for the client factory and connection in your application's `config.yml` file: ```yaml redis: type: basic @@ -95,6 +95,15 @@ redis: enabled: false ``` +Alternatively, you can use a [Redis URI string](https://redis.github.io/lettuce/user-guide/connecting-redis/#uri-syntax) to configure the connection: +```yaml +redis: + node: + type: uri + uri: "redis://127.0.0.1:6379?clientName=person-app" +``` + +This also supports `rediss://` for TLS connections, and `redis-sentinel://` for Sentinel. ### Lettuce Cluster Client In your Dropwizard `Configuration` class, configure a `RedisClusterClientFactory`: @@ -127,7 +136,7 @@ public void run(ExampleConfiguration config, Environment environment) { } ``` -Configure your factory in your `config.yml` file: +Finally, configure your factory in your `config.yml` file: ```yaml redis-cluster: type: cluster diff --git a/src/main/java/io/dropwizard/redis/uri/StringURIFactory.java b/src/main/java/io/dropwizard/redis/uri/StringURIFactory.java new file mode 100644 index 0000000..6dd22ea --- /dev/null +++ b/src/main/java/io/dropwizard/redis/uri/StringURIFactory.java @@ -0,0 +1,27 @@ +package io.dropwizard.redis.uri; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeName; +import io.lettuce.core.RedisURI; + +import jakarta.validation.constraints.NotNull; + +@JsonTypeName("uri") +public class StringURIFactory extends RedisURIFactory { + @NotNull + @JsonProperty + private String uri; + + public String getUri() { + return uri; + } + + public void setUri(final String uri) { + this.uri = uri; + } + + @Override + public RedisURI build() { + return RedisURI.create(uri); + } +} diff --git a/src/main/resources/META-INF/services/io.dropwizard.redis.uri.RedisURIFactory b/src/main/resources/META-INF/services/io.dropwizard.redis.uri.RedisURIFactory index 8b4f99a..6d2723d 100644 --- a/src/main/resources/META-INF/services/io.dropwizard.redis.uri.RedisURIFactory +++ b/src/main/resources/META-INF/services/io.dropwizard.redis.uri.RedisURIFactory @@ -1,2 +1,3 @@ io.dropwizard.redis.uri.RedisModeURIFactory io.dropwizard.redis.uri.SentinelModeURIFactory +io.dropwizard.redis.uri.StringURIFactory diff --git a/src/test/java/io/dropwizard/redis/uri/StringURIFactoryTest.java b/src/test/java/io/dropwizard/redis/uri/StringURIFactoryTest.java new file mode 100644 index 0000000..8153a02 --- /dev/null +++ b/src/test/java/io/dropwizard/redis/uri/StringURIFactoryTest.java @@ -0,0 +1,52 @@ +package io.dropwizard.redis.uri; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.io.Resources; +import io.dropwizard.configuration.YamlConfigurationFactory; +import io.dropwizard.jackson.DiscoverableSubtypeResolver; +import io.dropwizard.jackson.Jackson; +import io.dropwizard.jersey.validation.Validators; +import io.lettuce.core.RedisURI; +import java.time.Duration; +import org.junit.jupiter.api.Test; + +import java.io.File; + +import jakarta.validation.Validator; + +import static org.assertj.core.api.Assertions.assertThat; + +public class StringURIFactoryTest { + private final ObjectMapper objectMapper = Jackson.newObjectMapper(); + private final Validator validator = Validators.newValidator(); + private final YamlConfigurationFactory configFactory = new YamlConfigurationFactory<>( + RedisURIFactory.class, validator, objectMapper, "dw"); + + @Test + public void shouldBuildARedisURIFromString() throws Exception { + final File yml = new File(Resources.getResource("yaml/uri/string-redis-uri.yaml").toURI()); + final RedisURIFactory factory = configFactory.build(yml); + + assertThat(factory) + .isInstanceOf(StringURIFactory.class); + + final StringURIFactory stringFactory = (StringURIFactory) factory; + + assertThat(stringFactory.getUri()) + .isEqualTo("redis://hunter2@127.0.0.1:6379/1?timeout=90s&clientName=test"); + + final RedisURI redisURI = factory.build(); + assertThat(redisURI).isInstanceOf(RedisURI.class); + assertThat(redisURI.getHost()).isEqualTo("127.0.0.1"); + assertThat(redisURI.getPort()).isEqualTo(6379); + assertThat(redisURI.getDatabase()).isEqualTo(1); + assertThat(redisURI.getTimeout()).isEqualTo(Duration.ofSeconds(90)); + assertThat(redisURI.getClientName()).isEqualTo("test"); + } + + @Test + public void isDiscoverable() { + assertThat(new DiscoverableSubtypeResolver().getDiscoveredSubtypes()) + .contains(StringURIFactory.class); + } +} diff --git a/src/test/resources/yaml/uri/string-redis-uri.yaml b/src/test/resources/yaml/uri/string-redis-uri.yaml new file mode 100644 index 0000000..344d32f --- /dev/null +++ b/src/test/resources/yaml/uri/string-redis-uri.yaml @@ -0,0 +1,3 @@ +--- +type: uri +uri: "redis://hunter2@127.0.0.1:6379/1?timeout=90s&clientName=test"