Java 如何从Swagger ApiModelProperty注释生成示例POJO?
我们正在创建一个RESTAPI,它是使用Swagger的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
@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();
填充(结果,(地图)已解析);
返回结果;
}
受保护的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));
}
}