Skip to content

Commit 19555d1

Browse files
committed
Virtual thread pinning in AbstractOpenApiResource.getOpenApi. Fixes #2281
1 parent 0bfe92e commit 19555d1

File tree

2 files changed

+173
-148
lines changed

2 files changed

+173
-148
lines changed

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

Lines changed: 71 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
import java.util.Set;
4848
import java.util.TreeSet;
4949
import java.util.concurrent.Executors;
50+
import java.util.concurrent.locks.Lock;
51+
import java.util.concurrent.locks.ReentrantLock;
5052
import java.util.stream.Collectors;
5153

5254
import com.fasterxml.jackson.annotation.JsonView;
@@ -200,6 +202,10 @@ public abstract class AbstractOpenApiResource extends SpecFilter {
200202
*/
201203
protected final SpringDocCustomizers springDocCustomizers;
202204

205+
/**
206+
* The Reentrant lock.
207+
*/
208+
private final Lock reentrantLock = new ReentrantLock();
203209

204210
/**
205211
* Instantiates a new Abstract open api resource.
@@ -319,73 +325,78 @@ private void getOpenApi() {
319325
* @param locale the locale
320326
* @return the open api
321327
*/
322-
protected synchronized OpenAPI getOpenApi(Locale locale) {
323-
final OpenAPI openAPI;
324-
final Locale finalLocale = locale == null ? Locale.getDefault() : locale;
325-
if (openAPIService.getCachedOpenAPI(finalLocale) == null || springDocConfigProperties.isCacheDisabled()) {
326-
Instant start = Instant.now();
327-
openAPI = openAPIService.build(finalLocale);
328-
Map<String, Object> mappingsMap = openAPIService.getMappingsMap().entrySet().stream()
329-
.filter(controller -> (AnnotationUtils.findAnnotation(controller.getValue().getClass(),
330-
Hidden.class) == null))
331-
.filter(controller -> !isHiddenRestControllers(controller.getValue().getClass()))
332-
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a1, a2) -> a1));
333-
334-
Map<String, Object> findControllerAdvice = openAPIService.getControllerAdviceMap();
335-
if (OpenApiVersion.OPENAPI_3_1 == springDocConfigProperties.getApiDocs().getVersion())
336-
openAPI.openapi(OpenApiVersion.OPENAPI_3_1.getVersion());
337-
if (springDocConfigProperties.isDefaultOverrideWithGenericResponse()) {
338-
if (!CollectionUtils.isEmpty(mappingsMap))
339-
findControllerAdvice.putAll(mappingsMap);
340-
responseBuilder.buildGenericResponse(openAPI.getComponents(), findControllerAdvice, finalLocale);
341-
}
342-
getPaths(mappingsMap, finalLocale, openAPI);
343-
344-
Optional<CloudFunctionProvider> cloudFunctionProviderOptional = springDocProviders.getSpringCloudFunctionProvider();
345-
cloudFunctionProviderOptional.ifPresent(cloudFunctionProvider -> {
346-
List<RouterOperation> routerOperationList = cloudFunctionProvider.getRouterOperations(openAPI);
347-
if (!CollectionUtils.isEmpty(routerOperationList))
348-
this.calculatePath(routerOperationList, locale, openAPI);
349-
}
350-
);
351-
if (!CollectionUtils.isEmpty(openAPI.getServers()))
352-
openAPIService.setServersPresent(true);
353-
else
354-
openAPIService.setServersPresent(false);
355-
openAPIService.updateServers(openAPI);
356-
357-
if (springDocConfigProperties.isRemoveBrokenReferenceDefinitions())
358-
this.removeBrokenReferenceDefinitions(openAPI);
328+
protected OpenAPI getOpenApi(Locale locale) {
329+
this.reentrantLock.lock();
330+
try {
331+
final OpenAPI openAPI;
332+
final Locale finalLocale = locale == null ? Locale.getDefault() : locale;
333+
if (openAPIService.getCachedOpenAPI(finalLocale) == null || springDocConfigProperties.isCacheDisabled()) {
334+
Instant start = Instant.now();
335+
openAPI = openAPIService.build(finalLocale);
336+
Map<String, Object> mappingsMap = openAPIService.getMappingsMap().entrySet().stream()
337+
.filter(controller -> (AnnotationUtils.findAnnotation(controller.getValue().getClass(),
338+
Hidden.class) == null))
339+
.filter(controller -> !isHiddenRestControllers(controller.getValue().getClass()))
340+
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a1, a2) -> a1));
341+
342+
Map<String, Object> findControllerAdvice = openAPIService.getControllerAdviceMap();
343+
if (OpenApiVersion.OPENAPI_3_1 == springDocConfigProperties.getApiDocs().getVersion())
344+
openAPI.openapi(OpenApiVersion.OPENAPI_3_1.getVersion());
345+
if (springDocConfigProperties.isDefaultOverrideWithGenericResponse()) {
346+
if (!CollectionUtils.isEmpty(mappingsMap))
347+
findControllerAdvice.putAll(mappingsMap);
348+
responseBuilder.buildGenericResponse(openAPI.getComponents(), findControllerAdvice, finalLocale);
349+
}
350+
getPaths(mappingsMap, finalLocale, openAPI);
359351

360-
// run the optional customisers
361-
List<Server> servers = openAPI.getServers();
362-
List<Server> serversCopy = null;
363-
try {
364-
serversCopy = springDocProviders.jsonMapper()
365-
.readValue(springDocProviders.jsonMapper().writeValueAsString(servers), new TypeReference<List<Server>>() {});
366-
}
367-
catch (JsonProcessingException e) {
368-
LOGGER.warn("Json Processing Exception occurred: {}", e.getMessage());
369-
}
352+
Optional<CloudFunctionProvider> cloudFunctionProviderOptional = springDocProviders.getSpringCloudFunctionProvider();
353+
cloudFunctionProviderOptional.ifPresent(cloudFunctionProvider -> {
354+
List<RouterOperation> routerOperationList = cloudFunctionProvider.getRouterOperations(openAPI);
355+
if (!CollectionUtils.isEmpty(routerOperationList))
356+
this.calculatePath(routerOperationList, locale, openAPI);
357+
}
358+
);
359+
if (!CollectionUtils.isEmpty(openAPI.getServers()))
360+
openAPIService.setServersPresent(true);
361+
else
362+
openAPIService.setServersPresent(false);
363+
openAPIService.updateServers(openAPI);
364+
365+
if (springDocConfigProperties.isRemoveBrokenReferenceDefinitions())
366+
this.removeBrokenReferenceDefinitions(openAPI);
367+
368+
// run the optional customisers
369+
List<Server> servers = openAPI.getServers();
370+
List<Server> serversCopy = null;
371+
try {
372+
serversCopy = springDocProviders.jsonMapper()
373+
.readValue(springDocProviders.jsonMapper().writeValueAsString(servers), new TypeReference<List<Server>>() {});
374+
}
375+
catch (JsonProcessingException e) {
376+
LOGGER.warn("Json Processing Exception occurred: {}", e.getMessage());
377+
}
370378

371-
openAPIService.getContext().getBeansOfType(OpenApiLocaleCustomizer.class).values().forEach(openApiLocaleCustomizer -> openApiLocaleCustomizer.customise(openAPI, finalLocale));
372-
springDocCustomizers.getOpenApiCustomizers().ifPresent(apiCustomizers -> apiCustomizers.forEach(openApiCustomizer -> openApiCustomizer.customise(openAPI)));
373-
if (!CollectionUtils.isEmpty(openAPI.getServers()) && !openAPI.getServers().equals(serversCopy))
374-
openAPIService.setServersPresent(true);
379+
openAPIService.getContext().getBeansOfType(OpenApiLocaleCustomizer.class).values().forEach(openApiLocaleCustomizer -> openApiLocaleCustomizer.customise(openAPI, finalLocale));
380+
springDocCustomizers.getOpenApiCustomizers().ifPresent(apiCustomizers -> apiCustomizers.forEach(openApiCustomizer -> openApiCustomizer.customise(openAPI)));
381+
if (!CollectionUtils.isEmpty(openAPI.getServers()) && !openAPI.getServers().equals(serversCopy))
382+
openAPIService.setServersPresent(true);
375383

376384

377-
openAPIService.setCachedOpenAPI(openAPI, finalLocale);
385+
openAPIService.setCachedOpenAPI(openAPI, finalLocale);
378386

379-
LOGGER.info("Init duration for springdoc-openapi is: {} ms",
380-
Duration.between(start, Instant.now()).toMillis());
381-
}
382-
else {
383-
LOGGER.debug("Fetching openApi document from cache");
384-
openAPI = openAPIService.getCachedOpenAPI(finalLocale);
387+
LOGGER.info("Init duration for springdoc-openapi is: {} ms",
388+
Duration.between(start, Instant.now()).toMillis());
389+
}
390+
else {
391+
LOGGER.debug("Fetching openApi document from cache");
392+
openAPI = openAPIService.getCachedOpenAPI(finalLocale);
393+
openAPIService.updateServers(openAPI);
394+
}
385395
openAPIService.updateServers(openAPI);
396+
return openAPI; }
397+
finally {
398+
this.reentrantLock.unlock();
386399
}
387-
openAPIService.updateServers(openAPI);
388-
return openAPI;
389400
}
390401

391402
/**

0 commit comments

Comments
 (0)