You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何强制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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 07:00:58