Skip to content

Commit 682004a

Browse files
author
bnasslahsen
committed
Improvment for eterministic and alphabetical orderding.
1 parent 38bc3b6 commit 682004a

File tree

11 files changed

+198
-48
lines changed

11 files changed

+198
-48
lines changed

springdoc-openapi-common/src/main/java/org/springdoc/api/AbstractOpenApiResource.java

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,13 @@
4141
import java.util.stream.Collectors;
4242

4343
import com.fasterxml.jackson.annotation.JsonView;
44+
import com.fasterxml.jackson.core.JsonProcessingException;
4445
import com.fasterxml.jackson.databind.ObjectMapper;
46+
import com.fasterxml.jackson.databind.SerializationFeature;
4547
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
4648
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.Feature;
4749
import io.swagger.v3.core.filter.SpecFilter;
50+
import io.swagger.v3.core.util.Json;
4851
import io.swagger.v3.core.util.ReflectionUtils;
4952
import io.swagger.v3.core.util.Yaml;
5053
import io.swagger.v3.oas.annotations.Hidden;
@@ -995,15 +998,43 @@ protected void initOpenAPIBuilder() {
995998
}
996999

9971000
/**
998-
* Gets yaml mapper.
1001+
* Write yaml value string.
9991002
*
1000-
* @return the yaml mapper
1003+
* @param openAPI the open api
1004+
* @return the string
1005+
* @throws JsonProcessingException the json processing exception
10011006
*/
1002-
protected ObjectMapper getYamlMapper() {
1007+
protected String writeYamlValue(OpenAPI openAPI) throws JsonProcessingException {
1008+
String result;
10031009
ObjectMapper objectMapper = Yaml.mapper();
1010+
if (springDocConfigProperties.isWriterWithOrderByKeys())
1011+
objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
10041012
YAMLFactory factory = (YAMLFactory) objectMapper.getFactory();
10051013
factory.configure(Feature.USE_NATIVE_TYPE_ID, false);
1006-
return objectMapper;
1014+
if (!springDocConfigProperties.isWriterWithDefaultPrettyPrinter())
1015+
result = objectMapper.writeValueAsString(openAPI);
1016+
else
1017+
result = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(openAPI);
1018+
return result;
1019+
}
1020+
1021+
/**
1022+
* Write json value string.
1023+
*
1024+
* @param openAPI the open api
1025+
* @return the string
1026+
* @throws JsonProcessingException the json processing exception
1027+
*/
1028+
protected String writeJsonValue(OpenAPI openAPI) throws JsonProcessingException {
1029+
String result;
1030+
ObjectMapper objectMapper = Json.mapper();
1031+
if (springDocConfigProperties.isWriterWithOrderByKeys())
1032+
objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
1033+
if (!springDocConfigProperties.isWriterWithDefaultPrettyPrinter())
1034+
result = objectMapper.writeValueAsString(openAPI);
1035+
else
1036+
result = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(openAPI);
1037+
return result;
10071038
}
10081039

10091040
/**
@@ -1026,7 +1057,7 @@ private List<String> getConditionsToMatch(ConditionType conditionType, GroupConf
10261057
conditionsToMatch = (groupConfig != null) ? groupConfig.getProducesToMatch() : springDocConfigProperties.getProducesToMatch();
10271058
break;
10281059
case CONSUMES:
1029-
conditionsToMatch = (groupConfig != null) ? groupConfig.getConsumesToMatch(): springDocConfigProperties.getConsumesToMatch();
1060+
conditionsToMatch = (groupConfig != null) ? groupConfig.getConsumesToMatch() : springDocConfigProperties.getConsumesToMatch();
10301061
break;
10311062
default:
10321063
break;

springdoc-openapi-common/src/main/java/org/springdoc/core/SpringDocConfigProperties.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,11 @@ public class SpringDocConfigProperties {
127127
*/
128128
private boolean writerWithDefaultPrettyPrinter;
129129

130+
/**
131+
* The Writer with order by keys.
132+
*/
133+
private boolean writerWithOrderByKeys;
134+
130135
/**
131136
* The Default consumes media type.
132137
*/
@@ -531,6 +536,24 @@ public void setRemoveBrokenReferenceDefinitions(boolean removeBrokenReferenceDef
531536
this.removeBrokenReferenceDefinitions = removeBrokenReferenceDefinitions;
532537
}
533538

539+
/**
540+
* Is writer wither order by keys boolean.
541+
*
542+
* @return the boolean
543+
*/
544+
public boolean isWriterWithOrderByKeys() {
545+
return writerWithOrderByKeys;
546+
}
547+
548+
/**
549+
* Sets writer wither order by keys.
550+
*
551+
* @param writerWithOrderByKeys the writer wither order by keys
552+
*/
553+
public void setWriterWithOrderByKeys(boolean writerWithOrderByKeys) {
554+
this.writerWithOrderByKeys = writerWithOrderByKeys;
555+
}
556+
534557
/**
535558
* Is writer with default pretty printer boolean.
536559
*

springdoc-openapi-security/src/test/java/test/org/springdoc/api/app7/SpringDocApp7Test.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@
2121
import io.swagger.v3.oas.models.OpenAPI;
2222
import io.swagger.v3.oas.models.info.Info;
2323
import io.swagger.v3.oas.models.info.License;
24+
import test.org.springdoc.api.AbstractSpringDocTest;
25+
2426
import org.springframework.boot.autoconfigure.SpringBootApplication;
2527
import org.springframework.context.annotation.Bean;
26-
import test.org.springdoc.api.AbstractSpringDocTest;
2728

2829
public class SpringDocApp7Test extends AbstractSpringDocTest {
2930

springdoc-openapi-webflux-core/src/main/java/org/springdoc/webflux/api/OpenApiResource.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,17 @@
2020

2121
package org.springdoc.webflux.api;
2222

23-
import java.util.*;
23+
import java.util.ArrayList;
24+
import java.util.Comparator;
25+
import java.util.HashSet;
26+
import java.util.LinkedHashMap;
27+
import java.util.List;
28+
import java.util.Map;
29+
import java.util.Objects;
30+
import java.util.Optional;
31+
import java.util.Set;
2432

2533
import com.fasterxml.jackson.core.JsonProcessingException;
26-
import io.swagger.v3.core.util.Json;
2734
import io.swagger.v3.core.util.PathUtils;
2835
import io.swagger.v3.oas.annotations.Operation;
2936
import io.swagger.v3.oas.models.OpenAPI;
@@ -138,10 +145,7 @@ public Mono<String> openapiJson(ServerHttpRequest serverHttpRequest, @Value(API_
138145
throws JsonProcessingException {
139146
calculateServerUrl(serverHttpRequest, apiDocsUrl);
140147
OpenAPI openAPI = this.getOpenApi();
141-
if (!springDocConfigProperties.isWriterWithDefaultPrettyPrinter())
142-
return Mono.just(Json.mapper().writeValueAsString(openAPI));
143-
else
144-
return Mono.just(Json.mapper().writerWithDefaultPrettyPrinter().writeValueAsString(openAPI));
148+
return Mono.just(writeJsonValue(openAPI));
145149
}
146150

147151
/**
@@ -158,10 +162,7 @@ public Mono<String> openapiYaml(ServerHttpRequest serverHttpRequest,
158162
@Value(DEFAULT_API_DOCS_URL_YAML) String apiDocsUrl) throws JsonProcessingException {
159163
calculateServerUrl(serverHttpRequest, apiDocsUrl);
160164
OpenAPI openAPI = this.getOpenApi();
161-
if (!springDocConfigProperties.isWriterWithDefaultPrettyPrinter())
162-
return Mono.just(getYamlMapper().writeValueAsString(openAPI));
163-
else
164-
return Mono.just(getYamlMapper().writerWithDefaultPrettyPrinter().writeValueAsString(openAPI));
165+
return Mono.just(writeYamlValue(openAPI));
165166
}
166167

167168
@Override

springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/app81/OperationIdController.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@
1818

1919
package test.org.springdoc.api.app81;
2020

21+
import reactor.core.publisher.Mono;
22+
2123
import org.springframework.web.bind.annotation.GetMapping;
2224
import org.springframework.web.bind.annotation.RequestParam;
2325
import org.springframework.web.bind.annotation.RestController;
24-
import reactor.core.publisher.Mono;
2526

2627
@RestController
2728
public class OperationIdController {

springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/app81/SpringDocApp81Test.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,27 +22,27 @@
2222
*/
2323
package test.org.springdoc.api.app81;
2424

25+
import java.net.URI;
26+
import java.util.ArrayList;
27+
import java.util.Comparator;
28+
import java.util.List;
29+
import java.util.Map;
30+
import java.util.concurrent.ThreadLocalRandom;
31+
2532
import org.junit.jupiter.api.RepeatedTest;
2633
import org.springdoc.webflux.api.OpenApiResource;
34+
2735
import org.springframework.beans.factory.annotation.Autowired;
2836
import org.springframework.boot.autoconfigure.SpringBootApplication;
2937
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
3038
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
3139
import org.springframework.context.annotation.ComponentScan;
3240
import org.springframework.http.server.reactive.ServerHttpRequest;
3341
import org.springframework.test.context.ActiveProfiles;
34-
import org.springframework.test.context.TestPropertySource;
3542
import org.springframework.web.method.HandlerMethod;
3643
import org.springframework.web.reactive.result.method.RequestMappingInfo;
3744
import org.springframework.web.reactive.result.method.RequestMappingInfoHandlerMapping;
3845

39-
import java.net.URI;
40-
import java.util.ArrayList;
41-
import java.util.Comparator;
42-
import java.util.List;
43-
import java.util.Map;
44-
import java.util.concurrent.ThreadLocalRandom;
45-
4646
import static org.mockito.Mockito.mock;
4747
import static org.mockito.Mockito.when;
4848
import static org.skyscreamer.jsonassert.JSONAssert.assertEquals;

springdoc-openapi-webmvc-core/src/main/java/org/springdoc/webmvc/api/OpenApiResource.java

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,18 @@
2020

2121
package org.springdoc.webmvc.api;
2222

23-
import java.util.*;
23+
import java.util.ArrayList;
24+
import java.util.Comparator;
25+
import java.util.HashSet;
26+
import java.util.LinkedHashMap;
27+
import java.util.List;
28+
import java.util.Map;
29+
import java.util.Optional;
30+
import java.util.Set;
2431

2532
import javax.servlet.http.HttpServletRequest;
2633

2734
import com.fasterxml.jackson.core.JsonProcessingException;
28-
import io.swagger.v3.core.util.Json;
2935
import io.swagger.v3.core.util.PathUtils;
3036
import io.swagger.v3.oas.annotations.Operation;
3137
import io.swagger.v3.oas.models.OpenAPI;
@@ -173,10 +179,7 @@ public String openapiJson(HttpServletRequest request, @Value(API_DOCS_URL) Strin
173179
throws JsonProcessingException {
174180
calculateServerUrl(request, apiDocsUrl);
175181
OpenAPI openAPI = this.getOpenApi();
176-
if (!springDocConfigProperties.isWriterWithDefaultPrettyPrinter())
177-
return Json.mapper().writeValueAsString(openAPI);
178-
else
179-
return Json.mapper().writerWithDefaultPrettyPrinter().writeValueAsString(openAPI);
182+
return writeJsonValue(openAPI);
180183
}
181184

182185
/**
@@ -193,10 +196,7 @@ public String openapiYaml(HttpServletRequest request, @Value(DEFAULT_API_DOCS_UR
193196
throws JsonProcessingException {
194197
calculateServerUrl(request, apiDocsUrl);
195198
OpenAPI openAPI = this.getOpenApi();
196-
if (!springDocConfigProperties.isWriterWithDefaultPrettyPrinter())
197-
return getYamlMapper().writeValueAsString(openAPI);
198-
else
199-
return getYamlMapper().writerWithDefaultPrettyPrinter().writeValueAsString(openAPI);
199+
return writeYamlValue(openAPI);
200200
}
201201

202202
@Override
@@ -246,9 +246,9 @@ protected void calculatePath(Map<String, Object> restControllers, Map<RequestMap
246246
Map<String, String> regexMap = new LinkedHashMap<>();
247247
for (String pattern : patterns) {
248248
String operationPath = PathUtils.parsePath(pattern, regexMap);
249-
String[] produces = requestMappingInfo.getProducesCondition().getProducibleMediaTypes().stream().map(MimeType::toString).toArray(String[]::new);
250-
String[] consumes = requestMappingInfo.getConsumesCondition().getConsumableMediaTypes().stream().map(MimeType::toString).toArray(String[]::new);
251-
String[] headers = requestMappingInfo.getHeadersCondition().getExpressions().stream().map(Object::toString).toArray(String[]::new);
249+
String[] produces = requestMappingInfo.getProducesCondition().getProducibleMediaTypes().stream().map(MimeType::toString).toArray(String[]::new);
250+
String[] consumes = requestMappingInfo.getConsumesCondition().getConsumableMediaTypes().stream().map(MimeType::toString).toArray(String[]::new);
251+
String[] headers = requestMappingInfo.getHeadersCondition().getExpressions().stream().map(Object::toString).toArray(String[]::new);
252252
if (((actuatorProvider.isPresent() && actuatorProvider.get().isRestController(operationPath, handlerMethod.getBeanType()))
253253
|| isRestController(restControllers, handlerMethod, operationPath))
254254
&& isFilterCondition(handlerMethod, operationPath, produces, consumes, headers)) {
@@ -264,8 +264,8 @@ && isFilterCondition(handlerMethod, operationPath, produces, consumes, headers))
264264

265265
private Comparator<Map.Entry<RequestMappingInfo, HandlerMethod>> byReversedRequestMappingInfos() {
266266
return Comparator.<Map.Entry<RequestMappingInfo, HandlerMethod>, String>
267-
comparing(a -> a.getKey().toString())
268-
.reversed();
267+
comparing(a -> a.getKey().toString())
268+
.reversed();
269269
}
270270

271271
/**

springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app136/SpringDocApp136Test.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,17 @@
2222
*/
2323
package test.org.springdoc.api.app136;
2424

25+
import java.util.ArrayList;
26+
import java.util.Comparator;
27+
import java.util.List;
28+
import java.util.Map;
29+
import java.util.concurrent.ThreadLocalRandom;
30+
31+
import javax.servlet.http.HttpServletRequest;
32+
2533
import org.junit.jupiter.api.RepeatedTest;
2634
import org.springdoc.webmvc.api.OpenApiResource;
35+
2736
import org.springframework.beans.factory.annotation.Autowired;
2837
import org.springframework.boot.autoconfigure.SpringBootApplication;
2938
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
@@ -33,14 +42,6 @@
3342
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
3443
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
3544

36-
import javax.servlet.http.HttpServletRequest;
37-
38-
import java.util.ArrayList;
39-
import java.util.Comparator;
40-
import java.util.List;
41-
import java.util.Map;
42-
import java.util.concurrent.ThreadLocalRandom;
43-
4445
import static org.mockito.Mockito.mock;
4546
import static org.mockito.Mockito.when;
4647
import static org.skyscreamer.jsonassert.JSONAssert.assertEquals;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
*
3+
* * Copyright 2019-2020 the original author or authors.
4+
* *
5+
* * Licensed under the Apache License, Version 2.0 (the "License");
6+
* * you may not use this file except in compliance with the License.
7+
* * You may obtain a copy of the License at
8+
* *
9+
* * https://www.apache.org/licenses/LICENSE-2.0
10+
* *
11+
* * Unless required by applicable law or agreed to in writing, software
12+
* * distributed under the License is distributed on an "AS IS" BASIS,
13+
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* * See the License for the specific language governing permissions and
15+
* * limitations under the License.
16+
*
17+
*/
18+
19+
package test.org.springdoc.api.app138;
20+
21+
import org.springframework.web.bind.annotation.GetMapping;
22+
import org.springframework.web.bind.annotation.RestController;
23+
24+
@RestController
25+
public class HelloController {
26+
27+
@GetMapping("/testA")
28+
public void testA(String hello) {
29+
}
30+
31+
@GetMapping("/testB")
32+
public void testB(String hello) {
33+
}
34+
}

0 commit comments

Comments
 (0)