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

additionalProperties with Boolean value causes NPEs #1318

Closed
ches opened this issue Oct 1, 2015 · 11 comments
Closed

additionalProperties with Boolean value causes NPEs #1318

ches opened this issue Oct 1, 2015 · 11 comments
Milestone

Comments

@ches
Copy link
Contributor

ches commented Oct 1, 2015

I'll come back and provide a more minimal reproduction case, just wanted to file this while it's fresh (it seems fairly trivial to reproduce, and a quick grep shows a lot of code that seems to assume additionalProperties will be a map).

additionalProperties in JSON Schema can be an object or a Boolean. When I use a Boolean value, codegen blows up with an NPE (using rev 253c46a at time of this trace):

$ make gen
Running Swagger code generation
java -jar /Volumes/onner/onner-sdk-ios/vendor/swagger-codegen/modules/swagger-codegen-cli/target/swagger-codegen-cli.jar generate \
                --input-spec /Volumes/onner/onner-sdk-ios/../API/docs/swagger.json \
                --lang objc \
                --config /Volumes/onner/onner-sdk-ios/config.json \
                --output /Volumes/onner/onner-sdk-ios
reading from /Volumes/onner/onner-sdk-ios/../API/docs/swagger.json
[main] WARN io.swagger.util.PropertyDeserializer - no property from null, null, {ENUM=null, TITLE=null, DESCRIPTION=null, DEFAULT=null, PATTERN=null, DESCRIMINATOR=null, MIN_ITEMS=null, MAX_ITEMS=null, MIN_PROPERTIES=null, MAX_PROPERTIES=null, MIN_LENGTH=null, MAX_LENGTH=null, MINIMUM=null, MAXIMUM=null, EXCLUSIVE_MINIMUM=null, EXCLUSIVE_MAXIMUM=null, UNIQUE_ITEMS=null, EXAMPLE=null, TYPE=null, FORMAT=null, READ_ONLY=null, VENDOR_EXTENSIONS={}}
[main] WARN io.swagger.util.PropertyDeserializer - no property from null, null, {ENUM=null, TITLE=null, DESCRIPTION=null, DEFAULT=null, PATTERN=null, DESCRIMINATOR=null, MIN_ITEMS=null, MAX_ITEMS=null, MIN_PROPERTIES=null, MAX_PROPERTIES=null, MIN_LENGTH=null, MAX_LENGTH=null, MINIMUM=null, MAXIMUM=null, EXCLUSIVE_MINIMUM=null, EXCLUSIVE_MAXIMUM=null, UNIQUE_ITEMS=null, EXAMPLE=null, TYPE=null, FORMAT=null, READ_ONLY=null, VENDOR_EXTENSIONS={}}
(was java.lang.NullPointerException) (through reference chain: io.swagger.models.ModelImpl["additionalProperties"]) (through reference chain: io.swagger.models.Swagger["definitions"]->java.util.LinkedHashMap["JsonApi"])
reading from /Volumes/onner/onner-sdk-ios/../API/docs/swagger.json
[main] WARN io.swagger.util.PropertyDeserializer - no property from null, null, {ENUM=null, TITLE=null, DESCRIPTION=null, DEFAULT=null, PATTERN=null, DESCRIMINATOR=null, MIN_ITEMS=null, MAX_ITEMS=null, MIN_PROPERTIES=null, MAX_PROPERTIES=null, MIN_LENGTH=null, MAX_LENGTH=null, MINIMUM=null, MAXIMUM=null, EXCLUSIVE_MINIMUM=null, EXCLUSIVE_MAXIMUM=null, UNIQUE_ITEMS=null, EXAMPLE=null, TYPE=null, FORMAT=null, READ_ONLY=null, VENDOR_EXTENSIONS={}}
[main] WARN io.swagger.util.PropertyDeserializer - no property from null, null, {ENUM=null, TITLE=null, DESCRIPTION=null, DEFAULT=null, PATTERN=null, DESCRIMINATOR=null, MIN_ITEMS=null, MAX_ITEMS=null, MIN_PROPERTIES=null, MAX_PROPERTIES=null, MIN_LENGTH=null, MAX_LENGTH=null, MINIMUM=null, MAXIMUM=null, EXCLUSIVE_MINIMUM=null, EXCLUSIVE_MAXIMUM=null, UNIQUE_ITEMS=null, EXAMPLE=null, TYPE=null, FORMAT=null, READ_ONLY=null, VENDOR_EXTENSIONS={}}
(was java.lang.NullPointerException) (through reference chain: io.swagger.models.ModelImpl["additionalProperties"]) (through reference chain: io.swagger.models.Swagger["definitions"]->java.util.LinkedHashMap["JsonApi"])
Exception in thread "main" java.lang.RuntimeException: missing swagger input or config!
        at io.swagger.codegen.DefaultGenerator.generate(DefaultGenerator.java:63)
        at io.swagger.codegen.cmd.Generate.run(Generate.java:188)
        at io.swagger.codegen.SwaggerCodegen.main(SwaggerCodegen.java:35)
make: *** [gen] Error 1

The offending spec definition in this case is this one:

  # http://jsonapi.org/format/#document-jsonapi-object
  JsonApi:
    description: An object describing the server's implementation
    type: object
    properties:
      version:
        type: string
      meta:
        $ref: '#/definitions/Meta'
    additionalProperties: false

This API conforms to JSON API and derives definitions from the JSON Schema definition of JSON API, which declares additionalProperties: false here. The $ref here is inconsequential—commenting out the additionalProperties line (and others like it in the rest of the spec) avoids the codegen failure and succeeds.

@dolmen
Copy link

dolmen commented Oct 6, 2015

Here is a small test case:

{
  "swagger": "2.0",
  "info": {
    "version": "0.0.1",
    "title": "test of Swagger with boolean additionalProperties in schema definition"
  },
  "paths": {
    "/": {
      "get": {
        "produces": [ "application/json" ],
        "description": "xxx",
        "responses": {
          "200": {
            "schema": { "$ref": "#/definitions/Root" }
          }
        }
      }
    }
  },
  "definitions": {
    "Root": {
      "type": "object",
      "properties": {
        "foo": {
          "type": "string"
        }
      },
      "additionalProperties": false
    }
  }
}
java -jar ~/bin/swagger-codegen-cli.jar generate -i x.json -l html -o html
reading from x.json
[main] WARN io.swagger.util.PropertyDeserializer - no property from null, null, {ENUM=null, TITLE=null, DESCRIPTION=null, DEFAULT=null, PATTERN=null, DESCRIMINATOR=null, MIN_ITEMS=null, MAX_ITEMS=null, MIN_PROPERTIES=null, MAX_PROPERTIES=null, MIN_LENGTH=null, MAX_LENGTH=null, MINIMUM=null, MAXIMUM=null, EXCLUSIVE_MINIMUM=null, EXCLUSIVE_MAXIMUM=null, UNIQUE_ITEMS=null, EXAMPLE=null, TYPE=null, FORMAT=null, READ_ONLY=null, VENDOR_EXTENSIONS={}}
(was java.lang.NullPointerException) (through reference chain: io.swagger.models.ModelImpl["additionalProperties"]) (through reference chain: io.swagger.models.Swagger["definitions"]->java.util.LinkedHashMap["Root"])
reading from x.json
[main] WARN io.swagger.util.PropertyDeserializer - no property from null, null, {ENUM=null, TITLE=null, DESCRIPTION=null, DEFAULT=null, PATTERN=null, DESCRIMINATOR=null, MIN_ITEMS=null, MAX_ITEMS=null, MIN_PROPERTIES=null, MAX_PROPERTIES=null, MIN_LENGTH=null, MAX_LENGTH=null, MINIMUM=null, MAXIMUM=null, EXCLUSIVE_MINIMUM=null, EXCLUSIVE_MAXIMUM=null, UNIQUE_ITEMS=null, EXAMPLE=null, TYPE=null, FORMAT=null, READ_ONLY=null, VENDOR_EXTENSIONS={}}
(was java.lang.NullPointerException) (through reference chain: io.swagger.models.ModelImpl["additionalProperties"]) (through reference chain: io.swagger.models.Swagger["definitions"]->java.util.LinkedHashMap["Root"])
Exception in thread "main" java.lang.RuntimeException: missing swagger input or config!
    at io.swagger.codegen.DefaultGenerator.generate(DefaultGenerator.java:63)
    at io.swagger.codegen.cmd.Generate.run(Generate.java:188)
    at io.swagger.codegen.SwaggerCodegen.main(SwaggerCodegen.java:35)

@dolmen
Copy link

dolmen commented Oct 6, 2015

Related: swagger-api/swagger-core#1437

@dolmen
Copy link

dolmen commented Oct 6, 2015

@ches The definition additionalProperties that matters is not the one in JSON Schema that you linked to but the one in the Swagger spec.

@ches
Copy link
Contributor Author

ches commented Oct 6, 2015

@dolmen I'm aware that Swagger adds a slight semantic override, but in regard to additionalProperties the spec as written says:

The following properties are taken from the JSON Schema definition but their definitions were adjusted to the Swagger Specification. Their definition is the same as the one from JSON Schema, only where the original definition references the JSON Schema definition, the Schema Object definition is used instead.

• items
• allOf
• properties
• additionalProperties

My added emphasis is to stress that I'm pretty sure there is a conscious decision not to break backward compatibility implied there.

@dolmen
Copy link

dolmen commented Oct 6, 2015

@ches There is no "backward compatibility" involved here. This is just about maintaining the similar meaning, for consistency (not compatibility) with JSON Schema.

@ches
Copy link
Contributor Author

ches commented Oct 6, 2015

@dolmen Is that an "official" stance on JSON Schema compatibility?

Either way, I hope we can agree that the written spec and the implementation are currently inconsistent.

@fehguy
Copy link
Contributor

fehguy commented Oct 7, 2015

@ches there is an official stance on json-schema. Swagger supports a subset of JSON schema draft-4 which should be clearly documented in the swagger-spec.

The spec is the source of truth and projects may not implement all aspects of the spec 100%. If we have unimplemented features, we like to get community confirmation and feedback on the importance of the feature

@ches
Copy link
Contributor Author

ches commented Oct 7, 2015

Thanks @fehguy. I take

the Schema Object which is a subset of JSON Schema Draft 4

and my other above quotation to mean that for the subset that the Schema Object encompasses, the types should (eventually) be completely conformant to JSON Schema.

But I misread @dolmen's link above when I said that there is an inconsistency—the Swagger schema does include boolean in the anyOf for additionalProperties. So it's just the implementation in swagger-codegen and possibly elsewhere that isn't supporting it yet, and thus this issue. My apologies for the oversight and the ensuing diversion 😄

@webron
Copy link
Contributor

webron commented Oct 7, 2015

Sorry for taking a while to reply.

So we definitely need to make this clearer in the spec (and please feel free to open a ticket on it once we clarify it). The spec itself is a bit incomplete with regard to how additionalProperties is intended to work.

Unlike what's stated, additionalProperties can only take an object value. An empty object value is equivalent to setting the value to true. Now, the reason why false is not needed is because... that's the default value. Yes, this is different than how JSON Schema works, but that's our assumption all along (and again, will be clarified in the spec). We can go into the 'why' but that's what it is, and I do apologize for the confusion.

Given that, you should not require having to set additionalProperties: false at all and would not encounter the issue raised in this ticket.

@dolmen
Copy link

dolmen commented Oct 9, 2015

@webron Thanks for the clarification. The JSON schema for Swagger must be updated to match your definition to disallow "additionalProperties": true. I'll make a PR that add an enum.

About the codegen issue, note that codegen does not accept either an empty object ({}).
In JSON Schema, {} means anything is accepted.

Here is a test case where html generation fails:

{
  "swagger": "2.0",
  "info": {
    "version": "0.0.1",
    "title": "test of Swagger of boolean additionalProperties"
  },
  "paths": {
    "/": {
      "get": {
        "produces": [ "application/json" ],
        "description": "xxx",
        "responses": {
          "200": {
            "schema": { "$ref": "#/definitions/Root" }
          }
        }
      }
    }
  },
  "definitions": {
    "Root": {
      "type": "object",
      "properties": {
        "foo": {
          "type": "string"
        }
      },
      "additionalProperties": {}
    }
  }
}

dolmen added a commit to dolmen/swagger-spec that referenced this issue Oct 9, 2015
Following clarification of 'additionalProperties' for a schema by
@webron:
swagger-api/swagger-codegen#1318 (comment)

We now accept only `false` or a schema for `additionalProperties`.
`false` is the new default for `additionalProperties` (instead of `{}`
which means "anything is accepted" in JSON Schema).
@dolmen
Copy link

dolmen commented Oct 9, 2015

I wrote:

The JSON schema for Swagger must be updated to match your definition to disallow "additionalProperties": true. I'll make a PR that add an enum.

I just submitted OAI/OpenAPI-Specification#477

dolmen added a commit to dolmen/swagger-spec that referenced this issue Oct 16, 2015
Following clarification of 'additionalProperties' for a schema by
@webron:
swagger-api/swagger-codegen#1318 (comment)

We now longer accept boolean for 'additionalProperties':
additionalProperties can only be disallowed (the default, when
additionalProperties is not set) or of a fixed model (the schema object
given as the value).
@wing328 wing328 closed this as completed Oct 21, 2015
@fehguy fehguy modified the milestone: v2.1.4 Oct 26, 2015
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

5 participants