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

The files and directory structures output into generated-sources by swagger-codegen-maven-plugin are unusable #1737

Open
rdelaplante opened this issue Dec 17, 2015 · 17 comments

Comments

@rdelaplante
Copy link

Similar code generator plugins for SOAP, Thrift, WADL, etc. output the sources directly into /target/generated-sources/wsimport/. The contents of this directory is source code and package directories only; nothing else.

When swagger-codegen-maven-plugin is executed, it outputs a complete Maven project directory structure and build files into /target/generated-sources/swagger/. When Maven gets to the compile phase, the source files are not found and the build fails.

What gets generated by swagger-codegen-maven-plugin:

\---target
    +---generated-sources
    |   \---swagger
    |       |   build.gradle
    |       |   gradle.properties
    |       |   pom.xml
    |       |   README.md
    |       |   settings.gradle
    |       |
    |       \---src
    |           \---main
    |               |   AndroidManifest.xml
    |               |
    |               \---java
    |                   \---io
    |                       \---swagger
    |                           \---client
    |                               |   ApiClient.java
    |                               |   ApiException.java
    |                               |   Configuration.java
    |                               |   JSON.java
    |                               |   Pair.java
    |                               |   StringUtil.java
    |                               |
    |                               +---api
    |                               |       PetApi.java
    |                               |       StoreApi.java
    |                               |       UserApi.java
    |                               |
    |                               +---auth
    |                               |       ApiKeyAuth.java
    |                               |       Authentication.java
    |                               |       HttpBasicAuth.java
    |                               |       OAuth.java
    |                               |       OAuthFlow.java
    |                               |
    |                               \---model
    |                                       ApiResponse.java
    |                                       Category.java
    |                                       Order.java
    |                                       Pet.java
    |                                       Tag.java
    |                                       User.java

What it should be generating to be usable:

\---target
    +---generated-sources
    |   \---swagger
    |       \---io
    |           \---swagger
    |               \---client
    |                   |   ApiClient.java
    |                   |   ApiException.java
    |                   |   Configuration.java
    |                   |   JSON.java
    |                   |   Pair.java
    |                   |   StringUtil.java
    |                   |
    |                   +---api
    |                   |       PetApi.java
    |                   |       StoreApi.java
    |                   |       UserApi.java
    |                   |
    |                   +---auth
    |                   |       ApiKeyAuth.java
    |                   |       Authentication.java
    |                   |       HttpBasicAuth.java
    |                   |       OAuth.java
    |                   |       OAuthFlow.java
    |                   |
    |                   \---model
    |                           ApiResponse.java
    |                           Category.java
    |                           Order.java
    |                           Pet.java
    |                           Tag.java
    |                           User.java

When I move and delete files by hand I can get it to compile, package and run successfully.

IMO the swagger-codegen-maven-plugin is unusable in its current form.

@rdelaplante
Copy link
Author

tonytam on IRC suggested that I try these options in the plugin config:

<configOptions> 
    <sourceFolder>src/gen/java</sourceFolder> 
</configOptions> 
<output>.</output> 

I gave it a try:

  • just the sources and package directories were generated in src/gen/java (correct!) Don't they belong in /target/generated-sources/swagger/ ?
  • my project's own pom.xml file was overwritten
  • a bunch of unwanted project files were still generated (/build.gradle, /gradle.properties, /README.md, /settings.gradle)
  • My project would not compile. It told me that it couldn't find the generated classes.

@fehguy
Copy link
Contributor

fehguy commented Dec 17, 2015

Hi @rdelaplante I was just giving you the options. You can change it to <output>target/generated-sources</output>. You have full control

@rdelaplante
Copy link
Author

Thanks for the tip. I changed the plugin config to this:

<configOptions>
    <sourceFolder>swagger</sourceFolder>
</configOptions>
<output>target/generated-sources</output>

It now outputs just the source files and packages to /target/generated-sources/swagger/, and the unwanted project files are now placed in /target/generated-sources/. It now compiles, deploys and runs, but for some reason my IDE doesn't recognize the generated sources and I get a bunch of red error badges in my own code that uses the client. That wasn't happening earlier today. I'll investigate further tomorrow.

There is another error I'm getting at runtime, but I suspect that is related to the Maven plugin using the default jersey 1 client. I'm using plugin version 2.1.4 which doesn't support the library tag, so earlier I generated a client from the command line and made it use the jersey2 client which worked well. I'll investigate that further tomorrow.

It would be nice if the Maven plugin could make use of swagger-codegen's "selective generation" feature to not output any project files at all (build.gradle, gradle.properties, pom.xml, README.md, and settings.gradle):

https://github.com/swagger-api/swagger-codegen#selective-generation

@fehguy
Copy link
Contributor

fehguy commented Dec 17, 2015

Great, some progress. A couple comments

  • First, you can enable the jersey2 client by using the -Dlibrary=jersey2, or by setting
<environmentVariables>
   <library>jersey2</library>
</environmentVariables>
  • Next, you can enable the selective generation like such:
<configuration>
    <environmentVariables>
        <!-- models to generate -->
        <models>Account,MetricsSnapshot,Swagger</models>
        <!-- required by models as a helper -->
        <supportingFiles>StringUtil.java</supportingFiles>
    </environmentVariables>

@rdelaplante
Copy link
Author

More great tips, thank you. Below is how I have my plugin XML right now. I've managed to get it to output only the Java sources to /target/generated-sources/swagger/. It compiles successfully and my IDE recognizes the standardized directory layout so there are no red error badges. I just need to make sure that my own project's pom.xml includes all of the required dependencies.

I was not able to get it to use the jersey2 library even when adding the library tag to environmentVariables, or find documentation indicating that environment variable exists. I know that this issue has been tackled for the upcoming plugin version 2.1.5: #1696

I'm curious about the plugin's default settings and wiki documentation. I'm not aware of a situation where the current defaults are what a developer using Maven and this plugin would want (regarding where to generate files, and which files to generate).

<plugin>
    <groupId>io.swagger</groupId>
    <artifactId>swagger-codegen-maven-plugin</artifactId>
    <version>2.1.4</version>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <inputSpec>src/main/services/petstore.yaml</inputSpec>
                <language>java</language>
                <!-- <library>jersey2</library>  will be available in plugin 2.1.5 -->

                <invokerPackage>com.company.spike.swaggerspike1.client.petstore</invokerPackage>
                <apiPackage>com.company.spike.swaggerspike1.client.petstore.api</apiPackage>
                <modelPackage>com.company.spike.swaggerspike1.client.petstore.model</modelPackage>

                <!-- output to /target/generated-sources/swagger/ -->
                <configOptions>
                   <sourceFolder>swagger</sourceFolder>
                </configOptions>
                <output>target/generated-sources</output>
                <environmentVariables>
                    <!-- change default client library (here until plugin 2.1.5). Doesn't seem to work! -->
                    <library>jersey2</library>
                    <!-- generate all models -->
                    <models></models>
                    <!-- generate all APIs -->
                    <apis></apis>
                    <!-- generate just the supporting files that are Java source code (not project build files) -->
                    <supportingFiles>ApiClient.java,ApiException.java,Configuration.java,JSON.java,Pair.java,StringUtil.java,TypeRef.java,ApiKeyAuth.java,Authentication.java,HttpBasicAuth.java,OAuth.java,OAuthFlow.java</supportingFiles>
                </environmentVariables>
            </configuration>
        </execution>
    </executions>
</plugin>

@fehguy
Copy link
Contributor

fehguy commented Dec 22, 2015

Hi, you are right, the plugin is not capturing this variable. Please see here:

#1749

@jfiala
Copy link
Contributor

jfiala commented Mar 23, 2016

Regarding the buildpath errors in the IDE see #2437 for a quick solution (using build-helper-maven-plugin).

@ePaul
Copy link
Contributor

ePaul commented Mar 23, 2016

I'm usually using the maven-codegen-plugin from swagger-codegen-tooling, which is based on this one, and usually puts the files into the correct directories for compiling as a part of the current project (instead as its own project), at least for the languages included there. Though I'm not sure how much of the difference is due to the different plugin or the different languages.

@tisoft
Copy link

tisoft commented Nov 3, 2016

I have the same problem, that I don't want all the generated garbage, but only the source files. I solved it by adding the maven clean plugin to the generate-sources phase, which just deletes everything I don't need. Maybe this is helpful for someone else. :)

 <build>
        <plugins>
            <plugin>
                <groupId>io.swagger</groupId>
                <artifactId>swagger-codegen-maven-plugin</artifactId>
                <version>2.2.1</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                        <configuration>
                            <inputSpec>${project.basedir}/src/main/swagger/xxx.json</inputSpec>
                            <language>java</language>
                            <invokerPackage>com.hpe.xxx.augmentation.client</invokerPackage>
                            <apiPackage>com.hpe.xxx.augmentation.client.api</apiPackage>
                            <modelPackage>com.hpe.xxx.augmentation.client.dto</modelPackage>
                            <configOptions>
                                <library>jersey2</library>
                                <dateLibrary>java8</dateLibrary>
                            </configOptions>
                            <output>target/generated-sources/swagger</output>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-clean-plugin</artifactId>
                <executions>
                    <execution>
                        <id>clean-additional-generated-files</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>clean</goal>
                        </goals>
                        <configuration>
                            <excludeDefaultDirectories>true</excludeDefaultDirectories>
                            <filesets>
                                <fileset>
                                    <directory>${project.build.directory}/generated-sources/swagger</directory>
                                    <excludes>
                                        <exclude>src/main/java/**</exclude>
                                    </excludes>
                                    <followSymlinks>false</followSymlinks>
                                </fileset>
                            </filesets>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

@batwad
Copy link

batwad commented Nov 22, 2017

FYI I figured out how to get client-only sources generated that works in eclipse here: #2437 (comment)

@jasonCodesAway
Copy link

So close...yet so far away. After a few trying hours, I was unable to figure out how to auto-generate server stubs for any java language (I focused on msf4j). I kept getting unusable package structures generated, like "main.java.io.swagger.api" which contains classes that declared themselves to be packaged at "io.swagger.api.*"...no idea where that extra "main.java" is coming from. I would gladly buy someone a few beers if they'd walk me through going from a swagger json spec to auto-generated java stub code in msf4j via maven. For now, the manual command-line way is at least working for me. I didn't get any closer than this:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.wso2.msf4j</groupId>
        <artifactId>msf4j-service</artifactId>
        <version>2.5.2</version>
        <relativePath>../../msf4j-service/pom.xml</relativePath>
    </parent>
    <groupId>com.foo</groupId>
    <artifactId>state</artifactId>
    <packaging>jar</packaging>
    <name>State Service</name>
    <properties>
        <microservice.mainClass>com.foo.Main</microservice.mainClass>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>io.swagger</groupId>
                <artifactId>swagger-codegen-maven-plugin</artifactId>
                <version>2.2.3</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                        <configuration>
                            <inputSpec>src/main/resources/swagger.json</inputSpec>
                            <language>msf4j</language>
                            <generateSupportingFiles>false</generateSupportingFiles>
                            <modelPackage>com.foo.state</modelPackage>
                            <configOptions>
                                <sourceFolder>swagger</sourceFolder> 
                                <dateLibrary>java8</dateLibrary>
                            </configOptions>
                            <output>target/generated-sources</output>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
            <version>2.9.3</version>
        </dependency>
        <dependency>
            <groupId>com.eclipsesource.jaxrs</groupId>
            <artifactId>swagger-all</artifactId>
            <version>1.5.7</version>
        </dependency>
    </dependencies>
</project>

@michael-simons
Copy link
Contributor

FYI here's my current approach.

Goal Generate the client as the part of a bigger client project and integrate it fully with a standard maven build:

Step: Include Swagger dependencies and all the technology you need as dependencies

<dependencies>
	<!-- Needed for generating a Swagger client for PMS-API -->
	<dependency>
		<groupId>io.swagger</groupId>
		<artifactId>swagger-annotations</artifactId>
		<version>${swagger-annotations.version}</version>
	</dependency>
</dependencies>

Step: Configure the swaggercodegen maven plugin to your needs:

<build>
	<plugins>
		<plugin>
			<groupId>io.swagger</groupId>
			<artifactId>swagger-codegen-maven-plugin</artifactId>
			<version>${swagger-codegen.version}</version>
			<executions>
				<execution>
					<id>generate-swagger-client</id>
					<phase>generate-sources</phase>
					<goals>
						<goal>generate</goal>
					</goals>
					<configuration>
						<inputSpec>${basedir}/src/main/resources/pms-api/spec.json</inputSpec>
						<language>java</language>
						<invokerPackage>${base-package-generated-client}</invokerPackage>
						<apiPackage>${base-package-generated-client}.impl</apiPackage>
						<modelPackage>${base-package-generated-client}.model</modelPackage>
						<library>resttemplate</library>
						<configOptions>
							<dateLibrary>java8</dateLibrary>
						</configOptions>
						<output>${project.build.directory}/generated-sources/swagger-tmp</output>
					</configuration>
				</execution>
			</executions>
		</plugin>
	</plugins>
</build>

Note the temporary output directory: ${project.build.directory}/generated-sources/swagger-tmp.

Step: Move the interesting stuff into the right place:

<!-- Move the stuff we're actually interested in into the right place -->
<plugin>
	<groupId>com.coderplus.maven.plugins</groupId>
	<artifactId>copy-rename-maven-plugin</artifactId>
	<version>1.0.1</version>
	<executions>
		<execution>
			<id>rename-file</id>
			<phase>generate-sources</phase>
			<goals>
				<goal>rename</goal>
			</goals>
			<configuration>
				<sourceFile>${project.build.directory}/generated-sources/swagger-tmp/src/main/java</sourceFile>
				<destinationFile>${project.build.directory}/generated-sources/swagger</destinationFile>
			</configuration>
		</execution>
	</executions>
</plugin>

This moves swagger-tmp/src/main/java into generated-sources/swagger. It was needed to make IDEA and others tick with it. Having the leftovers from the full project did not work.

Step: Delete the rest:

<!-- This execution delelates all the crap generated by swagger which we don't want or need. Only a client
     using a resttemplate is neededn.
     -->
<plugin>
	<artifactId>maven-clean-plugin</artifactId>
	<executions>
		<execution>
			<id>clean-superfluous-swagger-generated-files</id>
			<phase>generate-sources</phase>
			<goals>
				<goal>clean</goal>
			</goals>
			<configuration>
				<excludeDefaultDirectories>true</excludeDefaultDirectories>
				<filesets>
					<fileset>
						<directory>${project.build.directory}/generated-sources/swagger-tmp</directory>
						<followSymlinks>false</followSymlinks>
					</fileset>
				</filesets>
			</configuration>
		</execution>
	</executions>
</plugin>

A colleaque than used the build-helper-maven-plugin for explicitly adding swagger to the generated sources, but that wasn't necessary for me.

TBH: This plugin here works in the sense it is a wrapper for a tool which generates a full Maven and even a full Gradle project. When used as a Maven plugin, my expectations are very different. I would have expected the plugin to do the stuff above for me.

@batwad
Copy link

batwad commented Feb 6, 2018

@michael-simons this is my standard approach to generating client or server models - the trick is to disable all superfluous generations (e.g. docs, tests, supporting files etc.)

I've accepted the fact that I'll have to write the resource interface by hand because there's no way to get the plugin to generate anything remotely useful without jumping through a thousand hoops.

It's also daft I have to use resttemplate just because I want Jackson and not GSON. That should be an option on its own.

And don't get me started on the limitations of datelibrary!

<plugin>
    <groupId>io.swagger</groupId>
    <artifactId>swagger-codegen-maven-plugin</artifactId>
    <version>2.2.3</version>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <inputSpec>${project.basedir}/src/main/resources/swagger/myswagger.json</inputSpec>
                <language>java</language>
                <generateApis>false</generateApis>
                <generateModels>true</generateModels>
                <generateModelDocumentation>false</generateModelDocumentation>
                <generateModelTests>false</generateModelTests>
                <generateSupportingFiles>false</generateSupportingFiles>
                <modelPackage>com.example.client</modelPackage>
                <configOptions>
                    <dateLibrary>java8</dateLibrary>
                    <sourceFolder>swagger</sourceFolder>
                    <library>resttemplate</library>
                </configOptions>
                <output>${project.build.directory}/generated-sources</output>
            </configuration>
        </execution>
    </executions>
</plugin>

@digital-abyss
Copy link

What version of maven are you using?
I think I hit this problem using maven 3.3.9, but seems to do the right thing once I started using maven 3.5.4

@nmaheshwari11
Copy link

Swagger-gen generates code in a single package. Is there any way we can define the package structure according to our requirement.

@ujjawal1152
Copy link

${project.basedir}/src/main/resources/swagger/myswagger.json
com.example.client
${project.build.directory}/generated-sources

Can We pass value of inputSpec,modelPackage and output through command line arguments from maven.

Thanks

@dragetd
Copy link

dragetd commented Apr 15, 2020

I really struggled with this issue for way too many hours. This issue alone contains more useful infos than the documentation.

I have yet to figure out a sensible workflow on how to actually use this plugin in any useful manner. I'd love to have it work 'right away' inside a project without needed to reconfigure and hack several things. :(

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