-
-
Notifications
You must be signed in to change notification settings - Fork 6.4k
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
[BUG][openapi-generator-maven-plugin] importmapping not respected since 5.4.0 #11506
Comments
I just encountered the a similar issue after upgrading to 5.4.0 Classes specified in importMappings are ignored and generated anyway. Here's an example:
|
I see the issue as well. The mapped imports are used in the generated Model, but the Model targeted by the importmapping is generated anyway. |
Same, but for the gradle plugin |
Same here |
Seems to me that #11217 removed the usage of the import mappings in the generated model. Additionally, defined import mappings will no longer be skipped during the model generation. We were relying heavily on this behavior to fix issues the spring generator has with anyOf/oneOf (by defining models that use anyOf/oneOf and setting them as import mappings). @wing328 Is there any other way to use our own models? What's described in https://openapi-generator.tech/docs/customization/#bringing-your-own-models no longer works. |
Same here, this is a "big regression" for us as we use it very often Any clue why removing this needed feature ? |
Hi In case of a fix for this bug, would it be released in a 5.4.x version? @wing328 @bbdouglas @sreeshas @jfiala @lukoyanov @cbornet @jeff9finger @karismann @Zomzog @lwlee2608 Thank you very much |
For those impacted by this, please revert to v5.3.1 for the time being. We need to come up with something else (e.g. schemaMapping) as importMapping was not designed for skipping model generation. (the logic for reusing importMapping to skip model generation was added in 4.x if I remember correctly) I'll try to come up with a fix for the v6.0.0 release. For those who want to repeat the issue fixed by #11217, define a model named "List" and you will see the model not being generated (which is not the correct behaviour) when using the Java client generator. Have a nice weekend everyone. |
@wing328 thanks for working on this, I understand it like the 6.0.0 version will introduce schemaMapping for skipping model generation, right? |
I previously used configOptions = [
'dateLibrary': 'custom',
]
typeMappings = [
'DateTime': 'ZonedDateTime',
]
importMappings = [
'ZonedDateTime': 'java.time.ZonedDateTime'
] With that configuration, the fields would be declared in the generated file with the fully qualified My current workaround is by removing configOptions = [
'dateLibrary': 'custom',
]
typeMappings = [
'DateTime': 'java.time.ZonedDateTime',
] Looking at the Gradle plugin's configuration options, it seems like using only |
@IncPlusPlus I tried to use It seems like the typeMapping What I am looking for is a way to skip codegen for some models and just use an import/fqn instead. Before 5.4.0 that could be done with |
Hi @wing328 In version 6.0.0, has this problem been fixed? Thank you |
Hi, Any news on this issue? |
Even in the version 5.3.1the problem is still there |
I might have a workaround if you can choose the name and location of your own model freely: Create an
Use that file in your openapi-generator-maven-plugin configuration: <plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>6.0.0</version>
<executions>
<execution>
<id>openapi-generator-server</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<generatorName>spring</generatorName>
<modelPackage>com.example.myproject.openapi.model</modelPackage>
<ignoreFileOverride>
./.openapi-generator-ignore
</ignoreFileOverride>
</configuration>
</execution>
</executions>
</plugin> Now move your own implementation to |
I reference an external schema in my openapi spec: MyRequest:
type: object
properties:
...
my_external_properties:
type: array
items:
$ref: 'http://openapi-host.example.com/#/components/schemas/ExternalDto' To avoid duplicated Dtos I found following workaround:
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>5.4.0</version>
<!-- TODO Remove this dependency-overrides when openapi-generator-maven-plugin (>5.4.0) has a dependency to
openapi-generator (>5.4.0) that has a dependency to
io.swagger.parser.v3:swagger-parser (>2.0.26)
This is because there is an issue with parsing absolute $ref that causes those to be parsed as if they where relative.
2.0.26: https://github.com/swagger-api/swagger-parser/blob/987fa8c632d01887bc0e901106edfc6e5f857bc6/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/processors/PathsProcessor.java#L281
2.0.31: https://github.com/swagger-api/swagger-parser/blob/2ba563c25d658fa2203d2317f0b2a08f97c95749/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/processors/PathsProcessor.java#L281 -->
<dependencies>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-core</artifactId>
<version>2.1.13</version>
</dependency>
<dependency>
<groupId>io.swagger.parser.v3</groupId>
<artifactId>swagger-parser</artifactId>
<version>2.0.31</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>generate-java-api-interface</id>
<phase>generate-sources</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<!--
See: https://openapi-generator.tech/docs/generators/spring
-->
<generatorName>spring</generatorName>
<output>.</output>
<generateModels>true</generateModels>
<modelPackage>${openapi.java.modelPackage}</modelPackage>
<generateApis>true</generateApis>
<apiPackage>${openapi.java.apiPackage}</apiPackage>
<modelNameSuffix>Dto</modelNameSuffix>
<!-- Use external Dtos (see dependencies)-->
<typeMappings>
<typeMapping>External=org.my.other.depnendecy.ExternalDto</typeMapping>
</typeMappings>
</configuration>
<plugin>
<groupId>net.revelc.code</groupId>
<artifactId>impsort-maven-plugin</artifactId>
<version>1.7.0</version>
<configuration>
<removeUnused>true</removeUnused>
<directories>
<directory>${openapi.java.sourceDir}</directory>
</directories>
</configuration>
<executions>
<execution>
<id>remove-unsued-imports</id>
<phase>generate-sources</phase>
<goals>
<goal>sort</goal>
</goals>
</execution>
</executions>
</plugin> |
Hi all, I've filed #12600 to add back the functionality. Please give it a try to see if it works for your use cases. |
I used to rely on to substitute OffsetDateTime with Instant. This no longer works, but the workaround meanwhile is to use a fully qualified class name in . In my case OffsetDateTime=java.time.Instant helps generate the right types with the minor inconvenience of seeing fully qualified class names for substituted types. The original import statement "import java.time.OffsetDateTime;" appears in the generated but remains unused. |
Hi @wing328 I have tried version 6.0.1 and it still does not work in my use case. Could you reopen the issue? I think this issue is very important. |
Sorry, using schemamapping instead of importmapping works fine in version 6.0.1 Thank you very much @wing328 |
@jorgerod sorry could you provide a little snip of code to clarify the case? Thanks, |
The following configuration works for us:
|
@enricojonas sorry, I just saw your message. With the configuration that @gong4soft gives you it works |
@jorgerod @gong4soft thanks for sharing. I tried it and unfortunately it doesn't do anything.
I have a couple of
in the API spec that I need to map to Java BigDecimal. Trying with the latest version 6.2.1.
works but then it does not do the import but instead inserts the full class name everywhere. |
The following configuration works for us: File: config.spring.yaml ---
apiPackage: work.hochguertel.quiz.api
basePackage: work.hochguertel.quiz.api
invokerPackage: work.hochguertel.quiz.api
dateLibrary: java8
delegatePattern: true
generatorName: spring
library: spring-boot
modelPackage: work.hochguertel.quiz.api.model
sourceFolder: src/main/java/
interfaceOnly: true
hideGenerationTimestamp: true
serializableModel: true
useTags: true
hateoas: true
withXml: true
supportingFilesToGenerate: ApiUtil.java
importMappings:
ResourceSupport: org.springframework.hateoas.RepresentationModel
Link: org.springframework.hateoas.Link
Links: org.springframework.hateoas.Links
Pageable: org.springframework.data.domain.Pageable
Page: org.springframework.data.domain.Page
typeMappings:
ResourceSupport: org.springframework.hateoas.RepresentationModel
Link: org.springframework.hateoas.Link
Links: org.springframework.hateoas.Links
Pageable: org.springframework.data.domain.Pageable
Page: org.springframework.data.domain.Page
schemaMappings:
ResourceSupport: org.springframework.hateoas.RepresentationModel
Link: org.springframework.hateoas.Link
Links: org.springframework.hateoas.Links
Pageable: org.springframework.data.domain.Pageable
Page: org.springframework.data.domain.Page File: api-v1.0.0.yaml openapi: 3.0.3
info:
title: Title
description: Title
version: 1.0.0
servers:
- url: 'http://localhost:8082/api/v1'
tags:
- name: Question
description: Everything about questions.
- name: Result
description: Everything about results of a exam.
- name: Category
description: Everything about categories.
paths:
/api/v1.0.0/questions/{questionId}:
get:
tags:
- Question
summary: Returns a single question.
description: Returns the question with the given question ID.
operationId: getQuestionById
parameters:
- $ref: '#/components/parameters/questionId'
responses:
200:
description: successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/Question'
application/xml:
schema:
$ref: '#/components/schemas/Question'
404:
description: Given question ID doesn't exist
content: { }
put:
tags:
- Question
summary: Updates a single question.
description: Updates the question with the given questionID.
operationId: updateQuestion
parameters:
- $ref: '#/components/parameters/questionId'
requestBody:
description: Question object
content:
application/json:
schema:
$ref: '#/components/schemas/Question'
application/xml:
schema:
$ref: '#/components/schemas/Question'
responses:
200:
description: successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/Question'
application/xml:
schema:
$ref: '#/components/schemas/Question'
404:
description: Question with ID doesn't exist.
content: { }
delete:
tags:
- Question
summary: Deletes a single question.
description: Deletes the question with the given questionID.
operationId: deleteQuestion
parameters:
- $ref: '#/components/parameters/questionId'
responses:
200:
description: successful operation
content: { }
404:
description: Question with ID doesn't exist.
content: { }
/api/v1.0.0/questions:
get:
tags:
- Question
summary: Returns a collection of questions.
description: Returns all available questions.
operationId: getQuestions
parameters:
- in: query
name: pageable
required: false
schema:
$ref: '#/components/schemas/Pageable'
responses:
200:
description: successful operation
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Question'
application/xml:
schema:
type: array
items:
$ref: '#/components/schemas/Question'
post:
tags:
- Question
summary: Creates a new Question
description: Creates a new question with answers and explainations
operationId: createQuestion
requestBody:
description: Question object
content:
application/json:
schema:
$ref: '#/components/schemas/Question'
application/xml:
schema:
$ref: '#/components/schemas/Question'
responses:
201:
description: Question added successfully
content:
application/json:
schema:
$ref: '#/components/schemas/Question'
application/xml:
schema:
$ref: '#/components/schemas/Question'
/api/v1.0.0/categories/{categoryId}:
get:
tags:
- Category
summary: Returns a given Category.
description: Returns a given Category.
operationId: getCategoryById
parameters:
- $ref: '#/components/parameters/categoryId'
responses:
200:
description: Category found.
content:
application/json:
schema:
$ref: '#/components/schemas/Category'
application/xml:
schema:
$ref: '#/components/schemas/Category'
404:
description: Category with ID doesn't exist.
content: { }
put:
tags:
- Category
summary: Updates a existing Category.
description: Updates a existing Category.
operationId: updatesCategory
parameters:
- $ref: '#/components/parameters/categoryId'
requestBody:
description: Category Object
content:
application/json:
schema:
$ref: '#/components/schemas/CategoryUpdate'
application/xml:
schema:
$ref: '#/components/schemas/CategoryUpdate'
responses:
200:
description: Category successfully updated.
content:
application/json:
schema:
$ref: '#/components/schemas/Category'
application/xml:
schema:
$ref: '#/components/schemas/Category'
404:
description: Category with ID doesn't exist.
content: { }
delete:
tags:
- Category
summary: Deletes a existing Category.
description: Deletes a existing Category.
operationId: deleteCategory
parameters:
- $ref: '#/components/parameters/categoryId'
responses:
200:
description: Category successfully deleted.
content: { }
404:
description: Category with ID doesn't exist.
content: { }
/api/v1.0.0/categories:
get:
tags:
- Category
summary: Returns a collection of categories.
description: Returns all available categories.
operationId: getCategories
parameters:
- in: query
name: pageable
required: false
schema:
$ref: '#/components/schemas/Pageable'
responses:
200:
description: successful operation
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Category'
application/xml:
schema:
type: array
items:
$ref: '#/components/schemas/Category'
# content:
# application/json:
# schema:
# type: object
# properties:
# questions:
# type: array
# items:
# $ref: '#/components/schemas/Category'
# page:
# $ref: '#/components/schemas/Page'
# application/xml:
# schema:
# type: object
# properties:
# questions:
# type: array
# items:
# $ref: '#/components/schemas/Category'
# page:
# $ref: '#/components/schemas/Page'
post:
tags:
- Category
summary: Creates a new Category.
description: Creates a new Category.
operationId: createCategory
requestBody:
description: Category Object
content:
application/json:
schema:
$ref: '#/components/schemas/Category'
application/xml:
schema:
$ref: '#/components/schemas/Category'
responses:
201:
description: Category successfully created.
content:
application/json:
schema:
$ref: '#/components/schemas/Category'
application/xml:
schema:
$ref: '#/components/schemas/Category'
/api/v1.0.0/questionresult/{questionId}:
post:
tags:
- Result
summary: Creates a result report of one question
description: Evaluates the given answers for a given question.
operationId: evaluateGivenAnswer
parameters:
- $ref: '#/components/parameters/questionId'
requestBody:
description: Question object
content:
application/json:
schema:
$ref: '#/components/schemas/QuestionAnswer'
application/xml:
schema:
$ref: '#/components/schemas/QuestionAnswer'
responses:
201:
description: Question result successfully created.
content:
application/json:
schema:
$ref: '#/components/schemas/QuestionResult'
application/xml:
schema:
$ref: '#/components/schemas/QuestionResult'
404:
description: Question with ID doesn't exist.
content: { }
/api/v1.0.0/questionresult:
post:
tags:
- Result
summary: Creates a Exam Report.
description: Evaluates the Exam.
operationId: evaluate
requestBody:
description: Object which represents a Exam report
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/ExamQuestionAnswer'
application/xml:
schema:
type: array
items:
$ref: '#/components/schemas/ExamQuestionAnswer'
responses:
201:
description: Exam result successfully created.
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/QuestionResult'
application/xml:
schema:
type: array
items:
$ref: '#/components/schemas/QuestionResult'
components:
responses:
NotFound:
description: The specified resource was not found.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
application/xml:
schema:
$ref: '#/components/schemas/Error'
Unauthorized:
description: Unauthorized.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
application/xml:
schema:
$ref: '#/components/schemas/Error'
schemas:
Error:
type: object
properties:
code:
type: string
message:
type: string
required:
- code
- message
Question:
description: a Object what represents a Multiple Choice question with answers.
type: object
properties:
id:
description: Identifier
type: string
quest:
description: Question itself as sentence (with Markdown code).
type: string
draft:
description: Marks a question as draft or not.
type: boolean
answers:
description: List of possibles Answers
type: array
items:
$ref: '#/components/schemas/Answer'
Answer:
description: Represents a Answering option, with explaination and if it's valid answer.
type: object
properties:
statement:
description: Answer statement (with Markdown code).
type: string
correct:
description: Is this a valid or a wrong answer?
type: boolean
explanation:
description: Explains why this Answer is valid or wrong (with Markdown code).
type: string
QuestionAnswer:
description: Represents a given Answer by a student for one Question. Index of the array represents the choice of answer per question.
type: array
items:
description: Each Index represents the choiced answer of the user from the array of answers of the question.
type: boolean
ExamQuestionAnswer:
description: Question and user's choices.
type: object
properties:
question:
description: Question Identifier
type: string
givenAnswers:
description: Represents a given Answer by a student for one Question. Index of the array represents the choice of answer per question.
type: array
items:
description: Each Index represents the choiced answer of the user from the array of answers of the question.
type: boolean
Category:
description: Represents a union of questions
type: object
properties:
id:
description: Identifier
type: string
name:
description: name of the category.
type: string
questions:
type: array
items:
$ref: '#/components/schemas/Question'
CategoryUpdate:
description: Represents a List of Questions.
type: object
properties:
name:
description: name of the category.
type: string
questions:
type: array
items:
type: string
QuestionResult:
description: Represents a answer-sheet of one question
type: object
properties:
question:
$ref: '#/components/schemas/Question'
your_choices:
description: list of boolean values, which represents students answer choices on the answer sheet.
type: array
items:
type: boolean
checked_results:
description: list of boolean values, which represents which answer of the student was correct or wrong.
type: array
items:
type: boolean
explainations:
description: list of string values, which gives for each answer (positioned) the explaination of the answer statement.
type: array
items:
type: string
validation:
description: list of boolean values, which represents the correct and wrong answers (positioned).
type: array
items:
type: boolean
Links:
description: HATEOAS Links
type: object
properties:
first:
$ref: "#/components/schemas/_href"
self:
$ref: "#/components/schemas/_href"
next:
$ref: "#/components/schemas/_href"
last:
$ref: "#/components/schemas/_href"
profile:
$ref: "#/components/schemas/_href"
search:
$ref: "#/components/schemas/_href"
Pageable:
description: Pagination
type: object
properties:
pageNumber:
description: the page to be returned.
type: number
pageSize:
description: the number of items to be returned.
type: number
offset:
description: the offset to be taken according to the underlying page and page size.
type: number
sort:
description: the sorting parameters.
type: number
Page:
description: Pagination
type: object
properties:
size:
description: Amount of items on this page.
type: number
totalElements:
description: Total amount of items of the resource.
type: number
totalPages:
description: Total amount of pages for this resource.
type: number
number:
description: Current page number.
type: number
_href:
description: Link to a resource
type: object
properties:
href:
description: URL
type: string
parameters:
questionId:
name: questionId
in: path
description: Question Identifier
required: true
schema:
type: string
categoryId:
name: categoryId
in: path
description: Category Identifier
required: true
schema:
type: string npx @openapitools/openapi-generator-cli generate -c ../../quiz/openapi/config.spring.yaml -i ../../quiz/openapi/api-v1.0.0.yaml -o ./build/openapi/spring No $ npx @openapitools/openapi-generator-cli version
6.2.1 |
This is to investigate OpenAPITools#14525 and OpenAPITools#11506.
I would like to draw attention to the fact that the names in the type mapping are case-sensitive. In other words, if you write:
the schema should be as follows:
Using lowercase naming also worked, but if you write the mapping like this:
and the schema like this:
the DTO is still being created. |
Bug Report Checklist
Description
The "importMappings" seem to have no effect with version 5.4.0.
With version 5.3.1 the below configuration resulted in a "StreamingResponseBody" in the generated class.
With version 5.4.0 a "Stream" class is imported but that one does not exist.
openapi-generator version
Issue occurs with openapi-generator-maven-plugin 5.4.0 and did not occur with the previous version 5.3.1.
OpenAPI declaration file content or url
If you post the code inline, please wrap it with
Generation Details
Plugin configuration:
Steps to reproduce
Run
mvn clean install
on the attached demo project.Related issues/PRs
No similar issues.
Suggest a fix
Not sure what causes the problems, but I assume it has to do with this change:
#11217
bug Demo application
bug-demo.zip
The text was updated successfully, but these errors were encountered: