Search in sources :

Example 1 with ModelConverterContext

use of io.swagger.v3.core.converter.ModelConverterContext in project swagger-core by swagger-api.

the class GericModelConverter method resolve.

@Override
public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterator<ModelConverter> next) {
    if (type.getType() instanceof Class<?>) {
        Class<?> cls = (Class<?>) type.getType();
        if (GenericModel.class.isAssignableFrom(cls)) {
            Schema impl = new Schema();
            impl.title(cls.getSimpleName());
            for (Entry<String, Class<?>> entry : GenericModel.getDeclaredProperties().entrySet()) {
                impl.addProperties(entry.getKey(), context.resolve(new AnnotatedType(entry.getValue())));
            }
            context.defineModel(impl.getTitle(), impl);
            return impl;
        }
    }
    if (next.hasNext()) {
        return next.next().resolve(type, context, next);
    } else {
        return null;
    }
}
Also used : AnnotatedType(io.swagger.v3.core.converter.AnnotatedType) Schema(io.swagger.v3.oas.models.media.Schema)

Example 2 with ModelConverterContext

use of io.swagger.v3.core.converter.ModelConverterContext in project swagger-core by swagger-api.

the class ModelResolver method resolveDiscriminator.

protected Discriminator resolveDiscriminator(JavaType type, ModelConverterContext context) {
    io.swagger.v3.oas.annotations.media.Schema declaredSchemaAnnotation = AnnotationsUtils.getSchemaDeclaredAnnotation(type.getRawClass());
    String disc = (declaredSchemaAnnotation == null) ? "" : declaredSchemaAnnotation.discriminatorProperty();
    if (disc.isEmpty()) {
        // longer method would involve AnnotationIntrospector.findTypeResolver(...) but:
        JsonTypeInfo typeInfo = type.getRawClass().getDeclaredAnnotation(JsonTypeInfo.class);
        if (typeInfo != null) {
            disc = typeInfo.property();
        }
    }
    if (!disc.isEmpty()) {
        Discriminator discriminator = new Discriminator().propertyName(disc);
        if (declaredSchemaAnnotation != null) {
            DiscriminatorMapping[] mappings = declaredSchemaAnnotation.discriminatorMapping();
            if (mappings != null && mappings.length > 0) {
                for (DiscriminatorMapping mapping : mappings) {
                    if (!mapping.value().isEmpty() && !mapping.schema().equals(Void.class)) {
                        discriminator.mapping(mapping.value(), constructRef(context.resolve(new AnnotatedType().type(mapping.schema())).getName()));
                    }
                }
            }
        }
        return discriminator;
    }
    return null;
}
Also used : DiscriminatorMapping(io.swagger.v3.oas.annotations.media.DiscriminatorMapping) AnnotatedType(io.swagger.v3.core.converter.AnnotatedType) JsonTypeInfo(com.fasterxml.jackson.annotation.JsonTypeInfo) Discriminator(io.swagger.v3.oas.models.media.Discriminator)

Example 3 with ModelConverterContext

use of io.swagger.v3.core.converter.ModelConverterContext in project swagger-core by swagger-api.

the class ModelResolver method resolveSchemaProperties.

protected Map<String, Schema> resolveSchemaProperties(JavaType a, Annotation[] annotations, ModelConverterContext context) {
    final Map<String, SchemaProperty> propList = new LinkedHashMap<>();
    SchemaProperties props = a.getRawClass().getAnnotation(SchemaProperties.class);
    if (props != null && props.value().length > 0) {
        for (SchemaProperty prop : props.value()) {
            propList.put(prop.name(), prop);
        }
    }
    SchemaProperty singleProp = a.getRawClass().getAnnotation(SchemaProperty.class);
    if (singleProp != null) {
        propList.put(singleProp.name(), singleProp);
    }
    props = AnnotationsUtils.getAnnotation(SchemaProperties.class, annotations);
    if (props != null && props.value().length > 0) {
        for (SchemaProperty prop : props.value()) {
            propList.put(prop.name(), prop);
        }
    }
    singleProp = AnnotationsUtils.getAnnotation(SchemaProperty.class, annotations);
    if (singleProp != null) {
        propList.put(singleProp.name(), singleProp);
    }
    if (propList.isEmpty()) {
        return null;
    }
    Map<String, Schema> schemaProperties = new LinkedHashMap<>();
    for (SchemaProperty prop : propList.values()) {
        String key = prop.name();
        if (StringUtils.isBlank(key)) {
            continue;
        }
        Annotation[] propAnnotations = new Annotation[] { prop.schema(), prop.array() };
        AnnotatedType propType = new AnnotatedType().type(String.class).ctxAnnotations(propAnnotations).resolveAsRef(true);
        Schema resolvedPropSchema = context.resolve(propType);
        if (resolvedPropSchema != null) {
            schemaProperties.put(key, resolvedPropSchema);
        }
    }
    return schemaProperties;
}
Also used : AnnotatedType(io.swagger.v3.core.converter.AnnotatedType) SchemaProperty(io.swagger.v3.oas.annotations.media.SchemaProperty) UUIDSchema(io.swagger.v3.oas.models.media.UUIDSchema) ComposedSchema(io.swagger.v3.oas.models.media.ComposedSchema) IntegerSchema(io.swagger.v3.oas.models.media.IntegerSchema) StringSchema(io.swagger.v3.oas.models.media.StringSchema) ObjectSchema(io.swagger.v3.oas.models.media.ObjectSchema) ArraySchema(io.swagger.v3.oas.models.media.ArraySchema) NumberSchema(io.swagger.v3.oas.models.media.NumberSchema) Schema(io.swagger.v3.oas.models.media.Schema) MapSchema(io.swagger.v3.oas.models.media.MapSchema) Annotation(java.lang.annotation.Annotation) LinkedHashMap(java.util.LinkedHashMap) SchemaProperties(io.swagger.v3.oas.annotations.media.SchemaProperties)

Example 4 with ModelConverterContext

use of io.swagger.v3.core.converter.ModelConverterContext in project swagger-core by swagger-api.

the class SamplePropertyExtendedConverter method resolve.

@Override
public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterator<ModelConverter> chain) {
    if (type.isSchemaProperty()) {
        JavaType _type = Json.mapper().constructType(type.getType());
        if (_type != null) {
            Class<?> cls = _type.getRawClass();
            if (MyCustomClass.class.isAssignableFrom(cls)) {
                Schema schema = new DateTimeSchema();
                super.resolveSchemaMembers(schema, type);
                return schema;
            }
        }
    }
    if (chain.hasNext()) {
        return chain.next().resolve(type, context, chain);
    } else {
        return null;
    }
}
Also used : JavaType(com.fasterxml.jackson.databind.JavaType) DateTimeSchema(io.swagger.v3.oas.models.media.DateTimeSchema) DateTimeSchema(io.swagger.v3.oas.models.media.DateTimeSchema) Schema(io.swagger.v3.oas.models.media.Schema)

Example 5 with ModelConverterContext

use of io.swagger.v3.core.converter.ModelConverterContext in project swagger-core by swagger-api.

the class ModelResolver method resolve.

@Override
public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context, Iterator<ModelConverter> next) {
    boolean isPrimitive = false;
    Schema model = null;
    List<String> requiredProps = new ArrayList<>();
    if (annotatedType == null) {
        return null;
    }
    if (this.shouldIgnoreClass(annotatedType.getType())) {
        return null;
    }
    final JavaType type;
    if (annotatedType.getType() instanceof JavaType) {
        type = (JavaType) annotatedType.getType();
    } else {
        type = _mapper.constructType(annotatedType.getType());
    }
    final Annotation resolvedSchemaOrArrayAnnotation = AnnotationsUtils.mergeSchemaAnnotations(annotatedType.getCtxAnnotations(), type);
    final io.swagger.v3.oas.annotations.media.Schema resolvedSchemaAnnotation = resolvedSchemaOrArrayAnnotation == null ? null : resolvedSchemaOrArrayAnnotation instanceof io.swagger.v3.oas.annotations.media.ArraySchema ? ((io.swagger.v3.oas.annotations.media.ArraySchema) resolvedSchemaOrArrayAnnotation).schema() : (io.swagger.v3.oas.annotations.media.Schema) resolvedSchemaOrArrayAnnotation;
    final io.swagger.v3.oas.annotations.media.ArraySchema resolvedArrayAnnotation = resolvedSchemaOrArrayAnnotation == null ? null : resolvedSchemaOrArrayAnnotation instanceof io.swagger.v3.oas.annotations.media.ArraySchema ? (io.swagger.v3.oas.annotations.media.ArraySchema) resolvedSchemaOrArrayAnnotation : null;
    final BeanDescription beanDesc;
    {
        BeanDescription recurBeanDesc = _mapper.getSerializationConfig().introspect(type);
        HashSet<String> visited = new HashSet<>();
        JsonSerialize jsonSerialize = recurBeanDesc.getClassAnnotations().get(JsonSerialize.class);
        while (jsonSerialize != null && !Void.class.equals(jsonSerialize.as())) {
            String asName = jsonSerialize.as().getName();
            if (visited.contains(asName))
                break;
            visited.add(asName);
            recurBeanDesc = _mapper.getSerializationConfig().introspect(_mapper.constructType(jsonSerialize.as()));
            jsonSerialize = recurBeanDesc.getClassAnnotations().get(JsonSerialize.class);
        }
        beanDesc = recurBeanDesc;
    }
    String name = annotatedType.getName();
    if (StringUtils.isBlank(name)) {
        // allow override of name from annotation
        if (!annotatedType.isSkipSchemaName() && resolvedSchemaAnnotation != null && !resolvedSchemaAnnotation.name().isEmpty()) {
            name = resolvedSchemaAnnotation.name();
        }
        if (StringUtils.isBlank(name) && !ReflectionUtils.isSystemType(type)) {
            name = _typeName(type, beanDesc);
        }
    }
    name = decorateModelName(annotatedType, name);
    // if we have a ref we don't consider anything else
    if (resolvedSchemaAnnotation != null && StringUtils.isNotEmpty(resolvedSchemaAnnotation.ref())) {
        if (resolvedArrayAnnotation == null) {
            return new Schema().$ref(resolvedSchemaAnnotation.ref()).name(name);
        } else {
            ArraySchema schema = new ArraySchema();
            resolveArraySchema(annotatedType, schema, resolvedArrayAnnotation);
            return schema.items(new Schema().$ref(resolvedSchemaAnnotation.ref()).name(name));
        }
    }
    if (!annotatedType.isSkipOverride() && resolvedSchemaAnnotation != null && !Void.class.equals(resolvedSchemaAnnotation.implementation())) {
        Class<?> cls = resolvedSchemaAnnotation.implementation();
        LOGGER.debug("overriding datatype from {} to {}", type, cls.getName());
        Annotation[] ctxAnnotation = null;
        if (resolvedArrayAnnotation != null && annotatedType.getCtxAnnotations() != null) {
            List<Annotation> annList = new ArrayList<>();
            for (Annotation a : annotatedType.getCtxAnnotations()) {
                if (!(a instanceof ArraySchema)) {
                    annList.add(a);
                }
            }
            annList.add(resolvedSchemaAnnotation);
            ctxAnnotation = annList.toArray(new Annotation[annList.size()]);
        } else {
            ctxAnnotation = annotatedType.getCtxAnnotations();
        }
        AnnotatedType aType = new AnnotatedType().type(cls).ctxAnnotations(ctxAnnotation).parent(annotatedType.getParent()).name(annotatedType.getName()).resolveAsRef(annotatedType.isResolveAsRef()).jsonViewAnnotation(annotatedType.getJsonViewAnnotation()).propertyName(annotatedType.getPropertyName()).skipOverride(true);
        if (resolvedArrayAnnotation != null) {
            ArraySchema schema = new ArraySchema();
            resolveArraySchema(annotatedType, schema, resolvedArrayAnnotation);
            Schema innerSchema = null;
            Schema primitive = PrimitiveType.createProperty(cls);
            if (primitive != null) {
                innerSchema = primitive;
            } else {
                innerSchema = context.resolve(aType);
                if (innerSchema != null && "object".equals(innerSchema.getType()) && StringUtils.isNotBlank(innerSchema.getName())) {
                    // create a reference for the items
                    if (context.getDefinedModels().containsKey(innerSchema.getName())) {
                        innerSchema = new Schema().$ref(constructRef(innerSchema.getName()));
                    }
                } else if (innerSchema != null && innerSchema.get$ref() != null) {
                    innerSchema = new Schema().$ref(StringUtils.isNotEmpty(innerSchema.get$ref()) ? innerSchema.get$ref() : innerSchema.getName());
                }
            }
            schema.setItems(innerSchema);
            return schema;
        } else {
            Schema implSchema = context.resolve(aType);
            if (implSchema != null && aType.isResolveAsRef() && "object".equals(implSchema.getType()) && StringUtils.isNotBlank(implSchema.getName())) {
                // create a reference for the items
                if (context.getDefinedModels().containsKey(implSchema.getName())) {
                    implSchema = new Schema().$ref(constructRef(implSchema.getName()));
                }
            } else if (implSchema != null && implSchema.get$ref() != null) {
                implSchema = new Schema().$ref(StringUtils.isNotEmpty(implSchema.get$ref()) ? implSchema.get$ref() : implSchema.getName());
            }
            return implSchema;
        }
    }
    if (model == null && !annotatedType.isSkipOverride() && resolvedSchemaAnnotation != null && StringUtils.isNotEmpty(resolvedSchemaAnnotation.type()) && !resolvedSchemaAnnotation.type().equals("object")) {
        PrimitiveType primitiveType = PrimitiveType.fromTypeAndFormat(resolvedSchemaAnnotation.type(), resolvedSchemaAnnotation.format());
        if (primitiveType == null) {
            primitiveType = PrimitiveType.fromType(type);
        }
        if (primitiveType == null) {
            primitiveType = PrimitiveType.fromName(resolvedSchemaAnnotation.type());
        }
        if (primitiveType != null) {
            Schema primitive = primitiveType.createProperty();
            model = primitive;
            isPrimitive = true;
        }
    }
    if (model == null && type.isEnumType()) {
        model = new StringSchema();
        _addEnumProps(type.getRawClass(), model);
        isPrimitive = true;
    }
    if (model == null) {
        PrimitiveType primitiveType = PrimitiveType.fromType(type);
        if (primitiveType != null) {
            model = PrimitiveType.fromType(type).createProperty();
            isPrimitive = true;
        }
    }
    if (!annotatedType.isSkipJsonIdentity()) {
        JsonIdentityInfo jsonIdentityInfo = AnnotationsUtils.getAnnotation(JsonIdentityInfo.class, annotatedType.getCtxAnnotations());
        if (jsonIdentityInfo == null) {
            jsonIdentityInfo = type.getRawClass().getAnnotation(JsonIdentityInfo.class);
        }
        if (model == null && jsonIdentityInfo != null) {
            JsonIdentityReference jsonIdentityReference = AnnotationsUtils.getAnnotation(JsonIdentityReference.class, annotatedType.getCtxAnnotations());
            if (jsonIdentityReference == null) {
                jsonIdentityReference = type.getRawClass().getAnnotation(JsonIdentityReference.class);
            }
            model = new GeneratorWrapper().processJsonIdentity(annotatedType, context, _mapper, jsonIdentityInfo, jsonIdentityReference);
            if (model != null) {
                return model;
            }
        }
    }
    if (model == null && annotatedType.getJsonUnwrappedHandler() != null) {
        model = annotatedType.getJsonUnwrappedHandler().apply(annotatedType);
        if (model == null) {
            return null;
        }
    }
    if ("Object".equals(name)) {
        return new Schema();
    }
    if (isPrimitive) {
        if (annotatedType.isSchemaProperty()) {
        // model.name(name);
        }
        XML xml = resolveXml(beanDesc.getClassInfo(), annotatedType.getCtxAnnotations(), resolvedSchemaAnnotation);
        if (xml != null) {
            model.xml(xml);
        }
        applyBeanValidatorAnnotations(model, annotatedType.getCtxAnnotations(), null);
        resolveSchemaMembers(model, annotatedType);
        if (resolvedArrayAnnotation != null) {
            ArraySchema schema = new ArraySchema();
            resolveArraySchema(annotatedType, schema, resolvedArrayAnnotation);
            schema.setItems(model);
            return schema;
        }
        if (type.isEnumType() && shouldResolveEnumAsRef(resolvedSchemaAnnotation)) {
            // Store off the ref and add the enum as a top-level model
            context.defineModel(name, model, annotatedType, null);
            // Return the model as a ref only property
            model = new Schema().$ref(Components.COMPONENTS_SCHEMAS_REF + name);
        }
        return model;
    }
    /**
     * --Preventing parent/child hierarchy creation loops - Comment 1--
     * Creating a parent model will result in the creation of child models. Creating a child model will result in
     * the creation of a parent model, as per the second If statement following this comment.
     *
     * By checking whether a model has already been resolved (as implemented below), loops of parents creating
     * children and children creating parents can be short-circuited. This works because currently the
     * ModelConverterContextImpl will return null for a class that already been processed, but has not yet been
     * defined. This logic works in conjunction with the early immediate definition of model in the context
     * implemented later in this method (See "Preventing parent/child hierarchy creation loops - Comment 2") to
     * prevent such
     */
    Schema resolvedModel = context.resolve(annotatedType);
    if (resolvedModel != null) {
        if (name != null && name.equals(resolvedModel.getName())) {
            return resolvedModel;
        }
    }
    Type jsonValueType = findJsonValueType(beanDesc);
    if (jsonValueType != null) {
        AnnotatedType aType = new AnnotatedType().type(jsonValueType).parent(annotatedType.getParent()).name(annotatedType.getName()).schemaProperty(annotatedType.isSchemaProperty()).resolveAsRef(annotatedType.isResolveAsRef()).jsonViewAnnotation(annotatedType.getJsonViewAnnotation()).propertyName(annotatedType.getPropertyName()).ctxAnnotations(annotatedType.getCtxAnnotations()).skipOverride(true);
        return context.resolve(aType);
    }
    List<Class<?>> composedSchemaReferencedClasses = getComposedSchemaReferencedClasses(type.getRawClass(), annotatedType.getCtxAnnotations(), resolvedSchemaAnnotation);
    boolean isComposedSchema = composedSchemaReferencedClasses != null;
    if (type.isContainerType()) {
        // TODO currently a MapSchema or ArraySchema don't also support composed schema props (oneOf,..)
        isComposedSchema = false;
        JavaType keyType = type.getKeyType();
        JavaType valueType = type.getContentType();
        String pName = null;
        if (valueType != null) {
            BeanDescription valueTypeBeanDesc = _mapper.getSerializationConfig().introspect(valueType);
            pName = _typeName(valueType, valueTypeBeanDesc);
        }
        Annotation[] schemaAnnotations = null;
        if (resolvedSchemaAnnotation != null) {
            schemaAnnotations = new Annotation[] { resolvedSchemaAnnotation };
        }
        if (keyType != null && valueType != null) {
            if (ReflectionUtils.isSystemType(type) && !annotatedType.isSchemaProperty() && !annotatedType.isResolveAsRef()) {
                context.resolve(new AnnotatedType().type(valueType).jsonViewAnnotation(annotatedType.getJsonViewAnnotation()));
                return null;
            }
            Schema addPropertiesSchema = context.resolve(new AnnotatedType().type(valueType).schemaProperty(annotatedType.isSchemaProperty()).ctxAnnotations(schemaAnnotations).skipSchemaName(true).resolveAsRef(annotatedType.isResolveAsRef()).jsonViewAnnotation(annotatedType.getJsonViewAnnotation()).propertyName(annotatedType.getPropertyName()).parent(annotatedType.getParent()));
            if (addPropertiesSchema != null) {
                if (StringUtils.isNotBlank(addPropertiesSchema.getName())) {
                    pName = addPropertiesSchema.getName();
                }
                if ("object".equals(addPropertiesSchema.getType()) && pName != null) {
                    // create a reference for the items
                    if (context.getDefinedModels().containsKey(pName)) {
                        addPropertiesSchema = new Schema().$ref(constructRef(pName));
                    }
                } else if (addPropertiesSchema.get$ref() != null) {
                    addPropertiesSchema = new Schema().$ref(StringUtils.isNotEmpty(addPropertiesSchema.get$ref()) ? addPropertiesSchema.get$ref() : addPropertiesSchema.getName());
                }
            }
            Schema mapModel = new MapSchema().additionalProperties(addPropertiesSchema);
            mapModel.name(name);
            model = mapModel;
        // return model;
        } else if (valueType != null) {
            if (ReflectionUtils.isSystemType(type) && !annotatedType.isSchemaProperty() && !annotatedType.isResolveAsRef()) {
                context.resolve(new AnnotatedType().type(valueType).jsonViewAnnotation(annotatedType.getJsonViewAnnotation()));
                return null;
            }
            Schema items = context.resolve(new AnnotatedType().type(valueType).schemaProperty(annotatedType.isSchemaProperty()).ctxAnnotations(schemaAnnotations).skipSchemaName(true).resolveAsRef(annotatedType.isResolveAsRef()).propertyName(annotatedType.getPropertyName()).jsonViewAnnotation(annotatedType.getJsonViewAnnotation()).parent(annotatedType.getParent()));
            if (items == null) {
                return null;
            }
            if (annotatedType.isSchemaProperty() && annotatedType.getCtxAnnotations() != null && annotatedType.getCtxAnnotations().length > 0) {
                if (!"object".equals(items.getType())) {
                    for (Annotation annotation : annotatedType.getCtxAnnotations()) {
                        if (annotation instanceof XmlElement) {
                            XmlElement xmlElement = (XmlElement) annotation;
                            if (xmlElement != null && xmlElement.name() != null && !"".equals(xmlElement.name()) && !JAXB_DEFAULT.equals(xmlElement.name())) {
                                XML xml = items.getXml() != null ? items.getXml() : new XML();
                                xml.setName(xmlElement.name());
                                items.setXml(xml);
                            }
                        }
                    }
                }
            }
            if (StringUtils.isNotBlank(items.getName())) {
                pName = items.getName();
            }
            if ("object".equals(items.getType()) && pName != null) {
                // create a reference for the items
                if (context.getDefinedModels().containsKey(pName)) {
                    items = new Schema().$ref(constructRef(pName));
                }
            } else if (items.get$ref() != null) {
                items = new Schema().$ref(StringUtils.isNotEmpty(items.get$ref()) ? items.get$ref() : items.getName());
            }
            Schema arrayModel = new ArraySchema().items(items);
            if (_isSetType(type.getRawClass())) {
                arrayModel.setUniqueItems(true);
            }
            arrayModel.name(name);
            model = arrayModel;
        } else {
            if (ReflectionUtils.isSystemType(type) && !annotatedType.isSchemaProperty() && !annotatedType.isResolveAsRef()) {
                return null;
            }
        }
    } else if (isComposedSchema) {
        model = new ComposedSchema().type("object").name(name);
    } else {
        AnnotatedType aType = OptionalUtils.unwrapOptional(annotatedType);
        if (aType != null) {
            model = context.resolve(aType);
            return model;
        } else {
            model = new Schema().type("object").name(name);
        }
    }
    if (!type.isContainerType() && StringUtils.isNotBlank(name)) {
        // define the model here to support self/cyclic referencing of models
        context.defineModel(name, model, annotatedType, null);
    }
    XML xml = resolveXml(beanDesc.getClassInfo(), annotatedType.getCtxAnnotations(), resolvedSchemaAnnotation);
    if (xml != null) {
        model.xml(xml);
    }
    if (!(model instanceof ArraySchema) || (model instanceof ArraySchema && resolvedArrayAnnotation == null)) {
        resolveSchemaMembers(model, annotatedType);
    }
    final XmlAccessorType xmlAccessorTypeAnnotation = beanDesc.getClassAnnotations().get(XmlAccessorType.class);
    // see if @JsonIgnoreProperties exist
    Set<String> propertiesToIgnore = resolveIgnoredProperties(beanDesc.getClassAnnotations(), annotatedType.getCtxAnnotations());
    List<Schema> props = new ArrayList<>();
    Map<String, Schema> modelProps = new LinkedHashMap<>();
    List<BeanPropertyDefinition> properties = beanDesc.findProperties();
    List<String> ignoredProps = getIgnoredProperties(beanDesc);
    properties.removeIf(p -> ignoredProps.contains(p.getName()));
    for (BeanPropertyDefinition propDef : properties) {
        Schema property = null;
        String propName = propDef.getName();
        Annotation[] annotations = null;
        AnnotatedMember member = propDef.getPrimaryMember();
        if (member == null) {
            final BeanDescription deserBeanDesc = _mapper.getDeserializationConfig().introspect(type);
            List<BeanPropertyDefinition> deserProperties = deserBeanDesc.findProperties();
            for (BeanPropertyDefinition prop : deserProperties) {
                if (StringUtils.isNotBlank(prop.getInternalName()) && prop.getInternalName().equals(propDef.getInternalName())) {
                    member = prop.getPrimaryMember();
                    break;
                }
            }
        }
        // it's ugly but gets around https://github.com/swagger-api/swagger-core/issues/415
        if (propDef.getPrimaryMember() != null) {
            final JsonProperty jsonPropertyAnn = propDef.getPrimaryMember().getAnnotation(JsonProperty.class);
            if (jsonPropertyAnn == null || !jsonPropertyAnn.value().equals(propName)) {
                if (member != null) {
                    java.lang.reflect.Member innerMember = member.getMember();
                    if (innerMember != null) {
                        String altName = innerMember.getName();
                        if (altName != null) {
                            final int length = altName.length();
                            for (String prefix : Arrays.asList("get", "is")) {
                                final int offset = prefix.length();
                                if (altName.startsWith(prefix) && length > offset && !Character.isUpperCase(altName.charAt(offset))) {
                                    propName = altName;
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
        PropertyMetadata md = propDef.getMetadata();
        if (member != null && !ignore(member, xmlAccessorTypeAnnotation, propName, propertiesToIgnore, propDef)) {
            List<Annotation> annotationList = new ArrayList<>();
            AnnotationMap annotationMap = member.getAllAnnotations();
            if (annotationMap != null) {
                for (Annotation a : annotationMap.annotations()) {
                    annotationList.add(a);
                }
            }
            annotations = annotationList.toArray(new Annotation[annotationList.size()]);
            if (hiddenByJsonView(annotations, annotatedType)) {
                continue;
            }
            JavaType propType = member.getType();
            if (propType != null && "void".equals(propType.getRawClass().getName())) {
                if (member instanceof AnnotatedMethod) {
                    propType = ((AnnotatedMethod) member).getParameterType(0);
                }
            }
            String propSchemaName = null;
            io.swagger.v3.oas.annotations.media.Schema ctxSchema = AnnotationsUtils.getSchemaAnnotation(annotations);
            if (AnnotationsUtils.hasSchemaAnnotation(ctxSchema)) {
                if (!StringUtils.isBlank(ctxSchema.name())) {
                    propSchemaName = ctxSchema.name();
                }
            }
            if (propSchemaName == null) {
                io.swagger.v3.oas.annotations.media.ArraySchema ctxArraySchema = AnnotationsUtils.getArraySchemaAnnotation(annotations);
                if (AnnotationsUtils.hasArrayAnnotation(ctxArraySchema)) {
                    if (AnnotationsUtils.hasSchemaAnnotation(ctxArraySchema.schema())) {
                        if (!StringUtils.isBlank(ctxArraySchema.schema().name())) {
                            propSchemaName = ctxArraySchema.schema().name();
                        }
                    }
                }
            }
            if (StringUtils.isNotBlank(propSchemaName)) {
                propName = propSchemaName;
            }
            Annotation propSchemaOrArray = AnnotationsUtils.mergeSchemaAnnotations(annotations, propType);
            final io.swagger.v3.oas.annotations.media.Schema propResolvedSchemaAnnotation = propSchemaOrArray == null ? null : propSchemaOrArray instanceof io.swagger.v3.oas.annotations.media.ArraySchema ? ((io.swagger.v3.oas.annotations.media.ArraySchema) propSchemaOrArray).schema() : (io.swagger.v3.oas.annotations.media.Schema) propSchemaOrArray;
            io.swagger.v3.oas.annotations.media.Schema.AccessMode accessMode = resolveAccessMode(propDef, type, propResolvedSchemaAnnotation);
            AnnotatedType aType = new AnnotatedType().type(propType).ctxAnnotations(annotations).parent(model).resolveAsRef(annotatedType.isResolveAsRef()).jsonViewAnnotation(annotatedType.getJsonViewAnnotation()).skipSchemaName(true).schemaProperty(true).propertyName(propName);
            final AnnotatedMember propMember = member;
            aType.jsonUnwrappedHandler(t -> {
                JsonUnwrapped uw = propMember.getAnnotation(JsonUnwrapped.class);
                if (uw != null && uw.enabled()) {
                    t.ctxAnnotations(null).jsonUnwrappedHandler(null).resolveAsRef(false);
                    handleUnwrapped(props, context.resolve(t), uw.prefix(), uw.suffix(), requiredProps);
                    return null;
                } else {
                    return new Schema();
                // t.jsonUnwrappedHandler(null);
                // return context.resolve(t);
                }
            });
            property = clone(context.resolve(aType));
            if (property != null) {
                Boolean required = md.getRequired();
                if (required != null && !Boolean.FALSE.equals(required)) {
                    addRequiredItem(model, propName);
                } else {
                    if (propDef.isRequired()) {
                        addRequiredItem(model, propName);
                    }
                }
                if (property.get$ref() == null) {
                    if (accessMode != null) {
                        switch(accessMode) {
                            case AUTO:
                                break;
                            case READ_ONLY:
                                property.readOnly(true);
                                break;
                            case READ_WRITE:
                                break;
                            case WRITE_ONLY:
                                property.writeOnly(true);
                                break;
                            default:
                        }
                    }
                }
                final BeanDescription propBeanDesc = _mapper.getSerializationConfig().introspect(propType);
                if (property != null && !propType.isContainerType()) {
                    if ("object".equals(property.getType())) {
                        // create a reference for the property
                        String pName = _typeName(propType, propBeanDesc);
                        if (StringUtils.isNotBlank(property.getName())) {
                            pName = property.getName();
                        }
                        if (context.getDefinedModels().containsKey(pName)) {
                            property = new Schema().$ref(constructRef(pName));
                        }
                    } else if (property.get$ref() != null) {
                        property = new Schema().$ref(StringUtils.isNotEmpty(property.get$ref()) ? property.get$ref() : property.getName());
                    }
                }
                property.setName(propName);
                JAXBAnnotationsHelper.apply(propBeanDesc.getClassInfo(), annotations, property);
                applyBeanValidatorAnnotations(property, annotations, model);
                props.add(property);
            }
        }
    }
    for (Schema prop : props) {
        modelProps.put(prop.getName(), prop);
    }
    if (modelProps.size() > 0) {
        model.setProperties(modelProps);
        for (String propName : requiredProps) {
            addRequiredItem(model, propName);
        }
    }
    /**
     * --Preventing parent/child hierarchy creation loops - Comment 2--
     * Creating a parent model will result in the creation of child models, as per the first If statement following
     * this comment. Creating a child model will result in the creation of a parent model, as per the second If
     * statement following this comment.
     *
     * The current model must be defined in the context immediately. This done to help prevent repeated
     * loops where  parents create children and children create parents when a hierarchy is present. This logic
     * works in conjunction with the "early checking" performed earlier in this method
     * (See "Preventing parent/child hierarchy creation loops - Comment 1"), to prevent repeated creation loops.
     *
     * As an aside, defining the current model in the context immediately also ensures that child models are
     * available for modification by resolveSubtypes, when their parents are created.
     */
    if (!type.isContainerType() && StringUtils.isNotBlank(name)) {
        context.defineModel(name, model, annotatedType, null);
    }
    /**
     * This must be done after model.setProperties so that the model's set
     * of properties is available to filter from any subtypes
     */
    if (!resolveSubtypes(model, beanDesc, context)) {
        model.setDiscriminator(null);
    }
    Discriminator discriminator = resolveDiscriminator(type, context);
    if (discriminator != null) {
        model.setDiscriminator(discriminator);
    }
    if (resolvedSchemaAnnotation != null) {
        String ref = resolvedSchemaAnnotation.ref();
        // consider ref as is
        if (!StringUtils.isBlank(ref)) {
            model.$ref(ref);
        }
        Class<?> not = resolvedSchemaAnnotation.not();
        if (!Void.class.equals(not)) {
            model.not((new Schema().$ref(context.resolve(new AnnotatedType().type(not).jsonViewAnnotation(annotatedType.getJsonViewAnnotation())).getName())));
        }
        if (resolvedSchemaAnnotation.requiredProperties() != null && resolvedSchemaAnnotation.requiredProperties().length > 0 && StringUtils.isNotBlank(resolvedSchemaAnnotation.requiredProperties()[0])) {
            for (String prop : resolvedSchemaAnnotation.requiredProperties()) {
                addRequiredItem(model, prop);
            }
        }
    }
    Map<String, Schema> patternProperties = resolvePatternProperties(type, annotatedType.getCtxAnnotations(), context);
    if (model != null && patternProperties != null && !patternProperties.isEmpty()) {
        if (model.getPatternProperties() == null) {
            model.patternProperties(patternProperties);
        } else {
            model.getPatternProperties().putAll(patternProperties);
        }
    }
    Map<String, Schema> schemaProperties = resolveSchemaProperties(type, annotatedType.getCtxAnnotations(), context);
    if (model != null && schemaProperties != null && !schemaProperties.isEmpty()) {
        if (model.getProperties() == null) {
            model.properties(schemaProperties);
        } else {
            model.getProperties().putAll(schemaProperties);
        }
    }
    if (isComposedSchema) {
        ComposedSchema composedSchema = (ComposedSchema) model;
        Class<?>[] allOf = resolvedSchemaAnnotation.allOf();
        Class<?>[] anyOf = resolvedSchemaAnnotation.anyOf();
        Class<?>[] oneOf = resolvedSchemaAnnotation.oneOf();
        List<Class<?>> allOfFiltered = Stream.of(allOf).distinct().filter(c -> !this.shouldIgnoreClass(c)).filter(c -> !(c.equals(Void.class))).collect(Collectors.toList());
        allOfFiltered.forEach(c -> {
            Schema allOfRef = context.resolve(new AnnotatedType().type(c).jsonViewAnnotation(annotatedType.getJsonViewAnnotation()));
            Schema refSchema = new Schema().$ref(allOfRef.getName());
            // allOf could have already being added during subtype resolving
            if (composedSchema.getAllOf() == null || !composedSchema.getAllOf().contains(refSchema)) {
                composedSchema.addAllOfItem(refSchema);
            }
            // remove shared properties defined in the parent
            if (isSubtype(beanDesc.getClassInfo(), c)) {
                removeParentProperties(composedSchema, allOfRef);
            }
        });
        List<Class<?>> anyOfFiltered = Stream.of(anyOf).distinct().filter(c -> !this.shouldIgnoreClass(c)).filter(c -> !(c.equals(Void.class))).collect(Collectors.toList());
        anyOfFiltered.forEach(c -> {
            Schema anyOfRef = context.resolve(new AnnotatedType().type(c).jsonViewAnnotation(annotatedType.getJsonViewAnnotation()));
            composedSchema.addAnyOfItem(new Schema().$ref(anyOfRef.getName()));
            // remove shared properties defined in the parent
            if (isSubtype(beanDesc.getClassInfo(), c)) {
                removeParentProperties(composedSchema, anyOfRef);
            }
        });
        List<Class<?>> oneOfFiltered = Stream.of(oneOf).distinct().filter(c -> !this.shouldIgnoreClass(c)).filter(c -> !(c.equals(Void.class))).collect(Collectors.toList());
        oneOfFiltered.forEach(c -> {
            Schema oneOfRef = context.resolve(new AnnotatedType().type(c).jsonViewAnnotation(annotatedType.getJsonViewAnnotation()));
            if (oneOfRef != null) {
                if (StringUtils.isBlank(oneOfRef.getName())) {
                    composedSchema.addOneOfItem(oneOfRef);
                } else {
                    composedSchema.addOneOfItem(new Schema().$ref(oneOfRef.getName()));
                }
                // remove shared properties defined in the parent
                if (isSubtype(beanDesc.getClassInfo(), c)) {
                    removeParentProperties(composedSchema, oneOfRef);
                }
            }
        });
        if (!composedModelPropertiesAsSibling) {
            if (composedSchema.getAllOf() != null && !composedSchema.getAllOf().isEmpty()) {
                if (composedSchema.getProperties() != null && !composedSchema.getProperties().isEmpty()) {
                    ObjectSchema propSchema = new ObjectSchema();
                    propSchema.properties(composedSchema.getProperties());
                    composedSchema.setProperties(null);
                    composedSchema.addAllOfItem(propSchema);
                }
            }
        }
    }
    if (!type.isContainerType() && StringUtils.isNotBlank(name)) {
        // define the model here to support self/cyclic referencing of models
        context.defineModel(name, model, annotatedType, null);
    }
    if (model != null && annotatedType.isResolveAsRef() && (isComposedSchema || "object".equals(model.getType())) && StringUtils.isNotBlank(model.getName())) {
        if (context.getDefinedModels().containsKey(model.getName())) {
            model = new Schema().$ref(constructRef(model.getName()));
        }
    } else if (model != null && model.get$ref() != null) {
        model = new Schema().$ref(StringUtils.isNotEmpty(model.get$ref()) ? model.get$ref() : model.getName());
    }
    if (model != null && resolvedArrayAnnotation != null) {
        if (!"array".equals(model.getType())) {
            ArraySchema schema = new ArraySchema();
            schema.setItems(model);
            resolveArraySchema(annotatedType, schema, resolvedArrayAnnotation);
            return schema;
        } else {
            if (model instanceof ArraySchema) {
                resolveArraySchema(annotatedType, (ArraySchema) model, resolvedArrayAnnotation);
            }
        }
    }
    resolveDiscriminatorProperty(type, context, model);
    model = resolveWrapping(type, context, model);
    return model;
}
Also used : JsonProperty(com.fasterxml.jackson.annotation.JsonProperty) UUIDSchema(io.swagger.v3.oas.models.media.UUIDSchema) Size(javax.validation.constraints.Size) Arrays(java.util.Arrays) JsonView(com.fasterxml.jackson.annotation.JsonView) AnnotationIntrospector(com.fasterxml.jackson.databind.AnnotationIntrospector) DiscriminatorMapping(io.swagger.v3.oas.annotations.media.DiscriminatorMapping) LoggerFactory(org.slf4j.LoggerFactory) StringUtils(org.apache.commons.lang3.StringUtils) XmlElementRef(javax.xml.bind.annotation.XmlElementRef) ObjectMapperFactory(io.swagger.v3.core.util.ObjectMapperFactory) PropertyMetadata(com.fasterxml.jackson.databind.PropertyMetadata) ComposedSchema(io.swagger.v3.oas.models.media.ComposedSchema) POJOPropertyBuilder(com.fasterxml.jackson.databind.introspect.POJOPropertyBuilder) AnnotationsUtils(io.swagger.v3.core.util.AnnotationsUtils) PatternProperties(io.swagger.v3.oas.annotations.media.PatternProperties) BigDecimal(java.math.BigDecimal) JsonValue(com.fasterxml.jackson.annotation.JsonValue) RefUtils.constructRef(io.swagger.v3.core.util.RefUtils.constructRef) Map(java.util.Map) AnnotatedMember(com.fasterxml.jackson.databind.introspect.AnnotatedMember) NamedType(com.fasterxml.jackson.databind.jsontype.NamedType) Max(javax.validation.constraints.Max) BeanDescription(com.fasterxml.jackson.databind.BeanDescription) Method(java.lang.reflect.Method) XmlAccessorType(javax.xml.bind.annotation.XmlAccessorType) Hidden(io.swagger.v3.oas.annotations.Hidden) Collection(java.util.Collection) Set(java.util.Set) IntegerSchema(io.swagger.v3.oas.models.media.IntegerSchema) Min(javax.validation.constraints.Min) Collectors(java.util.stream.Collectors) AnnotatedType(io.swagger.v3.core.converter.AnnotatedType) ExternalDocumentation(io.swagger.v3.oas.models.ExternalDocumentation) XML(io.swagger.v3.oas.models.media.XML) XmlAccessType(javax.xml.bind.annotation.XmlAccessType) InvocationTargetException(java.lang.reflect.InvocationTargetException) JsonIdentityReference(com.fasterxml.jackson.annotation.JsonIdentityReference) List(java.util.List) Stream(java.util.stream.Stream) JsonTypeInfo(com.fasterxml.jackson.annotation.JsonTypeInfo) AnnotatedClass(com.fasterxml.jackson.databind.introspect.AnnotatedClass) StringSchema(io.swagger.v3.oas.models.media.StringSchema) XmlElementRefs(javax.xml.bind.annotation.XmlElementRefs) Type(java.lang.reflect.Type) SchemaProperties(io.swagger.v3.oas.annotations.media.SchemaProperties) JsonUnwrapped(com.fasterxml.jackson.annotation.JsonUnwrapped) Pattern(javax.validation.constraints.Pattern) Annotation(java.lang.annotation.Annotation) Optional(java.util.Optional) PatternProperty(io.swagger.v3.oas.annotations.media.PatternProperty) ObjectSchema(io.swagger.v3.oas.models.media.ObjectSchema) JAXB_DEFAULT(io.swagger.v3.core.jackson.JAXBAnnotationsHelper.JAXB_DEFAULT) JsonIgnoreProperties(com.fasterxml.jackson.annotation.JsonIgnoreProperties) AnnotationMap(com.fasterxml.jackson.databind.introspect.AnnotationMap) ModelConverter(io.swagger.v3.core.converter.ModelConverter) Json(io.swagger.v3.core.util.Json) OptionalUtils(io.swagger.v3.core.util.OptionalUtils) DecimalMin(javax.validation.constraints.DecimalMin) HashMap(java.util.HashMap) ArraySchema(io.swagger.v3.oas.models.media.ArraySchema) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) Annotations(com.fasterxml.jackson.databind.util.Annotations) NumberSchema(io.swagger.v3.oas.models.media.NumberSchema) JsonSerialize(com.fasterxml.jackson.databind.annotation.JsonSerialize) JsonIgnore(com.fasterxml.jackson.annotation.JsonIgnore) PrimitiveType(io.swagger.v3.core.util.PrimitiveType) Schema(io.swagger.v3.oas.models.media.Schema) JavaType(com.fasterxml.jackson.databind.JavaType) AnnotatedMethod(com.fasterxml.jackson.databind.introspect.AnnotatedMethod) XmlAttribute(javax.xml.bind.annotation.XmlAttribute) Discriminator(io.swagger.v3.oas.models.media.Discriminator) Logger(org.slf4j.Logger) JsonIdentityInfo(com.fasterxml.jackson.annotation.JsonIdentityInfo) Iterator(java.util.Iterator) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper) MapSchema(io.swagger.v3.oas.models.media.MapSchema) IOException(java.io.IOException) ObjectIdGenerator(com.fasterxml.jackson.annotation.ObjectIdGenerator) XmlRootElement(javax.xml.bind.annotation.XmlRootElement) SchemaProperty(io.swagger.v3.oas.annotations.media.SchemaProperty) Constants(io.swagger.v3.core.util.Constants) ReflectionUtils(io.swagger.v3.core.util.ReflectionUtils) Annotated(com.fasterxml.jackson.databind.introspect.Annotated) ModelConverterContext(io.swagger.v3.core.converter.ModelConverterContext) DecimalMax(javax.validation.constraints.DecimalMax) Components(io.swagger.v3.oas.models.Components) NumberUtils(org.apache.commons.lang3.math.NumberUtils) ObjectIdGenerators(com.fasterxml.jackson.annotation.ObjectIdGenerators) SerializationFeature(com.fasterxml.jackson.databind.SerializationFeature) BeanPropertyDefinition(com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition) Collections(java.util.Collections) XmlElement(javax.xml.bind.annotation.XmlElement) JsonProperty(com.fasterxml.jackson.annotation.JsonProperty) UUIDSchema(io.swagger.v3.oas.models.media.UUIDSchema) ComposedSchema(io.swagger.v3.oas.models.media.ComposedSchema) IntegerSchema(io.swagger.v3.oas.models.media.IntegerSchema) StringSchema(io.swagger.v3.oas.models.media.StringSchema) ObjectSchema(io.swagger.v3.oas.models.media.ObjectSchema) ArraySchema(io.swagger.v3.oas.models.media.ArraySchema) NumberSchema(io.swagger.v3.oas.models.media.NumberSchema) Schema(io.swagger.v3.oas.models.media.Schema) MapSchema(io.swagger.v3.oas.models.media.MapSchema) ArrayList(java.util.ArrayList) AnnotatedMember(com.fasterxml.jackson.databind.introspect.AnnotatedMember) LinkedHashMap(java.util.LinkedHashMap) JsonSerialize(com.fasterxml.jackson.databind.annotation.JsonSerialize) ArraySchema(io.swagger.v3.oas.models.media.ArraySchema) ObjectSchema(io.swagger.v3.oas.models.media.ObjectSchema) PropertyMetadata(com.fasterxml.jackson.databind.PropertyMetadata) PrimitiveType(io.swagger.v3.core.util.PrimitiveType) StringSchema(io.swagger.v3.oas.models.media.StringSchema) MapSchema(io.swagger.v3.oas.models.media.MapSchema) HashSet(java.util.HashSet) BeanDescription(com.fasterxml.jackson.databind.BeanDescription) JsonIdentityReference(com.fasterxml.jackson.annotation.JsonIdentityReference) JavaType(com.fasterxml.jackson.databind.JavaType) AnnotatedType(io.swagger.v3.core.converter.AnnotatedType) XmlAccessorType(javax.xml.bind.annotation.XmlAccessorType) AnnotatedClass(com.fasterxml.jackson.databind.introspect.AnnotatedClass) AnnotatedMethod(com.fasterxml.jackson.databind.introspect.AnnotatedMethod) AnnotationMap(com.fasterxml.jackson.databind.introspect.AnnotationMap) BeanPropertyDefinition(com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition) ComposedSchema(io.swagger.v3.oas.models.media.ComposedSchema) JsonUnwrapped(com.fasterxml.jackson.annotation.JsonUnwrapped) Annotation(java.lang.annotation.Annotation) Discriminator(io.swagger.v3.oas.models.media.Discriminator) JsonIdentityInfo(com.fasterxml.jackson.annotation.JsonIdentityInfo) NamedType(com.fasterxml.jackson.databind.jsontype.NamedType) XmlAccessorType(javax.xml.bind.annotation.XmlAccessorType) AnnotatedType(io.swagger.v3.core.converter.AnnotatedType) XmlAccessType(javax.xml.bind.annotation.XmlAccessType) Type(java.lang.reflect.Type) PrimitiveType(io.swagger.v3.core.util.PrimitiveType) JavaType(com.fasterxml.jackson.databind.JavaType) XML(io.swagger.v3.oas.models.media.XML) XmlElement(javax.xml.bind.annotation.XmlElement)

Aggregations

Schema (io.swagger.v3.oas.models.media.Schema)8 AnnotatedType (io.swagger.v3.core.converter.AnnotatedType)6 ArraySchema (io.swagger.v3.oas.models.media.ArraySchema)6 ComposedSchema (io.swagger.v3.oas.models.media.ComposedSchema)6 IntegerSchema (io.swagger.v3.oas.models.media.IntegerSchema)6 MapSchema (io.swagger.v3.oas.models.media.MapSchema)6 NumberSchema (io.swagger.v3.oas.models.media.NumberSchema)6 ObjectSchema (io.swagger.v3.oas.models.media.ObjectSchema)6 StringSchema (io.swagger.v3.oas.models.media.StringSchema)6 UUIDSchema (io.swagger.v3.oas.models.media.UUIDSchema)6 JsonTypeInfo (com.fasterxml.jackson.annotation.JsonTypeInfo)4 Annotation (java.lang.annotation.Annotation)3 LinkedHashMap (java.util.LinkedHashMap)3 JavaType (com.fasterxml.jackson.databind.JavaType)2 NamedType (com.fasterxml.jackson.databind.jsontype.NamedType)2 PatternProperties (io.swagger.v3.oas.annotations.media.PatternProperties)2 PatternProperty (io.swagger.v3.oas.annotations.media.PatternProperty)2 JsonIdentityInfo (com.fasterxml.jackson.annotation.JsonIdentityInfo)1 JsonIdentityReference (com.fasterxml.jackson.annotation.JsonIdentityReference)1 JsonIgnore (com.fasterxml.jackson.annotation.JsonIgnore)1