“This is the 12th day of my participation in the First Challenge 2022. For details: First Challenge 2022.”

Hello everyone, I’m Ah Q!

We talked about springMVC and Swagger’s dependency on @RequestBody and found out what the problem is. In this article we will provide detailed answers on how to solve the problem!

To solve the problem

From the above analysis, it can be concluded that the fundamental problem here is the conflict between springMVC’s separate parameter parser functionality and Swagger functionality. One requirement cannot be annotated with @requestBody and the other must be annotated with @RequestBody, so there are two solutions

  • fromspringmvcStart by looking for ways to increase the priority of a custom parameter parser, as long as the custom parameter parser priority ratioRequestResponseBodyMethodProcessorHigh, can be added to the custom parameter@RequestBodyAnnotations,swaggerThe function will naturally return to normal.
  • fromswaggerGo ahead and figure out how to get rid of the top two parts Yeah@RequestBodyIs determined separately, not modifiedspringmvcRelated functions can also be madeswaggerFunction is normal.

Considering that changing springMVC functionality might have a big impact on future upgrades, we decided to use sections to change the behavior of the original Swagger in both places of @RequestBody so that Swagger functions properly.

Logical adjustments to request type determination

First, define an annotation

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface NoSwaggerExpand {

    /**
     * default swagger expand disable
     * @see OperationParameterReader#shouldExpand(springfox.documentation.service.ResolvedMethodParameter, com.fasterxml.classmate.ResolvedType)
     */
    boolean expand(a) default false;
}
Copy the code

Add it to the input parameter

    @ApiOperation(value = "demo", notes = "demo")
    @PostMapping(value = "/test")
    public Result<booleantest(@HdxDecrypt @NoSwaggerExpand @ApiParam(required = true) ReqDTO reqDTO) {
        try {
            log.info(ObjectMapperFactory.getObjectMapper().writeValueAsString(reqDTO));
        } catch (JsonProcessingException e) {
            log.error("", e);
        }
        return null;
    }
Copy the code

Then define the facets — omit parts consistent with the source code analyzed above, and give code only for the changes

@Slf4j
@Aspect
@Component
public class SwaggerExpandAspect {...@Around("execution(* springfox.documentation.spring.web.readers.operation.OperationParameterReader.apply(..) )"
    public Object pointCut(ProceedingJoinPoint point) throws Throwable {
        Object[] args = point.getArgs();
        OperationContext context = (OperationContext) args[0];
        context.operationBuilder().parameters(context.getGlobalOperationParameters());
        context.operationBuilder().parameters(readParameters(context));
        return null; }...private boolean shouldExpand(final ResolvedMethodParameter parameter, ResolvedType resolvedParamType) {
        return! parameter.hasParameterAnnotation(RequestBody.class) && ! parameter.hasParameterAnnotation(RequestPart.class) && ! parameter.hasParameterAnnotation(RequestParam.class) && ! parameter.hasParameterAnnotation(PathVariable.class) && ! isBaseType(typeNameFor(resolvedParamType.getErasedType())) && ! enumTypeDeterminer.isEnum(resolvedParamType.getErasedType()) && ! isContainerType(resolvedParamType) && ! isMapType(resolvedParamType) && ! noExpandAnnotaion(parameter); }private boolean noExpandAnnotaion(ResolvedMethodParameter parameter) {
        log.info("Start deciding whether to open the question.");
        if(! parameter.hasParameterAnnotation(NoSwaggerExpand.class)) {return false;
        }
        NoSwaggerExpand noSwaggerExpand = (NoSwaggerExpand) parameter.getAnnotations().stream().filter(item -> item instanceof NoSwaggerExpand).findAny().orElse(null);
        if (noSwaggerExpand.expand()) {
            return false;
        }
        return true; }}Copy the code

The most important thing is the modification here

We add a check on the custom annotation modifier so that the custom annotation modifier can be handled by Swagger as @requestBody.

Logical adjustment of the Definition property value population

Define a section again — omit sections consistent with the source code analyzed above, and give code only for the changes

@Slf4j
@Aspect
@Component
public class SwaggerDefinitionAspect {...@Around("execution(* springfox.documentation.spring.web.readers.operation.OperationModelsProvider.apply(..) )"
    public Object pointCut(ProceedingJoinPoint point) throws Throwable {
        Object[] args = point.getArgs();
        RequestMappingContext context = (RequestMappingContext) args[0];
        collectFromReturnType(context);
        collectParameters(context);
        collectGlobalModels(context);
        return null; }...private void collectParameters(RequestMappingContext context) {


        LOG.debug("Reading parameters models for handlerMethod |{}|", context.getName());

        List<resolvedmethodparameter> parameterTypes = context.getParameters();
        for (ResolvedMethodParameter parameterType : parameterTypes) {
            if (parameterType.hasParameterAnnotation(RequestBody.class)
                    || parameterType.hasParameterAnnotation(RequestPart.class)
            || parameterType.hasParameterAnnotation(NoSwaggerExpand.class)
            ) {
                ResolvedType modelType = context.alternateFor(parameterType.getParameterType());
                LOG.debug("Adding input parameter of type {}", resolvedTypeSignature(modelType).or("<null>"));
                context.operationModelsBuilder().addInputParam(modelType);
            }
        }
        LOG.debug("Finished reading parameters models for handlerMethod |{}|", context.getName()); }}Copy the code

There is only one change in the code here, so that input parameters that are modified by custom annotations can be added to the Definition property.

After the above two steps, we can fix the conflict between springMVC’s independent parameter parser function and Swagger function.

Post off

Ah Q will continue to update the Java practice of the article, interested in the public account can pay attention to: AH Q said the code, also can come to the technical group to discuss the problem!