Skip to content

Commit aad9645

Browse files
authored
fix: oneOfs with enums and strings can not be parsed (#182)
* fix: oneOfs with enums and strings can not be parsed in UnmarshalJSON function, if it's a value of the enum
1 parent 36111f4 commit aad9645

File tree

3 files changed

+86
-9
lines changed

3 files changed

+86
-9
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{{! NOTE: This is a custom STACKIT template which is not present in upsteam to support testing of oneOf models}}
2+
3+
4+
{{! tests only the adjusted cases in the Generator of UnmarshalJSON}}
5+
{{#useOneOfDiscriminatorLookup}}
6+
{{^discriminator}}
7+
// isOneOf
8+
9+
{{#composedSchemas.oneOf}}
10+
{{#-first}}
11+
func Test{{{classname}}}_UnmarshalJSON(t *testing.T) {
12+
type args struct {
13+
src []byte
14+
}
15+
tests := []struct {
16+
name string
17+
args args
18+
wantErr bool
19+
}{
20+
{{/-first}}
21+
{{#allowableValues.values}}
22+
{
23+
name: "success - {{dataType}} {{.}}",
24+
args: args{
25+
src: []byte(`"{{.}}"`),
26+
},
27+
wantErr: false,
28+
},
29+
{{/allowableValues.values}}
30+
{{^allowableValues.values}}{{^isModel}}
31+
{
32+
name: "success - {{dataType}} {{example}}",
33+
args: args{
34+
src: []byte(`"{{example}}"`),
35+
},
36+
wantErr: false,
37+
},
38+
{{/isModel}}{{/allowableValues.values}}
39+
{{#-last}}
40+
}
41+
for _, tt := range tests {
42+
t.Run(tt.name, func(t *testing.T) {
43+
v := &{{{classname}}}{}
44+
if err := v.UnmarshalJSON(tt.args.src); (err != nil) != tt.wantErr {
45+
t.Errorf("UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr)
46+
}
47+
marshalJson, err := v.MarshalJSON()
48+
if err != nil {
49+
t.Fatalf("failed marshalling {{classname}}: %v", err)
50+
}
51+
if string(marshalJson) != string(tt.args.src) {
52+
t.Fatalf("wanted %s, get %s", tt.args.src, marshalJson)
53+
}
54+
})
55+
}
56+
}
57+
{{/-last}}
58+
{{/composedSchemas.oneOf}}
59+
60+
{{/discriminator}}
61+
{{/useOneOfDiscriminatorLookup}}

templates/go/custom/model_test.mustache

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import (
1212

1313
{{#model}}
1414
{{^isEnum}}
15+
{{#oneOf}}
16+
{{#-first}}{{>custom/model_oneof_test}}{{/-first}}
17+
{{/oneOf}}
1518
{{^oneOf}}{{^anyOf}}
1619
{{>custom/model_simple_test}}
1720
{{/anyOf}}{{/oneOf}}

templates/go/model_oneof.mustache

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,21 +54,34 @@ func (dst *{{classname}}) UnmarshalJSON(data []byte) error {
5454
{{/discriminator}}
5555
{{^discriminator}}
5656
match := 0
57-
{{#oneOf}}
57+
{{! BEGIN - Workaround in case oneOf contains enums and strings. The enum value would match with both. }}
58+
{{! This workaround adds a regex check for the string (in case the api spec provides a regex) }}
59+
// Workaround until upstream issue is fixed:
60+
// https://github.com/OpenAPITools/openapi-generator/issues/21751
61+
// Tracking issue on our side: https://jira.schwarz/browse/STACKITSDK-226
62+
{{#composedSchemas.oneOf}}
63+
{{#dataType}}
5864
// try to unmarshal data into {{#lambda.type-to-name}}{{{.}}}{{/lambda.type-to-name}}
59-
err = json.Unmarshal(data, &dst.{{#lambda.type-to-name}}{{{.}}}{{/lambda.type-to-name}})
65+
dst{{classname}}{{-index}} := &{{classname}}{}
66+
err = json.Unmarshal(data, &dst{{classname}}{{-index}}.{{#lambda.type-to-name}}{{{.}}}{{/lambda.type-to-name}})
6067
if err == nil {
61-
json{{{.}}}, _ := json.Marshal(dst.{{#lambda.type-to-name}}{{{.}}}{{/lambda.type-to-name}})
62-
if string(json{{{.}}}) == "{}" { // empty struct
63-
dst.{{#lambda.type-to-name}}{{{.}}}{{/lambda.type-to-name}} = nil
64-
} else {
68+
json{{{.}}}, _ := json.Marshal(&dst{{classname}}{{-index}}.{{#lambda.type-to-name}}{{{.}}}{{/lambda.type-to-name}})
69+
{{#pattern}}
70+
regex := `{{.}}`
71+
regex = regexp.MustCompile("^\\/|\\/$").ReplaceAllString(regex, "$1") // Remove beginning slash and ending slash
72+
regex = regexp.MustCompile("\\\\(.)").ReplaceAllString(regex, "$1") // Remove duplicate escaping char for dots
73+
rawString := regexp.MustCompile(`^"|"$`).ReplaceAllString(*dst{{classname}}{{-index}}.{{#lambda.type-to-name}}{{dataType}}{{/lambda.type-to-name}}, "$1") // Remove quotes
74+
isMatched, _ := regexp.MatchString(regex, rawString)
75+
{{/pattern}}
76+
if string(json{{{.}}}) != "{}" {{#pattern}}&& isMatched {{/pattern}} { // empty struct
77+
dst.{{#lambda.type-to-name}}{{{.}}}{{/lambda.type-to-name}} = dst{{classname}}{{-index}}.{{#lambda.type-to-name}}{{{.}}}{{/lambda.type-to-name}}
6578
match++
6679
}
67-
} else {
68-
dst.{{#lambda.type-to-name}}{{{.}}}{{/lambda.type-to-name}} = nil
6980
}
7081

71-
{{/oneOf}}
82+
{{/dataType}}
83+
{{/composedSchemas.oneOf}}
84+
{{! END - Workaround in case oneOf contains enums and strings. The enum value would match with both. }}
7285
if match > 1 { // more than 1 match
7386
// reset to nil
7487
{{#oneOf}}

0 commit comments

Comments
 (0)