Skip to content

Commit f1e0fc9

Browse files
committed
add base uri customizer for OpenAPI 3.2
1 parent d1e2024 commit f1e0fc9

3 files changed

Lines changed: 62 additions & 9 deletions

File tree

json-schema-validator/src/main/java/io/openapiprocessor/jsonschema/schema/Resolver.java

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66
package io.openapiprocessor.jsonschema.schema;
77

88
import io.openapiprocessor.jsonschema.support.Types;
9+
import io.openapiprocessor.jsonschema.support.Uris;
910
import org.checkerframework.checker.nullness.qual.Nullable;
10-
import org.checkerframework.checker.nullness.qual.PolyNull;
1111
import org.slf4j.Logger;
1212
import org.slf4j.LoggerFactory;
1313

1414
import java.net.URI;
1515

16+
import static io.openapiprocessor.jsonschema.schema.SchemaVersionUtil.getSchemaVersion;
17+
1618
/**
1719
* loads the base document and resolves all internal and external $ref's. In case of an external
1820
* $ref it automatically downloads the referenced document if {@code autoLoadSchemas} is enabled.
@@ -26,8 +28,9 @@ public class Resolver {
2628
private static final Logger log = LoggerFactory.getLogger (Resolver.class);
2729

2830
public static class Settings {
29-
private SchemaVersion version;
31+
private final SchemaVersion version;
3032
private boolean autoLoadSchemas = false;
33+
private @Nullable BaseUriCustomizer baseUriCustomizer;
3134

3235
public Settings (SchemaVersion version) {
3336
this.version = version;
@@ -38,11 +41,26 @@ public Settings autoLoadSchemas (boolean load) {
3841
return this;
3942
}
4043

44+
public Settings baseUriCustomizer(BaseUriCustomizer provider) {
45+
this.baseUriCustomizer = provider;
46+
return this;
47+
}
48+
4149
public SchemaVersion getVersion () {
4250
return version;
4351
}
4452
}
4553

54+
public interface BaseUriCustomizer {
55+
/**
56+
* get a base uri from a document if available.
57+
*
58+
* @param document the document
59+
* @return base uri or null
60+
*/
61+
@Nullable URI get (URI documentUri, Object document);
62+
}
63+
4664
private final DocumentStore documents;
4765
private final DocumentLoader loader;
4866

@@ -95,9 +113,9 @@ public ResolverResult resolve (String resourcePath, Settings settings) {
95113
public ResolverResult resolve (URI documentUri, Object document, Settings settings) {
96114
ReferenceRegistry registry = new ReferenceRegistry ();
97115

98-
documents.addId (documentUri, document);
99-
Scope scope = Scope.createScope (documentUri, document, settings.version);
100-
Bucket bucket = toBucket (scope, document);
116+
Scope scope = createScope(documentUri, document, settings);
117+
documents.addId (scope.getBaseUri(), document);
118+
Bucket bucket = Bucket.createBucket(scope, document);
101119

102120
if (bucket == null) {
103121
return new ResolverResult (scope, document, registry, documents);
@@ -114,10 +132,23 @@ public ResolverResult resolve (URI documentUri, Object document, Settings settin
114132
return new ResolverResult (scope, document, registry, documents);
115133
}
116134

117-
private @Nullable Bucket toBucket (Scope scope, @PolyNull Object source) {
118-
if (!Types.isObject (source)) {
119-
return null;
135+
Scope createScope(URI documentUri, Object document, Settings settings) {
136+
SchemaVersion version = getSchemaVersion(documentUri, document, settings.version);
137+
138+
if (settings.baseUriCustomizer != null) {
139+
@Nullable URI baseUri = settings.baseUriCustomizer.get(documentUri, document);
140+
if (baseUri != null) {
141+
return Scope.createScope(documentUri, Uris.resolve(documentUri, baseUri), version);
142+
}
120143
}
121-
return new Bucket (scope, Types.asObject (source));
144+
145+
if (Types.isObject(document)) {
146+
String id = version.getIdProvider().getId(Types.asObject(document));
147+
if (id != null) {
148+
return Scope.createScope(documentUri, Uris.resolve(documentUri, id), version);
149+
}
150+
}
151+
152+
return Scope.createScope(documentUri, null, version);
122153
}
123154
}

json-schema-validator/src/main/java/io/openapiprocessor/jsonschema/schema/Scope.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ public static Scope createScope (URI documentUri, Object document, SchemaVersion
5454
return new Scope (documentUri, Uris.resolve(documentUri, id), version);
5555
}
5656

57+
public static Scope createScope (URI documentUri, @Nullable URI baseUri, SchemaVersion version) {
58+
return new Scope (documentUri, baseUri, version);
59+
}
60+
5761
/**
5862
* create the scope for the {@code document}. If {@code document} contains an id, it is the base uri, otherwise the
5963
* scope is the {@code documentUri}. If the {@code documentUri} matches a know json schema the result scope will use

json-schema-validator/src/test/kotlin/io/openapiprocessor/jsonschema/schema/ResolverSpec.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,4 +182,22 @@ class ResolverSpec: StringSpec({
182182
resolver.resolve(URI("memory:/instant.yaml"), settings)
183183
}
184184
}
185+
186+
"baseUri customizer can change base uri" {
187+
Memory.add("/schema.yaml", "${'$'}self: /base.yaml")
188+
189+
val store = DocumentStore()
190+
val loader = DocumentLoader(UriReader(), JacksonConverter())
191+
192+
val settings = Resolver.Settings (SchemaVersion.Draft4)
193+
.baseUriCustomizer { documentUri, document ->
194+
URI.create("/base.yaml")
195+
}
196+
197+
val resolver = Resolver(store, loader)
198+
val result = resolver.resolve(URI("memory:/schema.yaml"), settings)
199+
200+
result.scope.documentUri shouldBe URI("memory:/schema.yaml")
201+
result.scope.baseUri shouldBe URI("memory:/base.yaml")
202+
}
185203
})

0 commit comments

Comments
 (0)