Open senior42 opened 2 years ago
openapi: "3.0.3"
info:
title: »Issue« REST Api.
description: >-
An API that shows a generation issue.
termsOfService: http://swagger.io/terms/
contact:
name: Example Team
email: support@example.org
url: http://example.org/
license:
name: No license
url: https://choosealicense.com/no-permission/
version: 0.0.1-SNAPSHOT
servers:
- url: http://localhost:6666/issue
description: >-
Local jetty development server.
components:
schemas:
FieldIssueDescription:
type: object
properties:
issueDescription:
type: string
description: >-
A necessary model, otherwise the compilation failes.
example: "Buuu"
#components:
# schemas:
FooOut:
description: >-
The delivered error info.
type: object
allOf:
- $ref: '#/components/schemas/FieldIssueDescription'
required:
- issueDescription
paths:
/:
get:
description: >-
Get a list of all other endpoints.
operationId: doGet
responses:
200:
description: >-
The list of all endpoints .
content:
application/json:
example: {"0.":"/issue","1.":"/issue/foo"}
##paths:
# /default:
# get:
# description: >-
# A test to produces an error.
# operationId: doDefaultGet
## operationId: rootGet
# responses:
# 200:
# description: >-
# An error page.
# content:
# text/html:
# example: "<html><body style='background-color:#ffcccc'>ERROR</body><html>"
#paths:
/foo:
get:
description: >-
Get a FOO ...
operationId: doFooGet
responses:
200:
description: >-
The data about a FOO ...
content:
application/json:
schema:
$ref: '#/components/schemas/FooOut'
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example.issue.jaxrs-jersey</groupId>
<artifactId>issue.wrong.default.generation</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>org.example.issue.jaxrs-jersey</name>
<url>http://localhost:6666/issue</url>
<description>An example of a generation issue.</description>
<dependencies>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator</artifactId>
<version>5.2.1</version>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-cli</artifactId>
<version>5.2.1</version>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>5.2.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>4.0.0</version>
<executions>
<!-- The next code-generator block generate all necessary parts for
a JAXRS JERSEY server. -->
<execution>
<goals>
<goal>generate</goal>
</goals>
<!-- The following alpha sorted description comes from "https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator-maven-plugin/README.md" -->
<configuration>
<!-- "addCompileSourceRoot" - add the output directory to the project
as a source root. Default is: true -->
<!-- "additionalProperties" - sets additional properties that can
be referenced by the mustache templates in the format of name=value,name=value.
You can also have multiple occurrences of this option. default is: null -->
<!-- "apiPackage" - the package to use for generated api objects/classes.
Default: ??? -->
<apiPackage>org.example.issue.generated.api</apiPackage>
<!-- "artifactId" - sets project information in generated pom.xml/build.gradle
or other build script. Language-specific conversions occur in non-jvm generators.
Default is: ??? -->
<artifactId>issue.wrong.generated.default.stub</artifactId>
<!-- "artifactVersion" - sets project information in generated pom.xml/build.gradle
or other build script. Language-specific conversions occur in non-jvm generators.
Default is: ??? -->
<artifactVersion>0.0.1-SNAPSHOT</artifactVersion>
<!-- "auth" - adds authorization headers when fetching the OpenAPI
definitions remotely. Pass in a URL-encoded string of name:header with a
comma separating multiple values. default is: ??? -->
<!-- "configHelp" - dumps the configuration help for the specified
library (generates no sources) -->
<!-- "configOptions" - a map of language-specific parameters. To show
a full list of generator-specified parameters (options), please use configHelp
(explained below) -->
<!-- See the specific xml part below -->
<!-- "configurationFile" - Path to separate json configuration file.
File content should be in a json format {"optionKey":"optionValue", "optionKey1":"optionValue1"...}
Supported options can be different for each language. Run config-help -g
{generator name} command for language specific config options. Default is:
null -->
<!-- "enablePostProcessFile" - enable file post-processing hook. Default
is: null -->
<!-- "generateAliasAsModel" - generate alias (array, map) as model.
Default is: ??? -->
<!-- "generateApiTests" - generate the api tests (Only available if
generateApis is true). Default is: true -->
<!-- "generateApiDocumentation" - generate the api documentation (Only
available if generateApis is true). default is: true -->
<!-- "generateApis" - generate the apis. Default is: true -->
<!-- "generateModelDocumentation" - generate the model documentation
(Only available if generateModels is true). Default is: true -->
<!-- "generateModels" - generate the models. Default is: true -->
<!-- "generateModelTests" - generate the model tests (Only available
if generateModels is true). Default is: true -->
<!-- "generateSupportingFiles" - generate the supporting files. Default
is: true -->
<!-- "generatorName" - target generator name. default is: null -->
<generatorName>jaxrs-jersey</generatorName>
<!-- "gitRepoId" - sets git information of the project. Default is:
null -->
<!-- "gitUserId" - sets git information of the project. Default is:
null -->
<!-- "groupId" - sets project information in generated pom.xml/build.gradle
or other build script. Language-specific conversions occur in non-jvm generators.
Default is: ??? -->
<groupId>issue.wrong.default.generation</groupId>
<!-- "ignoreFileOverride" - specifies the full path to a .openapi-generator-ignore
used for pattern based overrides of generated outputs. Default is: ??? -->
<!-- "importMappings" - specifies mappings between a given class and
the import that should be used for that class in the format of type=import,type=import.
You can also have multiple occurrences of this option. default is: null -->
<!-- "inputSpec" - OpenAPI Spec file path. Default is: null -->
<inputSpec>${project.basedir}/issue.yaml</inputSpec>
<!-- "invokerPackage" - the package to use for the generated invoker
objects. Default is: ??? -->
<invokerPackage>org.example.issue.generated.invoker</invokerPackage>
<!-- "instantiationTypes" - sets instantiation type mappings in the
format of type=instantiatedType,type=instantiatedType. For example (in Java):
array=ArrayList,map=HashMap. In other words array types will get instantiated
as ArrayList in generated code. You can also have multiple occurrences of
this option. Default is: null -->
<!-- "languageSpecificPrimitives" - specifies additional language
specific primitive types in the format of type1,type2,type3,type3. For example:
String,boolean,Boolean,Double. You can also have multiple occurrences of
this option. Default is: null -->
<!-- "library" - library template (sub-template). Default is: ??? -->
<!-- "logToStderr" - write all log messages (not just errors) to STDOUT.
Default is: ??? -->
<!-- "modelNamePrefix" - Sets the prefix for model classes and enums.
Default is: ??? -->
<!-- "modelNameSuffix" - Sets the suffix for model classes and enums.
Default is: ??? -->
<!-- "modelPackage" - the package to use for generated model objects/classes -->
<modelPackage>org.example.issue.generated.model</modelPackage>
<!-- "modelsToGenerate" - A comma separated list of models to generate.
All models is the default. -->
<!-- "output" - target output path. Can also be set globally through
the openapi.generator.maven.plugin.output property. Default is: ${project.build.directory}/generated-sources/openapi -->
<!-- "removeOperationIdPrefix" - remove operationId prefix (e.g. user_getName
=> getName). Default is: ??? -->
<!-- "reservedWordsMappings" - specifies how a reserved name should
be escaped to. For example id=identifier. You can also have multiple occurrences
of this option. Default is: _<name> -->
<!-- "skip" - skip code generation (Can also be set globally through
the codegen.skip property). Default is: false -->
<!-- "skipIfSpecIsUnchanged" - Skip the execution if the source file
is older than the output folder. Can also be set globally through the codegen.skipIfSpecIsUnchanged
property). Default is: false -->
<!-- "skipOverwrite" - Specifies if the existing files should be overwritten
during the generation. Default is: false -->
<!-- "skipValidateSpec" - Whether or not to skip validating the input
spec prior to generation. By default, invalid specifications will result
in an error. Default is: false -->
<!-- "strictSpec" - Whether or not to treat an input document strictly
against the spec. 'MUST' and 'SHALL' wording in OpenAPI spec is strictly
adhered to. e.g. when false, no fixes will be applied to documents which
pass validation but don't follow the spec. Default is: ??? -->
<!-- "supportingFilesToGenerate" - A comma separated list of supporting
files to generate. All files is the default. -->
<!-- "templateDirectory" - directory with mustache templates. Default
is: ??? -->
<!-- "typeMappings" - sets mappings between OpenAPI spec types and
generated code types in the format of OpenAPIType=generatedType,OpenAPIType=generatedType.
For example: array=List,map=Map,string=String. You can also have multiple
occurrences of this option. Default is: null -->
<!-- "verbose" - verbose mode. Default is: false -->
<verbose>false</verbose>
<!-- "withXml" - enable XML annotations inside the generated models
and API (only works with Java language and libraries that provide support
for JSON and XML). Default is: ??? -->
<withXml>true</withXml>
<!-- The following alpha sorted options comes from / desribed on the
webpage: https://github.com/OpenAPITools/openapi-generator/blob/master/docs/generators/jaxrs-jersey.md -->
<!-- That is one of available code generators from the following webpage:
https://github.com/OpenAPITools/openapi-generator/tree/master/docs/generators -->
<!-- Date of the above links: 2019-05-28 -->
<configOptions>
<!-- "allowUnicodeIdentifiers" - boolean, toggles whether unicode
identifiers are allowed in names or not. Default is: false -->
<!-- "apiPackage" - package for generated api classes. Default is:
org.openapitools.client.api -->
<!-- See global configuration value -->
<!-- "artifactDescription" - artifact description in generated pom.xml.
Default is: OpenAPI Java -->
<artifactDescription>An example of a generation issue.</artifactDescription>
<!-- "artifactId" - artifact id in generated pom.xml. This also becomes
part of the generated library's filename. Default is: openapi-jaxrs-server -->
<!-- See global configuration value -->
<!-- "artifactUrl" - artifact URL in generated pom.xml. Default is:
https://github.com/openapitools/openapi-generator -->
<artifactUrl>http://localhost:6666/issue</artifactUrl>
<!-- "artifactVersion" - artifact version in generated pom.xml. This
also becomes part of the generated library's filename. Default is: 1.0.0 -->
<!-- See global configuration value -->
<!-- "bigDecimalAsString" - Treat BigDecimal values as Strings to
avoid precision loss. Default is: false -->
<!-- "booleanGetterPrefix" - Set booleanGetterPrefix. Default is:
get -->
<!-- "dateLibrary" - Option. Date library to use. Default is: legacy -->
<!--"java8" - Java 8 native JSR310 (preferred for jdk 1.8+) - note:
this also sets "java8" to true -->
<!-- "java8-localdatetime" - Java 8 using LocalDateTime (for legacy
app only) -->
<!-- "joda" - Joda (for legacy app only) -->
<!-- "legacy" - Legacy java.util.Date (if you really have a good
reason not to use threetenbp -->
<!-- "threetenbp" - Backport of JSR310 (preferred for jdk < 1.8) -->
<dateLibrary>legacy</dateLibrary>
<!-- "developerEmail" - developer email in generated pom.xml. Default
is: team@openapitools.org -->
<developerEmail>support@example.org</developerEmail>
<!-- "developerName" - developer name in generated pom.xml. Default
is: OpenAPI-Generator Contributors -->
<developerName>foo bar</developerName>
<!-- "developerOrganization" - developer organization in generated
pom.xml. Default is: OpenAPITools.org -->
<developerOrganization>example.org</developerOrganization>
<!-- "developerOrganizationUrl" - developer organization URL in generated
pom.xml. Default is: http://openapitools.org -->
<developerOrganizationUrl>http://www.example.org/</developerOrganizationUrl>
<!-- "disableHtmlEscaping" - Disable HTML escaping of JSON strings
when using gson (needed to avoid problems with byte[] fields). Default is:
false -->
<!-- "ensureUniqueParams" - Whether to ensure parameter names are
unique in an operation (rename parameters that are not). Default is: true -->
<!-- "fullJavaUtil" - whether to use fully qualified name for classes
under java.util. This option only works for Java API client. Default is:
false -->
<!-- "groupId" - group id in generated pom.xml. Default is: org.openapitools -->
<!-- See global configuration value -->
<!-- "hideGenerationTimestamp" - Hides the generation timestamp when
files are generated. Default is: false -->
<hideGenerationTimestamp>true</hideGenerationTimestamp>
<!-- "implFolder" - folder for generated implementation code. Default
is: src/main/java -->
<implFolder>src/main/java</implFolder>
<!-- "invokerPackage" - root package for generated code. Default
is: org.openapitools.api -->
<!-- See global configuration value -->
<!-- "java8" - Option. Use Java8 classes instead of third party equivalents.
Default is: false -->
<!-- "true" - Use Java 8 classes such as Base64 -->
<!-- "false" - Various third party libraries as needed -->
<java8>true</java8>
<!-- "library - library template (sub-template). default is: jersey2 -->
<!-- "jersey1" - Jersey core 1.x -->
<!-- "jersey2" - Jersey core 2.x -->
<!-- "licenseName" - The name of the license: Default is: Unlicense -->
<licenseName>No license</licenseName>
<!-- "licenseUrl" -The URL of the license. Default is: http://unlicense.org -->
<licenseUrl>https://choosealicense.com/no-permission/</licenseUrl>
<!-- "modelPackage" - package for generated models -->
<!-- See global configuration value -->
<!-- "parentArtifactId" - parent artifactId in generated pom N.B.
parentGroupId, parentArtifactId and parentVersion must all be specified for
any of them to take effect. Default is: null -->
<!-- "parentGroupId" - parent groupId in generated pom N.B. parentGroupId,
parentArtifactId and parentVersion must all be specified for any of them
to take effect. Default is: null -->
<!-- "parentVersion" - parent version in generated pom N.B. parentGroupId,
parentArtifactId and parentVersion must all be specified for any of them
to take effect. Default is: null -->
<!-- "prependFormOrBodyParameters" - Add form or body parameters
to the beginning of the parameter list. Default is: false -->
<!-- "scmConnection" - SCM connection in generated pom.xml. Default
is: scm:git:git@github.com:openapitools/openapi-generator.git -->
<scmConnection>null</scmConnection>
<!-- "scmDeveloperConnection" - SCM developer connection in generated
pom.xml. Default is: scm:git:git@github.com:openapitools/openapi-generator.git -->
<scmDeveloperConnection>null</scmDeveloperConnection>
<!-- "scmUrl" - SCM URL in generated pom.xml. Default is: https://github.com/openapitools/openapi-generator -->
<scmUrl>null</scmUrl>
<!-- "serializableModel" - boolean - toggle "implements Serializable"
for generated models. Default is: false -->
<!-- "serverPort" - The port on which the server should be started.
libraryDefault is: 8080 -->
<serverPort>6666</serverPort>
<!-- "snapshotVersion" - Uses a SNAPSHOT version. Default is: null -->
<!-- "true" - Use a SnapShot Version. HINT! This doesn't work -->
<!-- "false" - Use a Release Version. HINT! This doesn't work -->
<!-- "sortParamsByRequiredFlag" - Sort method arguments to place
required parameters before optional parameters.. Default is: true -->
<sortParamsByRequiredFlag>false</sortParamsByRequiredFlag>
<!-- "sourceFolder" - source folder for generated code. Default is:
src/main/java -->
<sourceFolder>src/main/java</sourceFolder>
<!-- "supportJava6" - Whether to support Java6 with the Jersey1/2
library. Default is: false -->
<!-- "title" - a title describing the application. Default is: OpenAPI
Server -->
<!-- "useBeanValidation" - Use BeanValidation API annotations. Default
is: true -->
<!-- "useTags" - use tags for creating interface and controller classnames.
Default is: false -->
<!-- "withXml" - whether to include support for application/xml content
type and include XML annotations in the model (works with libraries that
provide support for JSON and XML). Default is: false -->
<withXml>true</withXml>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
<!-- Deactivate the default phases: compile, testCompile -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<executions>
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<execution>
<id>default-testCompile</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
<!-- Deactivate the default phase: package -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>default-jar</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
<!-- Deactivate the default phase: install -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>default-install</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
<!-- Deactivate the default phase: deploy -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.7</version>
<executions>
<execution>
<id>default-deploy</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
</plugins>
<!-- Set the default action -->
<defaultGoal>clean process-resources</defaultGoal>
</build>
</project>
Description
This provides a test environment for the undesirable behaviour(s) (one to four) of the generated Java classes for:
We noticed this with the generator backend jaxrs-jersey in version 4.0.0. However, the problem still existed after an upgrade to 5.2.1..
But this could be unimportant if it is maybe a structural(?) problem that possibly affects all (code-) generators.
Reproducing
To be able to reproduce this, you need (at least) a Java (>= 1.8.0_301) and a maven (>= 3.6.1) installation. Then put the two files from this issue into a folder of your choice and start the generation;
mvn
alone is sufficient for this.After the generation was successful (hopefully ;-)), change to the subfolder
cd target/generated-sources/openapi
and start the example application throughmvn jetty:run
.Now you can successfully test the functioning of the endpoint
/foo
.You will see something like:
So far so goot.
But access to one level higher (
/
) fails!The assumption why this happens is an error in the generation of the corresponding Java class
src/main/java/org/example/issue/generated/api/DefaultApi.java
.In line 28 stand the following annotation:
@Path("/default")
.After stopping the jetty (
mvn jetty:stop
), do a bugfixing through change to@Path("/")
and a restart of the jetty, access works as expected.Workaround
This minimal API is just one part of a larger one we are working on. Our workaround is exactly the above change, but automated by
But it would be nice if this hack were no longer necessary in the foreseeable future!
Other stuff
Besides, three other generation problems can also be generated with this minimal application.
Double usage vs. Merging vs. Name generation
Since the root path
/
(yaml-file) is mapped to/default
(java-file), the question arises, what actually happens when this endpoint is modeled? This is already prepared in the comment block.I would have expected at least a warning to appear during generation. A cancellation would be better.
But anyway, at the moment the results to be generated are simply merged.
And in the end, is the whole thing perhaps only of an academic nature?!?
As long as the
operationId
is unique and the above problem is fixed, everything is fine. Really? Unfortunately, theoperationId
is not a mandatory value. At least here, when specified, it is checked for duplicate values. But even that is unfortunately not consistent. Therefore, please comment out the specifiedoperationId
value at the top endpoint (/
), uncomment the/default
endpoint and specify itsoperationId
withrootGet
(instead ofdoDefaultGet
). After a newmvn
(without error) you can now see (.../DefaultApi.java
) that the method namerootGet
was chosen for the (still incorrectly routed) root endpoint (/
) and the name, given by the specification, was changed. In my eyes, this is not an expected result.Due to the lack of a possibility to choose a name for the default path (
/
) that cannot also be chosen via the specification (to my knowledge), the only remaining option for a final solution (fixing) is to generate/move the treatment class in another location (aka package). Either implicitly (e.g. ${apiPackage}.root/RootApi.java
) or explicitly via a new configuration option (e.g.<rootPackage>...</rootPackage>
with the default value from the apiPackage option (so that this change does not create any major upheavals for existing projects when they are upgraded)).And an error message should always appear for duplicate
operationId
names, even if this only happens at the end of the tool chain when compiling. Of course, it would be better if an error message already appeared during API analysis if and whichoperationId
names overlap, e.g. in the Swagger editor.No models vs. Compilation errors
This minimal example is not as small as originally thought, because I had to insert something so that at least one model class is created. If no model is needed sematically,
import
statements are nevertheless created, which then produce compilation errors.It would be better that the generation of such references is omitted, if the API does not include model generations (however useful or not that may always be).