Skip to content

Commit

Permalink
Merge branch 'default-flat-object' of github.com:NaccOll/springdoc-op…
Browse files Browse the repository at this point in the history
…enapi into NaccOll-default-flat-object
  • Loading branch information
bnasslahsen committed Aug 20, 2022
2 parents fb02518 + 6720e1e commit 3ef246d
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 51 deletions.
Expand Up @@ -185,6 +185,7 @@ protected AbstractRequestService(GenericParameterService parameterBuilder, Reque
parameterCustomizers.ifPresent(customizers -> customizers.removeIf(Objects::isNull));
this.parameterCustomizers = parameterCustomizers;
this.localSpringDocParameterNameDiscoverer = localSpringDocParameterNameDiscoverer;
parameterBuilder.addIgnoreType(PARAM_TYPES_TO_IGNORE);
}

/**
Expand Down Expand Up @@ -239,7 +240,7 @@ public Operation build(HandlerMethod handlerMethod, RequestMethod requestMethod,
String[] reflectionParametersNames = Arrays.stream(handlerMethod.getMethod().getParameters()).map(java.lang.reflect.Parameter::getName).toArray(String[]::new);
if (pNames == null || Arrays.stream(pNames).anyMatch(Objects::isNull))
pNames = reflectionParametersNames;
parameters = DelegatingMethodParameter.customize(pNames, parameters, parameterBuilder.getDelegatingMethodParameterCustomizer());
parameters = parameterBuilder.customize(pNames, parameters, parameterBuilder.getDelegatingMethodParameterCustomizer());
RequestBodyInfo requestBodyInfo = new RequestBodyInfo();
List<Parameter> operationParameters = (operation.getParameters() != null) ? operation.getParameters() : new ArrayList<>();
Map<String, io.swagger.v3.oas.annotations.Parameter> parametersDocMap = getApiParameters(handlerMethod.getMethod());
Expand Down Expand Up @@ -322,7 +323,7 @@ else if (!RequestMethod.GET.equals(requestMethod)) {
Entry<String, Parameter> entry = it.next();
Parameter parameter = entry.getValue();
if (!ParameterIn.PATH.toString().equals(parameter.getIn())) {
io.swagger.v3.oas.models.media.Schema<?> itemSchema = new io.swagger.v3.oas.models.media.Schema() ;
io.swagger.v3.oas.models.media.Schema<?> itemSchema = new io.swagger.v3.oas.models.media.Schema();
itemSchema.setName(entry.getKey());
itemSchema.setDescription(parameter.getDescription());
itemSchema.setDeprecated(parameter.getDeprecated());
Expand Down
Expand Up @@ -29,23 +29,16 @@
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springdoc.api.annotations.ParameterObject;
import org.springdoc.core.converters.AdditionalModelsConverter;
import org.springdoc.core.customizers.DelegatingMethodParameterCustomizer;

import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;

Expand Down Expand Up @@ -103,33 +96,6 @@ public class DelegatingMethodParameter extends MethodParameter {
this.isNotRequired = isNotRequired;
}

/**
* Customize method parameter [ ].
*
* @param pNames the p names
* @param parameters the parameters
* @param optionalDelegatingMethodParameterCustomizer the optional delegating method parameter customizer
* @return the method parameter [ ]
*/
public static MethodParameter[] customize(String[] pNames, MethodParameter[] parameters, Optional<DelegatingMethodParameterCustomizer> optionalDelegatingMethodParameterCustomizer) {
List<MethodParameter> explodedParameters = new ArrayList<>();
for (int i = 0; i < parameters.length; ++i) {
MethodParameter p = parameters[i];
Class<?> paramClass = AdditionalModelsConverter.getParameterObjectReplacement(p.getParameterType());

if (!MethodParameterPojoExtractor.isSimpleType(paramClass) && (p.hasParameterAnnotation(ParameterObject.class) || AnnotatedElementUtils.isAnnotated(paramClass, ParameterObject.class))) {
MethodParameterPojoExtractor.extractFrom(paramClass).forEach(methodParameter -> {
optionalDelegatingMethodParameterCustomizer.ifPresent(customizer -> customizer.customize(p, methodParameter));
explodedParameters.add(methodParameter);
});
}
else {
String name = pNames != null ? pNames[i] : p.getParameterName();
explodedParameters.add(new DelegatingMethodParameter(p, name, null, false, false));
}
}
return explodedParameters.toArray(new MethodParameter[0]);
}

@Override
@NonNull
Expand Down Expand Up @@ -274,4 +240,4 @@ public static MethodParameter changeContainingClass(MethodParameter methodParame
return result;
}

}
}
Expand Up @@ -55,6 +55,8 @@
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springdoc.api.annotations.ParameterObject;
import org.springdoc.core.converters.AdditionalModelsConverter;
import org.springdoc.core.customizers.DelegatingMethodParameterCustomizer;
import org.springdoc.core.providers.ObjectMapperProvider;
import org.springdoc.core.providers.WebConversionServiceProvider;
Expand All @@ -64,6 +66,7 @@
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;
Expand Down Expand Up @@ -122,6 +125,13 @@ public class GenericParameterService {
*/
private final ObjectMapperProvider objectMapperProvider;

/**
* The constant PARAM_TYPES_TO_IGNORE.
*/
private final List<Class<?>> PARAM_TYPES_TO_IGNORE = Collections.synchronizedList(new ArrayList<>());

private final boolean defaultFlatParamObject;

/**
* Instantiates a new Generic parameter builder.
* @param propertyResolverUtils the property resolver utils
Expand All @@ -130,13 +140,18 @@ public class GenericParameterService {
* @param objectMapperProvider the object mapper provider
*/
public GenericParameterService(PropertyResolverUtils propertyResolverUtils, Optional<DelegatingMethodParameterCustomizer> optionalDelegatingMethodParameterCustomizer,
Optional<WebConversionServiceProvider> optionalWebConversionServiceProvider, ObjectMapperProvider objectMapperProvider) {
Optional<WebConversionServiceProvider> optionalWebConversionServiceProvider, ObjectMapperProvider objectMapperProvider, boolean defaultFlatParamObject) {
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.defaultFlatParamObject = defaultFlatParamObject;
}

protected void addIgnoreType(List<Class<?>> classes) {
PARAM_TYPES_TO_IGNORE.addAll(classes);
}

/**
Expand Down Expand Up @@ -333,9 +348,9 @@ Schema calculateSchema(Components components, ParameterInfo parameterInfo, Reque

if (parameterInfo.getParameterModel() == null || parameterInfo.getParameterModel().getSchema() == null) {
Type type = ReturnTypeParser.getType(methodParameter);
if(type instanceof Class && optionalWebConversionServiceProvider.isPresent()){
if (type instanceof Class && optionalWebConversionServiceProvider.isPresent()) {
WebConversionServiceProvider webConversionServiceProvider = optionalWebConversionServiceProvider.get();
if (!MethodParameterPojoExtractor.isSwaggerPrimitiveType((Class) type) && methodParameter.getParameterType().getAnnotation(io.swagger.v3.oas.annotations.media.Schema.class)==null)
if (!MethodParameterPojoExtractor.isSwaggerPrimitiveType((Class) type) && methodParameter.getParameterType().getAnnotation(io.swagger.v3.oas.annotations.media.Schema.class) == null)
type = webConversionServiceProvider.getSpringConvertedType(methodParameter.getParameterType());
}
schemaN = SpringDocAnnotationsUtils.extractSchema(components, type, jsonView, methodParameter.getParameterAnnotations());
Expand Down Expand Up @@ -566,6 +581,7 @@ public io.swagger.v3.oas.annotations.Parameter generateParameterBySchema(io.swag
public Class<? extends Annotation> annotationType() {
return io.swagger.v3.oas.annotations.Parameter.class;
}

@Override
public String name() {
return schema.name();
Expand Down Expand Up @@ -652,4 +668,47 @@ public String ref() {
}
};
}

/**
* Customize method parameter [ ].
*
* @param pNames the p names
* @param parameters the parameters
* @param optionalDelegatingMethodParameterCustomizer the optional delegating method parameter customizer
* @return the method parameter [ ]
*/
public MethodParameter[] customize(String[] pNames, MethodParameter[] parameters, Optional<DelegatingMethodParameterCustomizer> optionalDelegatingMethodParameterCustomizer) {
List<MethodParameter> explodedParameters = new ArrayList<>();
for (int i = 0; i < parameters.length; ++i) {
MethodParameter p = parameters[i];
Class<?> paramClass = AdditionalModelsConverter.getParameterObjectReplacement(p.getParameterType());
if (!MethodParameterPojoExtractor.isSimpleType(paramClass) && (p.hasParameterAnnotation(ParameterObject.class) || AnnotatedElementUtils.isAnnotated(paramClass, ParameterObject.class))) {
MethodParameterPojoExtractor.extractFrom(paramClass).forEach(methodParameter -> {
optionalDelegatingMethodParameterCustomizer.ifPresent(customizer -> customizer.customize(p, methodParameter));
explodedParameters.add(methodParameter);
});
}
else if (defaultFlatParamObject) {
boolean isSimpleType = MethodParameterPojoExtractor.isSimpleType(paramClass);
boolean hasAnnotation = p.hasParameterAnnotations();
boolean shouldFlat = !isSimpleType && !hasAnnotation;
if (shouldFlat && PARAM_TYPES_TO_IGNORE.stream().noneMatch(ignore -> ignore.isAssignableFrom(paramClass))) {
MethodParameterPojoExtractor.extractFrom(paramClass).forEach(methodParameter -> {
optionalDelegatingMethodParameterCustomizer
.ifPresent(customizer -> customizer.customize(p, methodParameter));
explodedParameters.add(methodParameter);
});
}
else {
String name = pNames != null ? pNames[i] : p.getParameterName();
explodedParameters.add(new DelegatingMethodParameter(p, name, null, false, false));
}
}
else {
String name = pNames != null ? pNames[i] : p.getParameterName();
explodedParameters.add(new DelegatingMethodParameter(p, name, null, false, false));
}
}
return explodedParameters.toArray(new MethodParameter[0]);
}
}
Expand Up @@ -28,6 +28,7 @@
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.nio.charset.Charset;
import java.time.Duration;
import java.time.LocalTime;
import java.util.ArrayList;
Expand Down Expand Up @@ -83,6 +84,7 @@ private MethodParameterPojoExtractor() {
SIMPLE_TYPES.add(OptionalDouble.class);
SIMPLE_TYPES.add(AtomicLong.class);
SIMPLE_TYPES.add(AtomicInteger.class);
SIMPLE_TYPES.add(Charset.class);

SIMPLE_TYPES.add(Map.class);
SIMPLE_TYPES.add(Iterable.class);
Expand Down Expand Up @@ -154,7 +156,7 @@ private static Class<?> extractType(Class<?> paramClass, Field field) {

if (fieldType instanceof Class<?>)
type = (Class<?>) fieldType;
else // This is the case for not reifiable types
else // This is the case for not reifiable types
type = null;
}

Expand All @@ -173,7 +175,7 @@ private static Stream<MethodParameter> fromSimpleClass(Class<?> paramClass, Fiel
Annotation[] fieldAnnotations = field.getDeclaredAnnotations();
try {
Parameter parameter = field.getAnnotation(Parameter.class);
boolean isNotRequired = parameter == null || !parameter.required();
boolean isNotRequired = parameter == null || !parameter.required();
Annotation[] finalFieldAnnotations = fieldAnnotations;
return Stream.of(Introspector.getBeanInfo(paramClass).getPropertyDescriptors())
.filter(d -> d.getName().equals(field.getName()))
Expand Down
Expand Up @@ -176,6 +176,11 @@ public class SpringDocConfigProperties {
*/
private boolean showSpringCloudFunctions;

/**
* The param default flatten
*/
private boolean defaultFlatParamObject;

/**
* The model Converters
*/
Expand Down Expand Up @@ -222,6 +227,18 @@ public void setShowSpringCloudFunctions(boolean showSpringCloudFunctions) {
this.showSpringCloudFunctions = showSpringCloudFunctions;
}

/**
* Is default flat param object
* @return the boolean
*/
public boolean isDefaultFlatParamObject() {
return defaultFlatParamObject;
}

public void setDefaultFlatParamObject(boolean defaultFlatParamObject) {
this.defaultFlatParamObject = defaultFlatParamObject;
}

/**
* Gets model converters.
*
Expand Down
Expand Up @@ -240,7 +240,7 @@ PolymorphicModelConverter polymorphicModelConverter(ObjectMapperProvider objectM
@Lazy(false)
OpenAPIService openAPIBuilder(Optional<OpenAPI> openAPI,
SecurityService securityParser,
SpringDocConfigProperties springDocConfigProperties,PropertyResolverUtils propertyResolverUtils,
SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils,
Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomisers,
Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomisers, Optional<JavadocProvider> javadocProvider) {
return new OpenAPIService(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomisers, serverBaseUrlCustomisers, javadocProvider);
Expand Down Expand Up @@ -335,16 +335,18 @@ ReturnTypeParser genericReturnTypeParser() {
* @param optionalDelegatingMethodParameterCustomizer the optional delegating method parameter customizer
* @param optionalWebConversionServiceProvider the optional web conversion service provider
* @param objectMapperProvider the object mapper provider
* @param springDocConfigProperties the springdoc config properties
* @return the generic parameter builder
*/
@Bean
@ConditionalOnMissingBean
@Lazy(false)
GenericParameterService parameterBuilder(PropertyResolverUtils propertyResolverUtils,
Optional<DelegatingMethodParameterCustomizer> optionalDelegatingMethodParameterCustomizer,
Optional<WebConversionServiceProvider> optionalWebConversionServiceProvider, ObjectMapperProvider objectMapperProvider) {
Optional<WebConversionServiceProvider> optionalWebConversionServiceProvider, ObjectMapperProvider objectMapperProvider,
SpringDocConfigProperties springDocConfigProperties) {
return new GenericParameterService(propertyResolverUtils, optionalDelegatingMethodParameterCustomizer,
optionalWebConversionServiceProvider, objectMapperProvider);
optionalWebConversionServiceProvider, objectMapperProvider, springDocConfigProperties.isDefaultFlatParamObject());
}

/**
Expand Down Expand Up @@ -411,7 +413,7 @@ static BeanFactoryPostProcessor springdocBeanFactoryPostProcessor2() {
@Lazy(false)
SpringDocProviders springDocProviders(Optional<ActuatorProvider> actuatorProvider, Optional<CloudFunctionProvider> springCloudFunctionProvider, Optional<SecurityOAuth2Provider> springSecurityOAuth2Provider,
Optional<RepositoryRestResourceProvider> repositoryRestResourceProvider, Optional<RouterFunctionProvider> routerFunctionProvider,
Optional<SpringWebProvider> springWebProvider, Optional<WebConversionServiceProvider> webConversionServiceProvider,
Optional<SpringWebProvider> springWebProvider, Optional<WebConversionServiceProvider> webConversionServiceProvider,
ObjectMapperProvider objectMapperProvider) {
return new SpringDocProviders(actuatorProvider, springCloudFunctionProvider, springSecurityOAuth2Provider, repositoryRestResourceProvider, routerFunctionProvider, springWebProvider, webConversionServiceProvider, objectMapperProvider);
}
Expand Down Expand Up @@ -611,7 +613,7 @@ CloudFunctionProvider springCloudFunctionProvider(Optional<FunctionCatalog> func
@Bean
@ConditionalOnMissingBean
@Lazy(false)
ObjectMapperProvider springDocObjectMapperProvider(SpringDocConfigProperties springDocConfigProperties){
ObjectMapperProvider springDocObjectMapperProvider(SpringDocConfigProperties springDocConfigProperties) {
return new ObjectMapperProvider(springDocConfigProperties);
}

Expand Down
Expand Up @@ -40,7 +40,6 @@
import io.swagger.v3.oas.models.parameters.Parameter;
import org.apache.commons.lang3.ArrayUtils;
import org.springdoc.core.AbstractRequestService;
import org.springdoc.core.DelegatingMethodParameter;
import org.springdoc.core.GenericParameterService;
import org.springdoc.core.MethodAttributes;
import org.springdoc.core.ParameterInfo;
Expand Down Expand Up @@ -149,7 +148,7 @@ public void buildParameters(OpenAPI openAPI, HandlerMethod handlerMethod, Reques
*/
public void buildCommonParameters(OpenAPI openAPI, RequestMethod requestMethod, MethodAttributes methodAttributes, Operation operation, String[] pNames, MethodParameter[] parameters,
DataRestRepository dataRestRepository) {
parameters = DelegatingMethodParameter.customize(pNames, parameters, parameterBuilder.getDelegatingMethodParameterCustomizer());
parameters = parameterBuilder.customize(pNames, parameters, parameterBuilder.getDelegatingMethodParameterCustomizer());
Class<?> domainType = dataRestRepository.getDomainType();
for (MethodParameter methodParameter : parameters) {
final String pName = methodParameter.getParameterName();
Expand Down
Expand Up @@ -37,4 +37,11 @@ public class Dog {
)
String displayName;

}
public String getDisplayName() {
return displayName;
}

public void setDisplayName(String displayName) {
this.displayName = displayName;
}
}
Expand Up @@ -27,4 +27,12 @@
public abstract class BaseClientModel {
@JsonProperty("id")
int id;

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}
}
Expand Up @@ -27,4 +27,12 @@
public class SpecificClientModel extends BaseClientModel {
@JsonProperty("name")
String name;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

0 comments on commit 3ef246d

Please sign in to comment.