J'ai un projet Spring Boot avec springfox-swagger2
2.7.0
et j'ai le contrôleur suivant:
@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 ...;
}
...
}
Je veux contrôler ce qui est affiché dans les documents en annotant la classe Id
, et cela ne fonctionne que pour certaines parties de l'annotation, mais pas pour toutes. La classe Id
(qui a un convertisseur enregistré de String
vers 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;
}
}
Maintenant, le Swagger JSON
renvoyé ressemble à ceci:
"parameters":[{
"name":"id",
"in":"query",
"description":"This is the description",
"required":true,
"type":"integer",
"default":"1f1f1f",
"format":"int64"
}]
Ma question (ou éventuellement un rapport de bogue) est la suivante: pourquoi certaines parties de l'annotation @ApiParam
sont-elles utilisées (comme value
, defaultValue
et required
), mais d'autres ne le sont pas, comme name
et type
? Pourquoi ne semble-t-il pas que je ne puisse pas modifier le name
ou le type
ici? Pour mon cas d'utilisation particulier, ce dernier est celui que je voudrais changer en string
.
Mise à jour
J'ai décidé d'ajouter le composant suivant avec l'aide de 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();
}
}
}
Les auteurs de springfox pensent que cela pourrait être un bogue: https://github.com/springfox/springfox / issues / 2107
4 réponses
Par défaut, les attributs @ApiParam 'nom' et 'type' sont utilisés pour remplacer le nom du paramètre et le type détecté des paramètres directs spécifiés dans la méthode API. Lorsque vous utilisez @ApiParam sur un champ, le type et le nom sont déduits par le nom du champ et son type déclaré et la valeur de remplacement pour le nom et le type ne sont pas pris en compte. (Cela semble par conception dans springfox, vous pouvez jeter un œil à l'implémentation springfox.documentation.swagger.readers.parameter.SwaggerExpandedParameterBuilder
)
Si vous souhaitez toujours modifier ce comportement, vous pouvez enregistrer une implémentation personnalisée de springfox.documentation.spi.service.ExpandedParameterBuilderPlugin
entrelacé.
Par exemple
@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;
}
}
J'espère que cela aide.
Idéalement, vous devez utiliser @ApiParam
avec les paramètres de méthode tandis que @ApiModelProperty
avec les propriétés du modèle.
public @interface ApiParam {
/**
* The parameter name.
* The name of the parameter will be derived from the field/method/parameter name,
* however you can override it.
* Path parameters must always be named as the path section they represent.
*/
String name() default "";
Je ne sais pas si l'attribut type est présent, mais voici la façon de traiter les types:
public @interface ApiModelProperty {
/**
* The data type of the parameter.
* This can be the class name or a primitive. The value will override the data type as read from the class
* property.
*/
String dataType() default "";
......
J'utilise la version 2.6.1 et je n'arrive pas à trouver l'attribut "type" dans @ApiParam alors que je peux voir que vous utilisez "type" avec cela. Assurez-vous donc qu'il est disponible. J'ai également mentionné que @ApiModelProperty fournit dataType () pour gérer le scénario que vous avez mentionné.
Une solution plus complète qui compile réellement et prend en compte le paramètre du type à la fois de la propriété de type ApiParam ou de la propriété Model dataType:
@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()));
}
}
}
}
De nouvelles questions
java
Java est un langage de programmation de haut niveau. Utilisez cette balise lorsque vous rencontrez des problèmes pour utiliser ou comprendre la langue elle-même. Cette balise est rarement utilisée seule et est le plus souvent utilisée en conjonction avec [spring], [spring-boot], [jakarta-ee], [android], [javafx], [hadoop], [gradle] et [maven].