
本文探讨了jedis 4.2.3版本中`unifiedjedis.jsonget()`方法在处理json数据时,将字节数组值意外地表示为以`.0`结尾的`double`类型的问题。该现象源于jedis底层使用的gson或org.json库对数字类型进行向上转型。文章提供了三种有效的解决方案:通过类型转换后手动处理`linkedhashmap`、利用`path`参数直接获取指定类型的字节数组,以及执行原始命令进行手动解析,旨在帮助开发者正确获取和处理原始字节数据。
在使用Jedis客户端库(尤其是4.2.3版本)与Redis的JSON模块交互时,开发者可能会遇到一个特定问题:当通过UnifiedJedis.jsonGet()方法获取存储在JSON中的字节数组(例如,表示为数字列表)时,返回的结果会将这些字节值显示为以.0结尾的double类型,而非原始的字节值。例如,一个存储为[60, 63, 120]的字节序列,可能会被错误地解析为[60.0, 63.0, 120.0]。
这一现象的根本原因在于Jedis 4.2.3版本内部处理JSON数据时,依赖于如Gson或org.json:json等第三方库。这些库在默认情况下,会将所有数字类型(包括原本可以表示为byte或int的整数)统一向上转型(upcast)为double类型,从而导致原始的字节值被附加了.0的浮点表示。这对于需要精确字节数据或希望避免不必要类型转换的应用程序来说,是一个需要解决的问题。
接下来,我们将探讨几种解决此问题的方法,以确保能够正确获取和处理Redis中存储的原始字节数组。
针对Jedis jsonGet方法返回double类型字节值的问题,以下提供三种不同的解决方案,每种方案都有其适用场景和优缺点。
UnifiedJedis.jsonGet()方法在未指定返回类型时,通常会返回一个Object类型的结果,该结果在内部通常是一个LinkedHashMap的实例,用于表示JSON对象的结构。我们可以将此Object强制转换为LinkedHashMap,然后遍历其内容,识别并转换那些被错误表示为double的字节值。
实现思路:
示例代码片段(概念性):
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.UnifiedJedis;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class JedisJsonByteConverter {
public static void main(String[] args) {
HostAndPort config = new HostAndPort("localhost", 6379);
UnifiedJedis client = new UnifiedJedis(config);
String key = "StandaloneResponse:9b970b5f-32c2-4265-92cb-9af9d6707782";
Object rawObject = client.jsonGet(key);
if (rawObject instanceof LinkedHashMap) {
LinkedHashMap<String, Object> resultMap = (LinkedHashMap<String, Object>) rawObject;
// 假设我们知道ReturnValue在variables下
if (resultMap.containsKey("variables") && resultMap.get("variables") instanceof LinkedHashMap) {
LinkedHashMap<String, Object> variables = (LinkedHashMap<String, Object>) resultMap.get("variables");
if (variables.containsKey("ReturnValue") && variables.get("ReturnValue") instanceof List) {
List<?> rawReturnValue = (List<?>) variables.get("ReturnValue");
List<Byte> byteList = new ArrayList<>();
for (Object item : rawReturnValue) {
if (item instanceof Double) {
byteList.add(((Double) item).byteValue());
} else {
// 处理非Double类型,或者抛出异常
System.err.println("Unexpected type in ReturnValue: " + item.getClass().getName());
}
}
System.out.println("Converted ReturnValue as bytes: " + byteList);
// 替换原始map中的ReturnValue
variables.put("ReturnValue", byteList);
}
}
System.out.println("Processed Object: " + resultMap);
} else {
System.out.println("Raw object is not a LinkedHashMap: " + rawObject);
}
client.close();
}
}注意事项:
Jedis的jsonGet方法支持通过Path对象来指定要获取的JSON路径,并且可以指定期望的返回类型。这是获取特定字节数组最直接且推荐的方法。通过明确告知Jedis我们期望ReturnValue字段返回Byte[]类型,Jedis将尝试进行相应的类型转换。
实现思路:
示例代码:
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.UnifiedJedis;
import redis.clients.jedis.json.Path;
public class JedisJsonGetByteArray {
public static void main(String[] args) {
HostAndPort config = new HostAndPort("localhost", 6379);
UnifiedJedis client = new UnifiedJedis(config);
String key = "StandaloneResponse:9b970b5f-32c2-4265-92cb-9af9d6707782";
// 假设ReturnValue在顶层对象的variables字段下
// 路径应根据实际JSON结构调整。例如,如果ReturnValue直接在根,路径为Path.ROOT
// 根据提供的问题输出,ReturnValue在 `variables` 字段下
Path returnValuePath = Path.of(".variables.ReturnValue");
try {
Byte[] returnValue = client.jsonGet(key, Byte[].class, returnValuePath);
if (returnValue != null) {
System.out.print("Retrieved ReturnValue as Byte array: [");
for (int i = 0; i < returnValue.length; i++) {
System.out.print(returnValue[i]);
if (i < returnValue.length - 1) {
System.out.print(", ");
}
}
System.out.println("]");
} else {
System.out.println("ReturnValue not found or could not be converted.");
}
} catch (Exception e) {
System.err.println("Error retrieving ReturnValue as Byte array: " + e.getMessage());
e.printStackTrace();
} finally {
client.close();
}
}
}注意事项:
如果前两种方法无法满足需求,或者需要更底层的控制,可以直接执行Redis的原始JSON GET命令,并手动解析返回的字符串结果。这种方法绕过了Jedis内部的JSON解析器,提供了最大的灵活性,但同时也增加了开发者的工作量。
实现思路:
示例代码:
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.UnifiedJedis;
import redis.clients.jedis.json.JsonProtocol;
import redis.clients.jedis.args.CommandArguments;
import redis.clients.jedis.util.SafeEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class JedisRawCommandGet {
public static void main(String[] args) {
HostAndPort config = new HostAndPort("localhost", 6379);
UnifiedJedis client = new UnifiedJedis(config);
String key = "StandaloneResponse:9b970b5f-32c2-4265-92cb-9af9d6707782";
try {
// 执行原始JSON GET命令,获取整个JSON字符串
// 注意:JsonProtocol.JsonCommand.GET 默认是获取整个JSON文档
// 如果需要特定路径,可能需要构造更复杂的命令,例如 JSON.GET <key> .variables.ReturnValue
// Jedis 4.x 的 executeCommand 接受 CommandArguments
// 这里我们先获取整个JSON,然后手动解析
CommandArguments args = new CommandArguments(JsonProtocol.JsonCommand.GET).add(key);
Object rawResponse = client.executeCommand(args);
if (rawResponse instanceof byte[]) {
String jsonString = SafeEncoder.encode((byte[]) rawResponse);
System.out.println("Raw JSON string from executeCommand: " + jsonString);
// 假设我们知道ReturnValue是一个数字列表,并且格式是 [val1, val2, ...]
// 这里需要更复杂的JSON解析逻辑,可以使用Jackson, Gson等库
// 简单示例:从字符串中提取数字列表
Pattern pattern = Pattern.compile("ReturnValue=\[([\d.,\s]+)\]");
Matcher matcher = pattern.matcher(jsonString);
if (matcher.find()) {
String numbersStr = matcher.group(1);
String[] numberTokens = numbersStr.split(",\s*");
List<Byte> byteList = new ArrayList<>();
for (String token : numberTokens) {
try {
// 移除 .0 后缀,并转换为 byte
byteList.add((byte) Double.parseDouble(token));
} catch (NumberFormatException e) {
System.err.println("Could not parse number token: " + token);
}
}
System.out.println("Parsed ReturnValue as bytes: " + byteList);
} else {
System.out.println("ReturnValue not found in raw JSON string.");
}
} else {
System.out.println("Raw response is not a byte array: " + rawResponse);
}
} catch (Exception e) {
System.err.println("Error executing raw command: " + e.getMessage());
e.printStackTrace();
} finally {
client.close();
}
}
}注意事项:
Jedis 4.2.3版本中jsonGet方法返回字节数组值时出现的.0后缀问题,主要是由于底层JSON解析库的默认类型向上转型行为。针对这个问题,我们提供了三种解决方案:
在大多数场景下,使用Path参数直接指定返回类型是解决此问题的最佳实践。它既保持了代码的简洁性,又有效地解决了类型转换的困扰。开发者应根据实际需求和对JSON结构的了解程度,选择最合适的解决方案。
以上就是深入解析Jedis jsonGet方法中字节数组值以.0结尾的问题及解决方案的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号