From 135ffbcb1bda934f31d47575c1d0f7428db34f51 Mon Sep 17 00:00:00 2001 From: junietrytwo Date: Mon, 13 Apr 2026 13:44:53 +0800 Subject: [PATCH] maven report in maven site --- modules/swagger-maven-plugin/pom.xml | 5 + .../v3/plugin/maven/SwaggerReport.java | 248 ++++++++++++++++++ 2 files changed, 253 insertions(+) create mode 100755 modules/swagger-maven-plugin/src/main/java/io/swagger/v3/plugin/maven/SwaggerReport.java diff --git a/modules/swagger-maven-plugin/pom.xml b/modules/swagger-maven-plugin/pom.xml index 633bf1ba23..3f59c71053 100644 --- a/modules/swagger-maven-plugin/pom.xml +++ b/modules/swagger-maven-plugin/pom.xml @@ -152,6 +152,11 @@ plexus-component-annotations 2.2.0 + + org.apache.maven.reporting + maven-reporting-api + 3.1.1 + io.swagger.core.v3 swagger-jaxrs2 diff --git a/modules/swagger-maven-plugin/src/main/java/io/swagger/v3/plugin/maven/SwaggerReport.java b/modules/swagger-maven-plugin/src/main/java/io/swagger/v3/plugin/maven/SwaggerReport.java new file mode 100755 index 0000000000..e049442c64 --- /dev/null +++ b/modules/swagger-maven-plugin/src/main/java/io/swagger/v3/plugin/maven/SwaggerReport.java @@ -0,0 +1,248 @@ +package io.swagger.v3.plugin.maven; + +import org.codehaus.doxia.sink.Sink; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.project.MavenProject; +import org.apache.maven.reporting.MavenReport; +import org.apache.maven.reporting.MavenReportException; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import java.util.Locale; + +/** + * Generates an interactive Swagger UI page from the project's OpenAPI + * specification and integrates it into the Maven site as a report. + * + *

By default the report looks for {@code openapi.json} or + * {@code openapi.yaml} in {@code ${project.build.directory}}. + * Run the {@code resolve} goal first to generate the spec file.

+ * + *

Usage in a consumer POM:

+ *
{@code
+ * 
+ *   
+ *     
+ *       io.swagger.core.v3
+ *       swagger-maven-plugin
+ *       
+ *         
+ *           
+ *             openapi-report
+ *           
+ *         
+ *       
+ *     
+ *   
+ * 
+ * }
+ * + * @since 2.2.48 + */ +@Mojo(name = "openapi-report", threadSafe = true) +public class SwaggerReport extends AbstractMojo implements MavenReport { + + private static final String OUTPUT_NAME = "swagger-ui"; + + @Parameter(defaultValue = "${project.reporting.outputDirectory}", + readonly = true, required = true) + private File reportOutputDirectory; + + /** + * Path to the OpenAPI spec file. When unset the report probes + * {@code ${project.build.directory}/openapi.json} then + * {@code ${project.build.directory}/openapi.yaml}. + */ + @Parameter(property = "swagger.report.specFile") + private File specFile; + + /** + * Skip generation of the OpenAPI report. + */ + @Parameter(property = "swagger.report.skip", defaultValue = "false") + private boolean skip; + + /** + * Swagger UI version loaded from the unpkg CDN. + */ + @Parameter(property = "swagger.report.swaggerUiVersion", + defaultValue = "5.18.2") + private String swaggerUiVersion; + + @Parameter(defaultValue = "${project}", readonly = true, required = true) + private MavenProject project; + + // -- AbstractMojo -------------------------------------------------------- + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + try { + generate(null, Locale.getDefault()); + } catch (MavenReportException e) { + throw new MojoExecutionException( + "Failed to generate OpenAPI report", e); + } + } + + // -- MavenReport --------------------------------------------------------- + + @Override + public void generate(Sink sink, Locale locale) throws MavenReportException { + File resolved = resolveSpecFile(); + if (resolved == null) { + getLog().warn("OpenAPI spec file not found. " + + "Run the swagger-maven-plugin:resolve goal first, " + + "or set to the path of your spec."); + return; + } + + File outputDir = getReportOutputDirectory(); + if (!outputDir.exists() && !outputDir.mkdirs()) { + throw new MavenReportException( + "Could not create report output directory: " + outputDir); + } + + try { + String specFileName = resolved.getName(); + Files.copy(resolved.toPath(), + new File(outputDir, specFileName).toPath(), + StandardCopyOption.REPLACE_EXISTING); + + String html = buildSwaggerUiPage(specFileName); + File htmlFile = new File(outputDir, OUTPUT_NAME + ".html"); + Files.write(htmlFile.toPath(), + html.getBytes(StandardCharsets.UTF_8)); + + getLog().info("OpenAPI report generated at " + + htmlFile.getAbsolutePath()); + } catch (IOException e) { + throw new MavenReportException( + "Failed to generate OpenAPI report", e); + } + } + + @Override + public String getOutputName() { + return OUTPUT_NAME; + } + + @Override + public String getCategoryName() { + return CATEGORY_PROJECT_REPORTS; + } + + @Override + public String getName(Locale locale) { + return "OpenAPI Specification"; + } + + @Override + public String getDescription(Locale locale) { + return "Interactive Swagger UI documentation for the project's " + + "OpenAPI specification."; + } + + @Override + public void setReportOutputDirectory(File directory) { + this.reportOutputDirectory = directory; + } + + @Override + public File getReportOutputDirectory() { + return reportOutputDirectory; + } + + @Override + public boolean isExternalReport() { + return true; + } + + @Override + public boolean canGenerateReport() { + return !skip && resolveSpecFile() != null; + } + + // -- internal ------------------------------------------------------------ + + File resolveSpecFile() { + if (specFile != null && specFile.isFile()) { + return specFile; + } + File buildDir = new File(project.getBuild().getDirectory()); + File json = new File(buildDir, "openapi.json"); + if (json.isFile()) { + return json; + } + File yaml = new File(buildDir, "openapi.yaml"); + if (yaml.isFile()) { + return yaml; + } + return null; + } + + private String buildSwaggerUiPage(String specFileName) { + String projectName = project.getName() != null + ? project.getName() : project.getArtifactId(); + String title = escapeHtml(projectName) + " \u2013 OpenAPI"; + + return "\n" + + "\n" + + "\n" + + " \n" + + " \n" + + " " + title + "\n" + + " \n" + + " \n" + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + "\n" + + "\n"; + } + + static String escapeHtml(String text) { + return text.replace("&", "&") + .replace("<", "<") + .replace(">", ">") + .replace("\"", """); + } + + static String escapeJs(String text) { + return text.replace("\\", "\\\\") + .replace("\"", "\\\"") + .replace("'", "\\'") + .replace("\n", "\\n") + .replace("\r", "\\r"); + } +}