springfox-swagger2坑

时间:2025-03-17 08:14:42

环境:jdk1.8+,spring boot(2.1.),springfox-swagger2(2.5.0),springfox-swagger-ui(2.5.0)

最近使用springfox-swagger2。本来好好的接口,有一天突然发现swagger显示的接口参数A跟原来不一致,接口参数的描述变成了另外一个类A1的描述。检查后发现接口没变。但是别的同事增加了另外一个接口,而接口中定义了一个同样类名的对象,即A跟A1的类名相同。导致springfox-swagger2在生成swagger对象时,ModelMapper在合并Model时类名相同的model会被覆盖。主要是因为DefaultModelProvider在生成model时id和name设置成了类名,存储在map中的key使用的是类名。

DefaultModelProvider会调用.

进一步调用TypeNameProviderPlugin extends Plugin<DocumentationType>.nameFor(DefaultTypeNameProvider或者ApiModelTypeNameProvider)

 

DefaultModelProvider

  private Model modelBuilder(ResolvedType propertiesHost,
                             Map<String, ModelProperty> properties,
                             ModelContext modelContext) {
    String typeName = ((modelContext, propertiesHost));
    ()
        .id(typeName)
        .type(propertiesHost)
        .name(typeName)
        .qualifiedType(simpleQualifiedTypeName(propertiesHost))
        .properties(properties)
        .description("")
        .baseModel("")
        .discriminator("")
        .subTypes(new ArrayList<String>());
    return (modelContext);
  }

 

@Component
public class TypeNameExtractor {
  private final TypeResolver typeResolver;
  private final PluginRegistry<TypeNameProviderPlugin, DocumentationType> typeNameProviders;

  @Autowired
  public TypeNameExtractor(TypeResolver typeResolver,
                           @Qualifier("typeNameProviderPluginRegistry")
                           PluginRegistry<TypeNameProviderPlugin, DocumentationType> typeNameProviders) {

     = typeResolver;
     = typeNameProviders;
  }

  public String typeName(ModelContext context) {
    ResolvedType type = asResolved(());
    if (isContainerType(type)) {
      return containerType(type);
    }
    return innerTypeName(type, context);
  }

  private ResolvedType asResolved(Type type) {
    return (type);
  }

  private String genericTypeName(ResolvedType resolvedType, ModelContext context) {
    ......
  }

  private String innerTypeName(ResolvedType type, ModelContext context) {
    if (().size() > 0 && ().getTypeParameters().length > 0) {
      return genericTypeName(type, context);
    }
    return simpleTypeName(type, context);
  }

  private String simpleTypeName(ResolvedType type, ModelContext context) {
    ......

    return typeName(new ModelNameContext((), ()));
  }

  private String typeName(ModelNameContext context) {
    TypeNameProviderPlugin selected =
        ((), new DefaultTypeNameProvider());
    return (());
  }
}

 


@Component
@Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER)
public class ApiModelTypeNameProvider extends DefaultTypeNameProvider {
  @Override
  public String nameFor(Class<?> type) {
    ApiModel annotation = findAnnotation(type, );
    String defaultTypeName = (type);
    if (annotation != null) {
      return fromNullable(emptyToNull(())).or(defaultTypeName);
    }
    return defaultTypeName;
  }

  @Override
  public boolean supports(DocumentationType delimiter) {
    return (delimiter);
  }
}


public class DefaultTypeNameProvider implements TypeNameProviderPlugin {

  @Override
  public boolean supports(DocumentationType delimiter) {
    return true;
  }

  @Override
  public String nameFor(Class<?> type) {
    return ();
  }
}

 

 

ModelMapper

Map<String, Model> modelsFromApiListings(Multimap<String, ApiListing> apiListings) {
  Map<String, > definitions = newHashMap();
  for (ApiListing each : ()) {
    (());
  }
  return mapModels(definitions);
}

简单处理是修改类名,保证不存在相同的类名。

还可以在每个类名上添加注解@ApiModel("xxxxx").这样在生成model名时(使用ApiModelTypeNameProvider)使用配置的xxxxx.

从源码分析,似乎springfox-swagger2也是提供了很多可扩展点。待以后有时间再研究