Skip to content

Commit 5062050

Browse files
authored
Merge pull request #287 from everit-org/ref-siblings-attempt1
Yet another attempt to fix #259
2 parents 8654bbd + 4ecca90 commit 5062050

File tree

8 files changed

+181
-28
lines changed

8 files changed

+181
-28
lines changed

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

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,38 @@ public Builder refValue(String refValue) {
5151
super.unprocessedProperties(unprocessedProperties);
5252
return this;
5353
}
54+
55+
@Override public ReferenceSchema.Builder title(String title) {
56+
if (retval != null) {
57+
retval.title = title;
58+
}
59+
super.title(title);
60+
return this;
61+
}
62+
63+
@Override public ReferenceSchema.Builder description(String description) {
64+
if (retval != null) {
65+
retval.description = description;
66+
}
67+
super.description(description);
68+
return this;
69+
}
70+
71+
@Override public ReferenceSchema.Builder schemaLocation(SchemaLocation location) {
72+
if (retval != null) {
73+
retval.schemaLocation = location;
74+
}
75+
super.schemaLocation(location);
76+
return this;
77+
}
78+
79+
public Builder copy() {
80+
Builder copy = new Builder();
81+
if (this.retval != null) {
82+
copy.build().setReferredSchema(this.retval.getReferredSchema());
83+
}
84+
return copy;
85+
}
5486
}
5587

5688
public static Builder builder() {
@@ -63,6 +95,12 @@ public static Builder builder() {
6395

6496
private Map<String, Object> unprocessedProperties;
6597

98+
private String title;
99+
100+
private String description;
101+
102+
private SchemaLocation schemaLocation;
103+
66104
public ReferenceSchema(final Builder builder) {
67105
super(builder);
68106
this.refValue = requireNonNull(builder.refValue, "refValue cannot be null");
@@ -105,6 +143,8 @@ public boolean equals(Object o) {
105143
Objects.equals(refValue, that.refValue) &&
106144
Objects.equals(unprocessedProperties, that.unprocessedProperties) &&
107145
Objects.equals(referredSchema, that.referredSchema) &&
146+
Objects.equals(title, that.title) &&
147+
Objects.equals(description, that.description) &&
108148
super.equals(that);
109149
} else {
110150
return false;
@@ -113,7 +153,7 @@ public boolean equals(Object o) {
113153

114154
@Override
115155
public int hashCode() {
116-
return Objects.hash(super.hashCode(), referredSchema, refValue, unprocessedProperties);
156+
return Objects.hash(super.hashCode(), referredSchema, refValue, unprocessedProperties, title, description);
117157
}
118158

119159
@Override
@@ -131,6 +171,18 @@ protected boolean canEqual(Object other) {
131171
}
132172

133173
@Override public Map<String, Object> getUnprocessedProperties() {
134-
return unprocessedProperties;
174+
return unprocessedProperties == null ? super.getUnprocessedProperties() : unprocessedProperties;
175+
}
176+
177+
@Override public String getTitle() {
178+
return title == null ? super.getTitle() : title;
179+
}
180+
181+
@Override public String getDescription() {
182+
return description == null ? super.getDescription() : description;
183+
}
184+
185+
@Override public SchemaLocation getLocation() {
186+
return schemaLocation == null ? super.getLocation() : schemaLocation;
135187
}
136188
}

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import java.util.List;
1212
import java.util.Map;
1313

14-
import org.everit.json.schema.ReferenceSchema;
1514
import org.everit.json.schema.SchemaException;
1615
import org.everit.json.schema.SchemaLocation;
1716
import org.everit.json.schema.loader.internal.ReferenceResolver;
@@ -43,14 +42,14 @@ static URI extractChildId(URI parentScopeId, Object childJson, String idKeyword)
4342

4443
final SchemaLocation pointerToCurrentObj;
4544

46-
final Map<String, ReferenceSchema.Builder> pointerSchemas;
45+
final Map<String, ReferenceKnot> pointerSchemas;
4746

4847
final JsonValue rootSchemaJson;
4948

5049
final JsonValue schemaJson;
5150

5251
LoadingState(LoaderConfig config,
53-
Map<String, ReferenceSchema.Builder> pointerSchemas,
52+
Map<String, ReferenceKnot> pointerSchemas,
5453
Object rootSchemaJson,
5554
Object schemaJson,
5655
URI parentScopeId,

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

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55

66
import java.net.URI;
77
import java.net.URISyntaxException;
8+
import java.util.ArrayList;
89
import java.util.HashMap;
10+
import java.util.List;
911
import java.util.Map;
1012

1113
import org.everit.json.schema.ReferenceSchema;
@@ -14,6 +16,28 @@
1416
import org.everit.json.schema.loader.internal.ReferenceResolver;
1517
import org.json.JSONObject;
1618

19+
class ReferenceKnot {
20+
21+
private Schema referredSchema;
22+
23+
private List<ReferenceSchema.Builder> refs = new ArrayList<>(1);
24+
25+
ReferenceSchema.Builder initReference(String refValue) {
26+
ReferenceSchema.Builder builder = new ReferenceSchema.Builder().refValue(refValue);
27+
if (referredSchema != null) {
28+
builder.build().setReferredSchema(referredSchema);
29+
}
30+
refs.add(builder);
31+
return builder;
32+
}
33+
34+
void resolveWith(Schema referredSchema) {
35+
refs.forEach(ref -> ref.build().setReferredSchema(referredSchema));
36+
this.referredSchema = referredSchema;
37+
}
38+
39+
}
40+
1741
/**
1842
* @author erosb
1943
*/
@@ -121,7 +145,7 @@ private JsonObject lookupObjById(JsonValue val, String idAttrVal) {
121145
private Schema.Builder<?> performQueryEvaluation(String mapKey, JsonPointerEvaluator pointerEvaluator) {
122146
String absolutePointer = ReferenceResolver.resolve(ls.id, mapKey).toString();
123147
if (ls.pointerSchemas.containsKey(absolutePointer)) {
124-
return ls.pointerSchemas.get(absolutePointer);
148+
return ls.pointerSchemas.get(absolutePointer).initReference(absolutePointer);
125149
}
126150
JsonValue referencedRawSchema = pointerEvaluator.query().getQueryResult();
127151
return createReferenceSchema(mapKey, absolutePointer, referencedRawSchema);
@@ -133,7 +157,7 @@ private Schema.Builder<?> performQueryEvaluation(String mapKey, JsonPointerEvalu
133157
Schema.Builder<?> lookup(String relPointerString, JsonObject ctx) {
134158
String absPointerString = ReferenceResolver.resolve(ls.id, relPointerString).toString();
135159
if (ls.pointerSchemas.containsKey(absPointerString)) {
136-
return ls.pointerSchemas.get(absPointerString);
160+
return ls.pointerSchemas.get(absPointerString).initReference(absPointerString);
137161
}
138162
JsonValue rawInternalReferenced = lookupObjById(ls.rootSchemaJson, absPointerString);
139163
if (rawInternalReferenced != null) {
@@ -143,9 +167,9 @@ Schema.Builder<?> lookup(String relPointerString, JsonObject ctx) {
143167
return performQueryEvaluation(relPointerString, JsonPointerEvaluator.forDocument(ls.rootSchemaJson(), relPointerString));
144168
}
145169
JsonPointerEvaluator pointer = createPointerEvaluator(absPointerString);
146-
ReferenceSchema.Builder refBuilder = ReferenceSchema.builder()
147-
.refValue(relPointerString);
148-
ls.pointerSchemas.put(absPointerString, refBuilder);
170+
ReferenceKnot knot = new ReferenceKnot();
171+
ReferenceSchema.Builder refBuilder = knot.initReference(relPointerString);
172+
ls.pointerSchemas.put(absPointerString, knot);
149173
JsonPointerEvaluator.QueryResult result = pointer.query();
150174

151175
URI resolutionScope = !isSameDocumentRef(absPointerString) ? withoutFragment(absPointerString) : ls.id;
@@ -157,15 +181,16 @@ Schema.Builder<?> lookup(String relPointerString, JsonObject ctx) {
157181
.rootSchemaJson(containingDocument).build();
158182
Schema referredSchema = childLoader.load().build();
159183
refBuilder.schemaLocation(SchemaLocation.parseURI(absPointerString));
160-
refBuilder.build().setReferredSchema(referredSchema);
184+
knot.resolveWith(referredSchema);
161185
return refBuilder;
162186
}
163187

164188
private Schema.Builder<?> createReferenceSchema(String relPointerString, String absPointerString, JsonValue rawReferenced) {
165-
ReferenceSchema.Builder refBuilder = ReferenceSchema.builder().refValue(relPointerString);
166-
ls.pointerSchemas.put(absPointerString, refBuilder);
189+
ReferenceKnot knot = new ReferenceKnot();
190+
ReferenceSchema.Builder refBuilder = knot.initReference(relPointerString);
191+
ls.pointerSchemas.put(absPointerString, knot);
167192
Schema referredSchema = new SchemaLoader(rawReferenced.ls).load().build();
168-
refBuilder.build().setReferredSchema(referredSchema);
193+
knot.resolveWith(referredSchema);
169194
return refBuilder;
170195
}
171196

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import org.everit.json.schema.EmptySchema;
2323
import org.everit.json.schema.FalseSchema;
2424
import org.everit.json.schema.FormatValidator;
25-
import org.everit.json.schema.ReferenceSchema;
2625
import org.everit.json.schema.Schema;
2726
import org.everit.json.schema.SchemaException;
2827
import org.everit.json.schema.SchemaLocation;
@@ -53,7 +52,7 @@ public static class SchemaLoaderBuilder {
5352

5453
Object rootSchemaJson;
5554

56-
Map<String, ReferenceSchema.Builder> pointerSchemas = new HashMap<>();
55+
Map<String, ReferenceKnot> pointerSchemas = new HashMap<>();
5756

5857
URI id;
5958

@@ -185,7 +184,7 @@ public SchemaLoaderBuilder resolutionScope(URI id) {
185184
return this;
186185
}
187186

188-
SchemaLoaderBuilder pointerSchemas(Map<String, ReferenceSchema.Builder> pointerSchemas) {
187+
SchemaLoaderBuilder pointerSchemas(Map<String, ReferenceKnot> pointerSchemas) {
189188
this.pointerSchemas = pointerSchemas;
190189
return this;
191190
}

core/src/test/java/org/everit/json/schema/loader/ReferenceLookupTest.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import static java.util.Collections.emptyMap;
44
import static org.everit.json.schema.TestSupport.asStream;
55
import static org.junit.Assert.assertEquals;
6+
import static org.junit.Assert.assertNotNull;
7+
import static org.junit.Assert.assertSame;
68
import static org.junit.Assert.assertTrue;
79
import static org.mockito.Mockito.mock;
810
import static org.mockito.Mockito.when;
@@ -11,13 +13,17 @@
1113
import java.util.Map;
1214

1315
import org.everit.json.schema.NumberSchema;
16+
import org.everit.json.schema.ObjectSchema;
1417
import org.everit.json.schema.ReferenceSchema;
1518
import org.everit.json.schema.ResourceLoader;
1619
import org.everit.json.schema.Schema;
1720
import org.everit.json.schema.SchemaLocation;
21+
import org.json.JSONObject;
1822
import org.junit.Before;
1923
import org.junit.Test;
2024

25+
import com.google.common.collect.ImmutableMap;
26+
2127
public class ReferenceLookupTest {
2228

2329
private static final Map<String, Object> rootSchemaJson = ResourceLoader.DEFAULT.readObj("ref-lookup-tests.json").toMap();
@@ -101,4 +107,27 @@ public void idAsJsonPointerWorks() {
101107
assertEquals("the ID can be a JSON pointer", actual.getDescription());
102108
}
103109

110+
@Test
111+
public void multipleReferencesToSameSchema() {
112+
JSONObject rawSchema = ResourceLoader.DEFAULT.readObj("multi-pointer.json");
113+
ObjectSchema actual = (ObjectSchema) SchemaLoader.load(rawSchema);
114+
115+
ReferenceSchema aRefSchema = (ReferenceSchema) actual.getPropertySchemas().get("a");
116+
assertEquals(aRefSchema.getUnprocessedProperties(), ImmutableMap.of("unproc0", "unproc0 of A"));
117+
assertEquals("A side", aRefSchema.getTitle());
118+
assertEquals("length of the A side", aRefSchema.getDescription());
119+
assertEquals(SchemaLocation.parseURI("#/properties/a"), aRefSchema.getLocation());
120+
assertNotNull(aRefSchema.getReferredSchema());
121+
122+
ReferenceSchema bRefSchema = (ReferenceSchema) actual.getPropertySchemas().get("b");
123+
assertEquals(bRefSchema.getUnprocessedProperties(), ImmutableMap.of("unproc0", "unproc0 of B"));
124+
assertEquals("length of the B side", bRefSchema.getDescription());
125+
assertEquals(SchemaLocation.parseURI("#/properties/b"), bRefSchema.getLocation());
126+
assertEquals("B side", bRefSchema.getTitle());
127+
assertNotNull(bRefSchema.getReferredSchema());
128+
129+
assertSame(aRefSchema.getReferredSchema(), bRefSchema.getReferredSchema());
130+
131+
}
132+
104133
}

core/src/test/java/org/everit/json/schema/loader/SchemaLoaderTest.java

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -747,23 +747,43 @@ public void commonPropsAreNotUnprocessedProps() {
747747

748748
@Test
749749
public void unprocessedPropertiesAreLoadedForRefElement() {
750-
SchemaLoader loader = SchemaLoader.builder()
751-
.draftV7Support()
752-
.useDefaults(true)
753-
.schemaJson(get("schemaRefWithUnprocessedProperties"))
754-
.build();
750+
SchemaLoader loader =
751+
SchemaLoader.builder()
752+
.draftV7Support()
753+
.useDefaults(true)
754+
.schemaJson(get("schemaRefWithUnprocessedProperties"))
755+
.build();
755756
ObjectSchema actual = (ObjectSchema) loader.load().build();
756757

757758
assertEquals(ImmutableMap.of(
758-
"unproc8", false
759-
), ((ReferenceSchema) actual.getPropertySchemas().get("prop4")).getReferredSchema().getUnprocessedProperties());
759+
"unproc6", false
760+
), actual.getPropertySchemas().get("prop3").getUnprocessedProperties());
760761

761-
assertEquals(ImmutableMap.of("unproc4", true, "unproc5", JSONObject.NULL),
762+
assertEquals(
763+
ImmutableMap.of("unproc8", false),
764+
((ReferenceSchema) actual.getPropertySchemas().get("prop4"))
765+
.getReferredSchema()
766+
.getUnprocessedProperties());
767+
768+
assertEquals(
769+
ImmutableMap.of("unproc4", true, "unproc5", JSONObject.NULL),
762770
actual.getPropertySchemas().get("prop2").getUnprocessedProperties());
763771

764-
assertEquals(ImmutableMap.of(
765-
"unproc7", JSONObject.NULL
766-
), actual.getPropertySchemas().get("prop4").getUnprocessedProperties());
772+
assertEquals(
773+
ImmutableMap.of("unproc7", JSONObject.NULL),
774+
actual.getPropertySchemas().get("prop4").getUnprocessedProperties());
775+
776+
assertEquals(
777+
ImmutableMap.of("unproc8", false),
778+
((ReferenceSchema) actual.getPropertySchemas().get("prop4")).getReferredSchema().getUnprocessedProperties());
779+
780+
assertEquals(
781+
ImmutableMap.of("unproc9", ImmutableMap.of("unproc9-01", false)),
782+
actual.getPropertySchemas().get("prop5").getUnprocessedProperties());
783+
784+
assertEquals(
785+
ImmutableMap.of("unproc8", false),
786+
((ReferenceSchema) actual.getPropertySchemas().get("prop5")).getReferredSchema().getUnprocessedProperties());
767787
}
768788

769789
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"type": "object",
3+
"properties": {
4+
"a": {
5+
"$ref": "#/definitions/Length",
6+
"title": "A side",
7+
"description": "length of the A side",
8+
"unproc0": "unproc0 of A"
9+
},
10+
"b": {
11+
"$ref": "#/definitions/Length",
12+
"title": "B side",
13+
"description": "length of the B side",
14+
"unproc0": "unproc0 of B"
15+
}
16+
},
17+
"definitions": {
18+
"Length": {
19+
"type": "integer",
20+
"minimum": 0
21+
}
22+
}
23+
}

core/src/test/resources/org/everit/jsonvalidator/testschemas.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,12 @@
722722
"prop4": {
723723
"$ref": "#/definitions/dateMonthDayYear",
724724
"unproc7": null
725+
},
726+
"prop5": {
727+
"$ref": "#/definitions/dateMonthDayYear",
728+
"unproc9": {
729+
"unproc9-01": false
730+
}
725731
}
726732
}
727733
}

0 commit comments

Comments
 (0)