4

I'm using jsonschema-generator to generate a JSON schema file based on my POJOs. Currently I'm doing it via a test that is run during the gradle build step. This works fine but it doesn't feel right as really what I'm doing is not testing anything.

I've also found this answer which details how to run it on gradle run but this is not ideal either as it will pointlessly execute this every time the application comes up but not when I build.

Therefore, is there a way to tell gradle (in build.gradle) to run a piece of Java code at build time?

For completeness, here the code I'm looking to run:

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.victools.jsonschema.generator.Option;
import com.github.victools.jsonschema.generator.OptionPreset;
import com.github.victools.jsonschema.generator.SchemaGenerator;
import com.github.victools.jsonschema.generator.SchemaGeneratorConfig;
import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder;
import com.mypackage.MyClass;
import org.junit.jupiter.api.Test;

import java.io.PrintWriter;
import java.util.Map;

@SuppressWarnings({"FieldCanBeLocal", "rawtypes"})
public class JsonSchemaGenerator {
    private final String SCHEMA_FOLDER = "schemas/";
    private final Map<Class, String> schemaToGenerate = Map.of(
            MyClass.class, "my-class.schema"
    );

    @Test
    public void generateJsonSchema() throws Exception {
        SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(new ObjectMapper(), OptionPreset.PLAIN_JSON);
        SchemaGeneratorConfig config = configBuilder.with(Option.DEFINITIONS_FOR_ALL_OBJECTS).build();
        SchemaGenerator generator = new SchemaGenerator(config);

        for (var entry : schemaToGenerate.entrySet()) {
            JsonNode jsonSchema = generator.generateSchema(entry.getKey());
            PrintWriter out = new PrintWriter(SCHEMA_FOLDER + entry.getValue());
            out.println(jsonSchema.toPrettyString());
            out.close();
        }
    }
}
Vlad Schnakovszki
  • 8,434
  • 6
  • 80
  • 114
  • You could create a script that does gradle build then gradle run, and use that instead of just gradle build. – Christine Mar 09 '20 at 15:57
  • Thanks for your suggestion @Christine. I don't think I can do that as it would bring up my application during the build on the CI box which would result in the build failing with a timeout so that wouldn't work in my case. – Vlad Schnakovszki Mar 09 '20 at 16:04
  • Then you need to edit the build file to make it happen the way you want it. – Christine Mar 09 '20 at 17:22
  • 1
    Hi @VladSchnakovszki, a Maven plugin is currently being worked on (https://github.com/victools/jsonschema-generator/issues/53). Once that is done, you might be able to trigger it from within your grade build somehow. – Carsten Mar 25 '20 at 06:12

1 Answers1

2

The JavaExec Plugin seems to meet your requirements.

This allows you to run a main() method and thereby any Java Code you want – including whatever JSON Schema generation you like.

This other answer also describes pretty much what you want to do.


Adapted from the linked documentation:

apply plugin: 'java'

task generateJsonSchema(type: JavaExec) {
  classpath = sourceSets.main.runtimeClasspath

  main = 'package.Main'

  // arguments to pass to the application
  args 'appArg1'
}

As per Jorn's comment below:

You can depend the build task on your custom task: build.dependsOn generateJsonSchema if your custom task is defined as task generateJsonSchema(type: JavaExec) { ... }

Carsten
  • 2,047
  • 1
  • 21
  • 46
  • `Exec` or `JavaExec` are generally correct, but this is not a good example... and no other task depends on it. – Martin Zeitler Apr 05 '20 at 17:48
  • You’re saying this can also not be included in the `grade build` then? – Carsten Apr 05 '20 at 17:50
  • 1
    You can depend the build task on your custom task: `build.dependsOn generateJsonSchema` if your custom task is defined as `task generateJsonSchema(type: JavaExec) { ... }` – Jorn Apr 05 '20 at 18:40
  • 1
    @Carsten All I said/wrote that the initial version of the answer had no dependency defined with `dependsOn` or `finalizedBy`, as the question was asking for. An `Exec` task, wich runs a JAR with `java` from the command line might even be more suitable, because the code in there might not change much, therefore build it once would suffice. – Martin Zeitler Apr 06 '20 at 04:43