Compare commits

...

3 Commits

2 changed files with 93 additions and 10 deletions

View File

@@ -81,7 +81,7 @@ public class JsonSchemaGenerator {
objectNode.put("type", "array");
}
replaceAnyOfWithOneOf(objectNode);
pullOfDefaultFromOneOf(objectNode);
pullDocumentationAndDefaultFromOneOf(objectNode);
removeRequiredOnPropsWithDefaults(objectNode);
return JacksonMapper.toMap(objectNode);
@@ -122,22 +122,35 @@ public class JsonSchemaGenerator {
// This hack exists because for Property we generate a oneOf for properties that are not strings.
// By default, the 'default' is in each oneOf which Monaco editor didn't take into account.
// So, we pull off the 'default' from any of the oneOf to the parent.
private void pullOfDefaultFromOneOf(ObjectNode objectNode) {
// same thing for documentation fields: 'title', 'description', '$deprecated'
private void pullDocumentationAndDefaultFromOneOf(ObjectNode objectNode) {
objectNode.findParents("oneOf").forEach(jsonNode -> {
if (jsonNode instanceof ObjectNode oNode) {
JsonNode oneOf = oNode.get("oneOf");
if (oneOf instanceof ArrayNode arrayNode) {
Iterator<JsonNode> it = arrayNode.elements();
JsonNode defaultNode = null;
while (it.hasNext() && defaultNode == null) {
var nodesToPullUp = new HashMap<String, Optional<JsonNode>>(Map.ofEntries(
Map.entry("default", Optional.empty()),
Map.entry("title", Optional.empty()),
Map.entry("description", Optional.empty()),
Map.entry("$deprecated", Optional.empty())
));
// find nodes to pull up
while (it.hasNext() && nodesToPullUp.containsValue(Optional.<JsonNode>empty())) {
JsonNode next = it.next();
if (next instanceof ObjectNode nextAsObj) {
defaultNode = nextAsObj.get("default");
nodesToPullUp.entrySet().stream()
.filter(node -> node.getValue().isEmpty())
.forEach(node -> node
.setValue(Optional.ofNullable(
nextAsObj.get(node.getKey())
)));
}
}
if (defaultNode != null) {
oNode.set("default", defaultNode);
}
// create nodes on parent
nodesToPullUp.entrySet().stream()
.filter(node -> node.getValue().isPresent())
.forEach(node -> oNode.set(node.getKey(), node.getValue().get()));
}
}
});
@@ -629,7 +642,7 @@ public class JsonSchemaGenerator {
try {
ObjectNode objectNode = generator.generateSchema(cls);
replaceAnyOfWithOneOf(objectNode);
pullOfDefaultFromOneOf(objectNode);
pullDocumentationAndDefaultFromOneOf(objectNode);
removeRequiredOnPropsWithDefaults(objectNode);
return JacksonMapper.toMap(extractMainRef(objectNode));

View File

@@ -249,6 +249,30 @@ class JsonSchemaGeneratorTest {
assertThat((List<String>) generate.get("required"), containsInAnyOrder("requiredWithNoDefault"));
}
@SuppressWarnings("unchecked")
@Test
void testDocumentation() {
Map<String, Object> generate = jsonSchemaGenerator.properties(Task.class, TaskWithDynamicDocumentedFields.class);
assertThat(generate, is(not(nullValue())));
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("stringProperty").get("title"), is("stringProperty title"));
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("stringProperty").get("description"), is("stringProperty description"));
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("stringProperty").get("$deprecated"), is(true));
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("integerProperty").get("title"), is("integerProperty title"));
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("integerProperty").get("description"), is("integerProperty description"));
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("integerProperty").get("$deprecated"), is(true));
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("stringPropertyWithDefault").get("title"), is("stringPropertyWithDefault title"));
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("stringPropertyWithDefault").get("description"), is("stringPropertyWithDefault description"));
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("stringPropertyWithDefault").get("$deprecated"), is(true));
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("stringPropertyWithDefault").get("default"), is("my string"));
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("integerPropertyWithDefault").get("title"), is("integerPropertyWithDefault title"));
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("integerPropertyWithDefault").get("description"), is("integerPropertyWithDefault description"));
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("integerPropertyWithDefault").get("$deprecated"), is(true));
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("integerPropertyWithDefault").get("default"), is("10000"));
}
@SuppressWarnings("unchecked")
@Test
void dashboard() throws URISyntaxException {
@@ -314,10 +338,11 @@ class JsonSchemaGeneratorTest {
private TestEnum testEnum;
@PluginProperty
@Schema(title = "Title from the attribute")
@Schema(title = "Title from the attribute", description = "Description from the attribute")
private TestClass testClass;
@PluginProperty(internalStorageURI = true)
@Schema(title = "Title from the attribute", description = "Description from the attribute")
private String uri;
@PluginProperty
@@ -392,4 +417,49 @@ class JsonSchemaGeneratorTest {
@NotNull
private Property<TaskWithEnum.TestClass> requiredWithNoDefault;
}
@SuperBuilder
@ToString
@EqualsAndHashCode
@Getter
@NoArgsConstructor
public static class TaskWithDynamicDocumentedFields extends Task implements RunnableTask<VoidOutput> {
@Deprecated(since="deprecation_version_1", forRemoval=true)
@Schema(
title = "integerPropertyWithDefault title",
description = "integerPropertyWithDefault description"
)
@Builder.Default
protected Property<Integer> integerPropertyWithDefault = Property.of(10000);
@Deprecated(since="deprecation_version_1", forRemoval=true)
@Schema(
title = "stringPropertyWithDefault title",
description = "stringPropertyWithDefault description"
)
@Builder.Default
protected Property<String> stringPropertyWithDefault = Property.of("my string");
@Deprecated(since="deprecation_version_1", forRemoval=true)
@Schema(
title = "stringProperty title",
description = "stringProperty description"
)
protected Property<String> stringProperty;
@Deprecated(since="deprecation_version_1", forRemoval=true)
@Schema(
title = "integerProperty title",
description = "integerProperty description"
)
protected Property<Integer> integerProperty;
@Override
public VoidOutput run(RunContext runContext) throws Exception {
return null;
}
}
}