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

WireMock gRPC扩展使用google.protobuf.StringValue时抛无效包装类型异常

WireMock gRPC扩展处理Protobuf包装类型字段报错问题

我基于WireMock的gRPC演示项目开发,定义了包含google.protobuf.StringValue包装类型的Protobuf协议:

syntax = "proto3";

option csharp_namespace = "My.Package";
option java_package = "com.my.package";

import "google/protobuf/wrappers.proto";

service MySvc {
  rpc GetBond(MyRequest) returns (MyResponse) {}
}

message MyRequest {
  string myValue = 1;
}

message MyResponse {
  bool success = 1;
  string message = 2;
  google.protobuf.StringValue messageStringValue = 3;
}

改写测试类GrpcTest.java如下:

import com.example.grpc.HelloRequest;
import com.example.grpc.HelloResponse;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.junit5.WireMockExtension;
import com.google.protobuf.StringValue;
import com.mine.My;
import com.mine.MySvcGrpc;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.StatusRuntimeException;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.wiremock.grpc.GrpcExtensionFactory;
import org.wiremock.grpc.dsl.WireMockGrpc;
import org.wiremock.grpc.dsl.WireMockGrpcService;
import wiremock.grpc.client.GreetingsClient;

import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
import static java.lang.Thread.sleep;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.wiremock.grpc.dsl.WireMockGrpc.Status;
import static org.wiremock.grpc.dsl.WireMockGrpc.equalToMessage;
import static org.wiremock.grpc.dsl.WireMockGrpc.message;
import static org.wiremock.grpc.dsl.WireMockGrpc.method;

public class GrpcTest {

    WireMockGrpcService mockGreetingService;
    WireMockGrpcService mockRefDataService;
    ManagedChannel channel;
    GreetingsClient greetingsClient;

    @RegisterExtension
    public static WireMockExtension wm =
            WireMockExtension.newInstance()
                    .options(
                            wireMockConfig()
                                    .port(9090)
                                    .withRootDirectory("src/test/resources/wiremock")
                                    .extensions(new GrpcExtensionFactory())
                    )
                    .build();

    @BeforeEach
    void init() {
        var wiremock = new WireMock(wm.getPort());
        mockRefDataService =
                new WireMockGrpcService(wiremock, MySvcGrpc.SERVICE_NAME);
    }

    @AfterEach
    void tearDown() {
        channel.shutdown();
    }

    @Test
    void dynamic_response_via_JSON() throws InterruptedException {
        mockRefDataService.stubFor(
                method("GetResponse")
                        .willReturn(WireMockGrpc.message(
                                My.MyResponse.newBuilder()
                                        .setSuccess(true)
                                        .setMessage("abc")
                                        .setMessageStringValue(StringValue.of("ASDAS"))
                        ))
        );
        System.out.println("START");
        sleep(30000);
    }
}

使用Postman向gRPC Mock Server发送请求时,抛出以下异常:

Exception in thread "grpc-default-executor-0" com.google.protobuf.InvalidProtocolBufferException: Invalid wrapper type: google.protobuf.StringValue
    at com.google.protobuf.util.JsonFormat$ParserImpl.mergeWrapper(JsonFormat.java:1616)
    at com.google.protobuf.util.JsonFormat$ParserImpl.access$2100(JsonFormat.java:1276)
    at com.google.protobuf.util.JsonFormat$ParserImpl$2.merge(JsonFormat.java:1352)
    at com.google.protobuf.util.JsonFormat$ParserImpl.merge(JsonFormat.java:1432)
    at com.google.protobuf.util.JsonFormat$ParserImpl.parseFieldValue(JsonFormat.java:1995)
    at com.google.protobuf.util.JsonFormat$ParserImpl.mergeField(JsonFormat.java:1646)
    at com.google.protobuf.util.JsonFormat$ParserImpl.mergeMessage(JsonFormat.java:1477)
    at com.google.protobuf.util.JsonFormat$ParserImpl.merge(JsonFormat.java:1435)
    at com.google.protobuf.util.JsonFormat$ParserImpl.merge(JsonFormat.java:1317)
    at com.google.protobuf.util.JsonFormat$Parser.merge(JsonFormat.java:449)
    at org.wiremock.grpc.internal.JsonMessageUtils.lambda$toMessage$1(JsonMessageUtils.java:36)
    at com.github.tomakehurst.wiremock.common.Exceptions.uncheck(Exceptions.java:72)
    at org.wiremock.grpc.internal.JsonMessageUtils.toMessage(JsonMessageUtils.java:36)
    at org.wiremock.grpc.internal.UnaryServerCallHandler.lambda$invoke$0(UnaryServerCallHandler.java:92)
    at com.github.tomakehurst.wiremock.http.AbstractRequestHandler.handle(AbstractRequestHandler.java:101)
    at org.wiremock.grpc.internal.UnaryServerCallHandler.invoke(UnaryServerCallHandler.java:60)
    at org.wiremock.grpc.internal.UnaryServerCallHandler.invoke(UnaryServerCallHandler.java:31)
    at io.grpc.stub.ServerCalls$UnaryServerCallHandler$UnaryServerCallListener.onHalfClose(ServerCalls.java:182)
    at io.grpc.internal.ServerCallImpl$ServerStreamListenerImpl.halfClosed(ServerCallImpl.java:351)
    at io.grpc.internal.ServerImpl$JumpToApplicationThreadServerStreamListener$1HalfClosed.runInContext(ServerImpl.java:860)
    at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
    at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at java.base/java.lang.Thread.run(Thread.java:833)

依赖版本信息

初始使用的依赖:

java.io
java.lang
java.util
Gradle: com.google.protobuf:protobuf-java:3.24.0
Gradle: io.grpc:grpc-api:1.59.0
Gradle: org.hamcrest:hamcrest:2.2
Gradle: org.junit.jupiter:junit-jupiter-api:5.10.0
Gradle: org.wiremock:wiremock-grpc-extension:0.3.0
Gradle: org.wiremock:wiremock:3.3.1

升级后的依赖(问题仍存在):

java.io
java.lang
java.util
Gradle: com.google.protobuf:protobuf-java:3.25.1
Gradle: io.grpc:grpc-api:1.63.0
Gradle: org.hamcrest:hamcrest:2.2
Gradle: org.junit.jupiter:junit-jupiter-api:5.10.0
Gradle: org.wiremock:wiremock-grpc-extension:0.6.0
Gradle: org.wiremock:wiremock:3.3.1

测试过程中的发现

  • 从willReturn()中移除.setMessageStringValue(StringValue.of("ASDAS"))后,请求可正常收到响应
  • 单独构建WireMockGrpc.message()时,生成的内容不符合预期:
    WireMockGrpc.message(
            My.MyResponse.newBuilder()
                    .setSuccess(true)
                    .setMessage("abc")
                    .setMessageStringValue(StringValue.of("ASDAS"))
    ).build();
    
    生成的Body内容:
    Body {content={
      "success": true,
      "message": "abc",
      "messageStringValue": "ASDAS" <- 此处应该是{"value": "ASDAS"}
    }, binary=false, json=false}
    
  • 改用.setMessageStringValue(StringValue.newBuilder().setValue("asda").build())也无法解决问题

问题分析及解决方案

从错误日志和生成的JSON结构可以看出,WireMock gRPC扩展在将Protobuf消息转换为JSON时,没有正确处理Google官方的包装类型(如StringValue),而是直接将其序列化为原始字符串,导致后续解析时抛出Invalid wrapper type异常。

临时解决方案:

  1. 规避方案:如果业务允许,暂时移除包装类型字段,改用普通字符串类型
  2. 手动构造JSON响应:跳过WireMockGrpc.message()方法,直接构造符合Protobuf JSON格式的响应内容:
    mockRefDataService.stubFor(
        method("GetResponse")
            .willReturn(WireMockGrpc.jsonMessage("{\"success\":true,\"message\":\"abc\",\"messageStringValue\":{\"value\":\"ASDAS\"}}"))
    );
    
  3. 反馈问题:向WireMock gRPC扩展项目提交Issue,等待官方修复该兼容性问题

内容的提问来源于stack exchange,提问作者yavorek

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 17:59:51