Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Json Schema Generator Plugin #1067

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pluginManager.apply(io.micronaut.build.MicronautQualityChecksParticipantPlugin)
repositories {
mavenCentral()
gradlePluginPortal()
// maven { url = uri("https://s01.oss.sonatype.org/content/repositories/snapshots/") }
maven { url = uri("https://s01.oss.sonatype.org/content/repositories/snapshots/") }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be removed before merging

}

project.extensions.create("micronautPlugins", MicronautPluginExtension, gradlePlugin)
Expand Down
3 changes: 3 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ micronaut-platform = "4.7.4" # This is the platform version, used in our tests
micronaut-aot = "2.6.0"
micronaut-testresources = "2.7.2"
micronaut-openapi = "6.13.2"
micronaut-jsonschema = "1.3.1-SNAPSHOT" # TODO: update to include new generation plugin
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix before merging


[libraries]
# Core
Expand Down Expand Up @@ -45,6 +46,8 @@ micronaut-openapi-generator = { module = "io.micronaut.openapi:micronaut-openapi

micronaut-testresources = { module = "io.micronaut.testresources:micronaut-test-resources-build-tools", version.ref = "micronaut-testresources" }

micronaut-jsonschema-generator = { module = "io.micronaut.jsonschema:micronaut-json-schema-generator", version.ref = "micronaut-jsonschema" }

mockserver-netty = { module = "org.mock-server:mockserver-netty", version.ref = "mockserver" }
mockserver-client = { module = "org.mock-server:mockserver-client-java", version.ref = "mockserver" }

Expand Down
15 changes: 15 additions & 0 deletions jsonschema-plugin/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
plugins {
id "io.micronaut.internal.build.gradle-plugin"
}

description = "Micronaut JSON Schema Gradle plugin"

micronautPlugins {
register('jsonschema', 'io.micronaut.gradle.jsonschema.MicronautJSONSchemaPlugin', 'Micronaut JSON Schema Plugin')
}

dependencies {
compileOnly libs.micronaut.jsonschema.generator
implementation projects.micronautMinimalPlugin
testImplementation testFixtures(projects.micronautMinimalPlugin)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package io.micronaut.gradle.jsonschema;

import io.micronaut.gradle.PluginsHelper;
import io.micronaut.gradle.jsonschema.tasks.AbstractJsonSchemaGenerator;
import io.micronaut.gradle.jsonschema.tasks.JsonSchemaFileGenerator;
import io.micronaut.gradle.jsonschema.tasks.JsonSchemaFolderGenerator;
import io.micronaut.gradle.jsonschema.tasks.JsonSchemaUrlGenerator;
import org.gradle.api.Action;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.file.Directory;
import org.gradle.api.file.SourceDirectorySet;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.SourceSetContainer;
import org.gradle.api.tasks.TaskProvider;

import javax.inject.Inject;
import java.io.File;
import java.util.List;
import java.util.function.Consumer;

import static org.codehaus.groovy.runtime.StringGroovyMethods.capitalize;

public abstract class DefaultJSONSchemaExtension implements JSONSchemaExtension {
private final Project project;
private final Configuration classpath;

@Inject
public DefaultJSONSchemaExtension(Project project, Configuration classpath) {
this.project = project;
this.classpath = classpath;
}

@Override
public void url(String url, Action<JsonSchemaSpec> spec) {
var urlSpec = project.getObjects().newInstance(JsonSchemaURLSpec.class);
configureCommonExtensionDefaults(urlSpec);
urlSpec.getInputUrl().convention("");
spec.execute(urlSpec);
var generator = project.getTasks().register(generateTaskName(url.substring(url.lastIndexOf("/") + 1)), JsonSchemaUrlGenerator.class, task -> {
task.setDescription("Generates source files from an URL of a JSON Schema file");
configureCommonProperties(task, urlSpec);
task.getJsonURL().convention(url);
});
addSourceDir(generator);
}

@Override
public void file(File file, Action<JsonSchemaSpec> spec) {
var regularFileProperty = project.getObjects().fileProperty();
var fileSpec = project.getObjects().newInstance(JsonSchemaFileSpec.class);
configureCommonExtensionDefaults(fileSpec);
fileSpec.getInputFile().convention(new File(""));
spec.execute(fileSpec);
var generator = project.getTasks().register(generateTaskName(file.getName()), JsonSchemaFileGenerator.class, task -> {
task.setDescription("Generates source files from an URL of a JSON Schema file");
configureCommonProperties(task, fileSpec);
task.getJsonFile().convention(regularFileProperty.fileValue(file));
});
addSourceDir(generator);
}

@Override
public void folder(File folder, Action<JsonSchemaSpec> spec) {
var regularDirProperty = project.getObjects().directoryProperty();
var folderSpec = project.getObjects().newInstance(JsonSchemaFolderSpec.class);
configureCommonExtensionDefaults(folderSpec);
folderSpec.getInputFolder().convention(new File(""));
elifKurtay marked this conversation as resolved.
Show resolved Hide resolved
spec.execute(folderSpec);
var generator = project.getTasks().register(generateTaskName(folder.getName()), JsonSchemaFolderGenerator.class, task -> {
task.setDescription("Generates source files from an URL of a JSON Schema file");
configureCommonProperties(task, folderSpec);
task.getInputDirectory().convention(regularDirProperty.fileValue(folder));
});
addSourceDir(generator);
}

private void configureCommonExtensionDefaults(JsonSchemaSpec spec) {
spec.getAcceptedUrlPatterns().convention(List.of());
spec.getLang().convention("JAVA");
spec.getOutputPackageName().convention("io.micronaut.jsonschema.generated");
spec.getOutputFileName().convention("");
spec.getOutputDirectory().convention(project.getLayout().getBuildDirectory().dir("generated/jsonschema/"));
}

private void configureCommonProperties(AbstractJsonSchemaGenerator<?, ?> task, JsonSchemaSpec schemaSpec) {
task.getClasspath().from(classpath);
task.getOutputDirectory().convention(schemaSpec.getOutputDirectory().dir(task.getName()));
task.getPackageName().convention(schemaSpec.getOutputPackageName());
task.getOutputFileName().convention(schemaSpec.getOutputFileName());
task.getAcceptedUrlPatterns().convention(schemaSpec.getAcceptedUrlPatterns());
task.getLanguage().convention(schemaSpec.getLang());
}

private void addSourceDir(TaskProvider<? extends AbstractJsonSchemaGenerator<?, ?>> generator) {
withJavaSourceSets(sourceSets -> {
var javaMain = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME).getJava();
javaMain.srcDir(generator.map(DefaultJSONSchemaExtension::mainSrcDir));
project.getPluginManager().withPlugin("org.jetbrains.kotlin.jvm", unused -> {
var ext = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME).getExtensions().getByName("kotlin");
if (ext instanceof SourceDirectorySet kotlinMain) {
kotlinMain.srcDir(generator.map(d -> DefaultJSONSchemaExtension.mainSrcDir(d, "kotlin")));
}
});
});
}

private void withJava(Runnable runnable) {
project.getPlugins().withId("java", unused -> runnable.run());
}

private void withJavaSourceSets(Consumer<? super SourceSetContainer> consumer) {
project.getPlugins().withId("java", unused -> consumer.accept(PluginsHelper.findSourceSets(project)));
}

private static Provider<Directory> mainSrcDir(AbstractJsonSchemaGenerator<?, ?> t, String language) {
return t.getOutputDirectory().dir("src/main/" + language);
}

private static Provider<Directory> mainSrcDir(AbstractJsonSchemaGenerator<?, ?> t) {
return mainSrcDir(t, "java");
}

private static String generateTaskName(String name) {
int endIndex = name.contains(".") ? name.indexOf(".") : name.length();
return "generatingSourcesFrom" + capitalize(name.substring(0, endIndex));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright 2003-2021 the original author or 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 io.micronaut.gradle.jsonschema;

import org.gradle.api.Action;
import org.gradle.api.provider.Property;

import java.io.File;

/**
* Configures the JSON Schema code generator.
*/
public interface JSONSchemaExtension {
/**
* The version of the Micronaut JSON Schema generator.
* @return the version
*/
Property<String> getVersion();

/**
* Configures generation, given a schema URL.
* @param url the url string of a json schema
* @param spec configuration for the server generation
*/
void url(String url, Action<JsonSchemaSpec> spec);

/**
* Configures generation, given a schema file.
* @param file the json file
* @param spec configuration for the server generation
*/
void file(File file, Action<JsonSchemaSpec> spec);

/**
* Configures generation, given a schema folder.
* @param folder the folder that includes json schemas
* @param spec configuration for the server generation
*/
void folder(File folder, Action<JsonSchemaSpec> spec);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.micronaut.gradle.jsonschema;

import org.gradle.api.provider.Property;

import java.io.File;

public interface JsonSchemaFileSpec extends JsonSchemaSpec {
Property<File> getInputFile();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.micronaut.gradle.jsonschema;

import org.gradle.api.provider.Property;

import java.io.File;

public interface JsonSchemaFolderSpec extends JsonSchemaSpec {
elifKurtay marked this conversation as resolved.
Show resolved Hide resolved
Property<File> getInputFolder();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.micronaut.gradle.jsonschema;

import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.provider.ListProperty;
import org.gradle.api.provider.Property;

public interface JsonSchemaSpec {
Property<String> getLang();

ListProperty<String> getAcceptedUrlPatterns();

Property<String> getOutputFileName();

Property<String> getOutputPackageName();

DirectoryProperty getOutputDirectory();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.micronaut.gradle.jsonschema;

import org.gradle.api.provider.Property;

public interface JsonSchemaURLSpec extends JsonSchemaSpec {
Property<String> getInputUrl();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright 2003-2021 the original author or 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 io.micronaut.gradle.jsonschema;

import io.micronaut.gradle.MicronautBasePlugin;
import io.micronaut.gradle.PluginsHelper;
import org.gradle.api.Plugin;
import org.gradle.api.Project;

import java.util.List;

public class MicronautJSONSchemaPlugin implements Plugin<Project> {

public static final String JSON_SCHEMA_GENERATOR_CONFIGURATION = "jsonSchemaGenerator";
public static final String JSON_SCHEMA_GENERATOR_CLASSPATH_CONFIGURATION = "jsonSchemaGeneratorClasspath";

@Override
public void apply(Project project) {
project.getPluginManager().apply(MicronautBasePlugin.class);
createJSONSchemaExtension(project);
}

private static void createJSONSchemaExtension(Project project) {
var micronautExtension = PluginsHelper.findMicronautExtension(project);
var generatorDependencies = project.getConfigurations().create(JSON_SCHEMA_GENERATOR_CONFIGURATION, conf -> {
conf.setCanBeResolved(false);
conf.setCanBeConsumed(false);
conf.setDescription("The JSON Schema Generator dependencies");
});
var generatorClasspath = project.getConfigurations().create(JSON_SCHEMA_GENERATOR_CLASSPATH_CONFIGURATION, conf -> {
conf.setCanBeResolved(true);
conf.setCanBeConsumed(false);
conf.setDescription("The JSON Schema Generator classpath");
conf.extendsFrom(generatorDependencies);
});
var jsonSchemaExtension = micronautExtension.getExtensions().create(JSONSchemaExtension.class, "jsonschema", DefaultJSONSchemaExtension.class, project, generatorClasspath);
jsonSchemaExtension.getVersion().convention("1.3.1-SNAPSHOT"); //TODO: update after released version of json schema
generatorDependencies.getDependencies().addAllLater(jsonSchemaExtension.getVersion().map(version ->
List.of(project.getDependencies().create("io.micronaut.jsonschema:micronaut-json-schema-generator:" + version))
));
}
}
Loading
Loading