From cba470c848ab03bdb18782b3bc13bc599b61f8f5 Mon Sep 17 00:00:00 2001 From: Tihomir Mateev Date: Mon, 30 Sep 2024 12:32:19 +0300 Subject: [PATCH] Load the Jackson-based implementation dynamically to avoid ClassNotFound --- RELEASE-NOTES.md | 6 ++---- docs/getting-started.md | 6 +++--- pom.xml | 17 ++++++++++++++++- .../java/io/lettuce/core/ClientOptions.java | 9 +++++---- .../lettuce/core/json/DefaultJsonParser.java | 5 ----- .../services/io.lettuce.core.json.JsonParser | 1 + .../core/RedisJsonCommandBuilderUnitTests.java | 2 +- .../core/json/DefaultJsonParserUnitTests.java | 12 ++++++------ .../core/json/DelegateJsonArrayUnitTests.java | 18 +++++++++--------- .../core/json/DelegateJsonObjectUnitTests.java | 4 ++-- .../core/json/DelegateJsonValueUnitTests.java | 10 +++++----- .../json/UnproccessedJsonValueUnitTests.java | 12 ++++++------ .../output/JsonValueListOutputUnitTests.java | 2 +- .../dynamic/RedisCommandFactoryBenchmark.java | 2 +- 14 files changed, 58 insertions(+), 48 deletions(-) create mode 100644 src/main/resources/META-INF/services/io.lettuce.core.json.JsonParser diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 481c2b4cf8..c174193228 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,11 +1,9 @@ Lettuce 6.4.0 RELEASE NOTES ============================== -The Redis team is delighted to announce general availability of Lettuce 6.4. +The Redis team is delighted to announce the general availability of Lettuce 6.5. -This Lettuce driver is now going to be shipped under the MIT licensing scheme. The `CLIENT SETINFO` -is now working in a fire-and-forget mode to allow better compatibility with Redis servers that do -not support this command. +Great news everybody! Lettuce 6.5.0 comes with RedisJSON support enabled. For more on that please consult with the [RedisJSON documentation](https://redis.io/docs/latest/develop/data-types/json/) and the . Lettuce 6 supports Redis 2.6+ up to Redis 7.x. In terms of Java runtime, Lettuce requires at least Java 8 and works with Java 21. diff --git a/docs/getting-started.md b/docs/getting-started.md index af6d3a6838..a9bdc97fd1 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -12,7 +12,7 @@ Add these lines to file pom.xml: io.lettuce lettuce-core - 6.4.0.RELEASE + 6.5.0.RELEASE ``` @@ -23,7 +23,7 @@ Add these lines to file ivy.xml: ``` xml - + ``` @@ -34,7 +34,7 @@ Add these lines to file build.gradle: ``` groovy dependencies { - implementation 'io.lettuce:lettuce-core:6.4.0.RELEASE' + implementation 'io.lettuce:lettuce-core:6.5.0.RELEASE' } ``` diff --git a/pom.xml b/pom.xml index bc3225af6a..da7a50f5c5 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ io.lettuce lettuce-core - 6.4.0.BUILD-SNAPSHOT + 6.5.0.BUILD-SNAPSHOT jar Lettuce @@ -546,6 +546,21 @@ test + + + + org.openjdk.jmh + jmh-core + 1.37 + test + + + org.openjdk.jmh + jmh-generator-annprocess + 1.37 + test + + diff --git a/src/main/java/io/lettuce/core/ClientOptions.java b/src/main/java/io/lettuce/core/ClientOptions.java index 9d8aeb4ad9..22262ab7e2 100644 --- a/src/main/java/io/lettuce/core/ClientOptions.java +++ b/src/main/java/io/lettuce/core/ClientOptions.java @@ -22,10 +22,11 @@ import java.io.Serializable; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.util.Iterator; +import java.util.ServiceLoader; import io.lettuce.core.api.StatefulConnection; import io.lettuce.core.internal.LettuceAssert; -import io.lettuce.core.json.DefaultJsonParser; import io.lettuce.core.json.JsonParser; import io.lettuce.core.protocol.DecodeBufferPolicies; import io.lettuce.core.protocol.DecodeBufferPolicy; @@ -71,8 +72,6 @@ public class ClientOptions implements Serializable { public static final TimeoutOptions DEFAULT_TIMEOUT_OPTIONS = TimeoutOptions.enabled(); - public static final JsonParser DEFAULT_JSON_PARSER = DefaultJsonParser.INSTANCE; - private final boolean autoReconnect; private final boolean cancelCommandsOnReconnectFailure; @@ -192,7 +191,7 @@ public static class Builder { private Charset scriptCharset = DEFAULT_SCRIPT_CHARSET; - private JsonParser jsonParser = DEFAULT_JSON_PARSER; + private JsonParser jsonParser; private SocketOptions socketOptions = DEFAULT_SOCKET_OPTIONS; @@ -203,6 +202,8 @@ public static class Builder { private TimeoutOptions timeoutOptions = DEFAULT_TIMEOUT_OPTIONS; protected Builder() { + Iterator services = ServiceLoader.load(JsonParser.class).iterator(); + jsonParser = services.hasNext() ? services.next() : null; } /** diff --git a/src/main/java/io/lettuce/core/json/DefaultJsonParser.java b/src/main/java/io/lettuce/core/json/DefaultJsonParser.java index a002d9782a..afab7afa70 100644 --- a/src/main/java/io/lettuce/core/json/DefaultJsonParser.java +++ b/src/main/java/io/lettuce/core/json/DefaultJsonParser.java @@ -24,11 +24,6 @@ */ public class DefaultJsonParser implements JsonParser { - public static final DefaultJsonParser INSTANCE = new DefaultJsonParser(); - - private DefaultJsonParser() { - } - @Override public JsonValue loadJsonValue(ByteBuffer bytes) { return new UnproccessedJsonValue(bytes, this); diff --git a/src/main/resources/META-INF/services/io.lettuce.core.json.JsonParser b/src/main/resources/META-INF/services/io.lettuce.core.json.JsonParser new file mode 100644 index 0000000000..f53cf85425 --- /dev/null +++ b/src/main/resources/META-INF/services/io.lettuce.core.json.JsonParser @@ -0,0 +1 @@ +io.lettuce.core.json.DefaultJsonParser \ No newline at end of file diff --git a/src/test/java/io/lettuce/core/RedisJsonCommandBuilderUnitTests.java b/src/test/java/io/lettuce/core/RedisJsonCommandBuilderUnitTests.java index 3c658ec509..424ca512dd 100644 --- a/src/test/java/io/lettuce/core/RedisJsonCommandBuilderUnitTests.java +++ b/src/test/java/io/lettuce/core/RedisJsonCommandBuilderUnitTests.java @@ -39,7 +39,7 @@ class RedisJsonCommandBuilderUnitTests { public static final String ID_BIKE_6 = "{\"id\":\"bike6\"}"; - public static final JsonParser PARSER = DefaultJsonParser.INSTANCE; + public static final JsonParser PARSER = new DefaultJsonParser(); public static final JsonValue ELEMENT = PARSER.createJsonValue(ID_BIKE_6); diff --git a/src/test/java/io/lettuce/core/json/DefaultJsonParserUnitTests.java b/src/test/java/io/lettuce/core/json/DefaultJsonParserUnitTests.java index 61efa3d25b..b99933fccf 100644 --- a/src/test/java/io/lettuce/core/json/DefaultJsonParserUnitTests.java +++ b/src/test/java/io/lettuce/core/json/DefaultJsonParserUnitTests.java @@ -23,7 +23,7 @@ class DefaultJsonParserUnitTests { void loadJsonValue() { final String unprocessed = "{\"a\":1,\"b\":2}"; - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); JsonValue jsonValue = parser.loadJsonValue(ByteBuffer.wrap(unprocessed.getBytes())); assertThat(jsonValue).isNotNull(); @@ -35,7 +35,7 @@ void loadJsonValue() { void createJsonValue() { final String unprocessed = "\"someValue\""; - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); JsonValue jsonValue = parser.createJsonValue(ByteBuffer.wrap(unprocessed.getBytes())); assertThat(jsonValue).isNotNull(); @@ -47,14 +47,14 @@ void createJsonValue() { void createJsonObject() { final String unprocessed = "{\"a\":1,\"b\":2}"; - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); JsonValue jsonValue = parser.createJsonObject(); assertThat(jsonValue).isNotNull(); assertThat(jsonValue.isJsonObject()).isTrue(); assertThat(jsonValue.asJsonObject().size()).isZero(); - parser = DefaultJsonParser.INSTANCE; + parser = new DefaultJsonParser(); jsonValue = parser.createJsonValue(ByteBuffer.wrap(unprocessed.getBytes())); assertThat(jsonValue).isNotNull(); @@ -72,7 +72,7 @@ void createJsonObject() { @Test void createJsonArray() { - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); JsonValue jsonValue = parser.createJsonArray(); assertThat(jsonValue).isNotNull(); @@ -93,7 +93,7 @@ void createJsonArray() { void parsingIssues() { final String unprocessed = "{a\":1,\"b\":2}"; - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); assertThatThrownBy(() -> parser.createJsonValue(unprocessed)).isInstanceOf(RedisJsonException.class); assertThatThrownBy(() -> parser.createJsonValue(ByteBuffer.wrap(unprocessed.getBytes()))) diff --git a/src/test/java/io/lettuce/core/json/DelegateJsonArrayUnitTests.java b/src/test/java/io/lettuce/core/json/DelegateJsonArrayUnitTests.java index f08cc63d90..1b681af0d3 100644 --- a/src/test/java/io/lettuce/core/json/DelegateJsonArrayUnitTests.java +++ b/src/test/java/io/lettuce/core/json/DelegateJsonArrayUnitTests.java @@ -21,7 +21,7 @@ class DelegateJsonArrayUnitTests { @Test void add() { - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); DelegateJsonArray underTest = new DelegateJsonArray(); underTest.add(parser.createJsonValue("\"test\"")).add(parser.createJsonValue("\"test2\"")) .add(parser.createJsonValue("\"test3\"")); @@ -37,7 +37,7 @@ void add() { @Test void addCornerCases() { - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); DelegateJsonArray underTest = new DelegateJsonArray(); underTest.add(null).add(parser.createJsonValue("null")).add(parser.createJsonValue("\"test3\"")); @@ -52,7 +52,7 @@ void addCornerCases() { @Test void getCornerCases() { - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); DelegateJsonArray underTest = new DelegateJsonArray(); underTest.add(parser.createJsonValue("\"test\"")).add(parser.createJsonValue("\"test2\"")) .add(parser.createJsonValue("\"test3\"")); @@ -63,7 +63,7 @@ void getCornerCases() { @Test void addAll() { - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); DelegateJsonArray array = new DelegateJsonArray(); array.add(parser.createJsonValue("\"test\"")).add(parser.createJsonValue("\"test2\"")) .add(parser.createJsonValue("\"test3\"")); @@ -83,7 +83,7 @@ void addAll() { @Test void asList() { - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); DelegateJsonArray underTest = new DelegateJsonArray(); underTest.add(parser.createJsonValue("1")).add(parser.createJsonValue("2")).add(parser.createJsonValue("3")); @@ -95,7 +95,7 @@ void asList() { @Test void getFirst() { - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); DelegateJsonArray underTest = new DelegateJsonArray(); underTest.add(parser.createJsonValue("\"test\"")).add(parser.createJsonValue("\"test2\"")) .add(parser.createJsonValue("\"test3\"")); @@ -107,7 +107,7 @@ void getFirst() { @Test void iterator() { - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); DelegateJsonArray underTest = new DelegateJsonArray(); underTest.add(parser.createJsonValue("1")).add(parser.createJsonValue("2")).add(parser.createJsonValue("3")); @@ -120,7 +120,7 @@ void iterator() { @Test void remove() { - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); DelegateJsonArray underTest = new DelegateJsonArray(); underTest.add(parser.createJsonValue("1")).add(parser.createJsonValue("2")).add(parser.createJsonValue("3")); @@ -132,7 +132,7 @@ void remove() { @Test void replace() { - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); DelegateJsonArray underTest = new DelegateJsonArray(); underTest.add(parser.createJsonValue("1")).add(parser.createJsonValue("2")).add(parser.createJsonValue("3")); underTest.replace(1, parser.createJsonValue("4")); diff --git a/src/test/java/io/lettuce/core/json/DelegateJsonObjectUnitTests.java b/src/test/java/io/lettuce/core/json/DelegateJsonObjectUnitTests.java index c542a41480..5a9bde49a1 100644 --- a/src/test/java/io/lettuce/core/json/DelegateJsonObjectUnitTests.java +++ b/src/test/java/io/lettuce/core/json/DelegateJsonObjectUnitTests.java @@ -18,7 +18,7 @@ class DelegateJsonObjectUnitTests { @Test void put() { - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); DelegateJsonObject underTest = new DelegateJsonObject(); underTest.put("test", parser.createJsonValue("\"test\"")).put("test2", parser.createJsonValue("1")).put("test2", @@ -31,7 +31,7 @@ void put() { @Test void remove() { - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); DelegateJsonObject underTest = new DelegateJsonObject(); underTest.put("test", parser.createJsonValue("\"test\"")).put("test2", parser.createJsonValue("1")).remove("test"); diff --git a/src/test/java/io/lettuce/core/json/DelegateJsonValueUnitTests.java b/src/test/java/io/lettuce/core/json/DelegateJsonValueUnitTests.java index 5fab965057..657572f09b 100644 --- a/src/test/java/io/lettuce/core/json/DelegateJsonValueUnitTests.java +++ b/src/test/java/io/lettuce/core/json/DelegateJsonValueUnitTests.java @@ -18,7 +18,7 @@ class DelegateJsonValueUnitTests { @Test void testString() { - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); JsonValue underTest = parser.createJsonValue("\"test\""); assertThat(underTest.toString()).isEqualTo("\"test\""); @@ -44,7 +44,7 @@ void testString() { @Test void testNumber() { - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); JsonValue underTest = parser.createJsonValue("1"); assertThat(underTest.toString()).isEqualTo("1"); @@ -70,7 +70,7 @@ void testNumber() { @Test void testNumberExtended() { - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); JsonValue underTest = parser.createJsonValue("1"); assertThat(underTest.isNumber()).isTrue(); @@ -92,7 +92,7 @@ void testNumberExtended() { @Test void testBoolean() { - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); JsonValue underTest = parser.createJsonValue("true"); assertThat(underTest.toString()).isEqualTo("true"); @@ -118,7 +118,7 @@ void testBoolean() { @Test void testNull() { - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); JsonValue underTest = parser.createJsonValue("null"); assertThat(underTest.toString()).isEqualTo("null"); diff --git a/src/test/java/io/lettuce/core/json/UnproccessedJsonValueUnitTests.java b/src/test/java/io/lettuce/core/json/UnproccessedJsonValueUnitTests.java index 369bae1689..1d35326f3f 100644 --- a/src/test/java/io/lettuce/core/json/UnproccessedJsonValueUnitTests.java +++ b/src/test/java/io/lettuce/core/json/UnproccessedJsonValueUnitTests.java @@ -38,7 +38,7 @@ void asString() { final String unprocessed = "{\"a\":1,\"b\":2}"; final String modified = "{\"a\":1}"; - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); ByteBuffer buffer = ByteBuffer.wrap(unprocessed.getBytes()); UnproccessedJsonValue underTest = new UnproccessedJsonValue(buffer, parser); @@ -55,7 +55,7 @@ void asString() { @Test void asTextual() { - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); ByteBuffer buffer = ByteBuffer.wrap("\"textual\"".getBytes()); UnproccessedJsonValue underTest = new UnproccessedJsonValue(buffer, parser); @@ -72,7 +72,7 @@ void asTextual() { @Test void asNull() { - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); ByteBuffer buffer = ByteBuffer.wrap("null".getBytes()); UnproccessedJsonValue underTest = new UnproccessedJsonValue(buffer, parser); @@ -88,7 +88,7 @@ void asNull() { @Test void asNumber() { - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); ByteBuffer buffer = ByteBuffer.wrap("1".getBytes()); UnproccessedJsonValue underTest = new UnproccessedJsonValue(buffer, parser); @@ -105,7 +105,7 @@ void asNumber() { @Test void asBoolean() { - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); ByteBuffer buffer = ByteBuffer.wrap("true".getBytes()); UnproccessedJsonValue underTest = new UnproccessedJsonValue(buffer, parser); @@ -122,7 +122,7 @@ void asBoolean() { @Test void asArray() { - DefaultJsonParser parser = DefaultJsonParser.INSTANCE; + DefaultJsonParser parser = new DefaultJsonParser(); ByteBuffer buffer = ByteBuffer.wrap("[1,2,3,4]".getBytes()); UnproccessedJsonValue underTest = new UnproccessedJsonValue(buffer, parser); diff --git a/src/test/java/io/lettuce/core/output/JsonValueListOutputUnitTests.java b/src/test/java/io/lettuce/core/output/JsonValueListOutputUnitTests.java index 0406133881..97cbf82759 100644 --- a/src/test/java/io/lettuce/core/output/JsonValueListOutputUnitTests.java +++ b/src/test/java/io/lettuce/core/output/JsonValueListOutputUnitTests.java @@ -22,7 +22,7 @@ class JsonValueListOutputUnitTests { @Test void set() { - JsonValueListOutput sut = new JsonValueListOutput<>(StringCodec.UTF8, DefaultJsonParser.INSTANCE); + JsonValueListOutput sut = new JsonValueListOutput<>(StringCodec.UTF8, new DefaultJsonParser()); sut.multi(2); sut.set(ByteBuffer.wrap("[1,2,3]".getBytes())); sut.set(ByteBuffer.wrap("world".getBytes())); diff --git a/src/test/jmh/io/lettuce/core/dynamic/RedisCommandFactoryBenchmark.java b/src/test/jmh/io/lettuce/core/dynamic/RedisCommandFactoryBenchmark.java index 04085e1d22..c9e575aa3e 100644 --- a/src/test/jmh/io/lettuce/core/dynamic/RedisCommandFactoryBenchmark.java +++ b/src/test/jmh/io/lettuce/core/dynamic/RedisCommandFactoryBenchmark.java @@ -31,7 +31,7 @@ public void setup() { redisCommandFactory = new RedisCommandFactory(new MockStatefulConnection(EmptyRedisChannelWriter.INSTANCE)); regularCommands = redisCommandFactory.getCommands(RegularCommands.class); - asyncCommands = new RedisAsyncCommandsImpl<>(EmptyStatefulRedisConnection.INSTANCE, StringCodec.UTF8, DefaultJsonParser.INSTANCE); + asyncCommands = new RedisAsyncCommandsImpl<>(EmptyStatefulRedisConnection.INSTANCE, StringCodec.UTF8, new DefaultJsonParser()); } @Benchmark