pwall567 / json-kotlin-gradle

Gradle JSON Schema code generation plugin
16 stars 7 forks source link

error: "Error creating output directory - build/generated-sources/kotlin/com/app" #1

Open arpel4 opened 3 years ago

arpel4 commented 3 years ago

Hi,

I'm trying to execute the gradle plugin but is trowing the following error: "Error creating output directory - build/generated-sources/kotlin/com/app". What could it be?

I've used a clean kotlin project from intelliJ.

Without the plugin using CodeGenerator() it's working fine with the shared json schema.

Also I've tried "outputDir.set(file("src/main/schema/example"))" but it will only generate:

data class Test3(
        val warehouse: BigDecimal? = null,
        val retail: BigDecimal? = null
    )

expected:

/*
 * Test.kt
 *
 * This code was generated by json-kotlin-schema-codegen - JSON Schema Code Generator
 * See https://github.com/pwall567/json-kotlin-schema-codegen
 *
 * It is not advisable to modify generated code as any modifications will be lost
 * when the generation process is re-run.
 */
import java.math.BigDecimal

import java.math.BigInteger

data class Test(
    /** Product identifier */
    val id: BigInteger,
    /** Name of the product */
    val name: String,
    val price: BigDecimal,
    val tags: List<String>? = null,
    val stock: Test3? = null,
    val stock2: Test3? = null
) {

    data class Test3(
        val warehouse: BigDecimal? = null,
        val retail: BigDecimal? = null
    )

}

build.gradle.kts:


import net.pwall.json.kotlin.codegen.gradle.JSONSchemaCodegenPlugin
import net.pwall.json.kotlin.codegen.gradle.JSONSchemaCodegen
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

buildscript {
    repositories {
                mavenLocal()
                jcenter()
            }
            dependencies {
                classpath("net.pwall.json:json-kotlin-gradle:0.34")

            }
        }

apply<JSONSchemaCodegenPlugin>()

configure<JSONSchemaCodegen> {
    packageName.set("com.app")
    inputFile.set(file("src/main/schema/example/example2.json")) // probably in src/main/resources/...
   // outputDir.set(file("src/main/schema/example"))
    pointer.set("/definitions") // a JSON Pointer to the group of definitions within the file
    generatorComment.set("comment...")
    classMappings { // configure specific class mappings if required
        byFormat("java.time.Duration", "duration")
    }
    schemaExtensions { // configure extension keyword uses if required
        patternValidation("x-type", "account-number", Regex("^[0-9]{4,10}$"))
    }
}

plugins {
    kotlin("jvm") version "1.5.10"
}

group = "me.arpel4"
version = "1.0-SNAPSHOT"

dependencies {
    implementation("net.pwall.json:json-kotlin-schema-codegen:0.35")
    implementation(kotlin("stdlib-jdk8"))
}

tasks.withType<KotlinCompile>() {
    kotlinOptions.jvmTarget = "11"
}

repositories {
    mavenCentral()
}

json-schema:


{
  "$schema": "http://json-schema.org/draft/2019-09/schema",
  "$id": "http://pwall.net/test",
  "title": "Product",
  "type": "object",
  "required": ["id", "name", "price"],
  "properties": {
    "id": {
      "type": "number",
      "format": "bigint",
      "description": "Product identifier"
    },
    "name": {
      "type": "string",
      "description": "Name of the product"
    },
    "price": {
      "type": "number"
    },
    "tags": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "stock": {
      "$ref": "#/definitions/test3"
    },
    "stock2": {
      "$ref": "#/definitions/test3"
    }
  },
  "definitions": {
    "test3": {
      "type": "object",
      "properties": {
        "warehouse": {
          "type": "number"
        },
        "retail": {
          "type": "number"
        }
      }
    }
  }
}
´´´
pwall567 commented 3 years ago

This looks a little bit like an issue that a colleague reported to me recently - she was using a Mac, and I couldn't reproduce the issue on my Linux machine. It seemed like the problem related to file permissions, but I can't be sure.

I'll look into it, but I don't have an answer right now.

pwall567 commented 3 years ago

I need to explain something about the Gradle plugin.

I found that the majority of uses of the Code Generator were to generate a set of classes from a Swagger or OpenAPI file. Users were pointing to the subsection of an API definition describing the data objects (e.g. "/components/schemas") and generating model classes for all of the definitions in that section.

It's this use case that the plugin was primarily intended to target, which is why one of the lines in the example is commented: "a JSON Pointer to the group of definitions within the file".

That's why it only generates "Test3" in your example - that is the only schema in the "definitions" section.

You can still use it for the example you're working with, but it requires a little rearrangement of the schema:

{
  "$schema": "http://json-schema.org/draft/2019-09/schema",
  "$id": "http://pwall.net/test",
  "title": "Product",
  "definitions": {
    "product": {
      "type": "object",
      "required": ["id", "name", "price"],
      "properties": {
        "id": {
          "type": "number",
          "format": "bigint",
          "description": "Product identifier"
        },
        "name": {
          "type": "string",
          "description": "Name of the product"
        },
        "price": {
          "type": "number"
        },
        "tags": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "stock": {
          "$ref": "#/definitions/test3"
        },
        "stock2": {
          "$ref": "#/definitions/test3"
        }
      }
    },
    "test3": {
      "type": "object",
      "properties": {
        "warehouse": {
          "type": "number"
        },
        "retail": {
          "type": "number"
        }
      }
    }
  },
  "$ref": "#/definitions/product"
}

In this version, the definition of the main class is moved into the "definitions" section, and separate classes will be generated for "product" and "test3".

If this doesn't fit your requirements, then I hope at least you're able to use the code generator without the plugin. I have found that the "buildSrc" functionality of Gradle is useful for generating code prior to a compilation task.

I'm not particularly expert on Gradle, so I'm not sure whether I'll be able to expand on the plugin to meet the full requirements for code generation, but I hope it's helpful for some use cases.

Regards, Peter

arpel4 commented 3 years ago

Hi, I can work with that json-schema format. 👍 thanks.

rgonciarz commented 2 years ago

@pwall567 hi, I reproduce exactly the same issue on my Linux desktop and I don't believe it's related with file permissions, rather than making sure there is a directory before we save a generated classes to.

My schema in directory: src/main/schema/foo

{
  "$id": "https://example.com/bar.json",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": ["name"],
  "properties": {
    "name": {
      "type": "string"
    }
  }
}

My config:

configure<JSONSchemaCodegen> {
    language.set("kotlin")
    packageName.set("com.example.model")
    inputFile.set(files("src/main/schema").singleFile)
}

Error creating output directory - build/generated-sources/kotlin/com/example/model/foo

When I create build/generated-sources/kotlin/com/example/model directory manually schema is generated properly. Foo package is handled properly as long as we have a model dir.

I experience exactly the same issue with no customization (default schema directory) and without any package.

rgonciarz commented 2 years ago

One more comment. Creating directories for packages is also buggy. for foo.Bar schema a proper class is generated but if you have foo1.foo2.Bar package then such directories won't be created.

pwall567 commented 2 years ago

Thanks for the additional information.

I still can't reproduce the problem, but I have changed the directory creation to use NIO Files.createDirectories(). Please try version 0.73 which incorporates this change – the NIO function also causes an exception to be thrown in the case of an error (instead of simply returning a boolean), and I would be interested to know what the exception details are if it is still failing.

pwall567 commented 2 years ago

As to your second comment – can you give more details? Is it just another manifestation of the same problem?