Skip to content

Commit 3676bcb

Browse files
committed
Make dynamic schema conversion public
Various teams need to be able to access the underlying Shape->Schema conversion and WrappedDocuments.
1 parent 8a228cf commit 3676bcb

File tree

18 files changed

+154
-65
lines changed

18 files changed

+154
-65
lines changed

client/dynamic-client/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ extra["displayName"] = "Smithy :: Java :: Dynamic client"
88
extra["moduleName"] = "software.amazon.smithy.java.dynamicclient"
99

1010
dependencies {
11+
api(project(":dynamic-schemas"))
1112
api(project(":client:client-core"))
1213

1314
testImplementation(project(":aws:client:aws-client-restjson"))

client/dynamic-client/src/main/java/software/amazon/smithy/java/dynamicclient/DocumentException.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import software.amazon.smithy.java.core.serde.ShapeDeserializer;
1212
import software.amazon.smithy.java.core.serde.ShapeSerializer;
1313
import software.amazon.smithy.java.core.serde.document.Document;
14+
import software.amazon.smithy.java.dynamicschemas.SchemaConverter;
15+
import software.amazon.smithy.java.dynamicschemas.WrappedDocument;
1416
import software.amazon.smithy.model.shapes.ShapeId;
1517

1618
/**
@@ -52,11 +54,11 @@ public Document getContents() {
5254
static final class SchemaGuidedExceptionBuilder implements ShapeBuilder<ModeledException> {
5355

5456
private final Schema target;
55-
private final SchemaGuidedDocumentBuilder delegateBuilder;
57+
private final ShapeBuilder<WrappedDocument> delegateBuilder;
5658

5759
SchemaGuidedExceptionBuilder(ShapeId service, Schema target) {
5860
this.target = target;
59-
this.delegateBuilder = new SchemaGuidedDocumentBuilder(service, target);
61+
this.delegateBuilder = SchemaConverter.createDocumentBuilder(target, service);
6062
}
6163

6264
@Override

client/dynamic-client/src/main/java/software/amazon/smithy/java/dynamicclient/DynamicClient.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
import software.amazon.smithy.java.core.schema.SerializableStruct;
3030
import software.amazon.smithy.java.core.serde.TypeRegistry;
3131
import software.amazon.smithy.java.core.serde.document.Document;
32+
import software.amazon.smithy.java.dynamicschemas.SchemaConverter;
33+
import software.amazon.smithy.java.dynamicschemas.WrappedDocument;
3234
import software.amazon.smithy.model.Model;
3335
import software.amazon.smithy.model.knowledge.ServiceIndex;
3436
import software.amazon.smithy.model.knowledge.TopDownIndex;
@@ -176,7 +178,7 @@ public CompletableFuture<Document> callAsync(
176178
RequestOverrideConfig overrideConfig
177179
) {
178180
var apiOperation = getApiOperation(operation);
179-
var inputStruct = new WrappedDocument(service.getId(), apiOperation.inputSchema(), input);
181+
var inputStruct = new WrappedDocument(apiOperation.inputSchema(), input, service.getId());
180182
return call(inputStruct, apiOperation, overrideConfig).thenApply(Function.identity());
181183
}
182184

@@ -192,7 +194,7 @@ public SerializableStruct createStruct(ToShapeId shape, Document value) {
192194
if (value.type() != ShapeType.MAP && value.type() != ShapeType.STRUCTURE) {
193195
throw new IllegalArgumentException("Document value must be a map or structure, found " + value.type());
194196
}
195-
return new WrappedDocument(service.getId(), schema, value);
197+
return new WrappedDocument(schema, value, service.getId());
196198
}
197199

198200
private ApiOperation<WrappedDocument, WrappedDocument> getApiOperation(String name) {

client/dynamic-client/src/main/java/software/amazon/smithy/java/dynamicclient/DynamicOperation.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
import software.amazon.smithy.java.core.schema.ShapeBuilder;
1313
import software.amazon.smithy.java.core.schema.TraitKey;
1414
import software.amazon.smithy.java.core.serde.TypeRegistry;
15+
import software.amazon.smithy.java.dynamicschemas.SchemaConverter;
16+
import software.amazon.smithy.java.dynamicschemas.WrappedDocument;
1517
import software.amazon.smithy.model.shapes.ShapeId;
1618

1719
final class DynamicOperation implements ApiOperation<WrappedDocument, WrappedDocument> {
@@ -69,12 +71,12 @@ public Schema outputSchema() {
6971

7072
@Override
7173
public ShapeBuilder<WrappedDocument> inputBuilder() {
72-
return new SchemaGuidedDocumentBuilder(service, inputSchema());
74+
return SchemaConverter.createDocumentBuilder(inputSchema(), service);
7375
}
7476

7577
@Override
7678
public ShapeBuilder<WrappedDocument> outputBuilder() {
77-
return new SchemaGuidedDocumentBuilder(service, outputSchema());
79+
return SchemaConverter.createDocumentBuilder(outputSchema(), service);
7880
}
7981

8082
@Override

client/dynamic-client/src/test/java/software/amazon/smithy/java/dynamicclient/DynamicOperationTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.junit.jupiter.api.Test;
1818
import software.amazon.smithy.java.core.schema.TraitKey;
1919
import software.amazon.smithy.java.core.serde.TypeRegistry;
20+
import software.amazon.smithy.java.dynamicschemas.SchemaConverter;
2021
import software.amazon.smithy.model.Model;
2122
import software.amazon.smithy.model.shapes.ShapeId;
2223
import software.amazon.smithy.model.traits.DeprecatedTrait;

config/spotbugs/filter.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,12 @@
5252

5353
<Match>
5454
<Bug pattern="EQ_DOESNT_OVERRIDE_EQUALS"/>
55-
<Class name="software.amazon.smithy.java.dynamicclient.SchemaGuidedDocumentBuilder$SchemaList"/>
55+
<Class name="software.amazon.smithy.java.dynamicschemas.SchemaGuidedDocumentBuilder$SchemaList"/>
5656
</Match>
5757

5858
<Match>
5959
<Bug pattern="EQ_DOESNT_OVERRIDE_EQUALS"/>
60-
<Class name="software.amazon.smithy.java.dynamicclient.SchemaGuidedDocumentBuilder$SchemaMap"/>
60+
<Class name="software.amazon.smithy.java.dynamicschemas.SchemaGuidedDocumentBuilder$SchemaMap"/>
6161
</Match>
6262

6363
<Match>

dynamic-schemas/README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# dynamic-schemas
2+
3+
Can dynamically create a Smithy-Java `Schema` from a Smithy model `Shape` and
4+
can wrap a document to have it appear to be a typed value using a schema.
5+
6+
## Example usage
7+
8+
```java
9+
// (1) Load up a model
10+
var model = Model.assembler()
11+
.addImport("/path/to/model.json")
12+
.assemble()
13+
.unwrap();
14+
15+
// (2) Create a SchemaConverter
16+
var schemaConverter = new SchemaConverter(model);
17+
18+
// (3) Convert a Shape to a Schema
19+
var shape = model.expectShape(ShapeId.from("com.example#Foo"));
20+
var schema = schemaConverter.getSchema(shape);
21+
```

dynamic-schemas/build.gradle.kts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
plugins {
2+
id("smithy-java.module-conventions")
3+
}
4+
5+
description = "This module provides a way to dynamically create Smithy Java schemas from a model"
6+
7+
extra["displayName"] = "Smithy :: Java :: Dynamic Schemas"
8+
extra["moduleName"] = "software.amazon.smithy.java.dynamicschemas"
9+
10+
dependencies {
11+
api(project(":core"))
12+
}
Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
package software.amazon.smithy.java.dynamicclient;
6+
package software.amazon.smithy.java.dynamicschemas;
77

88
import java.util.Collections;
99
import java.util.HashMap;
@@ -14,23 +14,47 @@
1414
import java.util.concurrent.ConcurrentMap;
1515
import software.amazon.smithy.java.core.schema.Schema;
1616
import software.amazon.smithy.java.core.schema.SchemaBuilder;
17+
import software.amazon.smithy.java.core.schema.ShapeBuilder;
1718
import software.amazon.smithy.model.Model;
1819
import software.amazon.smithy.model.shapes.Shape;
1920
import software.amazon.smithy.model.shapes.ShapeId;
2021
import software.amazon.smithy.model.shapes.ShapeType;
2122
import software.amazon.smithy.model.traits.Trait;
2223

23-
final class SchemaConverter {
24+
/**
25+
* Converts {@link Shape}s to {@link Schema}s.
26+
*/
27+
public final class SchemaConverter {
2428

2529
private final Model model;
2630
private final ConcurrentMap<Shape, Schema> schemas = new ConcurrentHashMap<>();
2731
private final Map<Shape, SchemaBuilder> recursiveBuilders = Collections.synchronizedMap(new HashMap<>());
2832

29-
SchemaConverter(Model model) {
33+
/**
34+
* @param model Model used when converting shapes to schemas.
35+
*/
36+
public SchemaConverter(Model model) {
3037
this.model = model;
3138
}
3239

33-
Schema getSchema(Shape shape) {
40+
/**
41+
* Create a schema-guided document shape builder.
42+
*
43+
* @param schema Schema used to inform deserialization.
44+
* @param serviceId The shape ID of the service that is used to provide default namespaces for relative shape IDs.
45+
* @return the created shape builder.
46+
*/
47+
public static ShapeBuilder<WrappedDocument> createDocumentBuilder(Schema schema, ShapeId serviceId) {
48+
return new SchemaGuidedDocumentBuilder(schema, serviceId);
49+
}
50+
51+
/**
52+
* Get the converted {@link Schema} of a Smithy {@link Shape}.
53+
*
54+
* @param shape Shape to get the converted schema from.
55+
* @return the converted schema.
56+
*/
57+
public Schema getSchema(Shape shape) {
3458
// Aggregate shapes are re-entrant and may need to recursively set values in the CHM.
3559
var result = schemas.get(shape);
3660

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
package software.amazon.smithy.java.dynamicclient;
6+
package software.amazon.smithy.java.dynamicschemas;
77

88
import java.util.ArrayList;
99
import java.util.HashMap;
@@ -23,9 +23,9 @@ final class SchemaGuidedDocumentBuilder implements ShapeBuilder<WrappedDocument>
2323
private Document result;
2424
private final Map<String, Document> map;
2525

26-
SchemaGuidedDocumentBuilder(ShapeId service, Schema target) {
27-
this.service = service;
26+
SchemaGuidedDocumentBuilder(Schema target, ShapeId service) {
2827
this.target = target;
28+
this.service = service;
2929
this.map = switch (target.type()) {
3030
case STRUCTURE, UNION, MAP -> new HashMap<>();
3131
default -> null;
@@ -43,9 +43,9 @@ public WrappedDocument build() {
4343
if (map.isEmpty() && target.type() == ShapeType.UNION) {
4444
throw new IllegalArgumentException("No value set for union document: " + schema().id());
4545
}
46-
return new WrappedDocument(service, target, Document.of(map));
46+
return new WrappedDocument(target, Document.of(map), service);
4747
} else if (result != null) {
48-
return new WrappedDocument(service, target, result);
48+
return new WrappedDocument(target, result, service);
4949
} else {
5050
throw new IllegalArgumentException("No value was set on document builder for " + schema().id());
5151
}

0 commit comments

Comments
 (0)