Skip to content

Commit aa7aba8

Browse files
committed
Fix Golang pattern validation with regex fails on commas #20079
1 parent ff0fe26 commit aa7aba8

File tree

88 files changed

+8104
-39
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+8104
-39
lines changed

modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenModel.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ public class CodegenModel implements IJsonSchemaValidationProperties {
251251
private String minimum;
252252
private String maximum;
253253
private String pattern;
254+
private String originalPattern;
254255
private Number multipleOf;
255256
private CodegenProperty items;
256257
private CodegenProperty additionalProperties;
@@ -363,7 +364,6 @@ public String getDiscriminatorName() {
363364
return discriminator == null ? null : discriminator.getPropertyName();
364365
}
365366

366-
367367
@Override
368368
public String getPattern() {
369369
return pattern;
@@ -374,6 +374,16 @@ public void setPattern(String pattern) {
374374
this.pattern = pattern;
375375
}
376376

377+
@Override
378+
public String getOriginalPattern() {
379+
return originalPattern;
380+
}
381+
382+
@Override
383+
public void setOriginalPattern(String originalPattern) {
384+
this.originalPattern = originalPattern;
385+
}
386+
377387
@Override
378388
public String getMaximum() {
379389
return maximum;
@@ -966,6 +976,7 @@ public boolean equals(Object o) {
966976
Objects.equals(getMinimum(), that.getMinimum()) &&
967977
Objects.equals(getMaximum(), that.getMaximum()) &&
968978
Objects.equals(getPattern(), that.getPattern()) &&
979+
Objects.equals(getOriginalPattern(), that.getOriginalPattern()) &&
969980
Objects.equals(getItems(), that.getItems()) &&
970981
Objects.equals(getAdditionalProperties(), that.getAdditionalProperties()) &&
971982
Objects.equals(getIsModel(), that.getIsModel()) &&
@@ -986,7 +997,7 @@ public int hashCode() {
986997
hasChildren, isMap, isOptional, isDeprecated, hasReadOnly, hasOnlyReadOnly, getExternalDocumentation(), getVendorExtensions(),
987998
getAdditionalPropertiesType(), getMaxProperties(), getMinProperties(), getUniqueItems(), getMaxItems(),
988999
getMinItems(), getMaxLength(), getMinLength(), getExclusiveMinimum(), getExclusiveMaximum(), getMinimum(),
989-
getMaximum(), getPattern(), getMultipleOf(), getItems(), getAdditionalProperties(), getIsModel(),
1000+
getMaximum(), getPattern(), getOriginalPattern(), getMultipleOf(), getItems(), getAdditionalProperties(), getIsModel(),
9901001
getAdditionalPropertiesIsAnyType(), hasDiscriminatorWithNonEmptyMapping,
9911002
isAnyType, getComposedSchemas(), hasMultipleTypes, isDecimal, isUuid, isUri, requiredVarsMap, ref,
9921003
uniqueItemsBoolean, schemaIsFromAdditionalProperties, isBooleanSchemaTrue, isBooleanSchemaFalse,
@@ -1079,6 +1090,7 @@ public String toString() {
10791090
sb.append(", minimum='").append(minimum).append('\'');
10801091
sb.append(", maximum='").append(maximum).append('\'');
10811092
sb.append(", pattern='").append(pattern).append('\'');
1093+
sb.append(", originalPattern='").append(originalPattern).append('\'');
10821094
sb.append(", multipleOf='").append(multipleOf).append('\'');
10831095
sb.append(", items='").append(items).append('\'');
10841096
sb.append(", additionalProperties='").append(additionalProperties).append('\'');

modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenParameter.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ public class CodegenParameter implements IJsonSchemaValidationProperties {
108108
* See <a href="https://web.archive.org/web/20240502205731/https://json-schema.org/draft/2020-12/json-schema-validation#name-pattern">JSON Schema Validation Spec, Section 6.3.3</a>
109109
*/
110110
public String pattern;
111+
112+
/** Original pattern validation for strings, kept unchanged from OpenAPI schema */
113+
public String originalPattern;
114+
111115
/**
112116
* See <a href="https://web.archive.org/web/20240502205731/https://json-schema.org/draft/2020-12/json-schema-validation#name-maxitems">JSON Schema Validation Spec, Section 6.4.1</a>
113117
*/
@@ -173,6 +177,7 @@ public CodegenParameter copy() {
173177
output.maxLength = this.maxLength;
174178
output.minLength = this.minLength;
175179
output.pattern = this.pattern;
180+
output.originalPattern = this.originalPattern;
176181
output.maxItems = this.maxItems;
177182
output.minItems = this.minItems;
178183
output.uniqueItems = this.uniqueItems;
@@ -291,7 +296,7 @@ public int hashCode() {
291296
items, mostInnerItems, additionalProperties, vars, requiredVars, vendorExtensions, hasValidation,
292297
getMaxProperties(), getMinProperties(), isNullable, isDeprecated, required, getMaximum(),
293298
getExclusiveMaximum(), getMinimum(), getExclusiveMinimum(), getMaxLength(), getMinLength(),
294-
getPattern(), getMaxItems(), getMinItems(), getUniqueItems(), contentType, multipleOf, isNull,isVoid,
299+
getPattern(), getOriginalPattern(), getMaxItems(), getMinItems(), getUniqueItems(), contentType, multipleOf, isNull,isVoid,
295300
additionalPropertiesIsAnyType, hasVars, hasRequired, isShort, isUnboundedInteger,
296301
hasDiscriminatorWithNonEmptyMapping, composedSchemas, hasMultipleTypes, schema, content,
297302
requiredVarsMap, ref, uniqueItemsBoolean, schemaIsFromAdditionalProperties,
@@ -398,6 +403,7 @@ public boolean equals(Object o) {
398403
Objects.equals(getMaxLength(), that.getMaxLength()) &&
399404
Objects.equals(getMinLength(), that.getMinLength()) &&
400405
Objects.equals(getPattern(), that.getPattern()) &&
406+
Objects.equals(getOriginalPattern(), that.getOriginalPattern()) &&
401407
Objects.equals(getMaxItems(), that.getMaxItems()) &&
402408
Objects.equals(getMinItems(), that.getMinItems()) &&
403409
Objects.equals(contentType, that.contentType) &&
@@ -496,6 +502,7 @@ public String toString() {
496502
sb.append(", maxLength=").append(maxLength);
497503
sb.append(", minLength=").append(minLength);
498504
sb.append(", pattern='").append(pattern).append('\'');
505+
sb.append(", originalPattern='").append(originalPattern).append('\'');
499506
sb.append(", maxItems=").append(maxItems);
500507
sb.append(", minItems=").append(minItems);
501508
sb.append(", uniqueItems=").append(uniqueItems);
@@ -584,6 +591,16 @@ public void setPattern(String pattern) {
584591
this.pattern = pattern;
585592
}
586593

594+
@Override
595+
public String getOriginalPattern() {
596+
return originalPattern;
597+
}
598+
599+
@Override
600+
public void setOriginalPattern(String originalPattern) {
601+
this.originalPattern = originalPattern;
602+
}
603+
587604
@Override
588605
public String getMaximum() {
589606
return maximum;

modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenProperty.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ public class CodegenProperty implements Cloneable, IJsonSchemaValidationProperti
9898
* pattern validation for strings, see http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.2.3
9999
*/
100100
public String pattern;
101+
102+
/** Original pattern validation for strings, kept unchanged from OpenAPI schema */
103+
public String originalPattern;
104+
101105
/**
102106
* A free-form property to include an example of an instance for this schema.
103107
*/
@@ -382,6 +386,16 @@ public void setPattern(String pattern) {
382386
this.pattern = pattern;
383387
}
384388

389+
@Override
390+
public String getOriginalPattern() {
391+
return originalPattern;
392+
}
393+
394+
@Override
395+
public void setOriginalPattern(String originalPattern) {
396+
this.originalPattern = originalPattern;
397+
}
398+
385399
@Override
386400
public String getMinimum() {
387401
return minimum;
@@ -986,6 +1000,7 @@ public String toString() {
9861000
sb.append(", maxLength=").append(maxLength);
9871001
sb.append(", minLength=").append(minLength);
9881002
sb.append(", pattern='").append(pattern).append('\'');
1003+
sb.append(", originalPattern='").append(originalPattern).append('\'');
9891004
sb.append(", example='").append(example).append('\'');
9901005
sb.append(", jsonSchema='").append(jsonSchema).append('\'');
9911006
sb.append(", minimum='").append(minimum).append('\'');
@@ -1175,6 +1190,7 @@ public boolean equals(Object o) {
11751190
Objects.equals(maxLength, that.maxLength) &&
11761191
Objects.equals(minLength, that.minLength) &&
11771192
Objects.equals(pattern, that.pattern) &&
1193+
Objects.equals(originalPattern, that.originalPattern) &&
11781194
Objects.equals(example, that.example) &&
11791195
Objects.equals(jsonSchema, that.jsonSchema) &&
11801196
Objects.equals(minimum, that.minimum) &&
@@ -1206,7 +1222,7 @@ public int hashCode() {
12061222
return Objects.hash(openApiType, baseName, complexType, getter, setter, description,
12071223
dataType, datatypeWithEnum, dataFormat, name, min, max, defaultValue,
12081224
defaultValueWithParam, baseType, containerType, containerTypeMapped, title, unescapedDescription,
1209-
maxLength, minLength, pattern, example, jsonSchema, minimum, maximum,
1225+
maxLength, minLength, pattern, originalPattern, example, jsonSchema, minimum, maximum,
12101226
exclusiveMinimum, exclusiveMaximum, required, deprecated,
12111227
hasMoreNonReadOnly, isPrimitiveType, isModel, isContainer, isString, isNumeric,
12121228
isInteger, isLong, isNumber, isFloat, isDouble, isDecimal, isByteArray, isBinary, isFile,

modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenResponse.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ public class CodegenResponse implements IJsonSchemaValidationProperties {
8686
private String minimum;
8787
private String maximum;
8888
public String pattern;
89+
public String originalPattern;
8990
public Number multipleOf;
9091
public CodegenProperty items;
9192
public CodegenProperty additionalProperties;
@@ -113,7 +114,7 @@ public int hashCode() {
113114
isMap, isOptional, isArray, isBinary, isFile, schema, jsonSchema, vendorExtensions, items, additionalProperties,
114115
vars, requiredVars, isNull, isVoid, hasValidation, isShort, isUnboundedInteger,
115116
getMaxProperties(), getMinProperties(), uniqueItems, getMaxItems(), getMinItems(), getMaxLength(),
116-
getMinLength(), exclusiveMinimum, exclusiveMaximum, getMinimum(), getMaximum(), getPattern(),
117+
getMinLength(), exclusiveMinimum, exclusiveMaximum, getMinimum(), getMaximum(), getPattern(), getOriginalPattern(),
117118
is1xx, is2xx, is3xx, is4xx, is5xx, additionalPropertiesIsAnyType, hasVars, hasRequired,
118119
hasDiscriminatorWithNonEmptyMapping, composedSchemas, hasMultipleTypes, responseHeaders, content,
119120
requiredVarsMap, ref, uniqueItemsBoolean, schemaIsFromAdditionalProperties);
@@ -200,6 +201,7 @@ public boolean equals(Object o) {
200201
Objects.equals(getMinimum(), that.getMinimum()) &&
201202
Objects.equals(getMaximum(), that.getMaximum()) &&
202203
Objects.equals(getPattern(), that.getPattern()) &&
204+
Objects.equals(getOriginalPattern(), that.getOriginalPattern()) &&
203205
Objects.equals(getMultipleOf(), that.getMultipleOf());
204206

205207
}
@@ -264,6 +266,16 @@ public void setPattern(String pattern) {
264266
this.pattern = pattern;
265267
}
266268

269+
@Override
270+
public String getOriginalPattern() {
271+
return originalPattern;
272+
}
273+
274+
@Override
275+
public void setOriginalPattern(String originalPattern) {
276+
this.originalPattern = originalPattern;
277+
}
278+
267279
@Override
268280
public String getMaximum() {
269281
return maximum;
@@ -616,6 +628,7 @@ public String toString() {
616628
sb.append(", minimum='").append(minimum).append('\'');
617629
sb.append(", maximum='").append(maximum).append('\'');
618630
sb.append(", pattern='").append(pattern).append('\'');
631+
sb.append(", originalPattern='").append(originalPattern).append('\'');
619632
sb.append(", multipleOf='").append(multipleOf).append('\'');
620633
sb.append(", items='").append(items).append('\'');
621634
sb.append(", additionalProperties='").append(additionalProperties).append('\'');

modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4893,6 +4893,7 @@ public CodegenResponse fromResponse(String responseCode, ApiResponse response) {
48934893
ModelUtils.syncValidationProperties(responseSchema, r);
48944894
if (responseSchema.getPattern() != null) {
48954895
r.setPattern(toRegularExpression(responseSchema.getPattern()));
4896+
r.setOriginalPattern(responseSchema.getPattern());
48964897
}
48974898

48984899
CodegenProperty cp = fromProperty("response", responseSchema, false);

modules/openapi-generator/src/main/java/org/openapitools/codegen/IJsonSchemaValidationProperties.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ public interface IJsonSchemaValidationProperties {
2929

3030
void setPattern(String pattern);
3131

32+
String getOriginalPattern();
33+
34+
void setOriginalPattern(String originalPattern);
35+
3236
String getMaximum();
3337

3438
void setMaximum(String maximum);

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractGoCodegen.java

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
import java.io.File;
3131
import java.util.*;
32+
import java.util.regex.Matcher;
3233

3334
import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER;
3435
import static org.openapitools.codegen.utils.StringUtils.camelize;
@@ -38,6 +39,7 @@ public abstract class AbstractGoCodegen extends DefaultCodegen implements Codege
3839

3940
private final Logger LOGGER = LoggerFactory.getLogger(AbstractGoCodegen.class);
4041
private static final String NUMERIC_ENUM_PREFIX = "_";
42+
private static final String X_GO_CUSTOM_TAG = "x-go-custom-tag";
4143

4244
@Setter
4345
protected boolean withGoCodegenComment = false;
@@ -785,9 +787,26 @@ public ModelsMap postProcessModels(ModelsMap objs) {
785787
}
786788

787789
if (cp.pattern != null) {
788-
cp.vendorExtensions.put("x-go-custom-tag", "validate:\"regexp=" +
789-
cp.pattern.replace("\\", "\\\\").replaceAll("^/|/$", "") +
790-
"\"");
790+
String regexp = String.format(Locale.getDefault(), "regexp=%s", cp.originalPattern);
791+
regexp = regexp.replace("\\", "\\\\");
792+
793+
// Replace backtick by \\x60, if found
794+
if (regexp.contains("`")) {
795+
regexp = regexp.replace("`", "\\x60");
796+
}
797+
798+
// Escape comma
799+
if (regexp.contains(",")) {
800+
regexp = regexp.replace(",", "\\\\,");
801+
}
802+
803+
// as the double quotes will be included in a string, ".......".....", they should be escaped once: ".....\"...."
804+
if (regexp.contains("\"")) {
805+
regexp = regexp.replace("\"", "\\\",");
806+
}
807+
808+
String validate = String.format(Locale.getDefault(), "validate:\"%s\"", regexp);
809+
cp.vendorExtensions.put(X_GO_CUSTOM_TAG, validate);
791810
}
792811

793812
// construct data tag in the template: x-go-datatag
@@ -813,8 +832,8 @@ public ModelsMap postProcessModels(ModelsMap objs) {
813832
}
814833

815834
// {{#vendorExtensions.x-go-custom-tag}} {{{.}}}{{/vendorExtensions.x-go-custom-tag}}
816-
if (StringUtils.isNotEmpty(String.valueOf(cp.vendorExtensions.getOrDefault("x-go-custom-tag", "")))) {
817-
goDataTag += " " + cp.vendorExtensions.get("x-go-custom-tag");
835+
if (StringUtils.isNotEmpty(String.valueOf(cp.vendorExtensions.getOrDefault(X_GO_CUSTOM_TAG, "")))) {
836+
goDataTag += " " + cp.vendorExtensions.get(X_GO_CUSTOM_TAG);
818837
}
819838

820839
// if it contains backtick, wrap with " instead

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptFetchClientCodegen.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,6 +1564,7 @@ public ExtendedCodegenModel(CodegenModel cm) {
15641564
this.setMinimum(cm.getMinimum());
15651565
this.setMaximum(cm.getMaximum());
15661566
this.setPattern(cm.getPattern());
1567+
this.setOriginalPattern(cm.getOriginalPattern());
15671568
this.setMultipleOf(cm.getMultipleOf());
15681569
this.setItems(cm.getItems());
15691570
this.setAdditionalProperties(cm.getAdditionalProperties());

modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1838,6 +1838,8 @@ public static void syncValidationProperties(Schema schema, IJsonSchemaValidation
18381838
String pattern = schema.getPattern();
18391839
if (pattern != null) vSB.withPattern();
18401840

1841+
String originalPattern = pattern;
1842+
18411843
BigDecimal multipleOf = schema.getMultipleOf();
18421844
if (multipleOf != null) vSB.withMultipleOf();
18431845

@@ -1867,7 +1869,7 @@ public static void syncValidationProperties(Schema schema, IJsonSchemaValidation
18671869
logWarnMessagesForIneffectiveValidations(new LinkedHashSet(setValidations), schema, SchemaValidations.OBJECT_VALIDATIONS);
18681870
} else if (isStringSchema(schema)) {
18691871
if (minLength != null || maxLength != null || pattern != null)
1870-
setStringValidations(minLength, maxLength, pattern, target);
1872+
setStringValidations(minLength, maxLength, pattern, originalPattern, target);
18711873
if (isDecimalSchema(schema)) {
18721874
if (multipleOf != null || minimum != null || maximum != null || exclusiveMinimum != null || exclusiveMaximum != null)
18731875
setNumericValidations(schema, multipleOf, minimum, maximum, exclusiveMinimum, exclusiveMaximum, target);
@@ -1886,7 +1888,7 @@ public static void syncValidationProperties(Schema schema, IJsonSchemaValidation
18861888
// anyType can have any validations set on it
18871889
setArrayValidations(minItems, maxItems, uniqueItems, target);
18881890
setObjectValidations(minProperties, maxProperties, target);
1889-
setStringValidations(minLength, maxLength, pattern, target);
1891+
setStringValidations(minLength, maxLength, pattern, originalPattern, target);
18901892
setNumericValidations(schema, multipleOf, minimum, maximum, exclusiveMinimum, exclusiveMaximum, target);
18911893
}
18921894

@@ -1906,10 +1908,11 @@ private static void setObjectValidations(Integer minProperties, Integer maxPrope
19061908
if (maxProperties != null) target.setMaxProperties(maxProperties);
19071909
}
19081910

1909-
private static void setStringValidations(Integer minLength, Integer maxLength, String pattern, IJsonSchemaValidationProperties target) {
1911+
private static void setStringValidations(Integer minLength, Integer maxLength, String pattern, String originalPattern, IJsonSchemaValidationProperties target) {
19101912
if (minLength != null) target.setMinLength(minLength);
19111913
if (maxLength != null) target.setMaxLength(maxLength);
19121914
if (pattern != null) target.setPattern(pattern);
1915+
if (originalPattern != null) target.setOriginalPattern(originalPattern);
19131916
}
19141917

19151918
private static void setNumericValidations(Schema schema, BigDecimal multipleOf, BigDecimal minimum, BigDecimal maximum, Boolean exclusiveMinimum, Boolean exclusiveMaximum, IJsonSchemaValidationProperties target) {

modules/openapi-generator/src/main/resources/go/model_oneof.mustache

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,16 @@ func (dst *{{classname}}) UnmarshalJSON(data []byte) error {
7979
} else if match == 1 {
8080
return nil // exactly one match
8181
} else { // no match
82-
return fmt.Errorf("data failed to match schemas in oneOf({{classname}})")
82+
{{#oneOf}}
83+
if err != nil {
84+
return fmt.Errorf("data failed to match schemas in oneOf({{classname}}): %v", err)
85+
} else {
86+
return fmt.Errorf("data failed to match schemas in oneOf({{classname}})")
87+
}
88+
{{/oneOf}}
89+
{{^oneOf}}
90+
return fmt.Errorf("data failed to match schemas in oneOf({{classname}})")
91+
{{/oneOf}}
8392
}
8493
{{/discriminator}}
8594
{{/useOneOfDiscriminatorLookup}}
@@ -114,7 +123,16 @@ func (dst *{{classname}}) UnmarshalJSON(data []byte) error {
114123
} else if match == 1 {
115124
return nil // exactly one match
116125
} else { // no match
117-
return fmt.Errorf("data failed to match schemas in oneOf({{classname}})")
126+
{{#oneOf}}
127+
if err != nil {
128+
return fmt.Errorf("data failed to match schemas in oneOf({{classname}}): %v", err)
129+
} else {
130+
return fmt.Errorf("data failed to match schemas in oneOf({{classname}})")
131+
}
132+
{{/oneOf}}
133+
{{^oneOf}}
134+
return fmt.Errorf("data failed to match schemas in oneOf({{classname}})")
135+
{{/oneOf}}
118136
}
119137
{{/useOneOfDiscriminatorLookup}}
120138
}

0 commit comments

Comments
 (0)