Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/jedis5-breaking.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
- `tsMRevRange(long fromTimestamp, long toTimestamp, String... filters)`
- `tsMRevRange(TSMRangeParams multiRangeParams)`

- `jsonNumIncrBy(String key, Path2 path, double value)` method now returns `Object` instead of `JSONArray`.
- Previously when it was returning JSONArray, returned would still be JSONArray. So simple type casting should be enough to handle this change.
- The returning object will be `List<Double>` when running under RESP3 protocol.

- `getAgeSeconds()` in `AccessControlLogEntry` now returns `Double` instead of `String`.

- Both `ftConfigGet(String option)` and `ftConfigGet(String indexName, String option)` methods now return `Map<String, Object>` instead of `Map<String, String>`.
Expand Down
18 changes: 13 additions & 5 deletions src/main/java/redis/clients/jedis/CommandObjects.java
Original file line number Diff line number Diff line change
Expand Up @@ -3460,7 +3460,8 @@ public final CommandObject<String> jsonMerge(String key, Path path, Object pojo)
}

public final CommandObject<Object> jsonGet(String key) {
return new CommandObject<>(commandArguments(JsonCommand.GET).key(key), new JsonObjectBuilder<>(Object.class));
return new CommandObject<>(commandArguments(JsonCommand.GET).key(key),
protocol != RedisProtocol.RESP3 ? JSON_GENERIC_OBJECT : JsonBuilderFactory.JSON_OBJECT);
}

public final <T> CommandObject<T> jsonGet(String key, Class<T> clazz) {
Expand All @@ -3472,7 +3473,7 @@ public final CommandObject<Object> jsonGet(String key, Path2... paths) {
}

public final CommandObject<Object> jsonGet(String key, Path... paths) {
return new CommandObject<>(commandArguments(JsonCommand.GET).key(key).addObjects((Object[]) paths), new JsonObjectBuilder<>(Object.class));
return new CommandObject<>(commandArguments(JsonCommand.GET).key(key).addObjects((Object[]) paths), JSON_GENERIC_OBJECT);
}

public final CommandObject<String> jsonGetAsPlainString(String key, Path path) {
Expand Down Expand Up @@ -3528,7 +3529,8 @@ public final CommandObject<Class<?>> jsonType(String key) {
}

public final CommandObject<List<Class<?>>> jsonType(String key, Path2 path) {
return new CommandObject<>(commandArguments(JsonCommand.TYPE).key(key).add(path), JsonBuilderFactory.JSON_TYPE_LIST);
return new CommandObject<>(commandArguments(JsonCommand.TYPE).key(key).add(path),
protocol != RedisProtocol.RESP3 ? JsonBuilderFactory.JSON_TYPE_LIST : JsonBuilderFactory.JSON_TYPE_RESPONSE_RESP3_COMPATIBLE);
}

public final CommandObject<Class<?>> jsonType(String key, Path path) {
Expand Down Expand Up @@ -3562,8 +3564,9 @@ public final CommandObject<Long> jsonStrLen(String key, Path path) {
return new CommandObject<>(commandArguments(JsonCommand.STRLEN).key(key).add(path), BuilderFactory.LONG);
}

public final CommandObject<JSONArray> jsonNumIncrBy(String key, Path2 path, double value) {
return new CommandObject<>(commandArguments(JsonCommand.NUMINCRBY).key(key).add(path).add(value), JsonBuilderFactory.JSON_ARRAY);
public final CommandObject<Object> jsonNumIncrBy(String key, Path2 path, double value) {
return new CommandObject<>(commandArguments(JsonCommand.NUMINCRBY).key(key).add(path).add(value),
JsonBuilderFactory.JSON_ARRAY_OR_DOUBLE_LIST);
}

public final CommandObject<Double> jsonNumIncrBy(String key, Path path, double value) {
Expand Down Expand Up @@ -4260,6 +4263,11 @@ public T build(Object data) {
}
}

/**
* {@link JsonObjectBuilder} for {@code Object.class}.
*/
private final Builder<Object> JSON_GENERIC_OBJECT = new JsonObjectBuilder<>(Object.class);

private class JsonObjectListBuilder<T> extends Builder<List<T>> {

private final Class<T> clazz;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/redis/clients/jedis/PipelineBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -3607,7 +3607,7 @@ public Response<Long> jsonStrLen(String key, Path path) {
}

@Override
public Response<JSONArray> jsonNumIncrBy(String key, Path2 path, double value) {
public Response<Object> jsonNumIncrBy(String key, Path2 path, double value) {
return appendCommand(commandObjects.jsonNumIncrBy(key, path, value));
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/redis/clients/jedis/TransactionBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -3775,7 +3775,7 @@ public Response<Long> jsonStrLen(String key, Path path) {
}

@Override
public Response<JSONArray> jsonNumIncrBy(String key, Path2 path, double value) {
public Response<Object> jsonNumIncrBy(String key, Path2 path, double value) {
return appendCommand(commandObjects.jsonNumIncrBy(key, path, value));
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/redis/clients/jedis/UnifiedJedis.java
Original file line number Diff line number Diff line change
Expand Up @@ -4056,7 +4056,7 @@ public Long jsonStrLen(String key, Path path) {
}

@Override
public JSONArray jsonNumIncrBy(String key, Path2 path, double value) {
public Object jsonNumIncrBy(String key, Path2 path, double value) {
return executeCommand(commandObjects.jsonNumIncrBy(key, path, value));
}

Expand Down
26 changes: 25 additions & 1 deletion src/main/java/redis/clients/jedis/json/JsonBuilderFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.json.JSONException;
import org.json.JSONObject;
import redis.clients.jedis.Builder;
import redis.clients.jedis.BuilderFactory;
import redis.clients.jedis.exceptions.JedisException;

public final class JsonBuilderFactory {
Expand Down Expand Up @@ -60,6 +61,21 @@ public List<Class<?>> build(Object data) {
}
};

public static final Builder<List<List<Class<?>>>> JSON_TYPE_RESPONSE_RESP3 = new Builder<List<List<Class<?>>>>() {
@Override
public List<List<Class<?>>> build(Object data) {
return ((List<Object>) data).stream().map(JSON_TYPE_LIST::build).collect(Collectors.toList());
}
};

public static final Builder<List<Class<?>>> JSON_TYPE_RESPONSE_RESP3_COMPATIBLE = new Builder<List<Class<?>>>() {
@Override
public List<Class<?>> build(Object data) {
List<List<Class<?>>> fullReply = JSON_TYPE_RESPONSE_RESP3.build(data);
return fullReply == null ? null : fullReply.get(0);
}
};

public static final Builder<Object> JSON_OBJECT = new Builder<Object>() {
@Override
public Object build(Object data) {
Expand All @@ -70,7 +86,6 @@ public Object build(Object data) {
if (!(data instanceof byte[])) {
return data;
}

String str = STRING.build(data);
if (str.charAt(0) == '{') {
try {
Expand Down Expand Up @@ -103,6 +118,15 @@ public JSONArray build(Object data) {
}
};

public static final Builder<Object> JSON_ARRAY_OR_DOUBLE_LIST = new Builder<Object>() {
@Override
public Object build(Object data) {
if (data == null) return null;
if (data instanceof List) return BuilderFactory.DOUBLE_LIST.build(data);
return JSON_ARRAY.build(data);
}
};

public static final Builder<List<JSONArray>> JSON_ARRAY_LIST = new Builder<List<JSONArray>>() {
@Override
public List<JSONArray> build(Object data) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ default List<JSONArray> jsonMGet(String... keys) {

List<Long> jsonStrLen(String key, Path2 path);

JSONArray jsonNumIncrBy(String key, Path2 path, double value);
Object jsonNumIncrBy(String key, Path2 path, double value);

List<Long> jsonArrAppend(String key, Path2 path, Object... objects);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ default Response<List<JSONArray>> jsonMGet(String... keys) {

Response<List<Long>> jsonStrLen(String key, Path2 path);

Response<JSONArray> jsonNumIncrBy(String key, Path2 path, double value);
Response<Object> jsonNumIncrBy(String key, Path2 path, double value);

Response<List<Long>> jsonArrAppend(String key, Path2 path, Object... objects);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,19 @@
import java.util.Collections;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Test;

import redis.clients.jedis.Pipeline;
import redis.clients.jedis.RedisProtocol;
import redis.clients.jedis.Response;
import redis.clients.jedis.json.JsonSetParams;
import redis.clients.jedis.json.Path;
import redis.clients.jedis.json.Path2;
import redis.clients.jedis.search.*;
import redis.clients.jedis.search.aggr.*;
import redis.clients.jedis.util.RedisProtocolUtil;

public class RedisModulesPipelineTest extends RedisModuleCommandsTestBase {

Expand Down Expand Up @@ -88,6 +91,8 @@ public void search() {

@Test
public void jsonV1() {
Assume.assumeFalse(RedisProtocolUtil.getRedisProtocol() == RedisProtocol.RESP3);

Map<String, String> hm1 = new HashMap<>();
hm1.put("hello", "world");
hm1.put("oh", "snap");
Expand Down
10 changes: 10 additions & 0 deletions src/test/java/redis/clients/jedis/modules/json/JsonObjects.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ public IRLObject() {
this.str = "string";
this.bool = true;
}

@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
final IRLObject other = (IRLObject) obj;
return Objects.equals(str, other.str)
&& Objects.equals(bool, other.bool);
}
}

@SuppressWarnings("unused")
Expand Down
57 changes: 26 additions & 31 deletions src/test/java/redis/clients/jedis/modules/json/RedisJsonV1Test.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,19 @@

import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.Assume;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import redis.clients.jedis.RedisProtocol;
import redis.clients.jedis.exceptions.JedisDataException;
import redis.clients.jedis.json.JsonSetParams;
import redis.clients.jedis.json.Path;
import redis.clients.jedis.json.commands.RedisJsonV1Commands;
import redis.clients.jedis.modules.RedisModuleCommandsTestBase;
import redis.clients.jedis.util.JsonObjectMapperTestUtil;
import redis.clients.jedis.util.RedisProtocolUtil;

public class RedisJsonV1Test extends RedisModuleCommandsTestBase {

Expand All @@ -35,6 +38,7 @@ public class RedisJsonV1Test extends RedisModuleCommandsTestBase {

@BeforeClass
public static void prepare() {
Assume.assumeFalse(RedisProtocolUtil.getRedisProtocol() == RedisProtocol.RESP3);
RedisModuleCommandsTestBase.prepare();
}

Expand All @@ -51,7 +55,7 @@ public void basicSetGetShouldSucceed() {
// naive set with a path
// jsonClient.jsonSet("null", null, ROOT_PATH);
jsonClient.jsonSet("null", ROOT_PATH, (Object) null);
assertNull(client.jsonGet("null", String.class, ROOT_PATH));
assertNull(jsonClient.jsonGet("null", String.class, ROOT_PATH));

// real scalar value and no path
jsonClient.jsonSet("str", ROOT_PATH, "strong");
Expand All @@ -61,7 +65,7 @@ public void basicSetGetShouldSucceed() {
IRLObject obj = new IRLObject();
jsonClient.jsonSet("obj", ROOT_PATH, obj);
Object expected = gson.fromJson(gson.toJson(obj), Object.class);
assertTrue(expected.equals(client.jsonGet("obj")));
assertTrue(expected.equals(jsonClient.jsonGet("obj")));

// check an update
Path p = Path.of(".str");
Expand Down Expand Up @@ -97,14 +101,14 @@ public void setWithoutAPathDefaultsToRootPath() {
public void setExistingPathOnlyIfNotExistsShouldFail() {
jsonClient.jsonSet("obj", ROOT_PATH, new IRLObject());
Path p = Path.of(".str");
assertNull(client.jsonSet("obj", p, "strangle", JsonSetParams.jsonSetParams().nx()));
assertNull(jsonClient.jsonSet("obj", p, "strangle", JsonSetParams.jsonSetParams().nx()));
}

@Test
public void setNonExistingPathOnlyIfExistsShouldFail() {
jsonClient.jsonSet("obj", ROOT_PATH, new IRLObject());
Path p = Path.of(".none");
assertNull(client.jsonSet("obj", p, "strangle", JsonSetParams.jsonSetParams().xx()));
assertNull(jsonClient.jsonSet("obj", p, "strangle", JsonSetParams.jsonSetParams().xx()));
}

@Test(expected = JedisDataException.class)
Expand All @@ -119,16 +123,7 @@ public void getMultiplePathsShouldSucceed() {
IRLObject obj = new IRLObject();
jsonClient.jsonSetLegacy("obj", obj);
Object expected = gson.fromJson(gson.toJson(obj), Object.class);
assertTrue(expected.equals(client.jsonGet("obj", Object.class, Path.of("bool"), Path.of("str"))));
}

@Test
public void getMultiplePathsShouldSucceedWithLegacy() {
// check multiple paths
IRLObject obj = new IRLObject();
jsonClient.jsonSetLegacy("obj", obj);
Object expected = gson.fromJson(gson.toJson(obj), Object.class);
assertTrue(expected.equals(client.jsonGet("obj", Object.class, Path.of("bool"), Path.of("str"))));
assertTrue(expected.equals(jsonClient.jsonGet("obj", Object.class, Path.of("bool"), Path.of("str"))));
}

@Test
Expand All @@ -139,15 +134,15 @@ public void toggle() {

Path pbool = Path.of(".bool");
// check initial value
assertTrue(client.jsonGet("obj", Boolean.class, pbool));
assertTrue(jsonClient.jsonGet("obj", Boolean.class, pbool));

// true -> false
jsonClient.jsonToggle("obj", pbool);
assertFalse(client.jsonGet("obj", Boolean.class, pbool));
assertFalse(jsonClient.jsonGet("obj", Boolean.class, pbool));

// false -> true
jsonClient.jsonToggle("obj", pbool);
assertTrue(client.jsonGet("obj", Boolean.class, pbool));
assertTrue(jsonClient.jsonGet("obj", Boolean.class, pbool));

// ignore non-boolean field
Path pstr = Path.of(".str");
Expand Down Expand Up @@ -186,7 +181,7 @@ public void delNonExistingPathsAreIgnored() {

@Test
public void typeChecksShouldSucceed() {
assertNull(client.jsonType("foobar"));
assertNull(jsonClient.jsonType("foobar"));
jsonClient.jsonSet("foobar", ROOT_PATH, new FooBarObject());
assertSame(Object.class, jsonClient.jsonType("foobar"));
assertSame(Object.class, jsonClient.jsonType("foobar", ROOT_PATH));
Expand All @@ -195,7 +190,7 @@ public void typeChecksShouldSucceed() {
assertSame(float.class, jsonClient.jsonType("foobar", Path.of(".fooF")));
assertSame(List.class, jsonClient.jsonType("foobar", Path.of(".fooArr")));
assertSame(boolean.class, jsonClient.jsonType("foobar", Path.of(".fooB")));
assertNull(client.jsonType("foobar", Path.of(".fooErr")));
assertNull(jsonClient.jsonType("foobar", Path.of(".fooErr")));
}

@Test
Expand Down Expand Up @@ -270,7 +265,7 @@ public void arrLen() {

@Test
public void arrLenDefaultPath() {
assertNull(client.jsonArrLen("array"));
assertNull(jsonClient.jsonArrLen("array"));
jsonClient.jsonSetLegacy("array", new int[]{1, 2, 3});
assertEquals(Long.valueOf(3), jsonClient.jsonArrLen("array"));
}
Expand Down Expand Up @@ -450,7 +445,7 @@ public void strAppend() {

@Test
public void strLen() {
assertNull(client.jsonStrLen("str"));
assertNull(jsonClient.jsonStrLen("str"));
jsonClient.jsonSet("str", ROOT_PATH, "foo");
assertEquals(Long.valueOf(3), jsonClient.jsonStrLen("str"));
assertEquals(Long.valueOf(3), jsonClient.jsonStrLen("str", ROOT_PATH));
Expand All @@ -464,10 +459,10 @@ public void numIncrBy() {

@Test
public void obj() {
assertNull(client.jsonObjLen("doc"));
assertNull(client.jsonObjKeys("doc"));
assertNull(client.jsonObjLen("doc", ROOT_PATH));
assertNull(client.jsonObjKeys("doc", ROOT_PATH));
assertNull(jsonClient.jsonObjLen("doc"));
assertNull(jsonClient.jsonObjKeys("doc"));
assertNull(jsonClient.jsonObjLen("doc", ROOT_PATH));
assertNull(jsonClient.jsonObjKeys("doc", ROOT_PATH));

String json = "{\"a\":[3], \"nested\": {\"a\": {\"b\":2, \"c\": 1}}}";
jsonClient.jsonSetWithPlainString("doc", ROOT_PATH, json);
Expand Down Expand Up @@ -500,8 +495,8 @@ public void plainString() {

@Test
public void resp() {
assertNull(client.jsonResp("resp"));
assertNull(client.jsonResp("resp", ROOT_PATH));
assertNull(jsonClient.jsonResp("resp"));
assertNull(jsonClient.jsonResp("resp", ROOT_PATH));

String json = "{\"foo\": {\"hello\":\"world\"}, \"bar\": [null, 3, 2.5, true]}";
jsonClient.jsonSetWithPlainString("resp", ROOT_PATH, json);
Expand Down Expand Up @@ -545,14 +540,14 @@ public void testJsonGsonParser() {

@Test
public void testDefaultJsonGsonParserStringsMustBeDifferent() {
Tick person = new Tick("foo", Instant.now());
Tick tick = new Tick("foo", Instant.now());

// using the default json gson parser which is automatically configured

jsonClient.jsonSet(person.getId(), ROOT_PATH, person);
jsonClient.jsonSet(tick.getId(), ROOT_PATH, tick);

Object valueExpected = jsonClient.jsonGet(person.getId(), Path.of(".created"));
assertNotEquals(valueExpected, person.getCreated().toString());
Object valueExpected = jsonClient.jsonGet(tick.getId(), Path.of(".created"));
assertNotEquals(valueExpected, tick.getCreated().toString());
}

@Test
Expand Down
Loading