All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springdoc.core.GenericParameterService Maven / Gradle / Ivy

The newest version!
/*
 *
 *  *
 *  *  *
 *  *  *  *
 *  *  *  *  * Copyright 2019-2022 the original author or authors.
 *  *  *  *  *
 *  *  *  *  * Licensed under the Apache License, Version 2.0 (the "License");
 *  *  *  *  * you may not use this file except in compliance with the License.
 *  *  *  *  * You may obtain a copy of the License at
 *  *  *  *  *
 *  *  *  *  *      https://www.apache.org/licenses/LICENSE-2.0
 *  *  *  *  *
 *  *  *  *  * Unless required by applicable law or agreed to in writing, software
 *  *  *  *  * distributed under the License is distributed on an "AS IS" BASIS,
 *  *  *  *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *  *  *  * See the License for the specific language governing permissions and
 *  *  *  *  * limitations under the License.
 *  *  *  *
 *  *  *
 *  *
 *
 */

package org.springdoc.core;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

import com.fasterxml.jackson.annotation.JsonView;
import io.swagger.v3.core.util.AnnotationsUtils;
import io.swagger.v3.core.util.PrimitiveType;
import io.swagger.v3.oas.annotations.enums.Explode;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.enums.ParameterStyle;
import io.swagger.v3.oas.annotations.extensions.Extension;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.examples.Example;
import io.swagger.v3.oas.models.media.ArraySchema;
import io.swagger.v3.oas.models.media.Content;
import io.swagger.v3.oas.models.media.FileSchema;
import io.swagger.v3.oas.models.media.ObjectSchema;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.parameters.Parameter;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springdoc.core.customizers.DelegatingMethodParameterCustomizer;
import org.springdoc.core.providers.JavadocProvider;
import org.springdoc.core.providers.ObjectMapperProvider;
import org.springdoc.core.providers.WebConversionServiceProvider;

import org.springframework.beans.factory.config.BeanExpressionContext;
import org.springframework.beans.factory.config.BeanExpressionResolver;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.io.Resource;
import org.springframework.web.context.request.RequestScope;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartRequest;

import static org.springdoc.core.Constants.DOT;

/**
 * The type Generic parameter builder.
 * @author bnasslahsen, coutin
 */
@SuppressWarnings("rawtypes")
public class GenericParameterService {

	/**
	 * The constant FILE_TYPES.
	 */
	private static final List> FILE_TYPES = Collections.synchronizedList(new ArrayList<>());

	/**
	 * The constant LOGGER.
	 */
	private static final Logger LOGGER = LoggerFactory.getLogger(GenericParameterService.class);

	static {
		FILE_TYPES.add(MultipartFile.class);
		FILE_TYPES.add(Resource.class);
		FILE_TYPES.add(MultipartRequest.class);
	}

	/**
	 * The Optional delegating method parameter customizer.
	 */
	private final Optional optionalDelegatingMethodParameterCustomizer;

	/**
	 * The Web conversion service.
	 */
	private final Optional optionalWebConversionServiceProvider;

	/**
	 * The Property resolver utils.
	 */
	private final PropertyResolverUtils propertyResolverUtils;

	/**
	 * The Expression context.
	 */
	private final BeanExpressionContext expressionContext;

	/**
	 * The Configurable bean factory.
	 */
	private final ConfigurableBeanFactory configurableBeanFactory;

	/**
	 * The Object mapper provider.
	 */
	private final ObjectMapperProvider objectMapperProvider;

	/**
	 * The javadoc provider.
	 */
	private final Optional javadocProviderOptional;

	/**
	 * Instantiates a new Generic parameter builder.
	 * @param propertyResolverUtils the property resolver utils
	 * @param optionalDelegatingMethodParameterCustomizer the optional delegating method parameter customizer
	 * @param optionalWebConversionServiceProvider the optional web conversion service provider
	 * @param objectMapperProvider the object mapper provider
	 * @param javadocProviderOptional the javadoc provider
	 */
	public GenericParameterService(PropertyResolverUtils propertyResolverUtils, Optional optionalDelegatingMethodParameterCustomizer,
			Optional optionalWebConversionServiceProvider, ObjectMapperProvider objectMapperProvider, Optional javadocProviderOptional) {
		this.propertyResolverUtils = propertyResolverUtils;
		this.optionalDelegatingMethodParameterCustomizer = optionalDelegatingMethodParameterCustomizer;
		this.optionalWebConversionServiceProvider = optionalWebConversionServiceProvider;
		this.configurableBeanFactory = propertyResolverUtils.getFactory();
		this.expressionContext = (configurableBeanFactory != null ? new BeanExpressionContext(configurableBeanFactory, new RequestScope()) : null);
		this.objectMapperProvider = objectMapperProvider;
		this.javadocProviderOptional = javadocProviderOptional;
	}

	/**
	 * Add file type.
	 *
	 * @param classes the classes
	 */
	public static void addFileType(Class... classes) {
		FILE_TYPES.addAll(Arrays.asList(classes));
	}

	/**
	 * Is file boolean.
	 *
	 * @param type the type
	 * @return the boolean
	 */
	public static boolean isFile(Class type) {
		return FILE_TYPES.stream().anyMatch(clazz -> clazz.isAssignableFrom(type));
	}

	/**
	 * Merge parameter parameter.
	 *
	 * @param existingParamDoc the existing param doc
	 * @param paramCalcul the param calcul
	 * @return the parameter
	 */
	public static Parameter mergeParameter(List existingParamDoc, Parameter paramCalcul) {
		Parameter result = paramCalcul;
		if (paramCalcul != null && paramCalcul.getName() != null) {
			final String name = paramCalcul.getName();
			final String in = paramCalcul.getIn();
			Parameter paramDoc = existingParamDoc.stream().filter(p ->
							name.equals(p.getName())
									&& (StringUtils.isEmpty(in) || StringUtils.isEmpty(p.getIn()) || in.equals(p.getIn()))
					).findAny()
					.orElse(null);
			if (paramDoc != null) {
				mergeParameter(paramCalcul, paramDoc);
				result = paramDoc;
			}
			else
				existingParamDoc.add(result);
		}
		return result;
	}

	/**
	 * Merge parameter.
	 *
	 * @param paramCalcul the param calcul
	 * @param paramDoc the param doc
	 */
	public static void mergeParameter(Parameter paramCalcul, Parameter paramDoc) {
		if (StringUtils.isBlank(paramDoc.getDescription()))
			paramDoc.setDescription(paramCalcul.getDescription());

		if (StringUtils.isBlank(paramDoc.getIn()))
			paramDoc.setIn(paramCalcul.getIn());

		if (paramDoc.getExample() == null)
			paramDoc.setExample(paramCalcul.getExample());

		if (paramDoc.getDeprecated() == null)
			paramDoc.setDeprecated(paramCalcul.getDeprecated());

		if (paramDoc.getRequired() == null)
			paramDoc.setRequired(paramCalcul.getRequired());

		if (paramDoc.getAllowEmptyValue() == null)
			paramDoc.setAllowEmptyValue(paramCalcul.getAllowEmptyValue());

		if (paramDoc.getAllowReserved() == null)
			paramDoc.setAllowReserved(paramCalcul.getAllowReserved());

		if (StringUtils.isBlank(paramDoc.get$ref()))
			paramDoc.set$ref(paramDoc.get$ref());

		if (paramDoc.getSchema() == null && paramDoc.getContent() == null)
			paramDoc.setSchema(paramCalcul.getSchema());

		if (paramDoc.getExamples() == null)
			paramDoc.setExamples(paramCalcul.getExamples());

		if (paramDoc.getExtensions() == null)
			paramDoc.setExtensions(paramCalcul.getExtensions());

		if (paramDoc.getStyle() == null)
			paramDoc.setStyle(paramCalcul.getStyle());

		if (paramDoc.getExplode() == null)
			paramDoc.setExplode(paramCalcul.getExplode());
	}

	/**
	 * Build parameter from doc parameter.
	 *
	 * @param parameterDoc the parameter doc
	 * @param components the components
	 * @param jsonView the json view
	 * @param locale the locale
	 * @return the parameter
	 */
	public Parameter buildParameterFromDoc(io.swagger.v3.oas.annotations.Parameter parameterDoc,
			Components components, JsonView jsonView, Locale locale) {
		Parameter parameter = new Parameter();
		if (StringUtils.isNotBlank(parameterDoc.description()))
			parameter.setDescription(propertyResolverUtils.resolve(parameterDoc.description(), locale));
		if (StringUtils.isNotBlank(parameterDoc.name()))
			parameter.setName(propertyResolverUtils.resolve(parameterDoc.name(), locale));
		if (StringUtils.isNotBlank(parameterDoc.in().toString()))
			parameter.setIn(parameterDoc.in().toString());
		if (StringUtils.isNotBlank(parameterDoc.example())) {
			try {
				parameter.setExample(objectMapperProvider.jsonMapper().readTree(parameterDoc.example()));
			}
			catch (IOException e) {
				parameter.setExample(parameterDoc.example());
			}
		}
		if (parameterDoc.deprecated())
			parameter.setDeprecated(parameterDoc.deprecated());
		if (parameterDoc.required())
			parameter.setRequired(parameterDoc.required());
		if (parameterDoc.allowEmptyValue())
			parameter.setAllowEmptyValue(parameterDoc.allowEmptyValue());
		if (parameterDoc.allowReserved())
			parameter.setAllowReserved(parameterDoc.allowReserved());

		if (parameterDoc.content().length > 0) {
			Optional optionalContent = AnnotationsUtils.getContent(parameterDoc.content(), null, null, null, components, jsonView, propertyResolverUtils.isOpenapi31());
			optionalContent.ifPresent(parameter::setContent);
		}
		else
			setSchema(parameterDoc, components, jsonView, parameter);

		setExamples(parameterDoc, parameter);
		setExtensions(parameterDoc, parameter, locale);
		setParameterStyle(parameter, parameterDoc);
		setParameterExplode(parameter, parameterDoc);

		return parameter;
	}

	/**
	 * Sets schema.
	 *
	 * @param parameterDoc the parameter doc
	 * @param components the components
	 * @param jsonView the json view
	 * @param parameter the parameter
	 */
	private void setSchema(io.swagger.v3.oas.annotations.Parameter parameterDoc, Components components, JsonView jsonView, Parameter parameter) {
		if (StringUtils.isNotBlank(parameterDoc.ref()))
			parameter.$ref(parameterDoc.ref());
		else {
			Schema schema = null;
			try {
				schema = AnnotationsUtils.getSchema(parameterDoc.schema(), null, false, parameterDoc.schema().implementation(), components, jsonView, propertyResolverUtils.isOpenapi31()).orElse(null);
				// Cast default value
				if (schema != null && schema.getDefault() != null) {
					PrimitiveType primitiveType = PrimitiveType.fromTypeAndFormat(schema.getType(), schema.getFormat());
					if (primitiveType != null) {
						Schema primitiveSchema = primitiveType.createProperty();
						primitiveSchema.setDefault(schema.getDefault());
						schema.setDefault(primitiveSchema.getDefault());
					}
				}
			}
			catch (Exception e) {
				LOGGER.warn(Constants.GRACEFUL_EXCEPTION_OCCURRED, e);
			}
			if (schema == null && parameterDoc.array() != null) {
				schema = AnnotationsUtils.getSchema(parameterDoc.schema(), parameterDoc.array(), true, parameterDoc.array().schema().implementation(), components, jsonView, propertyResolverUtils.isOpenapi31()).orElse(null);
				// default value not set by swagger-core for array !
				if (schema != null) {
					Object defaultValue = SpringDocAnnotationsUtils.resolveDefaultValue(parameterDoc.array().arraySchema().defaultValue(), objectMapperProvider.jsonMapper());
					schema.setDefault(defaultValue);
				}
			}
			parameter.setSchema(schema);
		}
	}

	/**
	 * Calculate schema schema.
	 *
	 * @param components the components
	 * @param parameterInfo the parameter info
	 * @param requestBodyInfo the request body info
	 * @param jsonView the json view
	 * @return the schema
	 */
	Schema calculateSchema(Components components, ParameterInfo parameterInfo, RequestBodyInfo requestBodyInfo, JsonView jsonView) {
		Schema schemaN;
		String paramName = parameterInfo.getpName();
		MethodParameter methodParameter = parameterInfo.getMethodParameter();

		if (parameterInfo.getParameterModel() == null || parameterInfo.getParameterModel().getSchema() == null) {
			Type type = ReturnTypeParser.getType(methodParameter);
			if (type instanceof Class && !((Class) type).isEnum() && optionalWebConversionServiceProvider.isPresent()) {
				WebConversionServiceProvider webConversionServiceProvider = optionalWebConversionServiceProvider.get();
				if (!MethodParameterPojoExtractor.isSwaggerPrimitiveType((Class) type) && methodParameter.getParameterType().getAnnotation(io.swagger.v3.oas.annotations.media.Schema.class) == null) {
					Class springConvertedType = webConversionServiceProvider.getSpringConvertedType(methodParameter.getParameterType());
					if (!(String.class.equals(springConvertedType) && ((Class) type).isEnum()) && requestBodyInfo == null)
						type = springConvertedType;
				}
			}
			schemaN = SpringDocAnnotationsUtils.extractSchema(components, type, jsonView, methodParameter.getParameterAnnotations(), propertyResolverUtils.getSpecVersion());
		}
		else
			schemaN = parameterInfo.getParameterModel().getSchema();

		if (requestBodyInfo != null) {
			schemaN = calculateRequestBodySchema(components, parameterInfo, requestBodyInfo, schemaN, paramName);
			JavadocProvider javadocProvider = javadocProviderOptional.orElse(null);
			if (schemaN != null && javadocProvider != null && !isRequestBodyPresent(parameterInfo)) {
				String paramJavadocDescription = getParamJavadoc(javadocProvider, methodParameter);
				if (schemaN.getProperties() != null && schemaN.getProperties().containsKey(parameterInfo.getpName())) {
					Map properties = schemaN.getProperties();
					if (!StringUtils.isBlank(paramJavadocDescription) && StringUtils.isBlank(properties.get(parameterInfo.getpName()).getDescription())) {
						properties.get(parameterInfo.getpName()).setDescription(paramJavadocDescription);
					}
				}
			}
		}

		return schemaN;
	}

	/**
	 * Calculate request body schema schema.
	 *
	 * @param components the components
	 * @param parameterInfo the parameter info
	 * @param requestBodyInfo the request body info
	 * @param schemaN the schema n
	 * @param paramName the param name
	 * @return the schema
	 */
	private Schema calculateRequestBodySchema(Components components, ParameterInfo parameterInfo, RequestBodyInfo requestBodyInfo, Schema schemaN, String paramName) {
		if (schemaN != null && StringUtils.isEmpty(schemaN.getDescription()) && parameterInfo.getParameterModel() != null) {
			String description = parameterInfo.getParameterModel().getDescription();
			if (schemaN.get$ref() != null && schemaN.get$ref().contains(AnnotationsUtils.COMPONENTS_REF)) {
				String key = schemaN.get$ref().substring(21);
				Schema existingSchema = components.getSchemas().get(key);
				if (!StringUtils.isEmpty(description))
					existingSchema.setDescription(description);
			}
			else
				schemaN.setDescription(description);
		}

		if (requestBodyInfo.getMergedSchema() != null) {
			requestBodyInfo.getMergedSchema().addProperty(paramName, schemaN);
			schemaN = requestBodyInfo.getMergedSchema();
		}
		else if (parameterInfo.isRequestPart() || schemaN instanceof FileSchema || schemaN instanceof ArraySchema && ((ArraySchema) schemaN).getItems() instanceof FileSchema) {
			schemaN = new ObjectSchema().addProperty(paramName, schemaN);
			requestBodyInfo.setMergedSchema(schemaN);
		}
		else
			requestBodyInfo.addProperties(paramName, schemaN);

		if (requestBodyInfo.getMergedSchema() != null && parameterInfo.isRequired())
			requestBodyInfo.getMergedSchema().addRequiredItem(parameterInfo.getpName());

		return schemaN;
	}

	/**
	 * Sets examples.
	 *
	 * @param parameterDoc the parameter doc
	 * @param parameter the parameter
	 */
	private void setExamples(io.swagger.v3.oas.annotations.Parameter parameterDoc, Parameter parameter) {
		Map exampleMap = new HashMap<>();
		if (parameterDoc.examples().length == 1 && StringUtils.isBlank(parameterDoc.examples()[0].name())) {
			Optional exampleOptional = AnnotationsUtils.getExample(parameterDoc.examples()[0]);
			exampleOptional.ifPresent(parameter::setExample);
		}
		else {
			for (ExampleObject exampleObject : parameterDoc.examples()) {
				AnnotationsUtils.getExample(exampleObject)
						.ifPresent(example -> exampleMap.put(exampleObject.name(), example));
			}
		}
		if (exampleMap.size() > 0) {
			parameter.setExamples(exampleMap);
		}
	}

	/**
	 * Sets extensions.
	 *
	 * @param parameterDoc the parameter doc
	 * @param parameter    the parameter
	 * @param locale       the locale
	 */
	private void setExtensions(io.swagger.v3.oas.annotations.Parameter parameterDoc, Parameter parameter, Locale locale)  {
		if (parameterDoc.extensions().length > 0) {
			Map extensionMap = AnnotationsUtils.getExtensions(propertyResolverUtils.isOpenapi31(), parameterDoc.extensions());
			if (propertyResolverUtils.isResolveExtensionsProperties()) {
				Map extensionsResolved = propertyResolverUtils.resolveExtensions(locale, extensionMap);
				extensionsResolved.forEach(parameter::addExtension);
			}
			else {
				extensionMap.forEach(parameter::addExtension);
			}
		}
	}

	/**
	 * Sets parameter explode.
	 *
	 * @param parameter the parameter
	 * @param p the p
	 */
	private void setParameterExplode(Parameter parameter, io.swagger.v3.oas.annotations.Parameter p) {
		if (isExplodable(p)) {
			if (Explode.TRUE.equals(p.explode())) {
				parameter.setExplode(Boolean.TRUE);
			}
			else if (Explode.FALSE.equals(p.explode())) {
				parameter.setExplode(Boolean.FALSE);
			}
		}
	}

	/**
	 * Sets parameter style.
	 *
	 * @param parameter the parameter
	 * @param p the p
	 */
	private void setParameterStyle(Parameter parameter, io.swagger.v3.oas.annotations.Parameter p) {
		if (StringUtils.isNotBlank(p.style().toString())) {
			parameter.setStyle(Parameter.StyleEnum.valueOf(p.style().toString().toUpperCase()));
		}
	}

	/**
	 * Is explodable boolean.
	 *
	 * @param p the p
	 * @return the boolean
	 */
	private boolean isExplodable(io.swagger.v3.oas.annotations.Parameter p) {
		io.swagger.v3.oas.annotations.media.Schema schema = p.schema();
		io.swagger.v3.oas.annotations.media.ArraySchema arraySchema = p.array();

		boolean explode = true;
		Class implementation = schema.implementation();
		if (implementation == Void.class && !schema.type().equals("object") && !schema.type().equals("array") && !AnnotationsUtils.hasArrayAnnotation(arraySchema)) {
			explode = false;
		}
		return explode;
	}

	/**
	 * Is file boolean.
	 *
	 * @param methodParameter the method parameter
	 * @return the boolean
	 */
	public boolean isFile(MethodParameter methodParameter) {
		if (methodParameter.getGenericParameterType() instanceof ParameterizedType) {
			ParameterizedType parameterizedType = (ParameterizedType) methodParameter.getGenericParameterType();
			return isFile(parameterizedType);
		}
		else {
			Class type = methodParameter.getParameterType();
			return isFile(type);
		}
	}

	/**
	 * Gets delegating method parameter customizer.
	 *
	 * @return the delegating method parameter customizer
	 */
	public Optional getDelegatingMethodParameterCustomizer() {
		return optionalDelegatingMethodParameterCustomizer;
	}

	/**
	 * Is file boolean.
	 *
	 * @param parameterizedType the parameterized type
	 * @return the boolean
	 */
	private boolean isFile(ParameterizedType parameterizedType) {
		Type type = parameterizedType.getActualTypeArguments()[0];
		Class fileClass = ResolvableType.forType(type).getRawClass();
		if (fileClass != null && isFile(fileClass))
			return true;
		else if (type instanceof WildcardType) {
			WildcardType wildcardType = (WildcardType) type;
			Type[] upperBounds = wildcardType.getUpperBounds();
			return MultipartFile.class.getName().equals(upperBounds[0].getTypeName());
		}
		return false;
	}

	/**
	 * Gets property resolver utils.
	 *
	 * @return the property resolver utils
	 */
	public PropertyResolverUtils getPropertyResolverUtils() {
		return propertyResolverUtils;
	}

	/**
	 * Gets optional web conversion service provider.
	 *
	 * @return the optional web conversion service provider
	 */
	public Optional getOptionalWebConversionServiceProvider() {
		return optionalWebConversionServiceProvider;
	}

	/**
	 * Resolve the given annotation-specified value,
	 * potentially containing placeholders and expressions.
	 * @param value the value
	 * @return the object
	 */
	public Object resolveEmbeddedValuesAndExpressions(String value) {
		if (this.configurableBeanFactory == null || this.expressionContext == null) {
			return value;
		}
		String placeholdersResolved = this.configurableBeanFactory.resolveEmbeddedValue(value);
		BeanExpressionResolver exprResolver = this.configurableBeanFactory.getBeanExpressionResolver();
		if (exprResolver == null) {
			return value;
		}
		return exprResolver.evaluate(placeholdersResolved, this.expressionContext);
	}

	/**
	 * Generate parameter by schema
	 *
	 * @param schema the schema
	 * @return the io.swagger.v3.oas.annotations.Parameter
	 */
	public io.swagger.v3.oas.annotations.Parameter generateParameterBySchema(io.swagger.v3.oas.annotations.media.Schema schema) {
		return new io.swagger.v3.oas.annotations.Parameter() {
			@Override
			public Class annotationType() {
				return io.swagger.v3.oas.annotations.Parameter.class;
			}

			@Override
			public String name() {
				return schema.name();
			}

			@Override
			public ParameterIn in() {
				return ParameterIn.DEFAULT;
			}

			@Override
			public String description() {
				return schema.description();
			}

			@Override
			public boolean required() {
				return schema.requiredMode().equals(RequiredMode.AUTO) ?
						schema.required() :
						schema.requiredMode().equals(RequiredMode.REQUIRED);
			}

			@Override
			public boolean deprecated() {
				return schema.deprecated();
			}

			@Override
			public boolean allowEmptyValue() {
				return false;
			}

			@Override
			public ParameterStyle style() {
				return ParameterStyle.DEFAULT;
			}

			@Override
			public Explode explode() {
				return Explode.DEFAULT;
			}

			@Override
			public boolean allowReserved() {
				return false;
			}

			@Override
			public io.swagger.v3.oas.annotations.media.Schema schema() {
				return schema;
			}

			@Override
			public io.swagger.v3.oas.annotations.media.ArraySchema array() {
				return null;
			}

			@Override
			public io.swagger.v3.oas.annotations.media.Content[] content() {
				return new io.swagger.v3.oas.annotations.media.Content[0];
			}

			@Override
			public boolean hidden() {
				return schema.hidden();
			}

			@Override
			public ExampleObject[] examples() {
				return new ExampleObject[0];
			}

			@Override
			public String example() {
				return schema.example();
			}

			@Override
			public Extension[] extensions() {
				return schema.extensions();
			}

			@Override
			public String ref() {
				return schema.ref();
			}
		};
	}

	/**
	 * Gets javadoc provider.
	 *
	 * @return the javadoc provider
	 */
	public JavadocProvider getJavadocProvider() {
		return javadocProviderOptional.orElse(null);
	}

	/**
	 * Is request body present boolean.
	 *
	 * @param parameterInfo the parameter info
	 * @return the boolean
	 */
	public boolean isRequestBodyPresent(ParameterInfo parameterInfo) {
		return parameterInfo.getMethodParameter().getParameterAnnotation(io.swagger.v3.oas.annotations.parameters.RequestBody.class) != null
				|| parameterInfo.getMethodParameter().getParameterAnnotation(org.springframework.web.bind.annotation.RequestBody.class) != null
				|| AnnotatedElementUtils.findMergedAnnotation(Objects.requireNonNull(parameterInfo.getMethodParameter().getMethod()), io.swagger.v3.oas.annotations.parameters.RequestBody.class) != null;
	}

	/**
	 * Gets param javadoc.
	 *
	 * @param javadocProvider the javadoc provider
	 * @param methodParameter the method parameter
	 * @return the param javadoc
	 */
	String getParamJavadoc(JavadocProvider javadocProvider, MethodParameter methodParameter) {
		String pName = methodParameter.getParameterName();
		DelegatingMethodParameter delegatingMethodParameter = (DelegatingMethodParameter) methodParameter;
		if (!delegatingMethodParameter.isParameterObject()) {
			return javadocProvider.getParamJavadoc(methodParameter.getMethod(), pName);
		}
		String fieldName;
		if (StringUtils.isNotEmpty(pName) && pName.contains(DOT))
			fieldName = StringUtils.substringAfterLast(pName, DOT);
		else fieldName = pName;

		String paramJavadocDescription = null;
		Class cls = ((DelegatingMethodParameter) methodParameter).getExecutable().getDeclaringClass();
		if (cls.getSuperclass() != null && "java.lang.Record".equals(cls.getSuperclass().getName())) {
			Map recordParamMap = javadocProvider.getRecordClassParamJavadoc(cls);
			if (recordParamMap.containsKey(fieldName)) {
				paramJavadocDescription = recordParamMap.get(fieldName);
			}
		}

		Field field = FieldUtils.getDeclaredField(cls, fieldName, true);
		String fieldJavadoc = javadocProvider.getFieldJavadoc(field);
		if (StringUtils.isNotBlank(fieldJavadoc)) {
			paramJavadocDescription = fieldJavadoc;
		}
		return paramJavadocDescription;
	}

	/**
	 * Is openapi 31 boolean.
	 *
	 * @return the boolean
	 */
	public boolean isOpenapi31() {
		return propertyResolverUtils.isOpenapi31();
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy