Skip to content

Commit d5c5f63

Browse files
authored
Merge pull request #186 from everit-org/issue174
Introducing SchemaExtractors in the loader package
2 parents bc51361 + 541b039 commit d5c5f63

File tree

20 files changed

+925
-255
lines changed

20 files changed

+925
-255
lines changed

core/src/main/java/org/everit/json/schema/CombinedSchema.java

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,26 +24,32 @@ public static class Builder extends Schema.Builder<CombinedSchema> {
2424

2525
private Collection<Schema> subschemas = new ArrayList<>();
2626

27+
private boolean synthetic;
28+
2729
@Override
2830
public CombinedSchema build() {
2931
return new CombinedSchema(this);
3032
}
3133

32-
public Builder criterion(final ValidationCriterion criterion) {
34+
public Builder criterion(ValidationCriterion criterion) {
3335
this.criterion = criterion;
3436
return this;
3537
}
3638

37-
public Builder subschema(final Schema subschema) {
39+
public Builder subschema(Schema subschema) {
3840
this.subschemas.add(subschema);
3941
return this;
4042
}
4143

42-
public Builder subschemas(final Collection<Schema> subschemas) {
44+
public Builder subschemas(Collection<Schema> subschemas) {
4345
this.subschemas = subschemas;
4446
return this;
4547
}
4648

49+
public Builder isSynthetic(boolean synthetic) {
50+
this.synthetic = synthetic;
51+
return this;
52+
}
4753
}
4854

4955
/**
@@ -127,26 +133,28 @@ public void validate(int subschemaCount, int matchingCount) {
127133
}
128134
};
129135

130-
public static Builder allOf(final Collection<Schema> schemas) {
136+
public static Builder allOf(Collection<Schema> schemas) {
131137
return builder(schemas).criterion(ALL_CRITERION);
132138
}
133139

134-
public static Builder anyOf(final Collection<Schema> schemas) {
140+
public static Builder anyOf(Collection<Schema> schemas) {
135141
return builder(schemas).criterion(ANY_CRITERION);
136142
}
137143

138144
public static Builder builder() {
139145
return new Builder();
140146
}
141147

142-
public static Builder builder(final Collection<Schema> subschemas) {
148+
public static Builder builder(Collection<Schema> subschemas) {
143149
return new Builder().subschemas(subschemas);
144150
}
145151

146-
public static Builder oneOf(final Collection<Schema> schemas) {
152+
public static Builder oneOf(Collection<Schema> schemas) {
147153
return builder(schemas).criterion(ONE_CRITERION);
148154
}
149155

156+
private final boolean synthetic;
157+
150158
private final Collection<Schema> subschemas;
151159

152160
private final ValidationCriterion criterion;
@@ -157,8 +165,9 @@ public static Builder oneOf(final Collection<Schema> schemas) {
157165
* @param builder
158166
* the builder containing the validation criterion and the subschemas to be checked
159167
*/
160-
public CombinedSchema(final Builder builder) {
168+
public CombinedSchema(Builder builder) {
161169
super(builder);
170+
this.synthetic = builder.synthetic;
162171
this.criterion = requireNonNull(builder.criterion, "criterion cannot be null");
163172
this.subschemas = requireNonNull(builder.subschemas, "subschemas cannot be null");
164173
}
@@ -176,7 +185,7 @@ public Collection<Schema> getSubschemas() {
176185
}
177186

178187
@Override
179-
public boolean definesProperty(final String field) {
188+
public boolean definesProperty(String field) {
180189
List<Schema> matching = new ArrayList<>();
181190
for (Schema subschema : subschemas) {
182191
if (subschema.definesProperty(field)) {
@@ -200,6 +209,7 @@ public boolean equals(Object o) {
200209
return that.canEqual(this) &&
201210
Objects.equals(subschemas, that.subschemas) &&
202211
Objects.equals(criterion, that.criterion) &&
212+
synthetic == that.synthetic &&
203213
super.equals(that);
204214
} else {
205215
return false;
@@ -208,15 +218,19 @@ public boolean equals(Object o) {
208218

209219
@Override
210220
void describePropertiesTo(JSONPrinter writer) {
211-
writer.key(criterion.toString());
212-
writer.array();
213-
subschemas.forEach(subschema -> subschema.describeTo(writer));
214-
writer.endArray();
221+
if (synthetic) {
222+
subschemas.forEach(subschema -> subschema.describePropertiesTo(writer));
223+
} else {
224+
writer.key(criterion.toString());
225+
writer.array();
226+
subschemas.forEach(subschema -> subschema.describeTo(writer));
227+
writer.endArray();
228+
}
215229
}
216230

217231
@Override
218232
public int hashCode() {
219-
return Objects.hash(super.hashCode(), subschemas, criterion);
233+
return Objects.hash(super.hashCode(), subschemas, criterion, synthetic);
220234
}
221235

222236
@Override

core/src/main/java/org/everit/json/schema/FalseSchema.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.everit.json.schema;
22

3+
import org.everit.json.schema.internal.JSONPrinter;
4+
35
/**
46
* @author erosb
57
*/
@@ -26,11 +28,18 @@ public FalseSchema(Builder builder) {
2628
super(builder);
2729
}
2830

29-
@Override void accept(Visitor visitor) {
31+
@Override
32+
void accept(Visitor visitor) {
3033
visitor.visitFalseSchema(this);
3134
}
3235

33-
@Override public String toString() {
36+
@Override
37+
public void describeTo(JSONPrinter writer) {
38+
writer.value(false);
39+
}
40+
41+
@Override
42+
public String toString() {
3443
return "false";
3544
}
3645
}

core/src/main/java/org/everit/json/schema/TrueSchema.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.everit.json.schema;
22

3+
import org.everit.json.schema.internal.JSONPrinter;
4+
35
/**
46
* @author erosb
57
*/
@@ -20,8 +22,13 @@ public TrueSchema(Builder builder) {
2022
super(builder);
2123
}
2224

23-
@Override public String toString() {
24-
return "true";
25+
@Override
26+
public void describeTo(JSONPrinter writer) {
27+
writer.value(true);
2528
}
2629

30+
@Override
31+
public String toString() {
32+
return "true";
33+
}
2734
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package org.everit.json.schema.loader;
2+
3+
import java.util.Collection;
4+
import java.util.HashSet;
5+
import java.util.Set;
6+
7+
import org.everit.json.schema.Schema;
8+
9+
class AdjacentSchemaExtractionState {
10+
11+
private final JsonObject context;
12+
13+
private final Set<Schema.Builder<?>> extractedSchemas;
14+
15+
AdjacentSchemaExtractionState(JsonObject context) {
16+
this(context, new HashSet<>());
17+
}
18+
19+
private AdjacentSchemaExtractionState(JsonObject context, Set<Schema.Builder<?>> extractedSchemas) {
20+
this.context = context;
21+
this.extractedSchemas = extractedSchemas;
22+
}
23+
24+
AdjacentSchemaExtractionState reduce(ExtractionResult result) {
25+
Set<Schema.Builder<?>> newExtractedSchemas = new HashSet<>(extractedSchemas.size() + result.extractedSchemas.size());
26+
newExtractedSchemas.addAll(extractedSchemas);
27+
newExtractedSchemas.addAll(result.extractedSchemas);
28+
JsonObject projectedContext = new ProjectedJsonObject(context, result.consumedKeys);
29+
return new AdjacentSchemaExtractionState(projectedContext, newExtractedSchemas);
30+
}
31+
32+
public JsonObject projectedSchemaJson() {
33+
return context;
34+
}
35+
36+
public Collection<Schema.Builder<?>> extractedSchemaBuilders() {
37+
return extractedSchemas;
38+
}
39+
}
Lines changed: 20 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,23 @@
11
package org.everit.json.schema.loader;
22

3-
import static java.lang.String.format;
4-
import static java.util.Arrays.asList;
53
import static java.util.Objects.requireNonNull;
4+
import static java.util.stream.Collectors.toList;
5+
import static java.util.stream.Collectors.toSet;
66

77
import java.util.ArrayList;
88
import java.util.Collection;
99
import java.util.HashMap;
10-
import java.util.List;
1110
import java.util.Map;
12-
import java.util.Optional;
11+
import java.util.Set;
1312
import java.util.function.Function;
14-
import java.util.stream.Collectors;
1513

1614
import org.everit.json.schema.CombinedSchema;
1715
import org.everit.json.schema.Schema;
1816

1917
/**
2018
* @author erosb
2119
*/
22-
class CombinedSchemaLoader {
20+
class CombinedSchemaLoader implements SchemaExtractor {
2321

2422
/**
2523
* Alias for {@code Function<Collection<Schema>, CombinedSchema.Builder>}.
@@ -38,45 +36,27 @@ private interface CombinedSchemaProvider
3836
COMB_SCHEMA_PROVIDERS.put("oneOf", CombinedSchema::oneOf);
3937
}
4038

41-
private final LoadingState ls;
42-
4339
private final SchemaLoader defaultLoader;
4440

45-
public CombinedSchemaLoader(LoadingState ls, SchemaLoader defaultLoader) {
46-
this.ls = requireNonNull(ls, "ls cannot be null");
41+
public CombinedSchemaLoader(SchemaLoader defaultLoader) {
4742
this.defaultLoader = requireNonNull(defaultLoader, "defaultLoader cannot be null");
4843
}
4944

50-
public Optional<Schema.Builder<?>> load() {
51-
List<String> presentKeys = COMB_SCHEMA_PROVIDERS.keySet().stream()
52-
.filter(ls.schemaJson()::containsKey)
53-
.collect(Collectors.toList());
54-
if (presentKeys.size() > 1) {
55-
throw ls.createSchemaException(format("expected at most 1 of 'allOf', 'anyOf', 'oneOf', %d found", presentKeys.size()));
56-
} else if (presentKeys.size() == 1) {
57-
String key = presentKeys.get(0);
58-
Collection<Schema> subschemas = new ArrayList<>();
59-
ls.schemaJson().require(key).requireArray()
60-
.forEach((i, subschema) -> {
61-
subschemas.add(defaultLoader.loadChild(subschema).build());
62-
});
63-
CombinedSchema.Builder combinedSchema = COMB_SCHEMA_PROVIDERS.get(key).apply(
64-
subschemas);
65-
Schema.Builder<?> baseSchema;
66-
if (ls.schemaJson().containsKey("type")) {
67-
baseSchema = defaultLoader.loadForType(ls.schemaJson().require("type"));
68-
} else {
69-
baseSchema = defaultLoader.sniffSchemaByProps();
70-
}
71-
if (baseSchema == null) {
72-
return Optional.of(combinedSchema);
73-
} else {
74-
return Optional.of(CombinedSchema.allOf(asList(baseSchema.build(),
75-
combinedSchema.build())));
76-
}
77-
} else {
78-
return Optional.empty();
79-
}
45+
@Override
46+
public ExtractionResult extract(JsonObject schemaJson) {
47+
Set<String> presentKeys = COMB_SCHEMA_PROVIDERS.keySet().stream()
48+
.filter(schemaJson::containsKey)
49+
.collect(toSet());
50+
Collection<Schema.Builder<?>> extractedSchemas = presentKeys.stream().map(key -> loadCombinedSchemaForKeyword(schemaJson, key))
51+
.collect(toList());
52+
return new ExtractionResult(presentKeys, extractedSchemas);
53+
}
54+
55+
private CombinedSchema.Builder loadCombinedSchemaForKeyword(JsonObject schemaJson, String key) {
56+
Collection<Schema> subschemas = new ArrayList<>();
57+
schemaJson.require(key).requireArray()
58+
.forEach((i, subschema) -> subschemas.add(defaultLoader.loadChild(subschema).build()));
59+
return COMB_SCHEMA_PROVIDERS.get(key).apply(subschemas);
8060
}
8161

8262
}

core/src/main/java/org/everit/json/schema/loader/JsonObject.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,13 @@
1212
import java.util.function.Function;
1313

1414
import org.everit.json.schema.SchemaException;
15-
import org.json.JSONObject;
1615

1716
/**
1817
* @author erosb
1918
*/
20-
final class JsonObject extends JsonValue {
19+
class JsonObject extends JsonValue {
2120

22-
private final Map<String, Object> storage;
21+
final Map<String, Object> storage;
2322

2423
JsonObject(Map<String, Object> storage) {
2524
super(storage);

0 commit comments

Comments
 (0)