org.jreleaser.engine.schema.JsonSchemaGenerator Maven / Gradle / Ivy
The newest version!
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright 2020-2024 The JReleaser authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jreleaser.engine.schema;
import com.fasterxml.classmate.ResolvedType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.github.victools.jsonschema.generator.Option;
import com.github.victools.jsonschema.generator.OptionPreset;
import com.github.victools.jsonschema.generator.SchemaGenerationContext;
import com.github.victools.jsonschema.generator.SchemaGenerator;
import com.github.victools.jsonschema.generator.SchemaGeneratorConfig;
import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder;
import com.github.victools.jsonschema.generator.SchemaVersion;
import com.github.victools.jsonschema.generator.impl.DefinitionKey;
import com.github.victools.jsonschema.generator.naming.DefaultSchemaDefinitionNamingStrategy;
import com.github.victools.jsonschema.module.jackson.JacksonModule;
import org.jreleaser.model.JReleaserException;
import org.jreleaser.model.JReleaserVersion;
import org.jreleaser.model.internal.JReleaserModel;
import org.jreleaser.model.internal.announce.Announce;
import org.jreleaser.model.internal.announce.HttpAnnouncer;
import org.jreleaser.model.internal.announce.WebhookAnnouncer;
import org.jreleaser.model.internal.download.AbstractSshDownloader;
import org.jreleaser.model.internal.download.FtpDownloader;
import org.jreleaser.model.internal.download.HttpDownloader;
import org.jreleaser.model.internal.upload.AbstractSshUploader;
import org.jreleaser.model.internal.upload.ArtifactoryUploader;
import org.jreleaser.model.internal.upload.FtpUploader;
import org.jreleaser.model.internal.upload.HttpUploader;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.LinkedHashMap;
import java.util.Map;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.nio.file.StandardOpenOption.CREATE;
import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
import static java.nio.file.StandardOpenOption.WRITE;
import static java.util.Collections.singletonMap;
import static org.jreleaser.bundle.RB.$;
/**
* @author Andres Almiray
* @since 1.4.0
*/
public final class JsonSchemaGenerator {
private JsonSchemaGenerator() {
// noop
}
public static void generate(PrintWriter out) {
Map mappings = new LinkedHashMap<>();
mappings.put("Map", "Properties");
mappings.put("Map", "StringProperties");
mappings.put("Map", "WebhookAnnouncerMap");
mappings.put("Map", "HttpAnnouncerMap");
mappings.put("Map", "ArchiveAssemblerMap");
mappings.put("Map", "JavaArchiveAssemblerMap");
mappings.put("Map", "JlinkAssemblerMap");
mappings.put("Map", "JpackageAssemblerMap");
mappings.put("Map", "NativeImageAssemblerMap");
mappings.put("Map", "DistributionMap");
mappings.put("Map", "DockerSpecMap");
mappings.put("Map", "JibSpecMap");
mappings.put("Map", "ArtifactoryUploaderMap");
mappings.put("Map", "GiteaUploaderMap");
mappings.put("Map", "GitlabUploaderMap");
mappings.put("Map", "FtpUploaderMap");
mappings.put("Map", "HttpUploaderMap");
mappings.put("Map", "SftpUploaderMap");
mappings.put("Map", "ScpUploaderMap");
mappings.put("Map", "S3UploaderMap");
mappings.put("Map", "FtpDownloaderMap");
mappings.put("Map", "HttpDownloaderMap");
mappings.put("Map", "SftpDownloaderMap");
mappings.put("Map", "ScpDownloaderMap");
mappings.put("Map", "ExtensionMap");
mappings.put("Map", "ArtifactoryMavenDeployerMap");
mappings.put("Map", "AzureMavenDeployerMap");
mappings.put("Map", "GiteaMavenDeployerMap");
mappings.put("Map", "GithubMavenDeployerMap");
mappings.put("Map", "GitlabMavenDeployerMap");
mappings.put("Map", "Nexus2MavenDeployerMap");
mappings.put("Map", "MavenCentralMavenDeployerMap");
mappings.put("Map", "SwidTagMap");
try {
SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_7, OptionPreset.PLAIN_JSON);
configBuilder.getObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
configBuilder.with(Option.SCHEMA_VERSION_INDICATOR);
configBuilder.with(Option.FORBIDDEN_ADDITIONAL_PROPERTIES_BY_DEFAULT);
configBuilder.with(Option.DEFINITION_FOR_MAIN_SCHEMA);
configBuilder.with(Option.DEFINITIONS_FOR_ALL_OBJECTS);
configBuilder.with(Option.MAP_VALUES_AS_ADDITIONAL_PROPERTIES);
configBuilder.with(Option.GETTER_METHODS);
configBuilder.with(Option.NONSTATIC_NONVOID_NONGETTER_METHODS);
configBuilder.with(Option.FIELDS_DERIVED_FROM_ARGUMENTFREE_METHODS);
configBuilder.with(Option.STRICT_TYPE_INFO);
JacksonModule jacksonModule = new JacksonModule();
configBuilder.with(jacksonModule);
configBuilder.forTypesInGeneral()
.withDescriptionResolver(scope -> scope.getType().getErasedType() == JReleaserModel.class ?
String.format("JReleaser %s", JReleaserVersion.getPlainVersion()) : null)
.withPatternPropertiesResolver(scope -> {
if (scope.getType().isInstanceOf(Map.class)) {
ResolvedType type = scope.getTypeParameterFor(Map.class, 1);
if (type.getErasedType() != String.class && type.getErasedType() != Object.class) {
return singletonMap("^[a-zA-Z][a-zA-Z0-9-]*[a-zA-Z0-9]?$", type);
}
}
return null;
})
.withAdditionalPropertiesResolver(scope -> {
if (scope.getType().isInstanceOf(Map.class)) {
ResolvedType type = scope.getTypeParameterFor(Map.class, 1);
if (type.getErasedType() == String.class || type.getErasedType() == Object.class) {
return scope.getTypeParameterFor(Map.class, 0);
}
}
return null;
})
.withDefinitionNamingStrategy(new DefaultSchemaDefinitionNamingStrategy() {
@Override
public String getDefinitionNameForKey(DefinitionKey key, SchemaGenerationContext context) {
String definitionNameForKey = super.getDefinitionNameForKey(key, context);
return mappings.getOrDefault(definitionNameForKey, definitionNameForKey);
}
});
configBuilder.forMethods()
.withIgnoreCheck(method -> {
if (method.isVoid() || !method.getName().startsWith("get") || method.getArgumentCount() != 0) {
return true;
}
Class> declaringType = method.getDeclaringType().getErasedType();
return declaringType != Announce.class &&
declaringType != HttpAnnouncer.class &&
declaringType != HttpDownloader.class &&
declaringType != HttpUploader.class &&
declaringType != ArtifactoryUploader.class &&
declaringType != FtpDownloader.class &&
declaringType != FtpUploader.class &&
declaringType != AbstractSshDownloader.class &&
declaringType != AbstractSshUploader.class &&
declaringType != WebhookAnnouncer.class;
});
SchemaGeneratorConfig config = configBuilder.build();
SchemaGenerator generator = new SchemaGenerator(config);
JsonNode jsonSchema = generator.generateSchema(JReleaserModel.class);
String fileName = String.format("jreleaser-schema-%s.json", JReleaserVersion.getPlainVersion());
Path schemaPath = Paths.get(fileName);
String json = configBuilder.getObjectMapper().writeValueAsString(jsonSchema);
Files.write(schemaPath, json.getBytes(UTF_8), CREATE, WRITE, TRUNCATE_EXISTING);
out.println("Schema written to " + schemaPath.toAbsolutePath());
} catch (Exception e) {
throw new JReleaserException($("ERROR_unexpected_error"), e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy