Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
12 changes: 12 additions & 0 deletions docs/customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,18 @@ Example:
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate -g java -i modules/openapi-generator/src/test/resources/3_0/required-properties.yaml -o /tmp/java-okhttp/ --openapi-normalizer NORMALIZER_CLASS=org.openapitools.codegen.OpenAPINormalizerTest$RemoveRequiredNormalizer
```

The class must be resolvable on the generation runtime classpath. When using the
[Gradle plugin](https://github.com/OpenAPITools/openapi-generator/tree/master/modules/openapi-generator-gradle-plugin),
a custom `NORMALIZER_CLASS` that isn't already on the plugin's own classpath must be added via the
`openApiGeneratorExtra` dependency configuration (or the `generatorClasspath` property) so it is forwarded to the
code generation worker in both `workerIsolation` modes (`process` and `classloader`) - see the plugin's README for
details.

Similarly, a custom generator selected by name or fully qualified class name must be resolvable on the generation
runtime classpath. With the Gradle plugin, add its jar or project output to `openApiGeneratorExtra` (preferred) or
`generatorClasspath` so it is forwarded to the code generation worker in both `process` and `classloader`
`workerIsolation` modes.

- `LOOSE_NULL_DEFINITIONS`: When set to true, allow more schema definitions in OpenAPI 3.0 spec to be the same as `null` in OpenAPI 3.1 spec by setting ModelUtils.looseNullDefinitions to true.

Example:
Expand Down
48 changes: 48 additions & 0 deletions modules/openapi-generator-gradle-plugin/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -480,8 +480,56 @@ warning].
|Gradle default (~512 MiB)
|Maximum heap size for the forked worker JVM when `workerIsolation` is `process` (e.g. `"512m"`, `"1g"`).
Has no effect when `workerIsolation` is `classloader`.

|generatorClasspath
|ConfigurableFileCollection
|(empty)
a|Additional classpath entries (jars, class directories, project outputs) forwarded to the code generation worker
in *both* `workerIsolation` modes (`process` and `classloader`). Required for any custom class referenced by name
in generator options - most notably a custom `NORMALIZER_CLASS` (see `openapiNormalizer`) or custom generator
selected by `generatorName`/FQCN - to be resolvable by the worker, since such classes are not on the plugin's own
runtime classpath.

For dependencies from a repository or another project, prefer adding them to the `openApiGeneratorExtra`
configuration created by this plugin (see below); `generatorClasspath` is a lower-level escape hatch for ad hoc
files/directories:

[source,groovy]
----
openApiGenerate {
generatorClasspath.from(files("libs/my-normalizer.jar", "libs/my-custom-generator.jar"))
}
----
|===

[NOTE]
====
The plugin creates an `openApiGeneratorExtra` dependency configuration (resolvable, not published) that entries
are automatically forwarded from into `generatorClasspath` for both `workerIsolation` modes. Use it to declare a

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P3: The new README sentence contains the grammatically incorrect phrase “forwarded from into generatorClasspath,” which makes the classpath forwarding relationship harder to understand. Rewording it to “automatically forwarded into” keeps the documentation clear.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator-gradle-plugin/README.adoc, line 508:

<comment>The new README sentence contains the grammatically incorrect phrase “forwarded from into `generatorClasspath`,” which makes the classpath forwarding relationship harder to understand. Rewording it to “automatically forwarded into” keeps the documentation clear.</comment>

<file context>
@@ -480,8 +480,56 @@ warning].
+[NOTE]
+====
+The plugin creates an `openApiGeneratorExtra` dependency configuration (resolvable, not published) that entries
+are automatically forwarded from into `generatorClasspath` for both `workerIsolation` modes. Use it to declare a
+custom `NORMALIZER_CLASS`, custom generator selected by `generatorName`/FQCN, or any other class referenced by name
+in generator options as a normal Gradle dependency - a published artifact, a local jar, or another project in the
</file context>
Suggested change
are automatically forwarded from into `generatorClasspath` for both `workerIsolation` modes. Use it to declare a
are automatically forwarded into `generatorClasspath` for both `workerIsolation` modes. Use it to declare a

custom `NORMALIZER_CLASS`, custom generator selected by `generatorName`/FQCN, or any other class referenced by name
in generator options as a normal Gradle dependency - a published artifact, a local jar, or another project in the
same build:

[source,groovy]
----
dependencies {
openApiGeneratorExtra("com.acme:my-normalizer:1.0.0") // custom NORMALIZER_CLASS
openApiGeneratorExtra("com.acme:my-custom-generator:1.0.0") // custom generator
openApiGeneratorExtra(project(":my-generator-module")) // project dependency; built automatically
openApiGeneratorExtra(files("libs/my-normalizer.jar")) // local normalizer jar/class directory
openApiGeneratorExtra(files("libs/my-custom-generator.jar")) // local generator jar/class directory
}

openApiGenerate {
generatorName = "com.acme.MyGenerator"
openapiNormalizer = ["NORMALIZER_CLASS": "com.acme.MyNormalizer"]
}
----

Without a corresponding entry in `openApiGeneratorExtra` or `generatorClasspath`, a custom `NORMALIZER_CLASS` or
custom generator selected by name/FQCN will fail to load with a clear error, regardless of `workerIsolation` mode.
====

[NOTE]
====
Configuring any one of `apiFilesConstrainedTo`, `modelFilesConstrainedTo`, or `supportingFilesConstrainedTo` results
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ class OpenApiGeneratorPlugin : Plugin<Project> {

generate.outputDir.convention(layout.buildDirectory.dir("generate-resources/main"))

// A dependency configuration users can add custom classes to (e.g. a jar containing a
// custom NORMALIZER_CLASS) so they are forwarded to the code generation worker's
// classpath, in both "process" and "classloader" workerIsolation modes. Not consumed or
// published; only resolved by this plugin.
val generatorExtraClasspath = configurations.create("openApiGeneratorExtra") {
isVisible = false
isCanBeConsumed = false
isCanBeResolved = true
description = "Additional classpath entries (e.g. custom NORMALIZER_CLASS jars) " +
"forwarded to the openApiGenerate worker in both process and classloader isolation."
}

tasks.apply {
register("openApiGenerators", GeneratorsTask::class.java).configure {
group = pluginGroup
Expand Down Expand Up @@ -174,6 +186,8 @@ class OpenApiGeneratorPlugin : Plugin<Project> {
generateRecursiveDependentModels.set(generate.generateRecursiveDependentModels)
workerIsolation.set(generate.workerIsolation)
maxWorkerHeapSize.set(generate.maxWorkerHeapSize)
generatorClasspath.from(generatorExtraClasspath)
generatorClasspath.from(generate.generatorClasspath)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,11 @@ open class OpenApiGeneratorGenerateExtension(private val project: Project) {
* Example rules: `REFACTOR_ALLOF_WITH_PROPERTIES_ONLY=true`,
* `REMOVE_ANYOF_ONEOF_AND_KEEP_PROPERTIES_ONLY=true`. See the OpenAPI Generator docs for
* the full list of normalizer rules.
*
* For the `NORMALIZER_CLASS` rule (a custom class extending `OpenAPINormalizer`), the class
* must be added to the [generatorClasspath] (or the `openApiGeneratorExtra` dependency
* configuration) so it is resolvable by the code generation worker in both `workerIsolation`
* modes; otherwise it will fail to load with a `ClassNotFoundException`.
*/
val openapiNormalizer = project.objects.mapProperty<String, String>()

Expand Down Expand Up @@ -536,6 +541,33 @@ open class OpenApiGeneratorGenerateExtension(private val project: Project) {
*/
val maxWorkerHeapSize = project.objects.property<String>()

/**
* Additional classpath entries (jars, class directories, project outputs) made visible to the
* code generation worker in *both* [workerIsolation] modes (`process` and `classloader`).
*
* This is the mechanism by which custom classes referenced by name in generator options -
* most notably a custom `NORMALIZER_CLASS` in [openapiNormalizer] - are resolved: such classes
* are not on the plugin's own runtime classpath, so without contributing them here the worker
* (particularly under `process` isolation, which runs in an isolated JVM) cannot load them.
*
* For the common case of depending on a published artifact or another project's output, prefer
* adding a dependency to the `openApiGeneratorExtra` configuration created by this plugin, e.g.:
* ```kotlin
* dependencies {
* openApiGeneratorExtra("com.acme:my-normalizer:1.0.0")
* openApiGeneratorExtra(project(":my-normalizer-module"))
* }
* ```
* Entries resolved from `openApiGeneratorExtra` are always included automatically; this
* property is an additional, lower-level escape hatch for ad hoc files or directories, e.g.:
* ```kotlin
* openApiGenerate {
* generatorClasspath.from(files("libs/my-normalizer.jar"))
* }
* ```
*/
val generatorClasspath: ConfigurableFileCollection = project.objects.fileCollection()

init {
applyDefaults()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,17 @@ abstract class GenerateTask : DefaultTask() {
@get:Input
abstract val maxWorkerHeapSize: Property<String>

/**
* Additional classpath entries forwarded to the code generation worker in both `process` and
* `classloader` [workerIsolation] modes. Populated by default from the `openApiGeneratorExtra`
* configuration, plus any files/directories added via the `openApiGenerate` extension's
* `generatorClasspath` property. Required for custom classes referenced by name in generator
* options (e.g. a custom `NORMALIZER_CLASS`) to be resolvable by the worker.
*/
@get:Optional
@get:Classpath
abstract val generatorClasspath: ConfigurableFileCollection

/**
* The verbosity of generation
*/
Expand Down Expand Up @@ -693,6 +704,11 @@ abstract class GenerateTask : DefaultTask() {
* Example rules: `REFACTOR_ALLOF_WITH_PROPERTIES_ONLY=true`,
* `REMOVE_ANYOF_ONEOF_AND_KEEP_PROPERTIES_ONLY=true`. See the OpenAPI Generator docs for
* the full list of normalizer rules.
*
* For the `NORMALIZER_CLASS` rule (a custom class extending `OpenAPINormalizer`), the class
* must be added to [generatorClasspath] (or the `openApiGeneratorExtra` dependency
* configuration) so it is resolvable by the code generation worker in both `workerIsolation`
* modes; otherwise it will fail to load with a `ClassNotFoundException`.
*/
@get:Optional
@get:Input
Expand Down Expand Up @@ -1148,6 +1164,7 @@ abstract class GenerateTask : DefaultTask() {
)
}
workerExecutor.processIsolation {
classpath.from(generatorClasspath)
maxWorkerHeapSize.orNull?.let { forkOptions.maxHeapSize = it }
}
}
Expand All @@ -1160,7 +1177,9 @@ abstract class GenerateTask : DefaultTask() {
"consider workerIsolation = \"process\" if you hit metaspace pressure)"
)
}
workerExecutor.classLoaderIsolation()
workerExecutor.classLoaderIsolation {
classpath.from(generatorClasspath)
}
}

else -> throw GradleException("Invalid workerIsolation mode: $isolation. Supported values are 'process' and 'classloader'.")
Expand Down
Loading
Loading