Skip to content

Commit 55d676f

Browse files
add patternProperties Validation and Test (membrane#1929)
* wip * fix * fix * add missing info * rm types * renaming
1 parent 39d36b5 commit 55d676f

File tree

3 files changed

+102
-0
lines changed

3 files changed

+102
-0
lines changed

core/src/main/java/com/predic8/membrane/core/openapi/validators/ObjectValidator.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import java.io.*;
2626
import java.util.*;
27+
import java.util.regex.Pattern;
2728

2829
import static com.predic8.membrane.core.openapi.util.Utils.*;
2930
import static java.lang.String.*;
@@ -75,6 +76,7 @@ public ValidationErrors validate(ValidationContext ctx, Object obj) {
7576
ValidationErrors errors = validateRequiredProperties(ctx, node);
7677
errors.add(validateAddionalProperties(ctx, node));
7778
errors.add(validateProperties(ctx, node));
79+
errors.add(validatePatternProperties(ctx, node));
7880
errors.add(validateSize(ctx, node));
7981
errors.add(validateDiscriminator(ctx,node));
8082
return errors;
@@ -234,11 +236,37 @@ private ValidationErrors validateProperties(ValidationContext ctx, JsonNode node
234236
return errors;
235237
}
236238

239+
private ValidationErrors validatePatternProperties(ValidationContext ctx, JsonNode node) {
240+
if(schema.getPatternProperties() == null) {
241+
return null;
242+
}
243+
ValidationErrors errors = new ValidationErrors();
244+
245+
getPatternPropertiesFromSchema().forEach((regex, propSchema) -> {
246+
Pattern pattern = Pattern.compile(regex);
247+
248+
for (Iterator<String> it = node.fieldNames(); it.hasNext(); ) {
249+
String fieldName = it.next();
250+
if (pattern.matcher(fieldName).matches()) {
251+
JsonNode childNode = node.get(fieldName);
252+
errors.add(new SchemaValidator(api, propSchema)
253+
.validate(ctx, childNode));
254+
}
255+
}
256+
});
257+
return errors;
258+
}
259+
237260
@SuppressWarnings({"rawtypes", "unchecked"})
238261
private Map<String, Schema> getPropertiesFromSchema() {
239262
return (Map<String, Schema>) schema.getProperties();
240263
}
241264

265+
@SuppressWarnings({"rawtypes", "unchecked"})
266+
private Map<String, Schema> getPatternPropertiesFromSchema() {
267+
return (Map<String, Schema>) schema.getPatternProperties();
268+
}
269+
242270
@SuppressWarnings("rawtypes")
243271
private ValidationErrors validateReadOnlyProperty(ValidationContext ctx, JsonNode node, String propertyName, Schema propertySchema) {
244272
if (propertySchema.getReadOnly() == null || !propertySchema.getReadOnly())
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/* Copyright 2025 predic8 GmbH, www.predic8.com
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License. */
14+
15+
package com.predic8.membrane.core.openapi.validators;
16+
17+
import com.predic8.membrane.core.openapi.model.Request;
18+
import jakarta.mail.internet.ParseException;
19+
import org.junit.jupiter.api.Test;
20+
21+
import static com.predic8.membrane.core.http.MimeType.APPLICATION_JSON;
22+
import static org.junit.jupiter.api.Assertions.assertEquals;
23+
import static org.junit.jupiter.api.Assertions.assertTrue;
24+
25+
public class PatternPropertiesTest extends AbstractValidatorTest{
26+
27+
@Override
28+
protected String getOpenAPIFileName() {
29+
return "/openapi/specs/pattern-properties.yaml";
30+
}
31+
32+
@Test
33+
void invalidRequest() throws ParseException {
34+
ValidationErrors errors = validator.validate(Request.post().mediaType(APPLICATION_JSON).path("/test").body("""
35+
{"foo": []}
36+
"""));
37+
assertEquals(1,errors.size());
38+
assertTrue(errors.toString().contains("Array has 0 items. This is less then minItems of 2."));
39+
}
40+
41+
@Test
42+
void validRequest() throws ParseException {
43+
ValidationErrors errors = validator.validate(Request.post().mediaType(APPLICATION_JSON).path("/test").body("""
44+
{"foo": [1, 2]}
45+
"""));
46+
assertEquals(0,errors.size());
47+
}
48+
49+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
openapi: "3.1.0"
2+
info:
3+
title: Pattern Properties API
4+
version: '1.0'
5+
paths:
6+
/test:
7+
post:
8+
requestBody:
9+
content:
10+
application/json:
11+
schema:
12+
properties:
13+
foo:
14+
type: "array"
15+
maxItems: 3
16+
bar:
17+
type: "array"
18+
patternProperties:
19+
f.o:
20+
minItems: 2
21+
additionalProperties:
22+
type: "integer"
23+
responses:
24+
"200":
25+
description: "OK"

0 commit comments

Comments
 (0)