Search in sources :

Example 1 with SchemaGenerationContext

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;
}
Also used : TypeContext(com.github.victools.jsonschema.generator.TypeContext) FieldScope(com.github.victools.jsonschema.generator.FieldScope) MethodScope(com.github.victools.jsonschema.generator.MethodScope) JsonSubTypes(com.fasterxml.jackson.annotation.JsonSubTypes) SubtypeResolver(com.github.victools.jsonschema.generator.SubtypeResolver) MemberScope(com.github.victools.jsonschema.generator.MemberScope) SchemaGenerationContext(com.github.victools.jsonschema.generator.SchemaGenerationContext) ResolvedType(com.fasterxml.classmate.ResolvedType) AttributeCollector(com.github.victools.jsonschema.generator.impl.AttributeCollector) Collectors(java.util.stream.Collectors) ObjectNode(com.fasterxml.jackson.databind.node.ObjectNode) ArrayNode(com.fasterxml.jackson.databind.node.ArrayNode) JsonTypeName(com.fasterxml.jackson.annotation.JsonTypeName) List(java.util.List) CustomDefinition(com.github.victools.jsonschema.generator.CustomDefinition) Stream(java.util.stream.Stream) JsonTypeInfo(com.fasterxml.jackson.annotation.JsonTypeInfo) CustomPropertyDefinition(com.github.victools.jsonschema.generator.CustomPropertyDefinition) CustomDefinitionProviderV2(com.github.victools.jsonschema.generator.CustomDefinitionProviderV2) Optional(java.util.Optional) SchemaKeyword(com.github.victools.jsonschema.generator.SchemaKeyword) ObjectNode(com.fasterxml.jackson.databind.node.ObjectNode) ArrayNode(com.fasterxml.jackson.databind.node.ArrayNode)

Example 2 with SchemaGenerationContext

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);
    }
}
Also used : Option(com.github.victools.jsonschema.generator.Option) TRUNCATE_EXISTING(java.nio.file.StandardOpenOption.TRUNCATE_EXISTING) SchemaGeneratorConfigBuilder(com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder) JReleaserModel(org.jreleaser.model.JReleaserModel) ResolvedType(com.fasterxml.classmate.ResolvedType) SchemaVersion(com.github.victools.jsonschema.generator.SchemaVersion) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) JsonNode(com.fasterxml.jackson.databind.JsonNode) Collections.singletonMap(java.util.Collections.singletonMap) Path(java.nio.file.Path) CommandLine(picocli.CommandLine) WRITE(java.nio.file.StandardOpenOption.WRITE) Files(java.nio.file.Files) OptionPreset(com.github.victools.jsonschema.generator.OptionPreset) SchemaGenerationContext(com.github.victools.jsonschema.generator.SchemaGenerationContext) DefinitionKey(com.github.victools.jsonschema.generator.impl.DefinitionKey) SchemaGenerator(com.github.victools.jsonschema.generator.SchemaGenerator) DefaultSchemaDefinitionNamingStrategy(com.github.victools.jsonschema.generator.naming.DefaultSchemaDefinitionNamingStrategy) JReleaserVersion(org.jreleaser.model.JReleaserVersion) Paths(java.nio.file.Paths) SchemaGeneratorConfig(com.github.victools.jsonschema.generator.SchemaGeneratorConfig) CREATE(java.nio.file.StandardOpenOption.CREATE) JReleaserException(org.jreleaser.util.JReleaserException) SerializationFeature(com.fasterxml.jackson.databind.SerializationFeature) JacksonModule(com.github.victools.jsonschema.module.jackson.JacksonModule) Path(java.nio.file.Path) SchemaGenerationContext(com.github.victools.jsonschema.generator.SchemaGenerationContext) SchemaGenerator(com.github.victools.jsonschema.generator.SchemaGenerator) JsonNode(com.fasterxml.jackson.databind.JsonNode) DefaultSchemaDefinitionNamingStrategy(com.github.victools.jsonschema.generator.naming.DefaultSchemaDefinitionNamingStrategy) JacksonModule(com.github.victools.jsonschema.module.jackson.JacksonModule) JReleaserException(org.jreleaser.util.JReleaserException) LinkedHashMap(java.util.LinkedHashMap) JReleaserException(org.jreleaser.util.JReleaserException) SchemaGeneratorConfig(com.github.victools.jsonschema.generator.SchemaGeneratorConfig) SchemaGeneratorConfigBuilder(com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder) JReleaserModel(org.jreleaser.model.JReleaserModel) DefinitionKey(com.github.victools.jsonschema.generator.impl.DefinitionKey) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) Collections.singletonMap(java.util.Collections.singletonMap) ResolvedType(com.fasterxml.classmate.ResolvedType)

Example 3 with SchemaGenerationContext

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());
}
Also used : SchemaGenerationContext(com.github.victools.jsonschema.generator.SchemaGenerationContext) ResolvedType(com.fasterxml.classmate.ResolvedType) Parameters(junitparams.Parameters) Test(org.junit.Test)

Example 4 with SchemaGenerationContext

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_" } };
}
Also used : TypeContext(com.github.victools.jsonschema.generator.TypeContext) AfterClass(org.junit.AfterClass) TypeContextFactory(com.github.victools.jsonschema.generator.impl.TypeContextFactory) RunWith(org.junit.runner.RunWith) SchemaGenerationContext(com.github.victools.jsonschema.generator.SchemaGenerationContext) DefinitionKey(com.github.victools.jsonschema.generator.impl.DefinitionKey) Test(org.junit.Test) ResolvedType(com.fasterxml.classmate.ResolvedType) PropertyNamingStrategies(com.fasterxml.jackson.databind.PropertyNamingStrategies) BigDecimal(java.math.BigDecimal) Mockito(org.mockito.Mockito) SchemaCleanUpUtils(com.github.victools.jsonschema.generator.impl.SchemaCleanUpUtils) Map(java.util.Map) JUnitParamsRunner(junitparams.JUnitParamsRunner) Assert(org.junit.Assert) NamingBase(com.fasterxml.jackson.databind.PropertyNamingStrategies.NamingBase) TestCaseName(junitparams.naming.TestCaseName) Parameters(junitparams.Parameters) Before(org.junit.Before) SchemaGenerationContext(com.github.victools.jsonschema.generator.SchemaGenerationContext) NamingBase(com.fasterxml.jackson.databind.PropertyNamingStrategies.NamingBase) DefinitionKey(com.github.victools.jsonschema.generator.impl.DefinitionKey) Map(java.util.Map) BigDecimal(java.math.BigDecimal)

Example 5 with SchemaGenerationContext

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);
    }
}
Also used : Arrays(java.util.Arrays) MemberScope(com.github.victools.jsonschema.generator.MemberScope) SchemaGeneratorGeneralConfigPart(com.github.victools.jsonschema.generator.SchemaGeneratorGeneralConfigPart) SchemaGeneratorConfigBuilder(com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder) ResolvedType(com.fasterxml.classmate.ResolvedType) Function(java.util.function.Function) ObjectNode(com.fasterxml.jackson.databind.node.ObjectNode) HashSet(java.util.HashSet) Module(com.github.victools.jsonschema.generator.Module) BigDecimal(java.math.BigDecimal) CustomDefinition(com.github.victools.jsonschema.generator.CustomDefinition) ConfigFunction(com.github.victools.jsonschema.generator.ConfigFunction) Schema(io.swagger.v3.oas.annotations.media.Schema) SchemaGeneratorConfigPart(com.github.victools.jsonschema.generator.SchemaGeneratorConfigPart) Predicate(java.util.function.Predicate) SchemaGenerationContext(com.github.victools.jsonschema.generator.SchemaGenerationContext) Set(java.util.Set) TypeScope(com.github.victools.jsonschema.generator.TypeScope) ArrayNode(com.fasterxml.jackson.databind.node.ArrayNode) ArraySchema(io.swagger.v3.oas.annotations.media.ArraySchema) List(java.util.List) Stream(java.util.stream.Stream) CustomPropertyDefinition(com.github.victools.jsonschema.generator.CustomPropertyDefinition) Optional(java.util.Optional) Collections(java.util.Collections) SchemaKeyword(com.github.victools.jsonschema.generator.SchemaKeyword) Schema(io.swagger.v3.oas.annotations.media.Schema) ArraySchema(io.swagger.v3.oas.annotations.media.ArraySchema) ArrayNode(com.fasterxml.jackson.databind.node.ArrayNode) HashSet(java.util.HashSet)

Aggregations

ResolvedType (com.fasterxml.classmate.ResolvedType)6 SchemaGenerationContext (com.github.victools.jsonschema.generator.SchemaGenerationContext)6 TypeContext (com.github.victools.jsonschema.generator.TypeContext)3 List (java.util.List)3 ArrayNode (com.fasterxml.jackson.databind.node.ArrayNode)2 ObjectNode (com.fasterxml.jackson.databind.node.ObjectNode)2 CustomDefinition (com.github.victools.jsonschema.generator.CustomDefinition)2 CustomPropertyDefinition (com.github.victools.jsonschema.generator.CustomPropertyDefinition)2 MemberScope (com.github.victools.jsonschema.generator.MemberScope)2 SchemaGeneratorConfigBuilder (com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder)2 SchemaKeyword (com.github.victools.jsonschema.generator.SchemaKeyword)2 SubtypeResolver (com.github.victools.jsonschema.generator.SubtypeResolver)2 DefinitionKey (com.github.victools.jsonschema.generator.impl.DefinitionKey)2 Schema (io.swagger.v3.oas.annotations.media.Schema)2 BigDecimal (java.math.BigDecimal)2 Map (java.util.Map)2 Optional (java.util.Optional)2 Collectors (java.util.stream.Collectors)2 Stream (java.util.stream.Stream)2 Parameters (junitparams.Parameters)2