Java 尝试记录子对象时,Restdoc抛出org.springframework.restdocs.snippet.SnippetException
我有一个OrderInfo类:Java 尝试记录子对象时,Restdoc抛出org.springframework.restdocs.snippet.SnippetException,java,mockmvc,spring-restdocs,Java,Mockmvc,Spring Restdocs,我有一个OrderInfo类: @ApiModel(description = "object needed to make an order") public class OrderInfo implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("purchase") private PurchaseInfo purchase = null; @J
@ApiModel(description = "object needed to make an order")
public class OrderInfo implements Serializable {
private static final long serialVersionUID = 1L;
@JsonProperty("purchase")
private PurchaseInfo purchase = null;
@JsonProperty("paymentMode")
private PaymentMode paymentMode = null;
@JsonProperty("serialNumber")
private String serialNumber = null;
public OrderInfo purchase(PurchaseInfo purchase) {
this.purchase = purchase;
return this;
}
@ApiModelProperty(required = true, value = "coming from commercialization")
@NotNull
@Valid
public PurchaseInfo getPurchase() {
return purchase;
}
public void setPurchase(PurchaseInfo purchase) {
this.purchase = purchase;
}
public OrderInfo paymentMode(PaymentMode paymentMode) {
this.paymentMode = paymentMode;
return this;
}
@ApiModelProperty(required = true, value = "")
@NotNull
@Valid
public PaymentMode getPaymentMode() {
return paymentMode;
}
public void setPaymentMode(PaymentMode paymentMode) {
this.paymentMode = paymentMode;
}
public OrderInfo serialNumber(String serialNumber) {
this.serialNumber = serialNumber;
return this;
}
@ApiModelProperty(value = "The serial number of the registered device")
public String getSerialNumber() {
return serialNumber;
}
public void setSerialNumber(String serialNumber) {
this.serialNumber = serialNumber;
}
}
具有PurchaseInfo子对象:
@ApiModel(description = "Info necessary to order a video, an episode or a season")
public class PurchaseInfo implements Serializable {
private static final long serialVersionUID = 1L;
@JsonProperty("id")
private String id = null;
@JsonProperty("pricingId")
private String pricingId = null;
@JsonProperty("price")
private Double price = null;
@JsonProperty("type")
private ArticleType type = null;
public PurchaseInfo id(String id) {
this.id = id;
return this;
}
@ApiModelProperty(required = true, value = "id of the commercialization")
@NotNull
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public PurchaseInfo pricingId(String pricingId) {
this.pricingId = pricingId;
return this;
}
@ApiModelProperty(required = true, value = "additional pricing of the commercialization")
@NotNull
public String getPricingId() {
return pricingId;
}
public void setPricingId(String pricingId) {
this.pricingId = pricingId;
}
public PurchaseInfo price(Double price) {
this.price = price;
return this;
}
@ApiModelProperty(required = true, value = "price of the commercialization")
@NotNull
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public PurchaseInfo type(ArticleType type) {
this.type = type;
return this;
}
@ApiModelProperty(required = true, value = "")
@NotNull
@Valid
public ArticleType getType() {
return type;
}
public void setType(ArticleType type) {
this.type = type;
}
}
以及生成的相应的字段描述符类:
public class OrderInfoFieldDescriptor {
public static FieldDescriptor[] fdOrderInfo = new FieldDescriptor[] {
fieldWithPath("purchase").description("coming from commercialization").type(PurchaseInfo.class),
fieldWithPath("paymentMode").description("").type(PaymentMode.class),
fieldWithPath("serialNumber").description("The serial number of the registered device").type(java.lang.String.class).optional() };
public static FieldDescriptor[] fdOrderInfoList = new FieldDescriptor[] {
fieldWithPath("[].purchase").description("coming from commercialization").type(PurchaseInfo.class),
fieldWithPath("[].paymentMode").description("").type(PaymentMode.class),
fieldWithPath("[].serialNumber").description("The serial number of the registered device").type(java.lang.String.class).optional() };
}
以及:
调用mockMvc.perform以生成具有OrderInfo.class类型的requestBody和responseBody的HTTP POST时:
mockMvc.perform(postRequest)
.andDo(document("orderInfoCreate", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()),
pathParameters(parameterWithName("username").description("the name of the user")),
responseFields(OrderInfoFieldDescriptor.fdOrderInfo),
requestFields(OrderInfoFieldDescriptor.fdOrderInfo))).andExpect(status().isCreated())
.andExpect(content().json(orderInfoAsJson));
验证适用于paymentMode和serialNumber,但在购买时失败,例外情况如下:
org.springframework.restdocs.snippet.SnippetException: The following parts of the payload were not documented:
{
"purchase" : {
"id" : "purchaseId",
"pricingId" : "pricingId",
"price" : 12.0,
"type" : "EPISODE"
},
"serialNumber" : "serialNumber"
}
即使请求主体和响应主体看起来很好:
MockHttpServletRequest:
HTTP Method = POST
Request URI = /api/users/myUserName/orders
Parameters = {}
Headers = [Content-Type:"application/json;charset=UTF-8", Host:"host:posrt", Accept:"application/json;charset=UTF-8", Cookie:"identity=cookieForTest"]
Body = {"purchase":{"id":"purchaseId","pricingId":"pricingId","price":12.0,"type":"EPISODE"},"paymentMode":"POSTPAID","serialNumber":"serialNumber"}
Session Attrs = {}
以及:
从Spring Boot 1x迁移到2x后出现此问题
你知道问题是什么吗
谢谢:)您似乎依靠
purchase
来记录purchase
及其包含的所有内容,即purchase.id
、purchase.pricingId
、purchase.price
和purchase.type
。这在1.1之前(包括1.1)的REST文档中起作用,但它会造成一个问题,即人们可能会意外地错过记录嵌套字段的过程,因为他们记录了其父字段。这在中进行了讨论,也在中进行了讨论。该问题在REST Docs 1.2中引入了一项更改,默认情况下,记录字段不再记录其所有子体。您会受到此更改的影响,因为升级到Spring Boot 2意味着您也升级到了REST Docs 2
如果您想保留现有行为,只需使用
purchase
记录它及其所有子体,则应将fieldWithPath
替换为subsectionWithPath
。如果您想记录purchase
下的所有内容,您应该为purchase.id
、purchase.pricingId
、purchase.price
和purchase.type添加额外的描述符。您是对的,REST文档已更新为2.0.3。在本例中,我们希望保留现有的行为,并且subsectionWithPath
选项完成了任务。谢谢你的帮助!
MockHttpServletRequest:
HTTP Method = POST
Request URI = /api/users/myUserName/orders
Parameters = {}
Headers = [Content-Type:"application/json;charset=UTF-8", Host:"host:posrt", Accept:"application/json;charset=UTF-8", Cookie:"identity=cookieForTest"]
Body = {"purchase":{"id":"purchaseId","pricingId":"pricingId","price":12.0,"type":"EPISODE"},"paymentMode":"POSTPAID","serialNumber":"serialNumber"}
Session Attrs = {}
MockHttpServletResponse:
Status = 201
Error message = null
Headers = [Content-Type:"application/json;charset=UTF-8"]
Content type = application/json;charset=UTF-8
Body = {"purchase":{"id":"purchaseId","pricingId":"pricingId","price":12.0,"type":"EPISODE"},"paymentMode":"POSTPAID","serialNumber":"serialNumber"}
Forwarded URL = null
Redirected URL = null
Cookies = []