Skip to content
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

[REQ] Support multiple YAML files for openapi-generator-maven-plugin #6379

Open
khaiqnguyen93 opened this issue May 20, 2020 · 14 comments
Open

Comments

@khaiqnguyen93
Copy link

khaiqnguyen93 commented May 20, 2020

I have a project that needs to use multiple YAML files, but the inputSpec doesn't support this.
I try a workaround solution by adding multiple executions of the maven plugin into the pom, this issue can be temporarily solved.
But in case I need to generate for many more files (YAML1, YAML2, YAML3,...), and in case my execution contains a big block of code like below:

<execution>
	<goals>
		<goal>generate</goal>
	</goals>
	<configuration>
		<inputSpec>${basedir}/api-spec/${swagger.version}/example1.yaml</inputSpec>
		<output>${basedir}</output>
		<templateDirectory>${basedir}/template/${swagger.version}</templateDirectory>
		<additionalProperties>apiVersion=${swagger.version},useApiAnnotation=false</additionalProperties>
		<generateSupportingFiles>false</generateSupportingFiles>
		<generateModelTests>false</generateModelTests>
		<generateApiTests>false</generateApiTests>
		<generateModelDocumentation>false</generateModelDocumentation>
		<generateApiDocumentation>false</generateApiDocumentation>
		<generatorName>jaxrs-spec</generatorName>
		<configOptions>
			<sourceFolder>src/main/java</sourceFolder>
			<implFolder>src/main/java</implFolder>
			<apiPackage>${swagger.api.package}</apiPackage>
			<interfaceOnly>true</interfaceOnly>
			<java8>true</java8>
			<modelPackage>${swagger.model.package}</modelPackage>
			<useSwaggerAnnotations>false</useSwaggerAnnotations>
			<generatePom>false</generatePom>
			<useBeanValidation>false</useBeanValidation>
		</configOptions>
		<typeMappings>
			<typeMapping>Date=String</typeMapping>
			<typeMapping>LocalDate=String</typeMapping>
		</typeMappings>
	</configuration>
</execution>
<execution>
           ..
</execution>
<execution>
           ...
</execution>

The above workaround is not good, can you support us for a feature that supports multiple YAML files?

@sreenath1506
Copy link

Do we have a fix available for this

@reitsma
Copy link

reitsma commented Apr 7, 2021

Actually, it is possible. I use a setup where I define the plugin in a pluginManagement section and a project with a plugin definition that generates two sets of models, one even inheriting from the other.
The managed plugin looks like this:

<plugin>
	<groupId>org.openapitools</groupId>
	<artifactId>openapi-generator-maven-plugin</artifactId>
	<version>${version-openapi-generator}</version>
	<configuration>
		<generatorName>jaxrs-spec</generatorName>
		<configOptions>
			<sortParamsByRequiredFlag>false</sortParamsByRequiredFlag>
			<java8>true</java8>
			<interfaceOnly>true</interfaceOnly>
			<sourceFolder>src/main/java</sourceFolder>
			<useSwaggerAnnotations>false</useSwaggerAnnotations>
			<useBeanValidation>false</useBeanValidation>
			<dateLibrary>java8</dateLibrary>
			<generatePom>false</generatePom>
			<disableHtmlEscaping>true</disableHtmlEscaping>
			<returnResponse>true</returnResponse>
			<openApiSpecFileLocation>${project.build.directory}/generated-sources/openapi/src/main/resources/META-INF</openApiSpecFileLocation>
			</configOptions>
		<configHelp>false</configHelp>
		<skipValidateSpec>false</skipValidateSpec>
		<generateApiTests>false</generateApiTests>
		<generateModels>true</generateModels>
		<generateModelTests>false</generateModelTests>
		<generateModelDocumentation>false</generateModelDocumentation>
		<generateSupportingFiles>false</generateSupportingFiles>
		<withXml>false</withXml>
	</configuration>
</plugin>

Then the plugin in the project pom looks like:

<plugin>
  <groupId>org.openapitools</groupId>
  <artifactId>openapi-generator-maven-plugin</artifactId>
  <executions>
	  <execution>
		  <id>base-model</id>
		  <goals>
		        <goal>generate</goal>
		  </goals>
		  <configuration>
                        <inputSpec>${project.basedir}/grapevine-api.yaml</inputSpec>
                        <apiPackage>com.vidinexus.grapevine.api</apiPackage>
                        <modelPackage>com.vidinexus.grapevine.api.model</modelPackage>
		  </configuration>
	  </execution>
	  <execution>
		  <id>inquiry</id>
		  <goals>
		        <goal>generate</goal>
		  </goals>
		  <configuration>
			<inputSpec>${project.basedir}/inquiry-api.yaml</inputSpec>
			<apiPackage>com.vidinexus.grapevine.api</apiPackage>
			<modelPackage>com.vidinexus.grapevine.api.model.inquiry</modelPackage>
			<languageSpecificPrimitives>Item,GeoLocation</languageSpecificPrimitives>
			<importMappings>Item=com.vidinexus.grapevine.api.model.Item, GeoLocation=com.vidinexus.grapevine.api.model.GeoLocation</importMappings>
			<typeMappings>Item=com.vidinexus.grapevine.api.model.Item</typeMappings>
  <generateApis>false</generateApis>
		  </configuration>
	  </execution>
  </executions>
</plugin>

Result: two sets of files are generated, one after the other. I myself was quite surprised it worked. I got a hint from here: https://maven.apache.org/guides/mini/guide-default-execution-ids.html.

@ole-v-v
Copy link

ole-v-v commented Mar 8, 2023

Will you excuse a late question? Do we know that the managed plugin is necessary? With versions 6.3.0 and 6.4.0I tried a naïve way with just two executions in the same plugin in my pom.xml, but it seems the plugin is overwriting generated Java files when generating for the second input file in spite of me specifying different package names. This leads to requests being routed to the wrong API and hence failing. Should I expect a managed plugin to fix this?
Generating from Swagger2.0 JSON files using the java generator.

agarkoff pushed a commit to agarkoff/openapi-demo that referenced this issue Apr 3, 2023
Используется вариант предложенный здесь OpenAPITools/openapi-generator#6379 для запуска двух конфигураций плагина с помощью pluginManagement.
@mlebihan
Copy link
Contributor

mlebihan commented Sep 1, 2023

@reitsma

I have to generate an API from those yaml I've received, all going into the same model, api generation folders:

catalogresponses.yaml
config.yaml
coverages.yaml
featuretypes.yaml
manifests.yaml

owsservices.yaml
settings.yaml
workspaces.yaml
catalog.yaml
coveragestores.yaml

datastores.yaml
layers.yaml
namespaces.yaml
styles.yaml

1) I don't understand really your inheritance system: who shall inherit from one another in my case?

2) Whatever, this would lead to add in my pom at least 70 lines (100 lines?) to perform my generation,
as these 14 files would require 13 copy paste of the same block, with only one line changing inside each block.

Don't you think this would be difficult and clumsy, in comparison to setting:

<inputspec>a,b,c,d</inputspec>

or

<inputspec>a b c d</inputspec>

or

<inputspect>*.yaml</inputspec> ?

@reitsma
Copy link

reitsma commented Sep 1, 2023

@ole-v-v : I don't think the managed plugin is really necessary, it should be a convenience in case the plugin is used multiple POMs. My knowledge of maven is not extensive enough to be 100% sure. It is complicated matter if Maven configuration is your full-time job. And openApiGenerator is also not known for its ease of use.

@reitsma
Copy link

reitsma commented Sep 1, 2023

@mlebihan : The inheritance between the generated models appeared indeed an issue. In the above example I could not get the inheritance correctly modelled. I ended up by using a single yaml file as within a single file the modelling of the inheritance was feasible.

Answering your question 2: You are quite right, unless you also want different model packages for each section. In my case I had a base API and a few derived APIs. I did want to mix them in a single package and, as a consequence, I needed to specify each package.

But as I said: I abandoned the idea of multiple executions in the end, because I couldn't get the relations between the schemas correctly modelled.

@Pierre491
Copy link

Pierre491 commented Sep 14, 2023

Hi
I solved it like this:
maven with ant plugin, which performs a for of a list and calls mvn generate-sources with variables,
the yaml list takes up one line, and perhaps it is also possible to read it from an external file

It's kind of ugly, but if you keep the models and apiInterfaces in a separate project that you then import into your main project it's not too annoying, if you have 20+ yaml file my solution could be useful

(tested on windows, not tested on linux)

ant-build.xml
<?xml version="1.0" encoding="UTF-8"?>
<project name="maven-antrun-" default="foreach-task">
    <target name="foreach-task">
        <!-- Definisci una lista di elementi su cui iterare -->
        <property
            name="yaml-service-list"
            value="yaml1,yaml2,yaml3"
        />

        <!-- Utilizza il costrutto foreach per iterare sugli elementi -->
        <foreach list="${yaml-service-list}" param="yaml-service" target="run-mvn-generate-sources"/>
    </target>

    <!-- Questo è il target che verrà chiamato per ciascun elemento -->
    <target name="run-mvn-generate-sources">
        <property name="mvn.pom" value="-f ./pom.xml"/>
        <property name="mvn.opts" value="-PgenerateSourceYaml -Dyaml-service=${yaml-service} -DavoidRecursiveLoop=true"/>
        <condition property="is-unix">
            <os family="unix"/>
        </condition>
        <if>
            <isset property="is-unix"/>
            <then>
                <property name="run.executable" value="sh"/>
                <property name="mvn.command" value="-c 'mvn ${mvn.pom} ${mvn.opts} generate-sources'"/>
            </then>
            <else>
                <property name="run.executable" value="cmd"/>
                <property name="mvn.command" value="/c mvn ${mvn.pom} ${mvn.opts} generate-sources"/>
            </else>
        </if>
        <echo level="info">${run.executable}> ${mvn.command}</echo>
        <exec dir="." executable="${run.executable}" failonerror="true">
            <arg line="${mvn.command}"/>
        </exec>
    </target>
</project>

Maven

to execute only with right profile

  <profiles>
    <profile>
      <id>generateSourceYaml</id>
      <activation>
        <activeByDefault>false</activeByDefault>
      </activation>
      <build>
        <plugins>
          <plugin>
            <groupId>org.openapitools</groupId>
            <artifactId>openapi-generator-maven-plugin</artifactId>
            <version>${openapi-generator.version}</version>
            <executions>
              <execution>
                <id>GenerateSpringAPIs</id>
                <goals>
                  <goal>generate</goal>
                </goals>
                <phase>generate-sources</phase>
                <configuration>
                  <generatorName>spring</generatorName>
                  <inputSpec>${project.basedir}/src/main/resources/yaml/${yaml-service}.yaml</inputSpec>
                  <output>${project.build.directory}/generated-sources/</output>
                  <modelPackage>com.mycompany.openapi.model.${yaml-service}</modelPackage>
                  <apiPackage>com.mycompany.openapi.service</apiPackage>
                  <configOptions>
                    <!--global config-->
                    <library>spring-boot</library>
                    <!--model config-->
                    <hideGenerationTimestamp>true</hideGenerationTimestamp>
                    <serializableModel>true</serializableModel>
                    <openApiNullable>false</openApiNullable>
                    <dateLibrary>java8</dateLibrary>
                    <!--api config-->
                    <useTags>true</useTags>
                    <delegatePattern>false</delegatePattern>
                    <implicitHeaders>true</implicitHeaders>
                    <useResponseEntity>true</useResponseEntity>
                    <useFeignClientUrl>false</useFeignClientUrl>
                    <unhandledException>true</unhandledException>
                    <interfaceOnly>true</interfaceOnly>
                    <skipDefaultInterface>true</skipDefaultInterface>
                  </configOptions>
                </configuration>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
    </profile>

  </profiles>

to execute with any profile (or starting profile)

<plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <executions>
          <execution>
            <id>generate-sources-all-yaml</id>
            <goals>
              <goal>run</goal>
            </goals>
            <phase>generate-sources</phase>
            <configuration>
              <target>
                <taskdef resource="net/sf/antcontrib/antcontrib.properties" classpathref="maven.plugin.classpath"/>
                <if>
                  <isset property="avoidRecursiveLoop"/>
                  <then>
                    <echo level="info">avoid recursive loop</echo>
                  </then>
                  <else>
                    <echo level="info">run ant-build.xml</echo>
                    <ant antfile="ant-build.xml"/>
                  </else>
                </if>
              </target>
            </configuration>
          </execution>
        </executions>
        <dependencies>
          <dependency>
            <groupId>org.apache.ant</groupId>
            <artifactId>ant</artifactId>
            <version>1.10.14</version>
          </dependency>
          <dependency>
            <groupId>org.apache.ant</groupId>
            <artifactId>ant-jsch</artifactId>
            <version>1.10.14</version>
          </dependency>
          <dependency>
            <groupId>ant-contrib</groupId>
            <artifactId>ant-contrib</artifactId>
            <version>1.0b3</version>
          </dependency>
        </dependencies>
      </plugin>

If there was a smarter solution I would love it

@SebastianSuchowiak
Copy link

Hi, I was able to generate sources for two different specs. I added a second execution goal and specified different output directories for the specs using the option from the config:

<executions>
  <execution>
    <id>api-1</id>
    <inputSpec>${project.basedir}/api-1.yaml</inputSpec>
    ...
    <output>${project.build.directory}/generated-sources/openapi-1</output>
  </execution>
  <execution>
    <id>api-2</id>
    <inputSpec>${project.basedir}/api-2.yaml</inputSpec>
    ...
    <output>${project.build.directory}/generated-sources/openapi-2</output>
  </execution>
<executions>

@rupert-jung-mw
Copy link

rupert-jung-mw commented Feb 21, 2024

For me, it only processes the first <execution>, the first one is ignored. I use different values. Version is 7.2.0
Update: My fault was to specify on both but as I had the same root folder, this deleted the first generated client.

@valb3r
Copy link

valb3r commented Mar 26, 2024

I think it is already supported with inputSpecRootDirectory (works properly with 7.4.0 version)

So the config can look like that:

         <plugin>
            <groupId>org.openapitools</groupId>
            <artifactId>openapi-generator-maven-plugin</artifactId>
            <version>${openapi-generator-maven-plugin.version}</version>
            <executions>
                <execution>
                    <id>Generate API from multiple YAML files</id>
                    <goals>
                        <goal>generate</goal>
                    </goals>
                    <configuration>
                        <inputSpecRootDirectory>${project.basedir}/src/main/resources/folder-with-api-yamls</inputSpecRootDirectory>
                        <generatorName>spring</generatorName>
                        <generateApiTests>false</generateApiTests>
                        <generateModelTests>false</generateModelTests>
                        <configOptions>
                            <sourceFolder>src/main/java</sourceFolder>
                            <basePackage>com.mycompany.generated</basePackage>
                            <configPackage>com.mycompany.generated</configPackage>
                            <modelPackage>com.mycompany.generated</modelPackage>
                            <apiPackage>com.mycompany.generated</apiPackage>
                            <useSpringBoot3>true</useSpringBoot3>
                            <interfaceOnly>true</interfaceOnly>
                            <skipOverwrite>true</skipOverwrite>
                            <dateLibrary>java8</dateLibrary>
                            <java8>false</java8>
                            <useTags>true</useTags>
                            <defaultInterfaces>false</defaultInterfaces>
                            <implicitHeaders>false</implicitHeaders>
                        </configOptions>
                    </configuration>
                </execution>
            </executions>
        </plugin>

@minesunny
Copy link

inputSpecRootDirectory

Do you know how to use inputSpecRootDirectory with openapi-generator-cli

@valb3r
Copy link

valb3r commented Apr 15, 2024

@minesunny openapi-generator generate -g spring -o out --input-spec-root-directory <MY-DIRECTORY-PATH> worked well for me (openapi-generator version 7.4.0)

npm based generator works with that as well:

"openapi-gen-merged": "openapi-generator-cli generate -g typescript-angular -o src/app/api2 --input-spec-root-directory <MY-DIRECTORY-PATH>",

@minesunny
Copy link

minesunny commented Apr 16, 2024

@minesunny openapi-generator generate -g spring -o out --input-spec-root-directory <MY-DIRECTORY-PATH> worked well for me (openapi-generator version 7.4.0)

npm based generator works with that as well:

"openapi-gen-merged": "openapi-generator-cli generate -g typescript-angular -o src/app/api2 --input-spec-root-directory <MY-DIRECTORY-PATH>",

thank you,it does work

@davidkubecka-ext43694
Copy link

I think it is already supported with inputSpecRootDirectory (works properly with 7.4.0 version)

This indeed works but all the generated classes are heaped onto a single package. Is there any way to have separate packages for separate source files?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests