简体   繁体   English

使用Spring REST文档记录空值

[英]Documenting null values with Spring REST Docs

Let's say we have the following API: 假设我们有以下API:

@RestController
public class PersonController {
    @GetMapping("/api/person")
    public List<Person> findPeople() {
        return Arrays.asList(new Person("Doe", "Foo", "John"), new Person("Doe", null, "Jane"));
    }
}

Where the model class looks like this: 模型类如下所示:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    private String lastName;
    private String middleName;
    private String firstName;
}

As you can see in the controller, the middleName property of the second object in the list is null . 正如您在控制器中看到的那样,列表中第二个对象的middleName属性为null I'm now trying to use Spring REST Docs to document the properties of the API, so I wrote the following test: 我现在正尝试使用Spring REST Docs来记录API的属性,因此我编写了以下测试:

@Test
public void findAllReturnsPeople() throws Exception {
    mockMvc.perform(get("/api/person").accept(MediaType.APPLICATION_JSON))
        .andExpect(jsonPath("$.[0].firstName", is("John")))
        .andExpect(jsonPath("$.[0].middleName", is("Foo")))
        .andExpect(jsonPath("$.[0].lastName", is("Doe")))
        .andExpect(jsonPath("$.[1].firstName", is("Jane")))
        .andExpect(jsonPath("$.[1].middleName", nullValue()))
        .andExpect(jsonPath("$.[1].lastName", is("Doe")))
        .andDo(document("person-get", responseFields(
            fieldWithPath("[].firstName").description("The given name of a person"),
            fieldWithPath("[].middleName").description("The optionally given middle name of a person"),
            fieldWithPath("[].lastName").description("The last- or family name of a person"))));
}

By using the responseFields() and fieldWithPath() properties, I'm trying to give a description to each field. 通过使用responseFields()fieldWithPath()属性,我试图对每个字段进行描述。 However, this approach fails for the middle name, throwing the following exception: 但是,对于中间名,此方法失败,并引发以下异常:

org.springframework.restdocs.snippet.SnippetException: Fields with the following paths were not found in the payload: [[].middleName]

    at org.springframework.restdocs.payload.AbstractFieldsSnippet.validateFieldDocumentation(AbstractFieldsSnippet.java:257)
    at org.springframework.restdocs.payload.AbstractFieldsSnippet.createModel(AbstractFieldsSnippet.java:167)
    at org.springframework.restdocs.snippet.TemplatedSnippet.document(TemplatedSnippet.java:83)
    at org.springframework.restdocs.generate.RestDocumentationGenerator.handle(RestDocumentationGenerator.java:206)
    at org.springframework.restdocs.mockmvc.RestDocumentationResultHandler.handle(RestDocumentationResultHandler.java:55)
    at org.springframework.test.web.servlet.MockMvc$1.andDo(MockMvc.java:183)
    at be.g00glen00b.apps.demoempty.DemoEmptyApplicationTests.findAllReturnsPeople(DemoEmptyApplicationTests.java:37)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)
    at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

However, when I change the code and change the middle name of the second Person object to "Bar" , the error disappears, and the snippet is correctly generated. 但是,当我更改代码并将第二个Person对象的中间名称更改为"Bar" ,错误消失了,并且正确生成了代码段。

Additionally, when I remove the fieldWithPath("[].middleName") code, and I run the test, I get the following exception: 此外,当我删除fieldWithPath("[].middleName")代码并运行测试时,出现以下异常:

org.springframework.restdocs.snippet.SnippetException: The following parts of the payload were not documented:
[ {
  "middleName" : "Foo"
}, {
  "middleName" : null
} ]

Which makes sense, since the middle name property isn't documented in that case. 这是有道理的,因为在这种情况下没有记录中间名属性。

My question is how can I prevent this error and document what the middleName property does? 我的问题是如何防止此错误并记录middleName属性的作用?

This is what I tried so far: 这是我到目前为止尝试过的:

  • Documenting only the non-null value, eg [0].middleName (this leads to the same exception) 仅记录非空值,例如[0].middleName (这导致相同的异常)
  • Changing the type explicitely to JsonFieldType.STRING or JsonFieldType.VARIES (this also leads to the same exception) 将类型显式更改为JsonFieldType.STRINGJsonFieldType.VARIES (这也会导致相同的异常)

You need to tell REST Docs that the field is optional. 您需要告诉REST文档该字段是可选的。 You can do this by calling the optional() method on the FieldDescriptor : 您可以通过在FieldDescriptor上调用optional()方法来实现:

.andDo(document("person-get", responseFields(
        fieldWithPath("[].firstName").description("The given name of a person"),
        fieldWithPath("[].middleName").description("The optionally given middle name of a person").optional(),
        fieldWithPath("[].lastName").description("The last- or family name of a person"))));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM