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);
}
}
}
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));
}
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);
}
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);
}
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());
}
}
}
Aggregations