如何强制protobuf Struct中exp字段为int64并保留其他任意键值对?
问题描述
定义了如下Protobuf消息:
message EchoResponse { string message = 1; google.protobuf.Struct jwtClaims = 2; }
执行以下代码将JSON合并到Struct时:
final var jwtClaimsStruct = Struct.newBuilder(); JsonFormat.parser() .merge(someJson, jwtClaimsStruct);
得到的结果中exp字段被转为double类型:
{ "message": "FFbarsdfasf", "jwtClaims": { "sub": "good", "exp": 1.664354816E9, "iss": "http://localhost", "jti": "3dbecf85-d5f2-2109-5a21-0d135fb35e8a" } }
需求:让exp字段保持int64类型,同时允许其他任意键值对保留原有类型。
解决方案
首先明确:google.protobuf.Struct的数值类型统一使用double存储,因此JSON中的整数会被默认解析为double。以下是几种可行的实现方式:
1. 解析前预处理特定字段
先将JSON解析为Java的Map结构,手动把exp字段转为Long类型后再构建Struct:
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.protobuf.Struct; import com.google.protobuf.util.JsonFormat; // 1. 将JSON字符串解析为Java Map ObjectMapper objectMapper = new ObjectMapper(); Map<String, Object> claimsMap = objectMapper.readValue(someJson, new TypeReference<Map<String, Object>>() {}); // 2. 处理exp字段,将Double类型转为Long if (claimsMap.containsKey("exp")) { Object expVal = claimsMap.get("exp"); if (expVal instanceof Double) { claimsMap.put("exp", ((Double) expVal).longValue()); } } // 3. 将处理后的Map转回JSON,再合并到Struct String processedJson = objectMapper.writeValueAsString(claimsMap); final var jwtClaimsStruct = Struct.newBuilder(); JsonFormat.parser().merge(processedJson, jwtClaimsStruct);
2. 序列化时输出整数格式
即便exp在Struct中存储为double,只要它是整数值,可以通过配置JsonFormat.Printer,让其输出为整数而非科学计数法格式:
import com.google.protobuf.util.JsonFormat; // 序列化EchoResponse时配置Printer String formattedJson = JsonFormat.printer() .omittingInsignificantWhitespace() .print(echoResponse);
3. 自定义动态字段消息(严格区分数值类型)
如果必须严格存储int64类型而非double,可以放弃使用google.protobuf.Struct,自定义支持多类型数值的消息:
// 定义支持多类型的数值消息 message TypedValue { oneof value { int64 int_value = 1; double double_value = 2; string string_value = 3; bool bool_value = 4; Struct struct_value = 5; ListValue list_value = 6; } } // 定义动态键值对消息 message DynamicClaims { map<string, TypedValue> claims = 1; } // 修改EchoResponse消息 message EchoResponse { string message = 1; DynamicClaims jwtClaims = 2; }
这种方式需要自定义解析逻辑,根据JSON中数值的类型选择存入对应的字段,能严格区分int64和double类型。
内容的提问来源于stack exchange,提问作者Archimedes Trajano
相关产品推荐
相关产品推荐

