[core] fix: SIMPLIFY_ANYOF_STRING_AND_ENUM_STRING for OpenAPI 3.1 specs
Fixes #25289
Related: #25288 fixes the same instanceof problem for SIMPLIFY_BOOLEAN_ENUM.
SIMPLIFY_ANYOF_STRING_AND_ENUM_STRING used instanceof StringSchema to find the string and enum branches of an anyOf. In 3.1 specs the parser creates JsonSchema instances, so the rule never applied and open enums such as anyOf: [{type: string}, {type: string, enum: [a, b]}] were not simplified.
Changes:
- New
ModelUtils.isSingleTypeSchema(schema, type): true when the schema has exactly the given type (typein 3.0, a single entry intypesin 3.1). The same helper is added in #25288 and #25290, identical and in the same place, so the two PRs merge cleanly in either order. processSimplifyAnyOfStringAndEnumStringchecks both branches withisSingleTypeSchema(s, "string")instead ofinstanceof StringSchema, and usesisEnum.- The rule now simplifies only when exactly one branch has an enum. If both branches are string enums, the
anyOfis left unchanged. Before, it collapsed to the first branch and dropped the values of the second. This also changes 3.0, but only whenSIMPLIFY_ONEOF_ANYOF_ENUMis disabled, since that rule runs first and merges both enums by default. - The unneeded
(StringSchema)casts are removed (getEnum()is onSchema).
Not covered:
- 3.1 type arrays such as
["string", "null"]are still not simplified. Strippingnullfirst is a job forNORMALIZE_31SPEC. formatis not considered. In 3.0 this is a small change: a string branch with aformatsuch asuuidordate(parsed as aStringSchemasubclass other thanStringSchemaitself) used to be skipped and is now treated like any other string branch, the same as in 3.1. The rule is opt-in and no sample enables it.- In 3.1,
SIMPLIFY_ONEOF_ANYOF_ENUMdoes not merge ananyOfof two string enums yet (EnumUtilscompares againstgetType(), which is null forJsonSchema). With this change thatanyOfis kept as is rather than losing values. - The rule stays opt-in. No default changes.
Testing:
- New
OpenAPINormalizerTest#testOpenAPINormalizerSimplifyAnyOfStringAndEnumString31Specwith a new specsrc/test/resources/3_1/simplifyAnyOfStringAndEnumString_test.yaml. It covers a$refenum branch, an inline enum branch, and ananyOfof two non-enum strings, which must stay unchanged. The test fails on master and passes with this change. - New
OpenAPINormalizerTest#testOpenAPINormalizerSimplifyAnyOfStringAndEnumStringKeepsTwoEnums31Spec: ananyOfof two string enums must keep both branches. It fails without the both-enum guard. - New
ModelUtilsTest#testIsSingleTypeSchema. OpenAPINormalizerTest(74 tests) and thecppboostbeasttests (whose normalizer overrides this method) pass.- No sample config enables this rule, so sample output is unchanged. All configs were regenerated with no changes.
PR checklist
- Read the contribution guidelines.
- Run the following to build the project and update samples:
(For Windows users, please run the script in WSL)./mvnw clean package || exit ./bin/generate-samples.sh ./bin/configs/*.yaml || exit ./bin/utils/export_docs_generators.sh || exit
Commit all changed files.
This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
These must match the expectations made by your contribution.
You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example./bin/generate-samples.sh bin/configs/java*.
IMPORTANT: Do NOT purge/delete any folders/files (e.g. tests) when regenerating the samples as manually written tests may be removed.
Regenerated all configs with./bin/generate-samples.sh ./bin/configs/*.yaml. Nothing changed.export_docs_generators.shwas not needed (no generator options changed). - If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.
cc @frol @farcaller @richardwhiuk @paladinzh @jacob-pro @dsteeley
Summary by cubic
Fixes the SIMPLIFY_ANYOF_STRING_AND_ENUM_STRING normalizer rule so it also simplifies open string enums in OpenAPI 3.1 specs.
The rule detected string/enum branches with instanceof StringSchema, but the 3.1 parser builds JsonSchema instances, so the rule silently never ran on 3.1 specs. A new helper, ModelUtils.isSingleTypeSchema, accepts a JsonSchema whose types is exactly ["string"] while keeping the 3.0 StringSchema check unchanged, and the now-unneeded (StringSchema) casts were removed since getEnum() lives on Schema. The rule now only simplifies when exactly one branch has an enum; an anyOf of two string enums stays intact instead of collapsing to the first branch and dropping values. The rule stays opt-in.
Known limitations:
- 3.1 type arrays such as
["string", "null"]remain unsimplified; strippingnullis left toNORMALIZE_31SPEC. - 3.0 schemas with a
formatstill don't match (the parser creates a non-StringSchemasubclass), and the 3.1 check ignoresformat.