尝试记录子对象时,Restdoc抛出org.springframework.restdocs.snippet.SnippetException

问题描述 投票:1回答:1

我有一个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;

  @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;
  }
}

并生成相应的FieldDescriptor类:

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()    };
}

和:

public class PurchaseInfoFieldDescriptor {
    public static FieldDescriptor[] fdPurchaseInfo = new FieldDescriptor[] {
        fieldWithPath("id").description("id of the commercialization").type(java.lang.String.class),
        fieldWithPath("pricingId").description("additional pricing of the commercialization").type(java.lang.String.class),
        fieldWithPath("price").description("price of the commercialization").type(java.lang.Double.class),
        fieldWithPath("type").description("").type(ArticleType.class)    };


    public static FieldDescriptor[] fdPurchaseInfoList = new FieldDescriptor[] {
        fieldWithPath("[].id").description("id of the commercialization").type(java.lang.String.class),
        fieldWithPath("[].pricingId").description("additional pricing of the commercialization").type(java.lang.String.class),
        fieldWithPath("[].price").description("price of the commercialization").type(java.lang.Double.class),
        fieldWithPath("[].type").description("").type(ArticleType.class)    };
}

当调用mockMvc.perform以使用requestBody和orderInfo.class类型的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 = {}

和:

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 = []

从Spring Boot 1x迁移到2x后出现此问题。

你知道问题是什么吗?

谢谢 :)

java mockmvc spring-restdocs
1个回答
3
投票

看起来你依靠purchase来记录purchase及其包含的所有内容,即purchase.idpurchase.pricingIdpurchase.pricepurchase.type。这在REST Docs中一直有效,包括1.1但它创建了一个问题,人们会在记录其父级时意外错过记录嵌套字段。这在this questionthis Spring REST Docs issue中进行了讨论。该问题引入了REST Docs 1.2中的更改,默认情况下,记录字段不再记录其所有后代。您受此更改的影响,因为升级到Spring Boot 2意味着您还升级到了REST Docs 2。

如果你想保留现有的行为并只使用purchase记录它及其所有后代,你应该用fieldWithPath替换subsectionWithPath。如果你想记录purchase下的所有内容,你应该为purchase.idpurchase.pricingIdpurchase.pricepurchase.type添加额外的描述符。

© www.soinside.com 2019 - 2024. All rights reserved.