当前位置: 首页 > 知识库问答 >
问题:

如何让springdoc-openapi在不更改toString的情况下使用@JSONValue枚举格式?

蒋岳
2023-03-14
public enum Suit {
    HEARTS("Hearts"), DIAMONDS("Diamonds"), CLUBS("Clubs"), SPADES("Spades");

    @JsonValue
    private final String jsonValue;

    Suit(String jsonValue) { this.jsonValue = jsonValue; }
}
{
  "openapi": "3.0.1",
  "info": { "title": "OpenAPI definition", "version": "v0" },
  "servers": [
    { "url": "http://localhost:8080", "description": "Generated server url" }
  ],
  "paths": { ... },
  "components": {
    "schemas": {
      "PlayingCard": {
        "type": "object",
        "properties": {
          "suit": {
            "type": "string",
            "enum": [ "Hearts", "Diamonds", "Clubs", "Spades" ]
          },
          "value": { "type": "integer", "format": "int32" }
        }
      }
    }
  }
}

springdoc-openapi项目中存在关闭问题#1101,该问题请求允许@jsonvalue影响枚举序列化。然而,这个问题已经结束,因为没有为它提交公关。

如何使枚举列表匹配RESTendpoint接受/返回的实际JSON类型,而不是tostring()值?

解决这个问题的第一个想法是使用来自Swagger Core的@schema(allowableValues={...}]注释。然而,不管是出于bug还是出于设计,这都是对值列表的添加,而不是替换:

@Schema(allowableValues = {"Hearts", "Diamonds", "Clubs", "Spades"})
public enum Suit {
    HEARTS("Hearts"), DIAMONDS("Diamonds"), CLUBS("Clubs"), SPADES("Spades");
    // ...
}
"suit": {
  "type": "string",
  "enum": [
    "HEARTS", 
    "DIAMONDS",
    "CLUBS",
    "SPADES",
    "Hearts",
    "Diamonds",
    "Clubs",
    "Spades"
  ]
}
plugins {
    id 'org.springframework.boot' version '2.5.3'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
}

sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'io.swagger.core.v3:swagger-annotations:2.1.10'
    implementation 'org.springdoc:springdoc-openapi-ui:1.5.10'
    implementation 'org.springframework.boot:spring-boot-starter-web'
}
package com.example.springdoc;

import com.fasterxml.jackson.annotation.JsonValue;

public class PlayingCard {
    private Suit suit;
    private Integer value;

    public Suit getSuit() { return suit; }
    public void setSuit(Suit suit) { this.suit = suit; }
    public Integer getValue() { return value; }
    public void setValue(Integer value) { this.value = value; }

    public enum Suit {
        HEARTS("Hearts"), DIAMONDS("Diamonds"), CLUBS("Clubs"), SPADES("Spades");

        @JsonValue
        private final String jsonValue;

        Suit(String jsonValue) { this.jsonValue = jsonValue; }
    }
}
package com.example.springdoc;

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/playingCard")
public class PlayingCardController {
    @PostMapping
    public PlayingCard echo(@RequestBody PlayingCard card) {
        return card;
    }
}

Swagger URL:http://localhost:8080/v3/api-docs

共有1个答案

许丁雷
2023-03-14

可以创建PropertyCustomizerSpring bean来自定义属性。这可以针对特定枚举类型进行,也可以针对所有枚举全局进行。

以下自定义器将显式设置特定枚举类型的枚举值:

import com.fasterxml.jackson.databind.JavaType;
import io.swagger.v3.core.converter.AnnotatedType;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.media.StringSchema;
import org.springdoc.core.customizers.PropertyCustomizer;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class SuitPropertyCustomizer implements PropertyCustomizer {
    @Override
    public Schema customize(Schema property, AnnotatedType type) {
        if (property instanceof StringSchema && isSuit(type)) {
            property.setEnum(List.of("Hearts", "Diamonds", "Clubs", "Spades"));
        }

        return property;
    }

    private boolean isSuit(AnnotatedType type) {
        return type.getType() instanceof JavaType && ((JavaType) type.getType()).isTypeOrSubTypeOf(Suit.class);
    }
}

下面的定制器将对所有枚举类型使用Jackson String表示,这意味着将在适当的情况下使用@jsonvalue注释。

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.core.converter.AnnotatedType;
import io.swagger.v3.core.util.Json;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.media.StringSchema;
import org.springdoc.core.customizers.PropertyCustomizer;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.stream.Collectors;

@Component
public class EnumValuePropertyCustomizer implements PropertyCustomizer {
    @Override
    public Schema customize(Schema property, AnnotatedType type) {
        if (property instanceof StringSchema && isEnumType(type)) {
            ObjectMapper objectMapper = Json.mapper();

            property.setEnum(Arrays.stream(((JavaType) type.getType()).getRawClass().getEnumConstants())
                    .map(e -> objectMapper.convertValue(e, String.class))
                    .collect(Collectors.toList()));
        }
        return property;
    }

    private boolean isEnumType(AnnotatedType type) {
        return type.getType() instanceof JavaType && ((JavaType) type.getType()).isEnumType();
    }
}
 类似资料:
  • 给定一个Spring Boot项目,该项目使用springdoc-openapi库公开一个OpenAPI(Swagger)endpoint,该endpoint记录了项目的Spring MVC控制器endpoint。 项目中的一个枚举使用Jackson在字段上提供的JsonValue来更改枚举的JSON表示形式。使用Lombok项目的getter注释将此枚举字段公开为getter: 然而,尽管Jac

  • 我是第一次玩Scala,所以请耐心等待。还使用 tapir 来声明 API,我在为枚举提供架构时遇到问题。 我定义了一堆枚举,它们是我的域模型的一部分,并扩展了Scala的。例如,这是其中之一: 并且还有许多使用它们的案例类。例如, 使用我们之前定义的枚举,例如: 我想让这个枚举实现一个添加隐式但又不修改原始状态枚举的特征(我不想将枚举 - 以及所有其他枚举 - 耦合到这个特征)。 特征如下所示:

  • 问题内容: 我正在尝试使用seaborn,因为它具有distplot功能。但是我更喜欢默认的matplotlib设置。导入seaborn时,它会自动更改图形的外观。 如何在不改变地块外观的情况下使用seaborn函数? 问题答案: 0.8版(2017年7月)更改了此行为。来自https://seaborn.pydata.org/whatsnew.html#v0-8-0-july-2017: 导入s

  • 我有一堆CSV文件,它们是作为数据流读取的。对于每个dataframe,我希望更改一些列名,如果某个dataframe中存在特定列: column_name_update_map={'aa':'xx';'bb':'yy'}

  • 问题内容: 如果我用javadoc 编写,它不会出现,因为标签在格式化文本方面具有特殊功能。 如何在Javadoc中显示此字符? 问题答案: 您可以使用为 < 和为 > 。

  • 我想在开关情况下使用以下枚举作为引用: 善良的看待沃尔菲