Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/gwt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何从Swagger ApiModelProperty注释生成示例POJO?_Java_Json_Swagger - Fatal编程技术网

Java 如何从Swagger ApiModelProperty注释生成示例POJO?

Java 如何从Swagger ApiModelProperty注释生成示例POJO?,java,json,swagger,Java,Json,Swagger,我们正在创建一个RESTAPI,它是使用Swagger的@ApiModelProperty注释记录的。我正在为API编写端到端测试,需要为一些请求生成JSON主体。假设我需要将以下JSON发布到端点: { "name": "dan", "age": "33" } 到目前为止,我创建了一个单独的类,其中包含所有必要的属性,可以使用Jackson将其序列化为JSON: @JsonIgnoreProperties(ignoreUnknown = true) public class MyPostRe

我们正在创建一个RESTAPI,它是使用Swagger的
@ApiModelProperty
注释记录的。我正在为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(或者更好地在基类AbstractModel)上编写一个静态方法getExample(),返回在Swagger注释中指定的MyAPIModel的示例实例吗?

在回答此问题时,这似乎是不可能的。我发现的最接近的可能性是:

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

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

  • 受保护的T getModelExample(类clazz){
    //获取包含示例的属性列表的swagger模型实例
    Map models=ModelConverters.getInstance().read(clazz);
    //将非字符串示例值解析为适当的对象,并编译表示示例对象的属性映射
    ExampleGenerator eg=新ExampleGenerator(型号);
    已解析对象=例如:resolveModelToExample(clazz.getSimpleName(),null,new HashSet());
    如果(!(已解析的映射实例)){
    //Model不是io.swagger.models.ModelImpl的实例,因此无法解析任何示例
    返回null;
    }
    T result=clazz.newInstance();
    填充(结果,(地图)已解析);
    返回结果;
    }
    
  • 因为在我们的例子中,我们只需要字符串、布尔值和int属性,所以至少有可能自己以一种疯狂的方式解析注释:
  • 受保护的T getModelExample(类clazz){
    试一试{
    T result=clazz.newInstance();
    for(字段:clazz.getDeclaredFields()){
    if(field.isAnnotationPresent(ApiModelProperty.class)){
    字符串exampleValue=field.getAnnotation(ApiModelProperty.class).example();
    如果(示例值!=null){
    布尔可访问=field.isAccessible();
    字段。setAccessible(true);
    设置字段(结果、字段、示例值);
    字段设置可访问(可访问);
    }
    }
    }
    返回结果;
    }捕获(实例化异常|非法访问异常e){
    抛出新的IllegalArgumentException(“无法创建模型示例”,e);
    }
    }
    私有void setField(T模型、字段、字符串值)抛出IllegalArgumentException、IllegalAccessException{
    类类型=field.getType();
    LOGGER.info(type.toString());
    if(String.class.equals(type)){
    字段集(模型、值);
    }else if(Boolean.TYPE.equals(TYPE)| | Boolean.class.equals(TYPE)){
    set(model,Boolean.parseBoolean(value));
    }else if(Integer.TYPE.equals(TYPE)| Integer.class.equals(TYPE)){
    set(model,Integer.parseInt(value));
    }
    }
    
    稍后我可能会在Github上打开一个问题/PR,建议为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;
    }
    
    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));
        }
    }