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

如何让openapi-generator-maven-plugin将请求头对象序列化为JSON

问题描述

我尝试使用openapi-generator-maven-plugin的Java生成器,将复杂对象序列化为JSON而非调用toString()方法,但生成的Java客户端无法实现请求头对象的JSON序列化效果。


相关代码与配置

自定义DTO类

@Data
public class RequestContextDTO {
  @Valid
  private TrackingDTO tracking;
}

@Data
public class TrackingDTO {
  private String trackingNumber;
}

OpenAPI YAML定义

openapi: 3.0.1
info:
  title: Test Header Serialization
  version: "1"
servers:
- url: http://localhost:8080
  description: Generated server url
paths:
  /test/:
    get:
      tags:
      - MyController
      summary: Test Header As Complex Object
      operationId: postRequestWithHeader
      parameters:
      - name: x-request-context
        in: header
        description: Request context
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RequestContextDTO"
      responses:
        "200":
          description: Success
components:
  schemas:
    RequestContextDTO:
      required:
      - businessContext
      - userInfo
      type: object
      properties:
        tracking:
          $ref: "#/components/schemas/TrackingDTO"
    TrackingDTO:
      required:
      - trackingNumber
      type: object
      properties:
        trackingNumber:
          type: string

Maven插件配置

<plugin>
    <groupId>org.openapitools</groupId>
    <artifactId>openapi-generator-maven-plugin</artifactId>
    <version>7.8.0</version>
    
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <inputSpec>/definitions/newApi.yaml</inputSpec>
                <generatorName>java</generatorName>

                <generateApiDocumentation>false</generateApiDocumentation>
                <configOptions>
                    <library>jersey3</library>
                    <useJakartaEe>true</useJakartaEe>
                    <dateLibrary>java8</dateLibrary>
                    <apiPackage>${client.package}.api</apiPackage>
                    <invokerPackage>${client.package}.api</invokerPackage>
                    <modelPackage>${client.package}.model</modelPackage>
                    <performBeanValidation>false</performBeanValidation>
                    <serializationLibrary>jackson</serializationLibrary>
                </configOptions>
            </configuration>
        </execution>
    </executions>
</plugin>

生成的问题代码

MyControllerApi生成代码

public class MyControllerApi {
  private ApiClient apiClient;
  
  public ApiResponse<Void> postRequestWithHeaderWithHttpInfo(RequestContextDTO xRequestContext) throws ApiException {
    if (xRequestContext == null) {
      throw new ApiException(400, "Missing the required parameter 'xRequestContext' when calling postRequestWithHeader");
    } else {
      Map<String, String> localVarHeaderParams = new LinkedHashMap();
      localVarHeaderParams.put("x-request-context", this.apiClient.parameterToString(xRequestContext));
      String localVarAccept = this.apiClient.selectHeaderAccept(new String[0]);
      String localVarContentType = this.apiClient.selectHeaderContentType(new String[0]);
      return this.apiClient.invokeAPI("MyControllerApi.postRequestWithHeader", "/test/", "GET", new ArrayList(), (Object)null, localVarHeaderParams, new LinkedHashMap(), new LinkedHashMap(), localVarAccept, localVarContentType, (String[])null, (GenericType)null, false);
    }
  }
}

ApiClient的parameterToString方法

public String parameterToString(Object param) {
  if (param == null) {
    return "";
  } else if (param instanceof Date) {
    return formatDate((Date) param);
  } else if (param instanceof OffsetDateTime) {
    return formatOffsetDateTime((OffsetDateTime) param);
  } else if (param instanceof Collection<?>) {
    StringBuilder b = new StringBuilder();
    for(Object o : (Collection<?>)param) {
      if(b.length() > 0) {
        b.append(',');
      }
      b.append(String.valueOf(o));
    }
    return b.toString();
  } else {
    return String.valueOf(param);
  }
}

当前生成的代码会调用RequestContextDTO的toString()方法而非序列化为JSON,请问能否通过插件配置或调整YAML实现请求头复杂对象的JSON序列化?


解决方案

可以通过以下几种方式实现需求:

1. 自定义ApiClient模板,修改参数序列化逻辑

openapi-generator支持通过Freemarker模板自定义生成逻辑:

  • 从openapi-generator源码中获取Java生成器的ApiClient.mustache模板
  • 修改parameterToString方法,增加复杂对象的JSON序列化分支:
    public String parameterToString(Object param) {
      if (param == null) {
        return "";
      } else if (param instanceof Date) {
        return formatDate((Date) param);
      } else if (param instanceof OffsetDateTime) {
        return formatOffsetDateTime((OffsetDateTime) param);
      } else if (param instanceof Collection<?>) {
        StringBuilder b = new StringBuilder();
        for(Object o : (Collection<?>)param) {
          if(b.length() > 0) {
            b.append(',');
          }
          b.append(parameterToString(o));
        }
        return b.toString();
      } else if (!isSimpleType(param.getClass())) {
        // 利用Jackson序列化复杂对象为JSON
        try {
          return getObjectMapper().writeValueAsString(param);
        } catch (JsonProcessingException e) {
          throw new RuntimeException("Failed to serialize parameter to JSON", e);
        }
      } else {
        return String.valueOf(param);
      }
    }
    
    // 辅助方法判断是否为简单类型
    private boolean isSimpleType(Class<?> clazz) {
      return clazz.isPrimitive() || clazz.equals(String.class) || clazz.equals(Integer.class) 
             || clazz.equals(Long.class) || clazz.equals(Double.class) || clazz.equals(Boolean.class)
             || clazz.equals(Float.class) || clazz.equals(Short.class) || clazz.equals(Byte.class);
    }
    
  • 在Maven插件配置中添加自定义模板目录:
    <configuration>
      <!-- 其他原有配置 -->
      <templateDirectory>${project.basedir}/src/main/resources/openapi-templates</templateDirectory>
    </configuration>
    

2. 调整OpenAPI YAML(辅助优化)

虽然OpenAPI 3.0支持头参数的content/application/json定义,但部分生成器对该场景支持有限,可尝试在schema中添加format: json标记:

parameters:
- name: x-request-context
  in: header
  required: true
  content:
    application/json:
      schema:
        $ref: "#/components/schemas/RequestContextDTO"
        format: json

该方式需结合模板修改使用,单独使用不一定生效。

3. 生成后手动扩展(临时方案)

若不想修改模板,可在生成代码后手动扩展ApiClient的parameterToString方法,或在调用API前自行序列化对象:

// 调用前手动序列化
RequestContextDTO context = new RequestContextDTO();
// 设置属性
String jsonContext = new ObjectMapper().writeValueAsString(context);
// 注意需修改API方法参数为String类型,或自行适配
myControllerApi.postRequestWithHeaderWithHttpInfo(jsonContext);

此方式需修改API调用代码,仅作为临时替代方案。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 02:00:56