swagger-codegen icon indicating copy to clipboard operation
swagger-codegen copied to clipboard

How to generate common classes to a separate package and then reuse them

Open eakonovalov opened this issue 5 years ago • 5 comments

I can define common classes in a separate schema file:

common.json { ... "components": { "schemas": { "FinancialContext": { ... } } }

and then reuse it in many other schemas: "financialContext": "$ref": "common.json#/components/schemas/FinancialContext" }

but when I generate models using swagger-codegen-maven-plugin this class will be duplicated in each package for each schema (I cannot generate all the classes to the same package because they can have other classes with the same name, but different content).

I want to be able to generate common.json to a separate package (this is actually possible now) and then all other executions of the plugin should import already generated classes from the common package instead of generating copies of the class in the apis packages.

eakonovalov avatar Jan 13 '21 22:01 eakonovalov

Have you found a solution ?

Kobee1203 avatar Jun 08 '22 13:06 Kobee1203

@eakonovalov Hi, have you found a solution for this ? We are facing a similar issue but I didn't find a way to resolve it yet.

riju4git avatar Apr 17 '23 19:04 riju4git

JFYI I have found the way how to do this, so in case anybody will search for solution in future this could help. The idea here is the combination of needed actions:

  1. Use OpenAPI Spec 3 $ref with Remote reference for all your common classes in multiple specification
# Folder structure
|── src
│    |── main
│    │   |── resources
│    |   |        |── bounded-context1-spec.yaml
|    |   |        |── bounded-context2-spec.yaml
|    |   |        |── common-classes.yaml
# bounded-context1-spec.yaml
openapi: 3.0.3
info:
  title: OpenAPI 3 spec example for bounded context 1
  version: 1.0.0
paths:
  /test:
    get:
      tags:
        - test
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: "common-classes.yaml#/components/schemas/Test"
    
# bounded-context2-spec.yaml
openapi: 3.0.3
info:
  title: OpenAPI 3 spec example for bounded context 2
  version: 1.0.0
paths:
  /test2:
    get:
      tags:
        - test2
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: "common-classes.yaml#/components/schemas/Test"
# common-classes.yaml
openapi: 3.0.3
info:
  title: Common Classes which are used by both bounded contexts
  version: 1.0.0
paths: {}
components:
  schemas:
    Test:
      type: object
      properties:
        message:
          type: string
  1. Additional execution step for swagger-codegen-plugin which is configured to generate only Models. (classes will be generated to com.test.common.model package)
# pom.xml
...
<plugin>
    <groupId>io.swagger</groupId>
    <artifactId>swagger-codegen-maven-plugin</artifactId>
    <version>2.3.1</version>
    <executions>
        <execution>
            <goals>
                <goal>generate-common-classes</goal>
            </goals>
            <configuration>
                <inputSpec>${project.basedir}/src/main/resources/common-classes.yaml</inputSpec>
                <modelPackage>com.test.common.model</modelPackage>
                <language>spring</language>
                <generateApis>false</generateApis>
            </configuration>
        </execution>
        <!-- Main execution steps for Bounded Contexts OpenAPI specs -->
    </executions>
</plugin>
...
  1. Add importMappings for common models into your main execution steps. This configuration will disable generation of common classes for specific bounded context and reuse classes generated in above step.
# pom.xml
...
<plugin>
    <groupId>io.swagger</groupId>
    <artifactId>swagger-codegen-maven-plugin</artifactId>
    <version>2.3.1</version>
    <executions>
        <execution>
            <goals>
                <goal>generate-common-classes</goal>
            </goals>
            <configuration>
                <inputSpec>${project.basedir}/src/main/resources/common-classes.yaml</inputSpec>
                <modelPackage>com.test.common.model</modelPackage>
                <language>spring</language>
                <generateApis>false</generateApis>
            </configuration>
        </execution>
        <!-- Main execution steps for Bounded Contexts OpenAPI specs -->
         <execution>
            <goals>
                <goal>generate-bounded-context-1</goal>
            </goals>
            <configuration>
                <inputSpec>${project.basedir}/src/main/resources/bounded-context1-spec.yaml</inputSpec>
                <<apiPackage>com.test.bounded-context2</apiPackage>
                <modelPackage>com.test.bounded-context2.model</modelPackage>
                <language>spring</language>
                <additionalProperties>
                  <additionalProperty>ignoreImportMappings=false</additionalProperty>
                </additionalProperties>
                <importMappings>
                  <importMapping>Test=com.test.common.model.Test</importMapping>
                </importMappings>
            </configuration>
        </execution>
        <execution>
            <goals>
                <goal>generate-bounded-context-2</goal>
            </goals>
            <configuration>
                <inputSpec>${project.basedir}/src/main/resources/bounded-context2-spec.yaml</inputSpec>
                <apiPackage>com.test.bounded-context2</apiPackage>
                <modelPackage>com.test.bounded-context2.model</modelPackage>
                <language>spring</language>
                <additionalProperties>
                  <additionalProperty>ignoreImportMappings=false</additionalProperty>
                </additionalProperties>
                <importMappings>
                  <importMapping>Test=com.test.common.model.Test</importMapping>
                </importMappings>
            </configuration>
        </execution>
    </executions>
</plugin>
...
  1. Profit 🙂

In case of additional questions do not hesitate to ask me

BTW I believe the issue could be closed for now

Demonian avatar Oct 18 '23 11:10 Demonian

Hi, even though it works, in my opinion the solution is not ideal, because you need to explicitly declare the mapping for each class you want to be "shared". It would be better to have an option to let the plugin know that every class imported from common-classes.yaml remote reference should use the common package instead.

gturi avatar Feb 04 '24 12:02 gturi