web-dev-qa-db-ja.com

swagger @ ApiParamは特定のプロパティを無視します

springfox-swagger22.7.0のSpringBootプロジェクトがあり、次のコントローラーがあります。

@Api(tags = { "Some" }, description = "CRUD for Some Stuff")
@RestController
@RequestMapping(path = "/some")
public class SomeController {

  @ApiOperation(value = "Get some")
  @GetMapping(value = "{someId}", produces = MediaType.APPLICATION_JSON_VALUE)
  public Response getSomeById(@PathVariable("someId") Id someId) {
    return ...;
  }
...
}

Idクラスに注釈を付けることでドキュメントに表示される内容を制御したいのですが、これは注釈の一部でのみ機能しますが、すべてではありません。 Idクラス(StringからIdへのコンバーターが登録されています):

public class Id {

  @ApiParam(value = "This is the description", defaultValue = "1f1f1f",required = true, name = "someId", type = "string")
  private final Long id;

  public Id(Long id) {
    this.id = id;
  }

  public Long getId() {
    return id;
  }
}

これで、返されるSwagger JSONは次のようになります。

"parameters":[{
  "name":"id",
  "in":"query",
  "description":"This is the description",
  "required":true,
  "type":"integer",
  "default":"1f1f1f",
  "format":"int64"
}]

私の質問(またはおそらくバグレポート)は、@ApiParamアノテーションの一部(valuedefaultValuerequiredなど)が使用されているのに、他の部分は使用されていない理由です。 't、nametypeのように?ここでnameまたはtypeを変更できないように見えるのはなぜですか?私の特定のユースケースでは、後者をstringに変更したいと思います。

更新

Skadyaの助けを借りて、次のコンポーネントを追加することにしました。

@Component
public class OverrideSwaggerApiParamBuilder implements 
ExpandedParameterBuilderPlugin {

  @Override
  public boolean supports(DocumentationType type) {
    return DocumentationType.SWAGGER_2 == type;
  }

  @Override
  public void apply(ParameterExpansionContext context) {
    Optional<ApiParam> apiParamOptional = findApiParamAnnotation(context.getField().getRawMember());
    if (apiParamOptional.isPresent()) {
      ApiParam param = apiParamOptional.get();
      context.getParameterBuilder()
          .name(param.name())
          .modelRef(new ModelRef(param.type()))
          .build();
    }
  }
}

Springfoxの作成者は、これがバグである可能性があると感じています: https://github.com/springfox/springfox/issues/2107

12
Michiel Haisma

デフォルトでは、@ ApiParam属性の「name」と「type」を使用してAPIメソッドで指定されたパラメーター名と検出された直接パラメーターのタイプをオーバーライドします。フィールドで@ApiParamを使用する場合、タイプと名前はフィールドの名前から推測され、宣言されたタイプと名前とタイプのオーバーライドされた値は考慮されません。 (springfoxの設計によるものですが、実装springfox.documentation.swagger.readers.parameter.SwaggerExpandedParameterBuilderをご覧ください)

それでもこの動作を変更したい場合は、springfox.documentation.spi.service.ExpandedParameterBuilderPluginインターレースのカスタム実装を登録できます。

例:.

@Component
public class OverrideSwaggerApiParamNameBuilder implements ExpandedParameterBuilderPlugin {

    @Override
    public boolean supports(DocumentationType type) {
        return DocumentationType.SWAGGER_2 == type;
    }

    @Override
    public void apply(ParameterExpansionContext context) {
        Optional<ApiParam> apiParamOptional = findApiParamAnnotation(context.getField().getRawMember());
        if (apiParamOptional.isPresent()) {
            fromApiParam(context, apiParamOptional.get());
        }
    }

    private void fromApiParam(ParameterExpansionContext context, ApiParam apiParam) {
        context.getParameterBuilder()
                .name(emptyToNull(apiParam.name()));
    }

    private String emptyToNull(String str) {
        return StringUtils.hasText(str) ? str : null;
    }
}

それが役に立てば幸い。

6
skadya

実際にコンパイルし、ApiParamタイププロパティまたはModeldataTypeプロパティの両方からのタイプの設定を考慮に入れるより完全なソリューション:

@Component
@Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1000)
public class OverrideSwaggerApiParamTypeBuilder extends 
SwaggerExpandedParameterBuilder implements ExpandedParameterBuilderPlugin {

public OverrideSwaggerApiParamTypeBuilder(DescriptionResolver descriptions, EnumTypeDeterminer enumTypeDeterminer) {
    super(descriptions, enumTypeDeterminer);
}

@Override
public boolean supports(DocumentationType type) {
    return DocumentationType.SWAGGER_2 == type;
}

public void apply(ParameterExpansionContext context) {
    super.apply(context);
    Optional<ApiModelProperty> apiModelPropertyOptional = context.findAnnotation(ApiModelProperty.class);
    if (apiModelPropertyOptional.isPresent()) {
        if(!StringUtils.isAllEmpty(apiModelPropertyOptional.get().dataType())) {
            context.getParameterBuilder().modelRef(new ModelRef(apiModelPropertyOptional.get().dataType()));
        }
    }

    Optional<ApiParam> apiParamOptional = context.findAnnotation(ApiParam.class);
    if (apiParamOptional.isPresent()) {
        if(!StringUtils.isAllEmpty(apiParamOptional.get().type())) {
            context.getParameterBuilder().modelRef(new ModelRef(apiParamOptional.get().type()));
        }
    }

}

}

0
aciobanu