Escape pipe symbol in Spring REST Docs

596 views Asked by At

I need to document an API that accepts a JSON represented by this class:

public class Message {
    
    @NotNull(message = "Sender cannot be null")
    private String sender;
    
    @Pattern(regexp="HI|HELLO",message = "Message can be only 'HI' or 'HELLO'")
    private String content;
    
    // Constructor, Getters and Setters..
}

Spring Docs autogenerates the following snippet:

.Request fields:
|===
|Path|Type|Constraints|Description

|sender
|String
|Must not be null
|Sender of the message

|content
|String
|Must match the regular expression `HI|HELLO`
|Content of the message

|===

Which is used by Asciidoctor to create a table in the pdf. However, in the pdf, the table is broken (because of the pipe):

enter image description here

How can I escape the pipe within the regular expression?

I found this issue, but seems to be related to another project.

This is the test class to generate the documentation (JUnit5):

@WebMvcTest(HomeController.class)
@AutoConfigureRestDocs(outputDir = "target/snippets")
public class HomeControllerTest {

    @Autowired
    private MockMvc mockMvc;
    
    @Test
    public void postMessageTest() throws Exception {
        ConstrainedFields constrainedFields = new ConstrainedFields(Message.class);
        
        this.mockMvc
                .perform(post("/message").content("{\"sender\":\"Marc\",\"content\":\"HI\"}")
                        .characterEncoding("utf-8")
                        .contentType(MediaType.APPLICATION_JSON))
                .andDo(print()).andExpect(status().isOk())
                .andDo(document("home-message", requestFields(
                        attributes(key("title").value("Request fields:")),
                        constrainedFields.withPath("sender").description("Sender of the message"),
                        constrainedFields.withPath("content").description("Content of the message")
                        )));
    }

    private static class ConstrainedFields {
        private final ConstraintDescriptions constraintDescriptions;
        
        ConstrainedFields(Class<?> input) {
            this.constraintDescriptions = new ConstraintDescriptions(input);
        }
        
        private FieldDescriptor withPath(String property) {
            return fieldWithPath(property).attributes(key("constraints").value(
                    // Let's assume there is only one constraint for each property
                    constraintDescriptions.descriptionsForProperty(property).get(0)));
        }
    }
}

The full project to reproduce the issue is here.

1

There are 1 answers

0
MarcoLucidi On BEST ANSWER

probably not the best solution, but, after doing little research, I found out that a simple \ character is enough to escape pipe character in asciidoctor documents (source). our goal then is to get this line in the .adoc snippet:

|Must match the regular expression `HI\|HELLO`

this is the method that extracts "constraints descriptions" in your code:

private FieldDescriptor withPath(String property) {
    return fieldWithPath(property).attributes(key("constraints").value(
            // Let's assume there is only one constraint for each property
            constraintDescriptions.descriptionsForProperty(property).get(0)));
}

here we have "full control" over the text that will be written in the .adoc. we could for example take the constraint description from constraintDescriptions.descriptionsForProperty(property), apply our escaping and than pass the escaped string to .value():

private FieldDescriptor withPath(String property) {
    // Let's assume there is only one constraint for each property
    String desc = constraintDescriptions.descriptionsForProperty(property).get(0);
    desc = desc.replace("|", "\\|");
    return fieldWithPath(property).attributes(key("constraints").value(desc));
}

this will produce the escaped line in the .adoc and will be correctly rendered in the .pdf:

pdf