Search in sources :

Example 1 with CustomDefinition

use of com.github.victools.jsonschema.generator.CustomDefinition in project jsonschema-generator by victools.

the class SchemaGenerationContextImpl method populateMemberSchema.

/**
 * Preparation Step: combine the collected attributes and the javaType's definition in the given targetNode.
 *
 * @param <M> type of target scope, i.e. either a field or method
 * @param scope field's type or method return value's type that should be represented by the given targetNode
 * @param targetNode node in the JSON schema that should represent the associated javaType and include the separately collected attributes
 * @param isNullable whether the field/method's return value the javaType refers to is allowed to be null in the declaringType
 * @param forceInlineDefinition whether to generate an inline definition without registering it in this context
 * @param collectedAttributes separately collected attribute for the field/method in their respective declaring type
 * @param ignoredDefinitionProvider first custom definition provider to ignore
 * @see #populateField(FieldScope, Map, Set)
 * @see #collectMethod(MethodScope, Map, Set)
 */
private <M extends MemberScope<?, ?>> void populateMemberSchema(M scope, ObjectNode targetNode, boolean isNullable, boolean forceInlineDefinition, ObjectNode collectedAttributes, CustomPropertyDefinitionProvider<M> ignoredDefinitionProvider) {
    final CustomDefinition customDefinition = this.generatorConfig.getCustomDefinition(scope, this, ignoredDefinitionProvider);
    if (customDefinition != null && customDefinition.isMeantToBeInline()) {
        targetNode.setAll(customDefinition.getValue());
        if (customDefinition.shouldIncludeAttributes()) {
            AttributeCollector.mergeMissingAttributes(targetNode, collectedAttributes);
            Set<String> allowedSchemaTypes = this.collectAllowedSchemaTypes(targetNode);
            ObjectNode typeAttributes = AttributeCollector.collectTypeAttributes(scope, this, allowedSchemaTypes);
            AttributeCollector.mergeMissingAttributes(targetNode, typeAttributes);
        }
        if (isNullable) {
            this.makeNullable(targetNode);
        }
    } else {
        // create an "allOf" wrapper for the attributes related to this particular field and its general type
        final ObjectNode referenceContainer;
        if (customDefinition != null && !customDefinition.shouldIncludeAttributes() || collectedAttributes == null || collectedAttributes.size() == 0) {
            // no need for the allOf, can use the sub-schema instance directly as reference
            referenceContainer = targetNode;
        } else if (customDefinition == null && scope.isContainerType()) {
            // same as above, but the collected attributes should be applied also for containers/arrays
            referenceContainer = targetNode;
            AttributeCollector.mergeMissingAttributes(targetNode, collectedAttributes);
        } else {
            // avoid mixing potential "$ref" element with contextual attributes by introducing an "allOf" wrapper
            // this is only relevant for DRAFT_7 and is being cleaned-up afterwards for newer DRAFT versions
            referenceContainer = this.generatorConfig.createObjectNode();
            targetNode.set(this.getKeyword(SchemaKeyword.TAG_ALLOF), this.generatorConfig.createArrayNode().add(referenceContainer).add(collectedAttributes));
        }
        // only add reference for separate definition if it is not a fixed type that should be in-lined
        try {
            this.traverseGenericType(scope, referenceContainer, isNullable, forceInlineDefinition, null);
        } catch (UnsupportedOperationException ex) {
            logger.warn("Skipping type definition due to error", ex);
        }
    }
}
Also used : CustomDefinition(com.github.victools.jsonschema.generator.CustomDefinition) ObjectNode(com.fasterxml.jackson.databind.node.ObjectNode)

Example 2 with CustomDefinition

use of com.github.victools.jsonschema.generator.CustomDefinition in project jsonschema-generator by victools.

the class SchemaGenerationContextImpl method traverseGenericType.

/**
 * Preparation Step: add the given targetType. Also catering for forced inline-definitions and ignoring custom definitions
 *
 * @param scope targeted scope to add
 * @param targetNode node in the JSON schema that should represent the targetType
 * @param isNullable whether the field/method's return value is allowed to be null in the declaringType in this particular scenario
 * @param forceInlineDefinition whether to generate an inline definition without registering it in this context
 * @param ignoredDefinitionProvider first custom definition provider to ignore
 */
private void traverseGenericType(TypeScope scope, ObjectNode targetNode, boolean isNullable, boolean forceInlineDefinition, CustomDefinitionProviderV2 ignoredDefinitionProvider) {
    ResolvedType targetType = scope.getType();
    if (!forceInlineDefinition && this.containsDefinition(targetType, ignoredDefinitionProvider)) {
        logger.debug("adding reference to existing definition of {}", targetType);
        this.addReference(targetType, targetNode, ignoredDefinitionProvider, isNullable);
        // nothing more to be done
        return;
    }
    final ObjectNode definition;
    final boolean includeTypeAttributes;
    final CustomDefinition customDefinition = this.generatorConfig.getCustomDefinition(targetType, this, ignoredDefinitionProvider);
    if (customDefinition != null && (customDefinition.isMeantToBeInline() || forceInlineDefinition)) {
        includeTypeAttributes = customDefinition.shouldIncludeAttributes();
        if (targetNode == null) {
            logger.debug("storing configured custom inline type for {} as definition (since it is the main schema \"#\")", targetType);
            definition = customDefinition.getValue();
            this.putDefinition(targetType, definition, ignoredDefinitionProvider);
        // targetNode will be populated at the end, in buildDefinitionsAndResolveReferences()
        } else {
            logger.debug("directly applying configured custom inline type for {}", targetType);
            targetNode.setAll(customDefinition.getValue());
            definition = targetNode;
        }
        if (isNullable) {
            this.makeNullable(definition);
        }
    } else {
        boolean isContainerType = this.typeContext.isContainerType(targetType);
        if (forceInlineDefinition || isContainerType && targetNode != null && customDefinition == null) {
            // always inline array types
            definition = targetNode;
        } else {
            definition = this.generatorConfig.createObjectNode();
            this.putDefinition(targetType, definition, ignoredDefinitionProvider);
            if (targetNode != null) {
                // targetNode is only null for the main class for which the schema is being generated
                this.addReference(targetType, targetNode, ignoredDefinitionProvider, isNullable);
            }
        }
        if (customDefinition != null) {
            logger.debug("applying configured custom definition for {}", targetType);
            definition.setAll(customDefinition.getValue());
            includeTypeAttributes = customDefinition.shouldIncludeAttributes();
        } else if (isContainerType) {
            logger.debug("generating array definition for {}", targetType);
            this.generateArrayDefinition(scope, definition, isNullable);
            includeTypeAttributes = true;
        } else {
            logger.debug("generating definition for {}", targetType);
            includeTypeAttributes = !this.addSubtypeReferencesInDefinition(targetType, definition);
        }
    }
    if (includeTypeAttributes) {
        Set<String> allowedSchemaTypes = this.collectAllowedSchemaTypes(definition);
        ObjectNode typeAttributes = AttributeCollector.collectTypeAttributes(scope, this, allowedSchemaTypes);
        // ensure no existing attributes in the 'definition' are replaced, by way of first overriding any conflicts the other way around
        typeAttributes.setAll(definition);
        // apply merged attributes
        definition.setAll(typeAttributes);
    }
    // apply overrides as the very last step
    this.generatorConfig.getTypeAttributeOverrides().forEach(override -> override.overrideTypeAttributes(definition, scope, this));
}
Also used : CustomDefinition(com.github.victools.jsonschema.generator.CustomDefinition) ObjectNode(com.fasterxml.jackson.databind.node.ObjectNode) ResolvedType(com.fasterxml.classmate.ResolvedType)

Example 3 with CustomDefinition

use of com.github.victools.jsonschema.generator.CustomDefinition in project jsonschema-generator by victools.

the class InlineSchemaModule method provideCustomSchemaDefinition.

@Override
public CustomDefinition provideCustomSchemaDefinition(ResolvedType javaType, SchemaGenerationContext context) {
    if (this.declaringTypes.contains(javaType)) {
        throw new IllegalArgumentException("Option.INLINE_ALL_SCHEMAS cannot be fulfilled due to a circular reference to " + context.getTypeContext().getFullTypeDescription(javaType));
    }
    if (context.getTypeContext().isContainerType(javaType)) {
        // container types are being in-lined by default and only handle container-item-scope if the container itself is not a custom definition
        return null;
    }
    this.declaringTypes.addLast(javaType);
    ObjectNode definition = context.createStandardDefinition(javaType, this);
    this.declaringTypes.removeLast();
    return new CustomDefinition(definition, true);
}
Also used : CustomDefinition(com.github.victools.jsonschema.generator.CustomDefinition) ObjectNode(com.fasterxml.jackson.databind.node.ObjectNode)

Example 4 with CustomDefinition

use of com.github.victools.jsonschema.generator.CustomDefinition in project jsonschema-generator by victools.

the class JsonSubTypesResolver method provideCustomSchemaDefinition.

/*
     * Providing custom schema definition for subtype.
     */
@Override
public CustomDefinition provideCustomSchemaDefinition(ResolvedType javaType, SchemaGenerationContext context) {
    Class<?> typeWithTypeInfo = this.getTypeDeclaringJsonTypeInfoAnnotation(javaType.getErasedType());
    if (typeWithTypeInfo == null || javaType.getErasedType().getAnnotation(JsonSubTypes.class) != null) {
        // no @JsonTypeInfo annotation found or the given javaType is the super type, that should be replaced
        return null;
    }
    JsonTypeInfo typeInfoAnnotation = typeWithTypeInfo.getAnnotation(JsonTypeInfo.class);
    JsonSubTypes subTypesAnnotation = typeWithTypeInfo.getAnnotation(JsonSubTypes.class);
    ObjectNode definition = this.createSubtypeDefinition(javaType, typeInfoAnnotation, subTypesAnnotation, null, context);
    if (definition == null) {
        return null;
    }
    return new CustomDefinition(definition, CustomDefinition.DefinitionType.STANDARD, CustomDefinition.AttributeInclusion.NO);
}
Also used : JsonSubTypes(com.fasterxml.jackson.annotation.JsonSubTypes) CustomDefinition(com.github.victools.jsonschema.generator.CustomDefinition) ObjectNode(com.fasterxml.jackson.databind.node.ObjectNode) JsonTypeInfo(com.fasterxml.jackson.annotation.JsonTypeInfo)

Example 5 with CustomDefinition

use of com.github.victools.jsonschema.generator.CustomDefinition in project jsonschema-generator by victools.

the class CustomEnumDefinitionProviderTest method testProvideCustomSchemaDefinition_withConst.

@Test
@Parameters(method = "parametersForTestProvideCustomSchemaDefinition")
public void testProvideCustomSchemaDefinition_withConst(Class<?> erasedType, boolean considerJsonValue, boolean considerJsonProperty, List<String> values) {
    Mockito.when(this.generationContext.getGeneratorConfig().shouldRepresentSingleAllowedValueAsConst()).thenReturn(true);
    ResolvedType type = this.typeContext.resolve(erasedType);
    CustomDefinition result = new CustomEnumDefinitionProvider(considerJsonValue, considerJsonProperty).provideCustomSchemaDefinition(type, this.generationContext);
    Assert.assertNotNull(result);
    Assert.assertFalse(result.isMeantToBeInline());
    ObjectNode customDefinitionNode = result.getValue();
    Assert.assertEquals(2, customDefinitionNode.size());
    Assert.assertEquals(SchemaKeyword.TAG_TYPE_STRING.forVersion(SchemaVersion.DRAFT_2019_09), customDefinitionNode.get(SchemaKeyword.TAG_TYPE.forVersion(SchemaVersion.DRAFT_2019_09)).asText());
    int expectedValueCount = values.size();
    if (expectedValueCount == 1) {
        JsonNode constNode = customDefinitionNode.get(SchemaKeyword.TAG_CONST.forVersion(SchemaVersion.DRAFT_2019_09));
        Assert.assertTrue(constNode.isTextual());
        Assert.assertEquals(values.get(0), constNode.asText());
    } else {
        JsonNode enumNode = customDefinitionNode.get(SchemaKeyword.TAG_ENUM.forVersion(SchemaVersion.DRAFT_2019_09));
        Assert.assertTrue(enumNode.isArray());
        ArrayNode arrayNode = (ArrayNode) enumNode;
        Assert.assertEquals(expectedValueCount, arrayNode.size());
        for (int index = 0; index < expectedValueCount; index++) {
            Assert.assertEquals(values.get(index), arrayNode.get(index).asText());
        }
    }
}
Also used : CustomDefinition(com.github.victools.jsonschema.generator.CustomDefinition) ObjectNode(com.fasterxml.jackson.databind.node.ObjectNode) JsonNode(com.fasterxml.jackson.databind.JsonNode) ArrayNode(com.fasterxml.jackson.databind.node.ArrayNode) ResolvedType(com.fasterxml.classmate.ResolvedType) Parameters(junitparams.Parameters) Test(org.junit.Test)

Aggregations

CustomDefinition (com.github.victools.jsonschema.generator.CustomDefinition)19 Test (org.junit.Test)14 ObjectNode (com.fasterxml.jackson.databind.node.ObjectNode)13 ResolvedType (com.fasterxml.classmate.ResolvedType)12 Parameters (junitparams.Parameters)9 AbstractTypeAwareTest (com.github.victools.jsonschema.generator.AbstractTypeAwareTest)8 FieldScope (com.github.victools.jsonschema.generator.FieldScope)6 JsonNode (com.fasterxml.jackson.databind.JsonNode)5 MethodScope (com.github.victools.jsonschema.generator.MethodScope)5 ArrayNode (com.fasterxml.jackson.databind.node.ArrayNode)4 CustomDefinitionProviderV2 (com.github.victools.jsonschema.generator.CustomDefinitionProviderV2)3 ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper)2 CustomPropertyDefinition (com.github.victools.jsonschema.generator.CustomPropertyDefinition)2 InstanceAttributeOverrideV2 (com.github.victools.jsonschema.generator.InstanceAttributeOverrideV2)2 Option (com.github.victools.jsonschema.generator.Option)2 SchemaGeneratorConfigPart (com.github.victools.jsonschema.generator.SchemaGeneratorConfigPart)2 SchemaGeneratorGeneralConfigPart (com.github.victools.jsonschema.generator.SchemaGeneratorGeneralConfigPart)2 SchemaVersion (com.github.victools.jsonschema.generator.SchemaVersion)2 TypeAttributeOverrideV2 (com.github.victools.jsonschema.generator.TypeAttributeOverrideV2)2 Arrays (java.util.Arrays)2