Skip to content

Commit 7858def

Browse files
committed
[NO-TICKET] Use virtual threads
1 parent b97cb1d commit 7858def

File tree

4 files changed

+44
-18
lines changed

4 files changed

+44
-18
lines changed

openapi-validation-core/src/main/java/com/getyourguide/openapi/validation/core/OpenApiRequestValidator.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,26 @@
1414
import java.net.URLDecoder;
1515
import java.nio.charset.StandardCharsets;
1616
import java.util.List;
17+
import java.util.concurrent.Executor;
1718
import java.util.concurrent.RejectedExecutionException;
18-
import java.util.concurrent.ThreadPoolExecutor;
1919
import javax.annotation.Nullable;
2020
import lombok.extern.slf4j.Slf4j;
2121
import org.apache.http.client.utils.URLEncodedUtils;
2222

2323
@Slf4j
2424
public class OpenApiRequestValidator {
25-
private final ThreadPoolExecutor threadPoolExecutor;
25+
private final Executor executor;
2626
private final OpenApiInteractionValidatorWrapper validator;
2727
private final ValidationReportToOpenApiViolationsMapper mapper;
2828

2929
public OpenApiRequestValidator(
30-
ThreadPoolExecutor threadPoolExecutor,
30+
Executor executor,
3131
MetricsReporter metricsReporter,
3232
OpenApiInteractionValidatorWrapper validator,
3333
ValidationReportToOpenApiViolationsMapper mapper,
3434
OpenApiRequestValidationConfiguration configuration
3535
) {
36-
this.threadPoolExecutor = threadPoolExecutor;
36+
this.executor = executor;
3737
this.validator = validator;
3838
this.mapper = mapper;
3939

@@ -74,7 +74,7 @@ public void validateResponseObjectAsync(
7474

7575
private void executeAsync(Runnable command) {
7676
try {
77-
threadPoolExecutor.execute(command);
77+
executor.execute(command);
7878
} catch (RejectedExecutionException ignored) {
7979
// ignored
8080
}

openapi-validation-core/src/test/java/com/getyourguide/openapi/validation/core/OpenApiRequestValidatorTest.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,30 +14,30 @@
1414
import java.net.URI;
1515
import java.util.HashMap;
1616
import java.util.List;
17+
import java.util.concurrent.Executor;
1718
import java.util.concurrent.RejectedExecutionException;
18-
import java.util.concurrent.ThreadPoolExecutor;
1919
import org.junit.jupiter.api.BeforeEach;
2020
import org.junit.jupiter.api.Test;
2121
import org.mockito.ArgumentCaptor;
2222
import org.mockito.Mockito;
2323

2424
public class OpenApiRequestValidatorTest {
2525

26-
private ThreadPoolExecutor threadPoolExecutor;
26+
private Executor executor;
2727
private OpenApiInteractionValidatorWrapper validator;
2828

2929
private OpenApiRequestValidator openApiRequestValidator;
3030

3131
@BeforeEach
3232
public void setup() {
33-
threadPoolExecutor = mock();
33+
executor = mock();
3434
validator = mock();
3535
MetricsReporter metricsReporter = mock();
3636
var mapper = mock(ValidationReportToOpenApiViolationsMapper.class);
3737
when(mapper.map(any(), any(), any(), any(), any())).thenReturn(List.of());
3838

3939
openApiRequestValidator = new OpenApiRequestValidator(
40-
threadPoolExecutor,
40+
executor,
4141
metricsReporter,
4242
validator,
4343
mapper,
@@ -47,7 +47,7 @@ public void setup() {
4747

4848
@Test
4949
public void testWhenThreadPoolExecutorRejectsExecutionThenItShouldNotThrow() {
50-
Mockito.doThrow(new RejectedExecutionException()).when(threadPoolExecutor).execute(any());
50+
Mockito.doThrow(new RejectedExecutionException()).when(executor).execute(any());
5151

5252
openApiRequestValidator.validateRequestObjectAsync(mock(), null, null, mock());
5353
}

spring-boot-starter/spring-boot-starter-core/src/main/java/com/getyourguide/openapi/validation/autoconfigure/LibraryAutoConfiguration.java

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import com.getyourguide.openapi.validation.core.mapper.ValidationReportToOpenApiViolationsMapper;
2626
import com.getyourguide.openapi.validation.core.metrics.DefaultMetricsReporter;
2727
import java.util.Optional;
28+
import java.util.concurrent.Executor;
2829
import java.util.concurrent.LinkedBlockingQueue;
2930
import java.util.concurrent.ThreadPoolExecutor;
3031
import java.util.concurrent.TimeUnit;
@@ -104,14 +105,7 @@ public OpenApiRequestValidator openApiRequestValidator(
104105
MetricsReporter metricsReporter,
105106
ValidatorConfiguration validatorConfiguration
106107
) {
107-
var threadPoolExecutor = new ThreadPoolExecutor(
108-
2,
109-
2,
110-
1000L,
111-
TimeUnit.MILLISECONDS,
112-
new LinkedBlockingQueue<>(10),
113-
new ThreadPoolExecutor.DiscardPolicy()
114-
);
108+
var threadPoolExecutor = createThreadPoolExecutor();
115109

116110
return new OpenApiRequestValidator(
117111
threadPoolExecutor,
@@ -122,4 +116,30 @@ public OpenApiRequestValidator openApiRequestValidator(
122116
properties.toOpenApiRequestValidationConfiguration()
123117
);
124118
}
119+
120+
private Executor createThreadPoolExecutor() {
121+
try {
122+
// Try to use virtual threads if available (Java 21+)
123+
var virtualThreadFactory = Thread.ofVirtual().factory();
124+
return new ThreadPoolExecutor(
125+
2,
126+
2,
127+
1000L,
128+
TimeUnit.MILLISECONDS,
129+
new LinkedBlockingQueue<>(10),
130+
virtualThreadFactory,
131+
new ThreadPoolExecutor.DiscardPolicy()
132+
);
133+
} catch (UnsupportedOperationException | NoSuchMethodError e) {
134+
// Fallback to ThreadPoolExecutor with regular threads for older Java versions
135+
return new ThreadPoolExecutor(
136+
2,
137+
2,
138+
1000L,
139+
TimeUnit.MILLISECONDS,
140+
new LinkedBlockingQueue<>(10),
141+
new ThreadPoolExecutor.DiscardPolicy()
142+
);
143+
}
144+
}
125145
}

spring-boot-starter/spring-boot-starter-web/src/test/java/com/getyourguide/openapi/validation/integration/controller/DefaultRestController.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.getyourguide.openapi.validation.test.exception.WithoutResponseStatusException;
55
import com.getyourguide.openapi.validation.test.openapi.web.DefaultApi;
66
import com.getyourguide.openapi.validation.test.openapi.web.model.PostTestRequest;
7+
import com.getyourguide.openapi.validation.test.openapi.web.model.TestEmailResponse;
78
import com.getyourguide.openapi.validation.test.openapi.web.model.TestResponse;
89
import java.time.LocalDate;
910
import java.util.Objects;
@@ -26,6 +27,11 @@ public ResponseEntity<TestResponse> getTest(String testCase, LocalDate date, Str
2627
return ResponseEntity.ok(new TestResponse().value(responseValue));
2728
}
2829

30+
@Override
31+
public ResponseEntity<TestEmailResponse> getTestEmail() {
32+
return ResponseEntity.ok(new TestEmailResponse().email("[email protected]"));
33+
}
34+
2935
@Override
3036
public ResponseEntity<TestResponse> postTest(PostTestRequest postTestRequest) {
3137
var responseStatus = postTestRequest.getResponseStatusCode();

0 commit comments

Comments
 (0)