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

如何从SwaggerParseResult还原原始JSON并实现深拷贝?

问题:OpenAPIV3Parser无法序列化SwaggerParseResult,导致深拷贝失败

我发现OpenAPIV3Parser只提供反序列化OpenAPI文档JSON的方法,没法把SwaggerParseResult序列化回JSON。比如我要对SwaggerParseResult做深拷贝,尝试把它序列化回JSON再反序列化生成新实例,但这么做得到的新SwaggerParseResult调用getOpenAPI()会返回null,没法被Swagger UI正常识别。现在需要找到可行的解决办法,前提是不能在内存里存原始JSON,且重新序列化后的JSON必须是有效的OpenAPI文档。

尝试的代码

package com.example.dynamicgateway.parser;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.parser.OpenAPIV3Parser;
import io.swagger.v3.parser.core.models.SwaggerParseResult;
import org.junit.jupiter.api.Test;

public class ParserTest {
    private final OpenAPIV3Parser parser = new OpenAPIV3Parser();
    @Test
    void testParser() throws JsonProcessingException {
        String testDoc = getTestDoc();
        SwaggerParseResult parseResult = parser.readContents(testDoc);
        // 试过带不带writerWithDefaultPrettyPrinter()都不行
        String reserializedDoc = new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(parseResult);
        // 反序列化后OpenApi为null
        SwaggerParseResult redeserializedDoc = parser.readContents(reserializedDoc);
    }

    String getTestDoc() {
        return """
                {
                  "openapi": "3.0.1",
                  "info": {
                    "title": "Hello World API",
                    "version": "1.0"
                  },
                  "servers": [
                    {
                      "url": "http://localhost:8090",
                      "description": "Generated server url"
                    }
                  ],
                  "paths": {
                    "/joy": {
                      "get": {
                        "tags": [
                          "Message Controller"
                        ],
                        "operationId": "getMessageOfJoy",
                        "responses": {
                          "200": {
                            "description": "OK",
                            "content": {
                              "*/*": {
                                "schema": {
                                  "$ref": "#/components/schemas/SuccessMessage"
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "/auth/hello-world": {
                      "get": {
                        "tags": [
                          "Message Controller"
                        ],
                        "operationId": "getHelloWorld",
                        "parameters": [
                          {
                            "name": "principal",
                            "in": "query",
                            "required": false,
                            "schema": {
                              "type": "string"
                            }
                          }
                        ],
                        "responses": {
                          "200": {
                            "description": "OK",
                            "content": {
                              "*/*": {
                                "schema": {
                                  "$ref": "#/components/schemas/SuccessMessage"
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "/error": {
                      "get": {
                        "tags": [
                          "my-error-controller"
                        ],
                        "operationId": "error",
                        "responses": {
                          "200": {
                            "description": "OK",
                            "content": {
                              "*/*": {
                                "schema": {
                                  "$ref": "#/components/schemas/FailureMessage"
                                }
                              }
                            }
                          }
                        }
                      },
                      "put": {
                        "tags": [
                          "my-error-controller"
                        ],
                        "operationId": "error_3",
                        "responses": {
                          "200": {
                            "description": "OK",
                            "content": {
                              "*/*": {
                                "schema": {
                                  "$ref": "#/components/schemas/FailureMessage"
                                }
                              }
                            }
                          }
                        }
                      },
                      "post": {
                        "tags": [
                          "my-error-controller"
                        ],
                        "operationId": "error_2",
                        "responses": {
                          "200": {
                            "description": "OK",
                            "content": {
                              "*/*": {
                                "schema": {
                                  "$ref": "#/components/schemas/FailureMessage"
                                }
                              }
                            }
                          }
                        }
                      },
                      "delete": {
                        "tags": [
                          "my-error-controller"
                        ],
                        "operationId": "error_5",
                        "responses": {
                          "200": {
                            "description": "OK",
                            "content": {
                              "*/*": {
                                "schema": {
                                  "$ref": "#/components/schemas/FailureMessage"
                                }
                              }
                            }
                          }
                        }
                      },
                      "options": {
                        "tags": [
                          "my-error-controller"
                        ],
                        "operationId": "error_6",
                        "responses": {
                          "200": {
                            "description": "OK",
                            "content": {
                              "*/*": {
                                "schema": {
                                  "$ref": "#/components/schemas/FailureMessage"
                                }
                              }
                            }
                          }
                        }
                      },
                      "head": {
                        "tags": [
                          "my-error-controller"
                        ],
                        "operationId": "error_1",
                        "responses": {
                          "200": {
                            "description": "OK",
                            "content": {
                              "*/*": {
                                "schema": {
                                  "$ref": "#/components/schemas/FailureMessage"
                                }
                              }
                            }
                          }
                        }
                      },
                      "patch": {
                        "tags": [
                          "my-error-controller"
                        ],
                        "operationId": "error_4",
                        "responses": {
                          "200": {
                            "description": "OK",
                            "content": {
                              "*/*": {
                                "schema": {
                                  "$ref": "#/components/schemas/FailureMessage"
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  },
                  "components": {
                    "schemas": {
                      "SuccessMessage": {
                        "type": "object",
                        "properties": {
                          "message": {
                            "type": "string"
                          }
                        }
                      },
                      "FailureMessage": {
                        "type": "object",
                        "properties": {
                          "message": {
                            "type": "string"
                          },
                          "method": {
                            "type": "string",
                            "enum": [
                              "GET",
                              "HEAD",
                              "POST",
                              "PUT",
                              "PATCH",
                              "DELETE",
                              "OPTIONS",
                              "TRACE"
                            ]
                          },
                          "request_path": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
                """;
    }
}

解决办法

问题出在直接序列化SwaggerParseResult上——这个类是解析过程的包装容器,包含解析元数据(错误、警告)和最终的OpenAPI对象,它本身不是为序列化设计的,直接用Jackson序列化会生成不符合OpenAPI规范的JSON,自然无法被OpenAPIV3Parser正确反序列化。

正确的处理流程:

  • 从SwaggerParseResult中取出核心的OpenAPI对象
  • 使用Swagger官方提供的序列化工具,将OpenAPI对象序列化为符合规范的JSON
  • 再用OpenAPIV3Parser反序列化该JSON,得到有效的SwaggerParseResult

具体实现

首先确保引入Swagger核心依赖(版本与你的parser保持一致):

<dependency>
    <groupId>io.swagger.core.v3</groupId>
    <artifactId>swagger-core</artifactId>
    <version>2.2.15</version>
</dependency>

修改后的测试代码:

package com.example.dynamicgateway.parser;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.core.util.Json;
import io.swagger.v3.parser.OpenAPIV3Parser;
import io.swagger.v3.parser.core.models.SwaggerParseResult;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertNotNull;

public class ParserTest {
    private final OpenAPIV3Parser parser = new OpenAPIV3Parser();
    // 使用Swagger官方配置好的ObjectMapper,保证序列化符合OpenAPI规范
    private final ObjectMapper openApiMapper = Json.mapper();

    @Test
    void testParser() throws JsonProcessingException {
        String testDoc = getTestDoc();
        SwaggerParseResult parseResult = parser.readContents(testDoc);
        
        // 确认初始解析得到的OpenAPI非空
        assertNotNull(parseResult.getOpenAPI());
        
        // 序列化核心的OpenAPI对象,而非SwaggerParseResult
        String reserializedDoc = openApiMapper.writerWithDefaultPrettyPrinter()
                .writeValueAsString(parseResult.getOpenAPI());
        
        // 反序列化JSON得到新的SwaggerParseResult
        SwaggerParseResult redeserializedDoc = parser.readContents(reserializedDoc);
        
        // 验证新实例的OpenAPI非空且有效
        assertNotNull(redeserializedDoc.getOpenAPI());
    }

    String getTestDoc() {
        return """
                {
                  "openapi": "3.0.1",
                  "info": {
                    "title": "Hello World API",
                    "version": "1.0"
                  },
                  "servers": [
                    {
                      "url": "http://localhost:8090",
                      "description": "Generated server url"
                    }
                  ],
                  "paths": {
                    "/joy": {
                      "get": {
                        "tags": [
                          "Message Controller"
                        ],
                        "operationId": "getMessageOfJoy",
                        "responses": {
                          "200": {
                            "description": "OK",
                            "content": {
                              "*/*": {
                                "schema": {
                                  "$ref": "#/components/schemas/SuccessMessage"
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "/auth/hello-world": {
                      "get": {
                        "tags": [
                          "Message Controller"
                        ],
                        "operationId": "getHelloWorld",
                        "parameters": [
                          {
                            "name": "principal",
                            "in": "query",
                            "required": false,
                            "schema": {
                              "type": "string"
                            }
                          }
                        ],
                        "responses": {
                          "200": {
                            "description": "OK",
                            "content": {
                              "*/*": {
                                "schema": {
                                  "$ref": "#/components/schemas/SuccessMessage"
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "/error": {
                      "get": {
                        "tags": [
                          "my-error-controller"
                        ],
                        "operationId": "error",
                        "responses": {
                          "200": {
                            "description": "OK",
                            "content": {
                              "*/*": {
                                "schema": {
                                  "$ref": "#/components/schemas/FailureMessage"
                                }
                              }
                            }
                          }
                        }
                      },
                      "put": {
                        "tags": [
                          "my-error-controller"
                        ],
                        "operationId": "error_3",
                        "responses": {
                          "200": {
                            "description": "OK",
                            "content": {
                              "*/*": {
                                "schema": {
                                  "$ref": "#/components/schemas/FailureMessage"
                                }
                              }
                            }
                          }
                        }
                      },
                      "post": {
                        "tags": [
                          "my-error-controller"
                        ],
                        "operationId": "error_2",
                        "responses": {
                          "200": {
                            "description": "OK",
                            "content": {
                              "*/*": {
                                "schema": {
                                  "$ref": "#/components/schemas/FailureMessage"
                                }
                              }
                            }
                          }
                        }
                      },
                      "delete": {
                        "tags": [
                          "my-error-controller"
                        ],
                        "operationId": "error_5",
                        "responses": {
                          "200": {
                            "description": "OK",
                            "content": {
                              "*/*": {
                                "schema": {
                                  "$ref": "#/components/schemas/FailureMessage"
                                }
                              }
                            }
                          }
                        }
                      },
                      "options": {
                        "tags": [
                          "my-error-controller"
                        ],
                        "operationId": "error_6",
                        "responses": {
                          "200": {
                            "description": "OK",
                            "content": {
                              "*/*": {
                                "schema": {
                                  "$ref": "#/components/schemas/FailureMessage"
                                }
                              }
                            }
                          }
                        }
                      },
                      "head": {
                        "tags": [
                          "my-error-controller"
                        ],
                        "operationId": "error_1",
                        "responses": {
                          "200": {
                            "description": "OK",
                            "content": {
                              "*/*": {
                                "schema": {
                                  "$ref": "#/components/schemas/FailureMessage"
                                }
                              }
                            }
                          }
                        }
                      },
                      "patch": {
                        "tags": [
                          "my-error-controller"
                        ],
                        "operationId": "error_4",
                        "responses": {
                          "200": {
                            "description": "OK",
                            "content": {
                              "*/*": {
                                "schema": {
                                  "$ref": "#/components/schemas/FailureMessage"
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  },
                  "components": {
                    "schemas": {
                      "SuccessMessage": {
                        "type": "object",
                        "properties": {
                          "message": {
                            "type": "string"
                          }
                        }
                      },
                      "FailureMessage": {
                        "type": "object",
                        "properties": {
                          "message": {
                            "type": "string"
                          },
                          "method": {
                            "type": "string",
                            "enum": [
                              "GET",
                              "HEAD",
                              "POST",
                              "PUT",
                              "PATCH",
                              "DELETE",
                              "OPTIONS",
                              "TRACE"
                            ]
                          },
                          "request_path": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
                """;
    }
}

关键说明

  • Json.mapper()是Swagger官方提供的ObjectMapper,已经预配置了OpenAPI对象的序列化规则,能生成完全符合规范的JSON文档
  • 不要直接操作SwaggerParseResult的序列化,它只是解析过程的结果容器,核心的API定义都在OpenAPI对象中
  • 如果需要完整拷贝SwaggerParseResult,可以在反序列化得到新的OpenAPI后,手动构建新的SwaggerParseResult实例并设置相关属性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 03:44:52