-
Notifications
You must be signed in to change notification settings - Fork 6k
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
[scala] updates for client default values, required attributes #7286
[scala] updates for client default values, required attributes #7286
Conversation
This uses consistent logic for optional types with default values in the scala client. Also, uses Option(default) instead of Some(default) to guard against people defining defaultValue = null. Option(null) becomes None while Some(null) defines a null value explicitly and will break maplike operations.
…but allows current samples to generate
I'm fixing additional issues found with string types and format specified (date, date-time, binary, byte). Will push an update to this PR when I've tested. |
This adds support for better support of type=string and format={date,date-time,binary,byte}. Previously, binary and byte were inconsistently defined as strings rather than byte arrays, while date/date-time were parsing default values into formats that did not match OpenAPI/Swagger 2.0 specifications for full-date and date-time. We may want to consider pulling in json4s-ext to support wider date formats and moving to date=LocalDate and date-time=ZonedDateTime. This will have breaking changes for consumers expecting binary/byte to be strings rather than byte arrays.
@@ -66,7 +78,7 @@ class {{classname}}( | |||
{{#allParams}} * @param {{paramName}} {{description}} {{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}} | |||
{{/allParams}} * @return {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} | |||
*/ | |||
def {{operationId}}({{#allParams}}{{paramName}}: {{#required}}{{dataType}}{{#defaultValue}} = {{{defaultValue}}}{{/defaultValue}}{{/required}}{{^required}}Option[{{dataType}}]{{#defaultValue}} = Option({{{defaultValue}}}){{/defaultValue}}{{^defaultValue}} = None{{/defaultValue}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}){{#returnType}}: Option[{{returnType}}]{{/returnType}} = { | |||
def {{operationId}}({{#allParams}}{{paramName}}: {{#required}}{{dataType}}{{#defaultValue}} = {{#isString}}"{{{defaultValue}}}"{{/isString}}{{^isString}}{{#isByteArray}}"{{/isByteArray}}{{#isDate}}dateFormatter.parse("{{/isDate}}{{#isDateTime}}dateTimeFormatter.parse("{{/isDateTime}}{{{defaultValue}}}{{#isDate}}"){{/isDate}}{{#isDateTime}}"){{/isDateTime}}{{#isByteArray}}".getBytes{{/isByteArray}}{{/isString}}{{/defaultValue}}{{/required}}{{^required}}Option[{{dataType}}]{{#defaultValue}} = Option({{#isString}}"{{{defaultValue}}}"{{/isString}}{{^isString}}{{#isByteArray}}"{{/isByteArray}}{{#isDate}}dateFormatter.parse("{{/isDate}}{{#isDateTime}}dateTimeFormatter.parse("{{/isDateTime}}{{{defaultValue}}}{{#isDate}}"){{/isDate}}{{#isDateTime}}"){{/isDateTime}}{{#isByteArray}}".getBytes{{/isByteArray}}{{/isString}}){{/defaultValue}}{{^defaultValue}} = None{{/defaultValue}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}){{#returnType}}: Option[{{returnType}}]{{/returnType}} = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The templating for defaultValue
cases is a little ugly. We may be able to abstract it out, but it relies on date formatters local to this file and I thought it may be odd to extract.
* @param b3 an octet string (optional, default to DEADBEEF) | ||
* @return Future(Hobby) | ||
*/ | ||
def getHobbiesAsync(s: Option[String] = Option("some string"), i: Option[Integer] = Option(1), l: Option[Long] = Option(2), b: Option[Boolean] = Option(true), f: Option[Float] = Option(0.1), d: Option[Double] = Option(10.005), datetime: Option[Date] = Option(dateTimeFormatter.parse("2018-01-01T08:30:00Z-04:00")), date: Option[Date] = Option(dateFormatter.parse("2018-01-01")), b2: Option[ArrayByte] = Option("c3dhZ2dlciBjb2RlZ2Vu".getBytes), b3: Option[ArrayByte] = Option("DEADBEEF".getBytes)): Future[Hobby] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Notice all optional fields here and their respective default values.
…y conflicting names
Ok. I've pushed my changes and also updated the original PR description. @gmarz would you mind also review this PR and the defaults in the integration tests? |
@jimschubert LGTM! 👍 @wing328 I noticed you added this to the 2.4.0 milestone...do you think 2.3.1 is more appropriate seeing that this is a bug fix? If we think the |
Thanks for reviewing. It's likely that anyone who requires default values has already created a custom template with fixes similar to these. The only code changes are mapping binary and byte to byte arrays. In my experience, binary isn't too common. Byte as a byte array would likely have little negative/unwanted impact. So I'd suggest 2.3.1. For instance, this change won't affect my team's Scala client generation, because I've customized our template to generate a finagle-http client which just relies on the generator class's file structure expectation. We don't use byte arrays, so the code change won't affect us. If it did, it would be a matter of adding A change I was going to make here, but considered too much of a breaking change, was to move the definition of the date formatters to a separate file as a utility object. This way, consumers can change format expectations in the file, and update |
@jimschubert @gmarz if this fix is urgent, I can merge it into 2.3.1. Currently, I've merged a few regression fixes for other generators into 2.3.1 and can include this one as well. Let me know. |
@wing328 without this fix, Scala client doesn't support some default values that it did before, and sync/async methods have inconsistent APIs in the built in templates. I'm not sure it's "urgent", as users could use 2.2.0 with little or no changes to templates. But I also think that because the fix introduced support for all default values, that's a net I positive over any existing code that needs to update string to byte array. The date string is configured to Open API 2.0 required format, which is a slight change from the previous format, which didn't parse Open API 2.0 specified format or ISO 8601 date strings consistently. |
Sorry, can't seem to edit that comment on mobile. To clarify, older versions of the Scala client didn't support default values for type=string with a format defined. A recent pr changed everything to |
OK. I think we need to include it in the patch release. Otherwise, users will need to use 2.2.3 or 2.4.0 later. |
@jimschubert can you please have a look at the following errors when you've time?
|
@wing328 I'll try to take a look a little later. I didn't write the base integration test comparer, so I'll have to dig into that and check it out. What version of Ubuntu and Java was that? I'll also setup a VM and test in the same OS to verify if it's an environment thing. |
@wing328 I'll have to provide a fix for the AbstractIntegrationTest class. The custom assertion does a naive comparison of directory listings:
The javadocs for list state there is no guarantee about ordering of this array.
It should be a relatively quick fix, I'll try to get it pushed by tomorrow evening. |
Per File#list() javadocs: There is no guarantee that the name strings in the resulting array will appear in any specific order; they are not, in particular, guaranteed to appear in alphabetical order. I'm unable to repro directory listing failures on OS X High Sierra or Ubuntu 16.04 under Parallels, so it's not clear to me if listing order is indeterminate per-platform or the behavior is just not defined and up to the platform's installed runtime. Sorting the array of strings prior to comparison should resolve this issue on every platform/runtime.
Script should match options in the integration test class
So, I fixed the issue with directory comparisons… On Travis, this results in a failure to compare file contents (see https://travis-ci.org/swagger-api/swagger-codegen/builds/326216751#L2550 ):
Which shouldn't happen, considering I've added this line to the template, see And this is included in the generated test file, see I've run this on OS X and Ubuntu without issues using Java 8. When I run locally via
I'm not sure if this is a Java 7 issue (I'll investigate this in Ubuntu tomorrow), or a build cache issue. I'm not too familiar with TravisCI or CircleCI and how they handle caching. If we run |
@jimschubert thanks for the update. I'll also take a look tomorrow. |
CI doesn't seem to pick up template changes in integration tests. Disabling scala client integration tests, pending investigation of the issue.
* master: (26 commits) [Scala] Fix async helper methods when body is optional (swagger-api#7274) [Rust] Recommend style based on 'rustfmt' defaults (swagger-api#7335) [Java:vertx] Initialize router in init method and re-use router member to create S… (swagger-api#7234) [Scala] Fix missing json4s import (swagger-api#7271) deploy snapshot version 2.3.1 [Ada] Add Ada support for server code generator swagger-api#6680 (swagger-api#7256) add shijinkui to scala technical committee Generate swagger yaml for go client (swagger-api#7281) use openjdk7 in travis to ensure it works with jdk7 docs(readme): update link to contributing guid (swagger-api#7332) Fix a regression bug that was introduce in a recent commit. Removed the tabs that were causing error in Play Framework (swagger-api#7241) Fix issue swagger-api#7262 with the parameter name in the path. The problem was that camelCase naming was forced only in this part of the code when everywhere else it is configurable. (swagger-api#7313) Java8 fix (swagger-api#7260) update to 2.3.1-SNAPSHOT fix typo, update 2017 to 2018 [Doc] add huawei cloud to companies list swagger-api#7308 (swagger-api#7309) Adding Peatio opensource as reference project (swagger-api#7267) Update README.md (swagger-api#7298) Update README.md (swagger-api#7299) [all] sys props in CodegenConstants ...
@wing328 I've skipped integration tests, since the runner has issues. This should be good. |
@jimschubert I think I might have found one issue with this change while testing a snapshot of 2.3.1. We have the following annotations for one of our responses:
Which produces the following in the spec:
Which in turn use to result in |
@jimschubert I opened #7371 |
PR checklist
./bin/
to update Petstore sample so that CIs can verify the change. (For instance, only need to run./bin/{LANG}-petstore.sh
and./bin/security/{LANG}-petstore.sh
if updating the {LANG} (e.g. php, ruby, python, etc) code generator or {LANG} client's mustache templates). Windows batch files can be found in.\bin\windows\
.3.0.0
branch for changes related to OpenAPI spec 3.0. Default:master
.Description of the PR
cc @clasnake @wing328
PRs #7274 and #7275 have logic around parameter types marked with "required" and their default values. While the fix in #7274 is most likely fine considering body parameters should work the same whether missing from the request or null, the fix in #7275 will break support for default parameter values in the scala client. This appears to be related to a comment about an edge case from a previously merged PR (see #7273 references), which I assume refer to the use of
Some(defaultValue)
rather thanOption(defaultValue)
.This PR fixes edge cases where
defaultValue
may benull
, which would result in a value defined as null (Some(null)
) rather than the intended scala-likeNone
. This is fixed by defaulting usingOption(defaultValue)
becauseOption(null)
results inNone
.This also undoes the workaround merged from #6538, which removed support for parameter default values in the scala client template.
The added integration test includes an optional model property without a default value (
Person.age
), an optional query string parameter without a default value (GET /people?age=???
) and an optional query string parameter with a default value (POST /people?size=???
). Please let me know if there are other conditions we'd like to test against.This includes a fix to the samples, pertaining to a missing import that is also fixed in #7271.
This also adds support for better support of type=string and format={date,date-time,binary,byte}. Previously, binary and byte were inconsistently defined as strings rather than byte arrays, while date/date-time were parsing default values into formats that did not match OpenAPI/Swagger 2.0 specifications for full-date and date-time.
We may want to consider pulling in json4s-ext to support wider date formats and moving to date=LocalDate and date-time=ZonedDateTime.
This will have breaking changes for consumers expecting binary/byte to be strings rather than byte arrays.
Note
If your team requires a workaround similar to that from #6538, I recommend customizing the template locally. This can be done with the following steps:
Where
path/to/scala-client-template
is your final desired location for templates.Then, when invoking swagger-codegen-cli, pass
-t path/to/scala-client-template
and this will use your customized templates.