【问题标题】:How to generate an example POJO from Swagger ApiModelProperty annotations?如何从 Swagger ApiModelProperty 注释生成示例 POJO?
【发布时间】:2018-11-20 22:58:40
【问题描述】:

我们正在创建一个使用 Swagger 的 @ApiModelProperty 注释记录的 REST API。我正在为 API 编写端到端测试,我需要为一些请求生成 JSON 正文。假设我需要将以下 JSON 发布到端点:

{ "name": "dan", "age": "33" }

到目前为止,我创建了一个包含所有必要属性的单独类,并且可以使用 Jackson 将其序列化为 JSON:

@JsonIgnoreProperties(ignoreUnknown = true)
public class MyPostRequest {
  private String name;
  private String age;
  // getters and fluid setters omitted...
  public static MyPostRequest getExample() {
    return new MyPostRequest().setName("dan").setAge("33");
  }
}

但是,我们注意到代码库中已经有一个非常相似的类,它定义了 API 接受的模型。在这个模型类中,每个属性的示例值已经在@ApiModelProperty 中定义:

@ApiModel(value = "MyAPIModel")
public class MyAPIModel extends AbstractModel {

  @ApiModelProperty(required = true, example = "dan")
  private String name;

  @ApiModelProperty(required = true, example = "33")
  private String age;

}

有没有一种简单的方法来生成一个 MyAPIModel 实例,其中填充了每个属性的示例值?注意:在转换为 JSON 之前,我需要能够在端到端测试中修改单个属性,以便测试不同的边缘情况。因此直接生成示例 JSON 是不够的。

基本上,我可以在 MyAPIModel 上编写一个静态方法 getExample()(或者在基类 AbstractModel 上更好),它返回 Swagger 注释中指定的 MyAPIModel 的示例实例?

【问题讨论】:

    标签: java json swagger


    【解决方案1】:

    截至本答案发布时,这似乎是不可能的。我发现的最接近的可能性是:

    1. io.swagger.converter.ModelConverters:方法read() 创建Model 对象,但这些模型中的example 成员为空。示例以字符串形式出现在 properties 成员中(直接取自 APIModelParameter 注释)。

    2. io.swagger.codegen.examples.ExampleGeneratorresolveModelToExample() 方法从ModelConverters.read() 获取输出,并生成一个表示对象及其属性的 Map(同时还解析非字符串属性,例如嵌套模型)。此方法用于序列化为 JSON。不幸的是,resolveModelToExample() 是私有的。如果可公开访问,为带注释的 Swagger API 模型类生成模型默认值的代码可能如下所示:

    protected <T extends AbstractModel> T getModelExample(Class<T> clazz) {
        // Get the swagger model instance including properties list with examples
        Map<String,Model> models = ModelConverters.getInstance().read(clazz);
        // Parse non-string example values into proper objects, and compile a map of properties representing an example object
        ExampleGenerator eg = new ExampleGenerator(models);
        Object resolved = eg.resolveModelToExample(clazz.getSimpleName(), null, new HashSet<String>());
        if (!(resolved instanceof Map<?,?>)) {
            // Model is not an instance of io.swagger.models.ModelImpl, and therefore no example can be resolved
            return null;
        }
        T result = clazz.newInstance();
        BeanUtils.populate(result, (Map<?,?>) resolved);
        return result;
    }
    
    1. 由于在我们的例子中我们只需要 String、boolean 和 int 属性,因此至少有可能以一种疯狂的 hackish 方式自己解析注释:
    protected <T extends MyModelBaseClass> T getModelExample(Class<T> clazz) {
        try {
            T result = clazz.newInstance();
            for(Field field  : clazz.getDeclaredFields()) {
                if (field.isAnnotationPresent(ApiModelProperty.class)) {
                    String exampleValue = field.getAnnotation(ApiModelProperty.class).example();
                    if (exampleValue != null) {
                        boolean accessible = field.isAccessible();
                        field.setAccessible(true);
                        setField(result, field, exampleValue);
                        field.setAccessible(accessible);
                    }
                }
            }
            return result;
        } catch (InstantiationException | IllegalAccessException e) {
            throw new IllegalArgumentException("Could not create model example", e);
        }
    }
    
    private <T extends MyModelBaseClass> void setField(T model, Field field, String value) throws IllegalArgumentException, IllegalAccessException {
        Class<?> type = field.getType();
        LOGGER.info(type.toString());
        if (String.class.equals(type)) {
            field.set(model, value);
        } else if (Boolean.TYPE.equals(type) || Boolean.class.equals(type)) {
            field.set(model, Boolean.parseBoolean(value));
        } else if (Integer.TYPE.equals(type) || Integer.class.equals(type)) {
            field.set(model, Integer.parseInt(value));
        }
    }
    

    我稍后可能会在 Github 上打开一个问题 / PR,以提议向 Swagger 添加功能。鉴于我们将示例模型实例发送到 API 作为测试的用例应该很常见,因此似乎没有其他人请求此功能,我对此感到非常惊讶。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-08-08
      • 2022-01-03
      • 1970-01-01
      • 2018-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多