use of com.github.victools.jsonschema.generator.SchemaGenerationContext in project jsonschema-generator by victools.
the class JsonSubTypesResolver method createSubtypeDefinition.
/**
* Create the custom schema definition for the given subtype, considering the {@link JsonTypeInfo#include()} setting.
*
* @param javaType targeted subtype
* @param typeInfoAnnotation annotation for looking up the type identifier and determining the kind of inclusion/serialization
* @param subTypesAnnotation annotation specifying the mapping from super to subtypes (potentially including the discriminator values)
* @param attributesToInclude optional: additional attributes to include on the actual/contained schema definition
* @param context generation context
* @return created custom definition (or {@code null} if no supported subtype resolution scenario could be detected
*/
private ObjectNode createSubtypeDefinition(ResolvedType javaType, JsonTypeInfo typeInfoAnnotation, JsonSubTypes subTypesAnnotation, ObjectNode attributesToInclude, SchemaGenerationContext context) {
final String typeIdentifier = this.getTypeIdentifier(javaType, typeInfoAnnotation, subTypesAnnotation);
if (typeIdentifier == null) {
return null;
}
final ObjectNode definition = context.getGeneratorConfig().createObjectNode();
switch(typeInfoAnnotation.include()) {
case WRAPPER_ARRAY:
definition.put(context.getKeyword(SchemaKeyword.TAG_TYPE), context.getKeyword(SchemaKeyword.TAG_TYPE_ARRAY));
ArrayNode itemsArray = definition.withArray(context.getKeyword(SchemaKeyword.TAG_ITEMS));
itemsArray.addObject().put(context.getKeyword(SchemaKeyword.TAG_TYPE), context.getKeyword(SchemaKeyword.TAG_TYPE_STRING)).put(context.getKeyword(SchemaKeyword.TAG_CONST), typeIdentifier);
if (attributesToInclude == null || attributesToInclude.isEmpty()) {
itemsArray.add(context.createStandardDefinitionReference(javaType, this));
} else {
itemsArray.addObject().withArray(context.getKeyword(SchemaKeyword.TAG_ALLOF)).add(context.createStandardDefinitionReference(javaType, this)).add(attributesToInclude);
}
break;
case WRAPPER_OBJECT:
definition.put(context.getKeyword(SchemaKeyword.TAG_TYPE), context.getKeyword(SchemaKeyword.TAG_TYPE_OBJECT));
ObjectNode propertiesNode = definition.with(context.getKeyword(SchemaKeyword.TAG_PROPERTIES));
if (attributesToInclude == null || attributesToInclude.isEmpty()) {
propertiesNode.set(typeIdentifier, context.createStandardDefinitionReference(javaType, this));
} else {
propertiesNode.with(typeIdentifier).withArray(context.getKeyword(SchemaKeyword.TAG_ALLOF)).add(context.createStandardDefinitionReference(javaType, this)).add(attributesToInclude);
}
definition.withArray(context.getKeyword(SchemaKeyword.TAG_REQUIRED)).add(typeIdentifier);
break;
case PROPERTY:
case EXISTING_PROPERTY:
final String propertyName = Optional.ofNullable(typeInfoAnnotation.property()).filter(name -> !name.isEmpty()).orElseGet(() -> typeInfoAnnotation.use().getDefaultPropertyName());
ObjectNode additionalPart = definition.withArray(context.getKeyword(SchemaKeyword.TAG_ALLOF)).add(context.createStandardDefinitionReference(javaType, this)).addObject();
if (attributesToInclude != null && !attributesToInclude.isEmpty()) {
additionalPart.setAll(attributesToInclude);
}
additionalPart.put(context.getKeyword(SchemaKeyword.TAG_TYPE), context.getKeyword(SchemaKeyword.TAG_TYPE_OBJECT)).with(context.getKeyword(SchemaKeyword.TAG_PROPERTIES)).with(propertyName).put(context.getKeyword(SchemaKeyword.TAG_CONST), typeIdentifier);
additionalPart.withArray(context.getKeyword(SchemaKeyword.TAG_REQUIRED)).add(propertyName);
break;
default:
return null;
}
return definition;
}
use of com.github.victools.jsonschema.generator.SchemaGenerationContext in project jreleaser by jreleaser.
the class JsonSchema method execute.
protected void execute() {
Map<String, String> mappings = new LinkedHashMap<>();
mappings.put("Map<String, Object>", "Properties");
mappings.put("Map<String, String>", "StringProperties");
mappings.put("Map<String, Webhook>", "WebhookMap");
mappings.put("Map<String, Archive>", "ArchiveMap");
mappings.put("Map<String, Jlink>", "JlinkMap");
mappings.put("Map<String, Jpackage>", "JpackageMap");
mappings.put("Map<String, NativeImage>", "NativeImageMap");
mappings.put("Map<String, Distribution>", "DistributionMap");
mappings.put("Map<String, DockerSpec>", "DockerSpecMap");
mappings.put("Map<String, Artifactory>", "ArtifactoryMap");
mappings.put("Map<String, Http>", "HttpMap");
mappings.put("Map<String, S3>", "S3Map");
try {
SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2019_09, OptionPreset.PLAIN_JSON);
configBuilder.getObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
configBuilder.with(Option.FORBIDDEN_ADDITIONAL_PROPERTIES_BY_DEFAULT);
configBuilder.with(Option.DEFINITION_FOR_MAIN_SCHEMA);
configBuilder.with(Option.DEFINITIONS_FOR_ALL_OBJECTS);
JacksonModule jacksonModule = new JacksonModule();
configBuilder.with(jacksonModule);
configBuilder.forTypesInGeneral().withDescriptionResolver(scope -> scope.getType().getErasedType() == JReleaserModel.class ? String.format("JReleaser %s", JReleaserVersion.getPlainVersion()) : null).withPatternPropertiesResolver(scope -> {
if (scope.getType().isInstanceOf(Map.class)) {
ResolvedType type = scope.getTypeParameterFor(Map.class, 1);
if (type.getErasedType() != String.class && type.getErasedType() != Object.class) {
return singletonMap("^[a-zA-Z-]+$", type);
}
}
return null;
}).withAdditionalPropertiesResolver(scope -> {
if (scope.getType().isInstanceOf(Map.class)) {
ResolvedType type = scope.getTypeParameterFor(Map.class, 1);
if (type.getErasedType() == String.class || type.getErasedType() == Object.class) {
return scope.getTypeParameterFor(Map.class, 0);
}
}
return null;
}).withDefinitionNamingStrategy(new DefaultSchemaDefinitionNamingStrategy() {
@Override
public String getDefinitionNameForKey(DefinitionKey key, SchemaGenerationContext context) {
String definitionNameForKey = super.getDefinitionNameForKey(key, context);
return mappings.getOrDefault(definitionNameForKey, definitionNameForKey);
}
});
SchemaGeneratorConfig config = configBuilder.build();
SchemaGenerator generator = new SchemaGenerator(config);
JsonNode jsonSchema = generator.generateSchema(JReleaserModel.class);
String fileName = String.format("jreleaser-%s-schema.json", JReleaserVersion.getPlainVersion());
Path schemaPath = Paths.get(fileName);
String json = configBuilder.getObjectMapper().writeValueAsString(jsonSchema);
Files.write(schemaPath, json.getBytes(), CREATE, WRITE, TRUNCATE_EXISTING);
parent().out.println("Schema written to " + schemaPath.toAbsolutePath());
} catch (Exception e) {
throw new JReleaserException($("ERROR_unexpected_error"), e);
}
}
use of com.github.victools.jsonschema.generator.SchemaGenerationContext in project jsonschema-generator by victools.
the class AttributeCollectorTest method testSetAdditionalProperties_ResolvedObjectClass.
@Test
@Parameters(source = SchemaVersion.class)
public void testSetAdditionalProperties_ResolvedObjectClass(SchemaVersion schemaVersion) {
SchemaGenerationContext generationContext = this.generateContext(schemaVersion);
ResolvedType resolvedObjectClass = generationContext.getTypeContext().resolve(Object.class);
this.collector.setAdditionalProperties(this.definitionNode, resolvedObjectClass, generationContext);
Assert.assertTrue(this.definitionNode.isEmpty());
}
use of com.github.victools.jsonschema.generator.SchemaGenerationContext in project jsonschema-generator by victools.
the class SchemaDefinitionNamingStrategyTest method parametersForTestExampleStrategy.
public Object[] parametersForTestExampleStrategy() {
NamingBase jacksonSnakeCase = (NamingBase) PropertyNamingStrategies.SNAKE_CASE;
SchemaDefinitionNamingStrategy snakeCase = new DefaultSchemaDefinitionNamingStrategy() {
@Override
public String getDefinitionNameForKey(DefinitionKey key, SchemaGenerationContext generationContext) {
return jacksonSnakeCase.translate(super.getDefinitionNameForKey(key, generationContext)).replaceAll("<_", "<").replaceAll(", _", ",");
}
};
NamingBase jacksonDotCase = (NamingBase) PropertyNamingStrategies.LOWER_DOT_CASE;
SchemaDefinitionNamingStrategy dotCase = new DefaultSchemaDefinitionNamingStrategy() {
@Override
public String getDefinitionNameForKey(DefinitionKey key, SchemaGenerationContext generationContext) {
return jacksonDotCase.translate(super.getDefinitionNameForKey(key, generationContext)).replaceAll("<.", "<").replaceAll(", .", "-");
}
};
SchemaDefinitionNamingStrategy inclPackage = (definitionKey, context) -> context.getTypeContext().getFullTypeDescription(definitionKey.getType());
return new Object[][] { { "Snake Case", snakeCase, typeContext.resolve(BigDecimal.class), "big_decimal", "big_decimal" }, { "Snake Case", snakeCase, typeContext.resolve(Map.class, String.class, BigDecimal.class), "map(string,big_decimal)", "map_string.big_decimal_" }, { "Dot Case", dotCase, typeContext.resolve(BigDecimal.class), "big.decimal", "big.decimal" }, { "Dot Case", dotCase, typeContext.resolve(Map.class, String.class, BigDecimal.class), "map(string-big.decimal)", "map_string-big.decimal_" }, { "Incl. Package", inclPackage, typeContext.resolve(BigDecimal.class), "java.math.BigDecimal", "java.math.BigDecimal" }, { "Incl. Package", inclPackage, typeContext.resolve(Map.class, String.class, BigDecimal.class), "java.util.Map(java.lang.String,java.math.BigDecimal)", "java.util.Map_java.lang.String.java.math.BigDecimal_" } };
}
use of com.github.victools.jsonschema.generator.SchemaGenerationContext in project jsonschema-generator by victools.
the class Swagger2Module method overrideInstanceAttributes.
/**
* Consider various remaining aspects.
* <ul>
* <li>{@code @Schema(not = ...)}</li>
* <li>{@code @Schema(allOf = ...)}</li>
* <li>{@code @Schema(minProperties = ...)}</li>
* <li>{@code @Schema(maxProperties = ...)}</li>
* <li>{@code @Schema(requiredProperties = ...)}</li>
* </ul>
*
* @param memberAttributes already collected schema for the field/method
* @param member targeted field/method
* @param context generation context
*/
protected void overrideInstanceAttributes(ObjectNode memberAttributes, MemberScope<?, ?> member, SchemaGenerationContext context) {
Schema annotation = this.getSchemaAnnotationValue(member, Function.identity(), x -> true).orElse(null);
if (annotation == null) {
return;
}
if (annotation.not() != Void.class) {
memberAttributes.set(context.getKeyword(SchemaKeyword.TAG_NOT), context.createDefinitionReference(context.getTypeContext().resolve(annotation.not())));
}
if (annotation.allOf().length > 0) {
Stream.of(annotation.allOf()).map(rawType -> context.getTypeContext().resolve(rawType)).map(context::createDefinitionReference).forEach(memberAttributes.withArray(context.getKeyword(SchemaKeyword.TAG_ALLOF))::add);
}
if (annotation.minProperties() > 0) {
memberAttributes.put(context.getKeyword(SchemaKeyword.TAG_PROPERTIES_MIN), annotation.minProperties());
}
if (annotation.maxProperties() > 0) {
memberAttributes.put(context.getKeyword(SchemaKeyword.TAG_PROPERTIES_MAX), annotation.maxProperties());
}
if (annotation.requiredProperties().length > 0) {
Set<String> alreadyMentionedRequiredFields = new HashSet<>();
ArrayNode requiredFieldNames = memberAttributes.withArray(context.getKeyword(SchemaKeyword.TAG_REQUIRED));
requiredFieldNames.forEach(arrayItem -> alreadyMentionedRequiredFields.add(arrayItem.asText()));
Stream.of(annotation.requiredProperties()).filter(field -> !alreadyMentionedRequiredFields.contains(field)).forEach(requiredFieldNames::add);
}
}
Aggregations