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 generation-result is not deterministic #47

Closed
ahoehma opened this issue May 4, 2020 · 7 comments
Closed

The generation-result is not deterministic #47

ahoehma opened this issue May 4, 2020 · 7 comments

Comments

@ahoehma
Copy link

ahoehma commented May 4, 2020

Describe the bug
I have a controller-class.
I'm able to generate json and yaml.
But every time I run the plugin the result looks different to the prev. one.
This is not so helpfull because I put the result into my git-repo.

<plugin>
        <groupId>io.swagger.core.v3</groupId>
        <artifactId>swagger-maven-plugin</artifactId>
        <version>${swagger-maven-plugin.version}</version>
        <configuration>
          <outputPath>${basedir}/src/openapi/</outputPath>
          <outputFileName>cc-${api.version}</outputFileName>
          <outputFormat>JSONANDYAML</outputFormat>
          <prettyPrint>TRUE</prettyPrint>
          <attachSwaggerArtifact>true</attachSwaggerArtifact>
          <resourceClasses>
            <resourceClasse>com.siemens.spice.cc.rest.service.ConfigurationController</resourceClasse>
          </resourceClasses>
        </configuration>
        <executions>
          <execution>
            <phase>compile</phase>
            <goals>
              <goal>resolve</goal>
            </goals>
          </execution>
        </executions>
      </plugin>

To Reproduce
Simply run the generation multiple time without any change.

Expected behavior
The generated json/yaml must create always the same output.

I tried to "fix" this behavior in io.openapitools.swagger.GenerateMojo.execute()

OpenAPI swagger = reader.read(reflectiveScanner.classes());

// XXX .... try to bring all the props in a "stable" order ...
swagger.paths(sortPaths(swagger.getPaths()));
swagger.components(sortComponents(swagger.getComponents()));

...

private Components sortComponents(Components components) {
        if (components==null)
            return null;
        Components r = new Components();
        r.setSchemas(sort(components.getSchemas()));
        return r;
    }

    private io.swagger.v3.oas.models.Paths sortPaths(io.swagger.v3.oas.models.Paths paths) {
        if (paths==null)
            return null;
        io.swagger.v3.oas.models.Paths r = new io.swagger.v3.oas.models.Paths();
        r.putAll(sort(paths));
        return r;
    }

    private <K extends Comparable<K>, V> Map<K, V> sort(Map<K, V> map) {
        return map
                .entrySet()
                .stream()
                .sorted(Map.Entry.comparingByKey())
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    }
``´


But I'm not sure if this is the right direction to go :)
@langecode
Copy link
Member

I am not sure whether the plugin is actually behaving differently than the Swagger framework itself. I mean we could add a sorting, as you suggest, but I am thinking whether this would more correctly be solved in Swagger itself as we are merely wrapping it.

@wanno-drijfhout
Copy link
Contributor

This problem seems to be reoccurring quite often in the Swagger framework itself. There are many open issues about this, even from 2017:

swagger-api/swagger-core#2775
swagger-api/swagger-core#2828
swagger-api/swagger-core#3266
swagger-api/swagger-core#2400

What is the best way to solve this matter both properly and swiftly you reckon, @langecode ? How can I help?

@langecode
Copy link
Member

Well, if there is that many open issued with Swagger Code it seems not very high priority and I do acknowledge it can be a problem if you want to do a simple diff between outputs (we actually did do a diff tool for OpenAPI specifications that does it semantically - however I do not think we ported that to OpenAPI 3 yet: https://github.com/openapi-tools/open-api-diff).

If it has value to you I think it would be ok to include a sorting option to the plugin as suggested by @ahoehma - I am not working much with Java these days so it is a little hard to find the time to implement it - but feel free to do a PR and I shall find the time to look through that.

@hiddewie
Copy link
Contributor

hiddewie commented Jul 1, 2020

@wanno-drijfhout @langecode @ahoehma We generated a pull request for this issue. This causes blocking problems when adopting this plugin.

@wanno-drijfhout
Copy link
Contributor

wanno-drijfhout commented Jul 3, 2020

@langecode I fear updating to the new version doesn't lead to a deterministic or sorted output. @hiddewie found a bug in the refactoring and created PR #50 .

@ahoehma
Copy link
Author

ahoehma commented Aug 10, 2020

Feedback ... now I'm using 2.1.4 and I still have some random jumps of paths in the output.json/yaml.

<plugin>
        <groupId>io.openapitools.swagger</groupId>
        <artifactId>swagger-maven-plugin</artifactId>
        <version>${swagger-maven-plugin.version}</version>
        <configuration>
          <outputDirectory>${basedir}/src/openapi/</outputDirectory>
          <outputFormats>JSON,YAML</outputFormats>
          <prettyPrint>true</prettyPrint>
          <attachSwaggerArtifact>true</attachSwaggerArtifact>
          <swaggerConfig>
            <info>
              <title>SPICE Configuration Service API</title>
              <license>
                <name>The Siemens Inner Source License - 1.1</name>
                <url>https://code.siemens.com/ebconf/spice-configuration-cluster/-/blob/develop/LICENSE</url>
              </license>
              <description></description>
              <version>${api.version}</version>
            </info>
          </swaggerConfig>
        </configuration>
        <executions>
          <execution>
            <id>cc-configuration</id>
            <phase>process-classes</phase>
            <goals>
              <goal>generate</goal>
            </goals>
            <configuration>
              <resourcePackages>
                <resourcePackage>com.siemens.spice.cc.rest.service.configuration</resourcePackage>
              </resourcePackages>
              <outputFilename>cc-${api.version}-configuration</outputFilename>
            </configuration>
          </execution>
          <execution>
            <id>cc-settings</id>
            <phase>process-classes</phase>
            <goals>
              <goal>generate</goal>
            </goals>
            <configuration>
              <resourcePackages>
                <resourcePackage>com.siemens.spice.cc.rest.service.settings</resourcePackage>
              </resourcePackages>
              <outputFilename>cc-${api.version}-settings</outputFilename>
            </configuration>
          </execution>
          <execution>
            <id>cc-products</id>
            <phase>process-classes</phase>
            <goals>
              <goal>generate</goal>
            </goals>
            <configuration>
              <resourcePackages>
                <resourcePackage>com.siemens.spice.cc.rest.service.products</resourcePackage>
              </resourcePackages>
              <outputFilename>cc-${api.version}-products</outputFilename>
            </configuration>
          </execution>
          <execution>
            <id>cc-brain</id>
            <phase>process-classes</phase>
            <goals>
              <goal>generate</goal>
            </goals>
            <configuration>
              <resourcePackages>
                <resourcePackage>com.siemens.spice.cc.rest.service.brain</resourcePackage>
              </resourcePackages>
              <outputFilename>cc-${api.version}-brain</outputFilename>
            </configuration>
          </execution>
          <execution>
            <id>cc-history</id>
            <phase>process-classes</phase>
            <goals>
              <goal>generate</goal>
            </goals>
            <configuration>
              <resourcePackages>
                <resourcePackage>com.siemens.spice.cc.rest.service.history</resourcePackage>
              </resourcePackages>
              <outputFilename>cc-${api.version}-history</outputFilename>
            </configuration>
          </execution>
        </executions>
        <dependencies>
          <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>runtime</scope>
          </dependency>
        </dependencies>
      </plugin>

@hiddewie
Copy link
Contributor

@ahoehma There seem to be more things that need to be sorted, e.g. #50 (comment). The current solution is a workaround, and should be solved in swagger-core). PRs and issues have also been referenced opened there.

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

No branches or pull requests

4 participants