001/* 002 * Copyright 2017-2021 original authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.micronaut.maven.jsonschema; 017 018import io.micronaut.core.util.StringUtils; 019import io.micronaut.maven.AbstractMicronautMojo; 020import org.apache.maven.plugin.MojoExecutionException; 021import org.apache.maven.plugin.MojoFailureException; 022import org.apache.maven.plugins.annotations.LifecyclePhase; 023import org.apache.maven.plugins.annotations.Mojo; 024import org.apache.maven.plugins.annotations.Parameter; 025import org.apache.maven.project.MavenProject; 026 027import java.io.File; 028import java.nio.file.Path; 029import java.util.List; 030 031import io.micronaut.jsonschema.generator.SourceGenerator; 032import io.micronaut.jsonschema.generator.utils.SourceGeneratorConfigBuilder; 033import io.micronaut.jsonschema.generator.loaders.UrlLoader; 034 035import javax.inject.Inject; 036 037/** 038 * Json Schema generator mojo provides the parameters for all generators and the invoker logic. 039 * <p> 040 * Expects single or multiple schema files as input via a URL, file, or directory; 041 * and generates all required source code representing the validation form in the targeted language. 042 * </p> 043 */ 044@Mojo(name = JsonSchemaGeneratorMojo.MOJO_NAME, defaultPhase = LifecyclePhase.GENERATE_SOURCES) 045public class JsonSchemaGeneratorMojo extends AbstractMicronautMojo { 046 public static final String MOJO_NAME = "generate-jsonschema"; 047 048 static final String MICRONAUT_SCHEMA_PREFIX = "micronaut.jsonschema.generator"; 049 static final String IO_MICRONAUT_SCHEMA_PREFIX = "io.micronaut.jsonschema"; 050 051 /** 052 * The URL to an input resource, pointing to a JSON schema. 053 */ 054 @Parameter(property = MICRONAUT_SCHEMA_PREFIX + ".input-url") 055 private String inputURL; 056 057 /** 058 * The input file containing the schema. 059 * This file will be used as a source for generating or processing schemas. 060 */ 061 @Parameter(property = MICRONAUT_SCHEMA_PREFIX + ".input-file") 062 private File inputFile; 063 064 /** 065 * The directory containing multiple input files or schema files. 066 * The Mojo will process all schema files in this directory. 067 */ 068 @Parameter(property = MICRONAUT_SCHEMA_PREFIX + ".input-directory") 069 private File inputDirectory; 070 071 /** 072 * The programming language to be used for schema generation. Default is "JAVA". 073 * Other values may be supported depending on the version of micronaut-sourcegen module. 074 */ 075 @Parameter(property = MICRONAUT_SCHEMA_PREFIX + ".language", defaultValue = "JAVA") 076 private String language; 077 078 /** 079 * The output directory where generated sources or files will be placed. 080 * By default, this points to `${project.build.directory}/generated-sources/jsonschema`. 081 */ 082 @Parameter(defaultValue = "${project.build.directory}/generated-sources/jsonschema") 083 private File outputDirectory; 084 085 /** 086 * The package name for the generated classes or schemas. 087 * Default value is specified as "io.micronaut.jsonschema". 088 */ 089 @Parameter(property = MICRONAUT_SCHEMA_PREFIX + ".output-package-name", defaultValue = IO_MICRONAUT_SCHEMA_PREFIX) 090 private String outputPackageName; 091 092 /** 093 * The name of the output file where the generated schema or data will be saved only if there is a single output source. 094 */ 095 @Parameter(property = MICRONAUT_SCHEMA_PREFIX + ".output-file-name") 096 private String outputFileName; 097 098 /** 099 * A list of accepted URL patterns. Used to filter or validate input resources 100 * based on their URL. URLs matching at least one pattern will be accepted. 101 * Default value is "^https://.* /.*.json". 102 */ 103 @Parameter(property = MICRONAUT_SCHEMA_PREFIX + ".accepted-url-patterns") 104 private List<String> acceptedUrlPatterns; 105 106 /** 107 * The property that defines if this mojo is used. 108 */ 109 @Parameter(property = MICRONAUT_SCHEMA_PREFIX + ".enabled", defaultValue = StringUtils.FALSE) 110 private boolean enabled; 111 112 private final MavenProject project; 113 114 @SuppressWarnings("CdiInjectionPointsInspection") 115 @Inject 116 public JsonSchemaGeneratorMojo(final MavenProject project) { 117 this.project = project; 118 } 119 120 @Override 121 public void execute() throws MojoExecutionException, MojoFailureException { 122 if (!enabled) { 123 if (getLog().isDebugEnabled()) { 124 getLog().debug(MOJO_NAME + " is disabled"); 125 } 126 return; 127 } 128 129 var langGenerator = new SourceGenerator(language.toUpperCase()); 130 131 if (acceptedUrlPatterns != null && !acceptedUrlPatterns.isEmpty()) { 132 UrlLoader.addAllowedUrlPatterns(acceptedUrlPatterns); 133 } 134 135 Path outputDirPath = getSourceDirectory(language); 136 project.addCompileSourceRoot(outputDirPath.toString()); 137 138 var builder = new SourceGeneratorConfigBuilder() 139 .withOutputFolder(outputDirPath) 140 .withOutputPackageName(outputPackageName) 141 .withOutputFileName(outputFileName); 142 143 var message = "Generating sources for JSON schema from %s in the directory: %s"; 144 var relativePath = relativize(outputDirPath); 145 if (inputURL != null) { 146 builder.withJsonUrl(inputURL); 147 message = message.formatted("URL [" + inputURL + "]", relativePath); 148 } else if (inputFile != null) { 149 builder.withJsonFile(inputFile); 150 message = message.formatted("file [" + relativize(inputFile.toPath()) + "]", relativePath); 151 } else if (inputDirectory != null) { 152 builder.withInputFolder(inputDirectory.toPath()); 153 message = message.formatted("directory [" + relativize(inputDirectory.toPath()) + "]", relativePath); 154 } else { 155 var msg = new StringBuilder("In the generate-jsonschema goal, one of the following parameters needs to be specified:") 156 .append(System.lineSeparator()) 157 .append("%s.input-file".formatted(MICRONAUT_SCHEMA_PREFIX)) 158 .append(System.lineSeparator()) 159 .append("%s.input-url".formatted(MICRONAUT_SCHEMA_PREFIX)) 160 .append(System.lineSeparator()) 161 .append("%s.input-directory".formatted(MICRONAUT_SCHEMA_PREFIX)) 162 .append(System.lineSeparator()); 163 throw new MojoFailureException(msg.toString()); 164 } 165 166 try { 167 getLog().info(message); 168 langGenerator.generate(builder.build()); 169 } catch (Exception e) { 170 throw new MojoExecutionException("Error when generating JSON schema", e); 171 } 172 } 173 174 private String relativize(Path path) { 175 return project.getBasedir().toPath().relativize(path).toString(); 176 } 177 178 private Path getSourceDirectory(String language) { 179 return outputDirectory.toPath().resolve("src/main/" + language.toLowerCase()); 180 } 181}