question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Serialisation of OpenAPI is not stable

See original GitHub issue

moved from swagger-api/swagger-parser/issues/728 reported by @jmini

We have observed a strange behaviour with the Serialisation of an OpenAPI instance with Yaml.mapper().writeValueAsString(openAPI) produces different results:

--- a/src/main/resources/openapi.yaml
+++ b/src/main/resources/openapi.yaml
@@ -97,11 +97,11 @@ paths:
           type: array
           items:
             type: string
-            default: available
             enum:
             - available
             - pending
             - sold
+            default: available
       responses:
         200:
           description: successful operation
@@ -678,20 +678,20 @@ paths:
           type: array
           items:
             type: string
-            default: $
             enum:
             - '>'
             - $
+            default: $
       - name: enum_header_string
         in: header
         description: Header parameter enum test (string)
         schema:
           type: string
-          default: -efg
           enum:
           - _abc
           - -efg
           - (xyz)
+          default: -efg
       - name: enum_query_string_array
         in: query
         description: Query parameter enum test (string array)
@@ -701,20 +701,20 @@ paths:
           type: array
           items:
             type: string
-            default: $
             enum:
             - '>'
             - $
+            default: $
       - name: enum_query_string
         in: query
         description: Query parameter enum test (string)
         schema:
           type: string
-          default: -efg
           enum:
           - _abc
           - -efg
           - (xyz)
+          default: -efg
       - name: enum_query_integer
         in: query
         description: Query parameter enum test (double)
@@ -743,18 +743,18 @@ paths:
                   description: Form parameter enum test (string array)
                   items:
                     type: string
-                    default: $
                     enum:
                     - '>'
                     - $
+                    default: $
                 enum_form_string:
                   type: string
                   description: Form parameter enum test (string)
-                  default: -efg
                   enum:
                   - _abc
                   - -efg
                   - (xyz)
+                  default: -efg
       responses:
         400:
           description: Invalid request
@@ -1214,11 +1214,11 @@ components:
         name: Name
     EnumClass:
       type: string
-      default: -efg
       enum:
       - _abc
       - -efg
       - (xyz)
+      default: -efg
     List:
       type: object
       properties:

From a semantic point of view, the content is the same. But my expectation is to get the content always serialised the same way.

I did not understood what is producing the difference. Maybe it depends from the JVM.

In my opinion io.swagger.v3.core.jackson.SchemaSerializer could and should be improved. It seems to me that the defaultSerializer is not working as expected.

I am open for suggestions.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:6 (1 by maintainers)

github_iconTop GitHub Comments

1reaction
masc3dcommented, Jun 19, 2019

I think a solution for stable serialization should be provided in the core.

as long as the solution is not alpha sorting @jmini.

model structure / order is important and can’t just be discarded. there has to be a better way.

1reaction
jminicommented, Jun 18, 2018

Work around until this is solved:

I am using MapperFeature.SORT_PROPERTIES_ALPHABETICALLY feature like this:

 Yaml.mapper()
    .configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
    .writeValueAsString(openAPI);

And because this is not suitable for the OpenAPI instance (the root object) itself, an OpenAPISerializer is registered (to force order for the OpenAPI serialization)

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

import io.swagger.v3.oas.models.OpenAPI;

import java.io.IOException;
import java.util.Map.Entry;

public class OpenAPISerializer extends JsonSerializer<OpenAPI> {

    @Override
    public void serialize(OpenAPI value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (value != null) {
            gen.writeStartObject();
            gen.writeStringField("openapi", value.getOpenapi());
            if(value.getInfo() != null) {
                gen.writeObjectField("info", value.getInfo());
            }
            if(value.getExternalDocs() != null) {
                gen.writeObjectField("externalDocs", value.getExternalDocs());
            }
            if(value.getServers() != null) {
                gen.writeObjectField("servers", value.getServers());
            }
            if(value.getSecurity() != null) {
                gen.writeObjectField("security", value.getSecurity());
            }
            if(value.getTags() != null) {
                gen.writeObjectField("tags", value.getTags());
            }
            if(value.getPaths() != null) {
                gen.writeObjectField("paths", value.getPaths());
            }
            if(value.getComponents() != null) {
                gen.writeObjectField("components", value.getComponents());
            }
            if(value.getExtensions() != null) {
                for (Entry<String, Object> e : value.getExtensions().entrySet()) {
                    gen.writeObjectField(e.getKey(), e.getValue());
                }
            }
            gen.writeEndObject();
        }
    }
}

Like this:

SimpleModule module = new SimpleModule("OpenAPIModule");
module.addSerializer(OpenAPI.class, new OpenAPISerializer());
   
 Yaml.mapper()
    .registerModule(module)
    .configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
    .writeValueAsString(openAPI);

I think a solution for stable serialization should be provided in the core.

Any feedback?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Generic object names not being serialized when using ...
In this case it is a generic map instead of a "json" named object. Is there something I am doing wrong in the...
Read more >
Parameter Serialization - Swagger
Serialization means translating data structures or object state into a format that can be transmitted and reconstructed later. OpenAPI 3.0 supports arrays ...
Read more >
What's the Difference Between OpenAPI Types 2.0, 3.0, and ...
A deep look into different OpenAPI versions starting from 2.0 to the latest release candidate.
Read more >
Schema generation rules · GitBook - Goswagger.Io
Go-swagger models are the go data structures used for serialization and ... anyOf , oneOf and not constructs are not supported (this is...
Read more >
OpenAPI — flask-rest-api 0.17.0 documentation - Read the Docs
Schemas passed in Blueprint.arguments to deserialize arguments are parsed ... It comes in handy if an OpenAPI feature is not supported, but it...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found