Skip to content
This repository was archived by the owner on Dec 19, 2023. It is now read-only.

Commit ff60bb2

Browse files
committed
Merge branch 'alex859-parameter-default-value'
2 parents 5bba23c + aecf855 commit ff60bb2

File tree

11 files changed

+171
-33
lines changed

11 files changed

+171
-33
lines changed

docs/index.html

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -946,16 +946,20 @@ <h3 id="snippets-path-parameters"><a class="link" href="#snippets-path-parameter
946946
<div class="sect2">
947947
<h3 id="snippets-request-parameters"><a class="link" href="#snippets-request-parameters">Request parameters snippet</a></h3>
948948
<div class="paragraph">
949-
<p><a href="https://github.com/ScaCap/spring-auto-restdocs/blob/master/spring-auto-restdocs-core/src/main/java/capital/scalable/restdocs/request/RequestParametersSnippet.java">Request parameters snippet</a> automatically lists query parameters including their type, whether they are optional, and their Javadoc with constraints.</p>
949+
<p><a href="https://github.com/ScaCap/spring-auto-restdocs/blob/master/spring-auto-restdocs-core/src/main/java/capital/scalable/restdocs/request/RequestParametersSnippet.java">Request parameters snippet</a> automatically lists query parameters including their type, whether they are optional, and their Javadoc with constraints. If a default value is set, it will also be included.</p>
950950
</div>
951951
<div class="listingblock">
952952
<div class="title">Code</div>
953953
<div class="content">
954954
<pre class="highlightjs highlight"><code class="language-java" data-lang="java">/**
955955
* @param descMatch Lookup on description field.
956+
* @param lang Lookup on language.
956957
*/
957958
@RequestMapping("search")
958-
public Page&lt;ItemResponse&gt; searchItem(@RequestParam("desc") String descMatch) { ... }</code></pre>
959+
public Page&lt;ItemResponse&gt; searchItem(
960+
@RequestParam("desc") String descMatch,
961+
@RequestParam(value= "language", required = false, defaultValue = "en") String lang
962+
) { ... }</code></pre>
959963
</div>
960964
</div>
961965
<table class="tableblock frame-all grid-all spread">
@@ -981,13 +985,20 @@ <h3 id="snippets-request-parameters"><a class="link" href="#snippets-request-par
981985
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
982986
<td class="tableblock halign-left valign-top"><p class="tableblock">Lookup on description field.</p></td>
983987
</tr>
988+
<tr>
989+
<td class="tableblock halign-left valign-top"><p class="tableblock">language</p></td>
990+
<td class="tableblock halign-left valign-top"><p class="tableblock">String</p></td>
991+
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
992+
<td class="tableblock halign-left valign-top"><p class="tableblock">Lookup on language.
993+
</p><p class="tableblock">Default value: "en".</p></td>
994+
</tr>
984995
</tbody>
985996
</table>
986997
</div>
987998
<div class="sect2">
988999
<h3 id="snippets-request-headers"><a class="link" href="#snippets-request-headers">Request headers snippet</a></h3>
9891000
<div class="paragraph">
990-
<p><a href="https://github.com/ScaCap/spring-auto-restdocs/blob/master/spring-auto-restdocs-core/src/main/java/capital/scalable/restdocs/request/RequestHeaderSnippet.java">Request headers snippet</a> automatically lists headers with their type, whether they are optional, and their Javadoc with constraints.</p>
1001+
<p><a href="https://github.com/ScaCap/spring-auto-restdocs/blob/master/spring-auto-restdocs-core/src/main/java/capital/scalable/restdocs/request/RequestHeaderSnippet.java">Request headers snippet</a> automatically lists headers with their type, whether they are optional, and their Javadoc with constraints. If a default value is set, it will also be included.</p>
9911002
</div>
9921003
<div class="listingblock">
9931004
<div class="title">Code</div>
@@ -996,7 +1007,9 @@ <h3 id="snippets-request-headers"><a class="link" href="#snippets-request-header
9961007
* @param lang Language we want the response in.
9971008
*/
9981009
@RequestMapping("/all")
999-
public ItemResponse getItem(@RequestHeader("Accept-Language") String lang) { ... }</code></pre>
1010+
public ItemResponse getItem(
1011+
@RequestHeader(value = "Accept-Language", required = false, defaultValue = "en") String lang
1012+
) { ... }</code></pre>
10001013
</div>
10011014
</div>
10021015
<table class="tableblock frame-all grid-all spread">
@@ -1019,8 +1032,9 @@ <h3 id="snippets-request-headers"><a class="link" href="#snippets-request-header
10191032
<tr>
10201033
<td class="tableblock halign-left valign-top"><p class="tableblock">Accept-Language</p></td>
10211034
<td class="tableblock halign-left valign-top"><p class="tableblock">String</p></td>
1022-
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
1023-
<td class="tableblock halign-left valign-top"><p class="tableblock">Language we want the response in.</p></td>
1035+
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
1036+
<td class="tableblock halign-left valign-top"><p class="tableblock">Language we want the response in.
1037+
</p><p class="tableblock">Default value: "en".</p></td>
10241038
</tr>
10251039
</tbody>
10261040
</table>
@@ -1736,7 +1750,7 @@ <h4 id="contributing-building-build"><a class="link" href="#contributing-buildin
17361750
</div>
17371751
<div id="footer">
17381752
<div id="footer-text">
1739-
Last updated 2017-11-04 09:58:35 GMT
1753+
Last updated 2017-11-04 17:46:45 GMT
17401754
</div>
17411755
</div>
17421756
<link rel="stylesheet" href="highlight/styles/github.min.css">

spring-auto-restdocs-core/src/main/java/capital/scalable/restdocs/constraints/ConstraintReader.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public interface ConstraintReader {
2424
String CONSTRAINTS_ATTRIBUTE = "constraints";
2525
String OPTIONAL_ATTRIBUTE = "optionals";
2626
String DEPRECATED_ATTRIBUTE = "deprecated";
27+
String DEFAULT_VALUE_ATTRIBUTE = "default-value";
2728

2829
List<String> getConstraintMessages(Class<?> javaBaseClass, String javaFieldName);
2930

spring-auto-restdocs-core/src/main/java/capital/scalable/restdocs/request/AbstractParameterSnippet.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static capital.scalable.restdocs.OperationAttributeHelper.getHandlerMethod;
2121
import static capital.scalable.restdocs.OperationAttributeHelper.getJavadocReader;
2222
import static capital.scalable.restdocs.constraints.ConstraintReader.CONSTRAINTS_ATTRIBUTE;
23+
import static capital.scalable.restdocs.constraints.ConstraintReader.DEFAULT_VALUE_ATTRIBUTE;
2324
import static capital.scalable.restdocs.constraints.ConstraintReader.DEPRECATED_ATTRIBUTE;
2425
import static capital.scalable.restdocs.constraints.ConstraintReader.OPTIONAL_ATTRIBUTE;
2526
import static capital.scalable.restdocs.util.FieldDescriptorUtil.assertAllDocumented;
@@ -41,6 +42,7 @@
4142
import org.springframework.restdocs.operation.Operation;
4243
import org.springframework.restdocs.payload.FieldDescriptor;
4344
import org.springframework.restdocs.snippet.Attributes.Attribute;
45+
import org.springframework.web.bind.annotation.ValueConstants;
4446
import org.springframework.web.method.HandlerMethod;
4547

4648
abstract class AbstractParameterSnippet<A extends Annotation> extends StandardTableSnippet
@@ -90,11 +92,22 @@ private void addFieldDescriptor(HandlerMethod handlerMethod,
9092
Attribute constraints = constraintAttribute(param, constraintReader);
9193
Attribute optionals = optionalsAttribute(param, annot);
9294
Attribute deprecated = deprecatedAttribute(param, annot, javadocReader);
93-
descriptor.attributes(constraints, optionals, deprecated);
95+
final Attribute defaultValue = defaultValueAttribute(annot);
96+
if (defaultValue == null) {
97+
descriptor.attributes(constraints, optionals, deprecated);
98+
} else {
99+
descriptor.attributes(constraints, optionals, deprecated, defaultValue);
100+
}
94101

95102
fieldDescriptors.add(descriptor);
96103
}
97104

105+
abstract protected String getDefaultValue(A annotation);
106+
107+
protected boolean isCustomDefaultValue(final String defaultValue) {
108+
return defaultValue != null && !ValueConstants.DEFAULT_NONE.equals(defaultValue);
109+
}
110+
98111
protected Attribute constraintAttribute(MethodParameter param,
99112
ConstraintReader constraintReader) {
100113
return new Attribute(CONSTRAINTS_ATTRIBUTE, constraintReader.getConstraintMessages(param));
@@ -110,6 +123,13 @@ protected Attribute deprecatedAttribute(MethodParameter param, A annot,
110123
param.getParameterAnnotation(Deprecated.class) != null ? "" : null);
111124
}
112125

126+
protected Attribute defaultValueAttribute(A annot) {
127+
final String defaultValue = getDefaultValue(annot);
128+
129+
return isCustomDefaultValue(defaultValue) ?
130+
new Attribute(DEFAULT_VALUE_ATTRIBUTE, defaultValue) : null;
131+
}
132+
113133
protected abstract boolean isRequired(MethodParameter param, A annot);
114134

115135
protected abstract String getPath(A annot);

spring-auto-restdocs-core/src/main/java/capital/scalable/restdocs/request/PathParametersSnippet.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,10 @@ public String getHeader() {
6161
protected boolean shouldFailOnUndocumentedParams() {
6262
return failOnUndocumentedParams;
6363
}
64+
65+
@Override
66+
protected String getDefaultValue(final PathVariable annotation) {
67+
// @PathVariable does not have a default value
68+
return null;
69+
}
6470
}

spring-auto-restdocs-core/src/main/java/capital/scalable/restdocs/request/RequestHeaderSnippet.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,9 @@ public String getHeader() {
6161
protected boolean shouldFailOnUndocumentedParams() {
6262
return failOnUndocumentedParams;
6363
}
64+
65+
@Override
66+
protected String getDefaultValue(final RequestHeader annotation) {
67+
return annotation.defaultValue();
68+
}
6469
}

spring-auto-restdocs-core/src/main/java/capital/scalable/restdocs/request/RequestParametersSnippet.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ private boolean isPageable(MethodParameter param) {
8383
param.getParameterType().getCanonicalName());
8484
}
8585

86-
8786
@Override
8887
public String getHeader() {
8988
return "Query parameters";
@@ -93,4 +92,9 @@ public String getHeader() {
9392
protected boolean shouldFailOnUndocumentedParams() {
9493
return failOnUndocumentedParams;
9594
}
95+
96+
@Override
97+
protected String getDefaultValue(final RequestParam annotation) {
98+
return annotation.defaultValue();
99+
}
96100
}

spring-auto-restdocs-core/src/main/java/capital/scalable/restdocs/snippet/StandardTableSnippet.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static capital.scalable.restdocs.OperationAttributeHelper.determineTemplateFormatting;
2020
import static capital.scalable.restdocs.OperationAttributeHelper.getHandlerMethod;
2121
import static capital.scalable.restdocs.constraints.ConstraintReader.CONSTRAINTS_ATTRIBUTE;
22+
import static capital.scalable.restdocs.constraints.ConstraintReader.DEFAULT_VALUE_ATTRIBUTE;
2223
import static capital.scalable.restdocs.constraints.ConstraintReader.DEPRECATED_ATTRIBUTE;
2324
import static capital.scalable.restdocs.constraints.ConstraintReader.OPTIONAL_ATTRIBUTE;
2425
import static capital.scalable.restdocs.javadoc.JavadocUtil.convertFromJavadoc;
@@ -34,6 +35,7 @@
3435
import java.util.Map;
3536

3637
import capital.scalable.restdocs.util.TemplateFormatting;
38+
import org.apache.commons.lang3.StringUtils;
3739
import org.springframework.restdocs.operation.Operation;
3840
import org.springframework.restdocs.payload.FieldDescriptor;
3941
import org.springframework.restdocs.snippet.TemplatedSnippet;
@@ -99,7 +101,8 @@ protected Map<String, Object> createModelForDescriptor(FieldDescriptor descripto
99101

100102
String optional = resolveOptional(descriptor, templateFormatting);
101103
List<String> constraints = resolveConstraints(descriptor);
102-
description = joinAndFormat(description, constraints, templateFormatting);
104+
final String defaultValue = resolveDefaultValue(descriptor);
105+
description = joinAndFormat(description, constraints, defaultValue, templateFormatting);
103106

104107
Map<String, Object> model = new HashMap<>();
105108
model.put("path", path);
@@ -109,6 +112,11 @@ protected Map<String, Object> createModelForDescriptor(FieldDescriptor descripto
109112
return model;
110113
}
111114

115+
private String defaultValuePrefix(final String description) {
116+
// if we have no description, we don't want to add new lines
117+
return StringUtils.isEmpty(description) ? StringUtils.EMPTY : "\n\n";
118+
}
119+
112120
private List<String> resolveConstraints(FieldDescriptor descriptor) {
113121
return (List<String>) descriptor.getAttributes()
114122
.get(CONSTRAINTS_ATTRIBUTE);
@@ -134,6 +142,15 @@ private String resolveDeprecated(FieldDescriptor descriptor) {
134142
}
135143
}
136144

145+
private String resolveDefaultValue(FieldDescriptor descriptor) {
146+
Object defaultValue = descriptor.getAttributes().get(DEFAULT_VALUE_ATTRIBUTE);
147+
if (defaultValue != null) {
148+
return "Default value: \"" + toString(defaultValue) + "\".";
149+
} else {
150+
return "";
151+
}
152+
}
153+
137154
private String toString(Object value) {
138155
if (value != null) {
139156
return trimToEmpty(value.toString());
@@ -143,7 +160,7 @@ private String toString(Object value) {
143160
}
144161

145162
private String joinAndFormat(String description, List<String> constraints,
146-
TemplateFormatting templateFormatting) {
163+
final String defaultValue, TemplateFormatting templateFormatting) {
147164
StringBuilder res = new StringBuilder(description);
148165
if (!description.isEmpty() && !description.endsWith(".")) {
149166
res.append('.');
@@ -155,6 +172,9 @@ private String joinAndFormat(String description, List<String> constraints,
155172
}
156173

157174
res.append(constr.toString());
175+
if (StringUtils.isNotEmpty(defaultValue)) {
176+
res.append(defaultValuePrefix(description)).append(defaultValue);
177+
}
158178

159179
return res.toString().replace("|", "\\|");
160180
}

spring-auto-restdocs-core/src/test/java/capital/scalable/restdocs/request/RequestHeaderSnippetTest.java

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017 the original author or authors.
2+
* Copyright 2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -33,9 +33,8 @@
3333
import org.springframework.restdocs.AbstractSnippetTests;
3434
import org.springframework.restdocs.snippet.SnippetException;
3535
import org.springframework.restdocs.templates.TemplateFormat;
36-
import org.springframework.web.bind.annotation.GetMapping;
37-
import org.springframework.web.bind.annotation.PostMapping;
3836
import org.springframework.web.bind.annotation.RequestHeader;
37+
import org.springframework.web.bind.annotation.RequestMapping;
3938
import org.springframework.web.method.HandlerMethod;
4039

4140
public class RequestHeaderSnippetTest extends AbstractSnippetTests {
@@ -71,7 +70,32 @@ public void simpleRequest() throws Exception {
7170
.row("id", "Integer", "false", "An integer.")
7271
.row("subId", "String", "false", "A string.")
7372
.row("partId", "Integer", "false", "An integer.")
74-
.row("yetAnotherId", "String", "true", "A string."));
73+
.row("yetAnotherId", "String", "true",
74+
"A string.\n\nDefault value: \"ID\"."));
75+
76+
new RequestHeaderSnippet().document(operationBuilder
77+
.attribute(HandlerMethod.class.getName(), handlerMethod)
78+
.attribute(JavadocReader.class.getName(), javadocReader)
79+
.attribute(ConstraintReader.class.getName(), constraintReader)
80+
.build());
81+
}
82+
83+
@Test
84+
public void simpleRequestDefaultValueParameterNotDocumented() throws Exception {
85+
HandlerMethod handlerMethod = createHandlerMethod("updateItem", Integer.class, String.class,
86+
int.class, String.class);
87+
initParameters(handlerMethod);
88+
mockParamComment("updateItem", "id", "An integer");
89+
mockParamComment("updateItem", "otherId", "A string");
90+
mockParamComment("updateItem", "partId", "An integer");
91+
// yetAnotherId will have an automatic description about its default value
92+
93+
this.snippets.expect(REQUEST_HEADERS).withContents(
94+
tableWithHeader("Parameter", "Type", "Optional", "Description")
95+
.row("id", "Integer", "false", "An integer.")
96+
.row("subId", "String", "false", "A string.")
97+
.row("partId", "Integer", "false", "An integer.")
98+
.row("yetAnotherId", "String", "true", "Default value: \"ID\"."));
7599

76100
new RequestHeaderSnippet().document(operationBuilder
77101
.attribute(HandlerMethod.class.getName(), handlerMethod)
@@ -101,13 +125,13 @@ public void noHandlerMethod() throws Exception {
101125

102126
@Test
103127
public void failOnUndocumentedHeaders() throws Exception {
104-
HandlerMethod handlerMethod = createHandlerMethod("updateItem", Integer.class, String.class,
105-
int.class, String.class);
128+
HandlerMethod handlerMethod =
129+
createHandlerMethod("updateRequiredHeader", Integer.class, String.class, int.class);
106130
initParameters(handlerMethod);
107131

108132
thrown.expect(SnippetException.class);
109133
thrown.expectMessage(
110-
"Following request headers were not documented: [id, subId, partId, yetAnotherId]");
134+
"Following request headers were not documented: [id, subId, partId]");
111135

112136
new RequestHeaderSnippet().failOnUndocumentedParams(true).document(operationBuilder
113137
.attribute(HandlerMethod.class.getName(), handlerMethod)
@@ -151,16 +175,24 @@ private HandlerMethod createHandlerMethod(String name, Class<?>... parameterType
151175

152176
private static class TestResource {
153177

154-
@GetMapping("/items")
178+
@RequestMapping(value = "/items")
155179
public void updateItem(@RequestHeader Integer id,
156180
@RequestHeader("subId") String otherId,
157-
// partId is required anyway, because it's a primitive type
158181
@RequestHeader(required = false) int partId,
159-
@RequestHeader(required = false) String yetAnotherId) {
182+
// required anyway, because it's a primitive type
183+
@RequestHeader(required = false, defaultValue = "ID") String yetAnotherId) {
184+
// NOOP
185+
}
186+
187+
@RequestMapping(value = "/itemsRequired")
188+
public void updateRequiredHeader(@RequestHeader Integer id,
189+
@RequestHeader("subId") String otherId,
190+
// required anyway, because it's a primitive type
191+
@RequestHeader(required = false) int partId) {
160192
// NOOP
161193
}
162194

163-
@PostMapping("/items")
195+
@RequestMapping(value = "/items")
164196
public void updateItem() {
165197
// NOOP
166198
}

spring-auto-restdocs-core/src/test/java/capital/scalable/restdocs/request/RequestParametersSnippetTest.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,28 @@ public void simpleRequestWithPrimitives() throws Exception {
8888
tableWithHeader("Parameter", "Type", "Optional", "Description")
8989
.row("param1", "Decimal", "false", "A decimal.")
9090
.row("param2", "Boolean", "false", "A boolean.")
91-
.row("param3", "Integer", "true", "An integer."));
91+
.row("param3", "Integer", "true", "An integer.\n\nDefault value: \"1\"."));
92+
93+
new RequestParametersSnippet().document(operationBuilder
94+
.attribute(HandlerMethod.class.getName(), handlerMethod)
95+
.attribute(JavadocReader.class.getName(), javadocReader)
96+
.attribute(ConstraintReader.class.getName(), constraintReader)
97+
.build());
98+
}
99+
100+
@Test
101+
public void simpleRequestWithPrimitivesDefaultValueParameterNotDocumented() throws Exception {
102+
HandlerMethod handlerMethod = createHandlerMethod("searchItem2", double.class,
103+
boolean.class, int.class);
104+
initParameters(handlerMethod);
105+
mockParamComment("searchItem2", "param1", "A decimal");
106+
mockParamComment("searchItem2", "param2", "A boolean");
107+
108+
this.snippets.expect(REQUEST_PARAMETERS).withContents(
109+
tableWithHeader("Parameter", "Type", "Optional", "Description")
110+
.row("param1", "Decimal", "false", "A decimal.")
111+
.row("param2", "Boolean", "false", "A boolean.")
112+
.row("param3", "Integer", "true", "Default value: \"1\"."));
92113

93114
new RequestParametersSnippet().document(operationBuilder
94115
.attribute(HandlerMethod.class.getName(), handlerMethod)

0 commit comments

Comments
 (0)