Skip to content

Commit 3022d32

Browse files
committed
Add Spring Boot 3 integration modules
Motivation: Spring 6 and Spring Boot 3 have been released. https://spring.io/blog/2022/11/24/spring-boot-3-0-goes-ga Note that the added modules will not be published until we refactor `spring-boot2-autoconfigure` internals. Modifications: - Add Spring Boot 3 integrations symmetirically with Spring Boot 2. - `publish` flags are not added intentionally. - Set the release target for Spring Boot 3 and examples to Java 17. - Add `PortUtil` and migrate off `SocketUtils`. - Migrate AutoConfiguration in spring.factories to `o.s.b.a.AutoConfiguration.imports`. https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.7-Release-Notes#new-autoconfiguration-annotation - Change `management.metrics.export.defaults.enabled` to `management.promethus.metrics.export.enabled` in tests spring-projects/spring-boot#30381 - Fix compile errors in the webflux integration - Migrate moved `LocalServerPort` and `LocalManagementPort`. Depedencies: - Add Spring Boot 3.0.0 - Add `hibernate-validator 8.0.0 - Bump Micrometer into 1.10.2 - Add Jakarta dependencies - jakarta-inject 2.0.1 - jakarta-validation 3.0.2 - jakarta-websocket 2.1.0 Result: You can now use Spring Boot 3 with Armeria.
1 parent d04f823 commit 3022d32

File tree

58 files changed

+421
-92
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+421
-92
lines changed

build.gradle

+9-9
Original file line numberDiff line numberDiff line change
@@ -178,15 +178,15 @@ configure(projectsWithFlags('java')) {
178178
}
179179

180180
tasks.withType(JavaCompile) { task ->
181-
if (task.path.startsWith(':examples:')) {
182-
// Target Java 11 for examples.
183-
options.release.set(11)
184-
// IntelliJ fails to compile example projects with IntelliJ compiler because of a wrong target
185-
// bytecode version which is marked as Java 8 without the following options.
186-
// See https://github.com/line/armeria/pull/3712
187-
sourceCompatibility = '11'
188-
targetCompatibility = '11'
189-
} else {
181+
if (task.path.startsWith(':spring:boot3') || task.path.startsWith(':examples')) {
182+
// Target Java 17 for examples and Spring Boot 3
183+
options.release.set(17)
184+
// IntelliJ fails to compile example projects with IntelliJ compiler because of a wrong target
185+
// bytecode version which is marked as Java 8 without the following options.
186+
// See https://github.com/line/armeria/pull/3712
187+
sourceCompatibility = '17'
188+
targetCompatibility = '17'
189+
} else {
190190
// Target Java 8 for the rest of them.
191191
options.release.set(8)
192192
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright 2022 LINE Corporation
3+
*
4+
* LINE Corporation licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. You may obtain a copy of the License at:
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
17+
package com.linecorp.armeria.internal.common.util;
18+
19+
import java.io.IOException;
20+
import java.net.InetSocketAddress;
21+
import java.net.ServerSocket;
22+
import java.util.Random;
23+
import java.util.concurrent.ThreadLocalRandom;
24+
25+
public final class PortUtil {
26+
27+
private static final int PORT_MIN = 1024;
28+
private static final int PORT_RANGE = 64511;
29+
private static final int PORT_MAX = PORT_MIN + PORT_RANGE;
30+
31+
public static int unusedTcpPort() {
32+
final Random random = ThreadLocalRandom.current();
33+
for (int i = 0; i < PORT_RANGE; i++) {
34+
final int candidatePort = random.nextInt(PORT_RANGE) + PORT_MIN;
35+
try (ServerSocket ss = new ServerSocket()) {
36+
ss.bind(new InetSocketAddress("127.0.0.1", candidatePort));
37+
return candidatePort;
38+
} catch (IOException e) {
39+
// Port in use or unable to bind.
40+
continue;
41+
}
42+
}
43+
44+
throw new IllegalStateException(
45+
"Failed to find an unused TCP port in the range [" + PORT_MIN + ", " + PORT_MAX + "] after + " +
46+
PORT_RANGE + " attempts");
47+
}
48+
49+
private PortUtil() {}
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright 2022 LINE Corporation
3+
*
4+
* LINE Corporation licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. You may obtain a copy of the License at:
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
17+
package com.linecorp.armeria.internal.common.util;
18+
19+
import java.io.IOException;
20+
import java.net.InetSocketAddress;
21+
import java.net.ServerSocket;
22+
23+
import org.junit.jupiter.api.Test;
24+
25+
class PortUtilTest {
26+
27+
@Test
28+
void shouldAcquireUnusedPort() throws IOException {
29+
final int port = PortUtil.unusedTcpPort();
30+
try (ServerSocket serverSocket = new ServerSocket()) {
31+
// Make sure the ServerSocket is successfully bound to the port.
32+
serverSocket.bind(new InetSocketAddress("127.0.0.1", port));
33+
}
34+
}
35+
}

dependencies.toml

+55-4
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,13 @@ grpc-kotlin = "1.3.0"
3737
guava = "31.1-jre"
3838
hamcrest = "2.2"
3939
hbase = "1.2.6"
40-
hibernate-validator = "6.2.3.Final"
40+
hibernate-validator6 = "6.2.3.Final"
41+
hibernate-validator8 = "8.0.0.Final"
4142
j2objc = "1.3"
4243
jackson = "2.13.4"
44+
jakarta-inject = "2.0.1"
45+
jakarta-validation = "3.0.2"
46+
jakarta-websocket= "2.1.0"
4347
javax-annotation = "1.3.2"
4448
javax-inject = "1"
4549
javax-jsr311 = "1.1.1"
@@ -64,7 +68,7 @@ kotlin = "1.7.20"
6468
kotlin-coroutine = "1.6.4"
6569
ktlint-gradle-plugin = "11.0.0"
6670
logback = "1.2.11"
67-
micrometer = "1.9.4"
71+
micrometer = "1.10.2"
6872
micrometer13 = "1.3.20"
6973
mockito = "4.8.0"
7074
monix = "3.4.1"
@@ -111,6 +115,7 @@ slf4j = "1.7.36"
111115
spring = "5.3.23"
112116
spring-boot1 = "1.5.22.RELEASE"
113117
spring-boot2 = "2.7.4"
118+
spring-boot3 = "3.0.0"
114119
testng = "7.5"
115120
thrift09 = { strictly = "0.9.3-1" }
116121
thrift012 = { strictly = "0.12.0" }
@@ -467,16 +472,32 @@ exclusions = [
467472

468473
# Validator is only used for examples and testings in Spring
469474
# version 7 starts using jakarta api, which isn't compatible with spring-boot2
470-
[libraries.hibernate-validator]
475+
[libraries.hibernate-validator6]
471476
module = "org.hibernate.validator:hibernate-validator"
472-
version.ref = "hibernate-validator"
477+
version.ref = "hibernate-validator6"
478+
[libraries.hibernate-validator8]
479+
module = "org.hibernate.validator:hibernate-validator"
480+
version.ref = "hibernate-validator8"
473481

474482
# We do not depend on j2objc-annotations. We just need this to stop Javadoc from
475483
# complaining about "unknown enum constant Level.FULL".
476484
[libraries.j2objc]
477485
module = "com.google.j2objc:j2objc-annotations"
478486
version.ref = "j2objc"
479487

488+
[libraries.jakarta-inject]
489+
module = "jakarta.inject:jakarta.inject-api"
490+
version.ref = "jakarta-inject"
491+
[libraries.jakarta-validation]
492+
module = "jakarta.validation:jakarta.validation-api"
493+
version.ref = "jakarta-validation"
494+
[libraries.jakarta-websocket]
495+
module = "jakarta.websocket:jakarta.websocket-api"
496+
version.ref = "jakarta-websocket"
497+
[libraries.jakarta-websocket-client]
498+
module = "jakarta.websocket:jakarta.websocket-client-api"
499+
version.ref = "jakarta-websocket"
500+
480501
[libraries.jackson-annotations]
481502
module = "com.fasterxml.jackson.core:jackson-annotations"
482503
javadocs = "https://fasterxml.github.io/jackson-annotations/javadoc/2.13/"
@@ -1020,6 +1041,36 @@ exclusions = "org.springframework.boot:spring-boot-starter-reactor-netty"
10201041
module = "org.springframework.boot:spring-boot-configuration-processor"
10211042
version.ref = "spring-boot2"
10221043

1044+
[libraries.spring-boot3-actuator-autoconfigure]
1045+
module = "org.springframework.boot:spring-boot-actuator-autoconfigure"
1046+
version.ref = "spring-boot3"
1047+
[libraries.spring-boot3-autoconfigure]
1048+
module = "org.springframework.boot:spring-boot-autoconfigure"
1049+
version.ref = "spring-boot3"
1050+
[libraries.spring-boot3-starter]
1051+
module = "org.springframework.boot:spring-boot-starter"
1052+
version.ref = "spring-boot3"
1053+
javadocs = "https://docs.spring.io/spring/docs/current/javadoc-api/"
1054+
[libraries.spring-boot3-starter-actuator]
1055+
module = "org.springframework.boot:spring-boot-starter-actuator"
1056+
version.ref = "spring-boot3"
1057+
[libraries.spring-boot3-starter-security]
1058+
module = "org.springframework.boot:spring-boot-starter-security"
1059+
version.ref = "spring-boot3"
1060+
[libraries.spring-boot3-starter-test]
1061+
module = "org.springframework.boot:spring-boot-starter-test"
1062+
version.ref = "spring-boot3"
1063+
[libraries.spring-boot3-starter-web]
1064+
module = "org.springframework.boot:spring-boot-starter-web"
1065+
version.ref = "spring-boot3"
1066+
[libraries.spring-boot3-starter-webflux]
1067+
module = "org.springframework.boot:spring-boot-starter-webflux"
1068+
version.ref = "spring-boot3"
1069+
exclusions = "org.springframework.boot:spring-boot-starter-reactor-netty"
1070+
[libraries.spring-boot3-configuration-processor]
1071+
module = "org.springframework.boot:spring-boot-configuration-processor"
1072+
version.ref = "spring-boot3"
1073+
10231074
# jdk 11 is required from testng version 7.6
10241075
[libraries.testng]
10251076
module = "org.testng:testng"

examples/spring-boot-minimal-kotlin/build.gradle.kts

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ plugins {
88

99
dependencies {
1010
implementation(project(":spring:boot2-starter"))
11-
implementation(libs.hibernate.validator)
11+
// TODO(ikhoon): Migrate version to v8
12+
implementation(libs.hibernate.validator6)
1213

1314
implementation(project(":spring:boot2-actuator-starter"))
1415

examples/spring-boot-minimal/build.gradle

+5-5
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,20 @@ plugins {
33
}
44

55
dependencies {
6-
implementation project(':spring:boot2-starter')
7-
implementation libs.hibernate.validator
6+
implementation project(':spring:boot3-starter')
7+
implementation libs.hibernate.validator8
88

99
// Preprocessor that enables you to use JavaDoc to add description to REST API parameters.
1010
// If you don't want to use it, you can use the annotation
1111
// com.linecorp.armeria.server.annotation.Description otherwise.
1212
compileOnly project(':annotation-processor')
1313
annotationProcessor project(':annotation-processor')
1414

15-
annotationProcessor libs.spring.boot2.configuration.processor
15+
annotationProcessor libs.spring.boot3.configuration.processor
1616

17-
runtimeOnly project(':spring:boot2-actuator-starter')
17+
runtimeOnly project(':spring:boot3-actuator-starter')
1818

1919
testImplementation libs.json.unit.fluent
2020
testImplementation libs.junit5.jupiter.api
21-
testImplementation libs.spring.boot2.starter.test
21+
testImplementation libs.spring.boot3.starter.test
2222
}

examples/spring-boot-webflux/src/test/java/example/springframework/boot/webflux/HelloApplicationIntegrationTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import org.junit.jupiter.api.Test;
77
import org.springframework.boot.test.context.SpringBootTest;
88
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
9-
import org.springframework.boot.web.server.LocalServerPort;
9+
import org.springframework.boot.test.web.server.LocalServerPort;
1010
import org.springframework.http.client.reactive.ClientHttpConnector;
1111
import org.springframework.test.context.ActiveProfiles;
1212
import org.springframework.test.web.reactive.server.WebTestClient;

it/multipart/src/test/java/com/linecorp/armeria/common/multipart/SpringServerMultipartTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import org.junit.jupiter.api.Test;
2323
import org.springframework.boot.test.context.SpringBootTest;
2424
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
25-
import org.springframework.boot.web.server.LocalServerPort;
25+
import org.springframework.boot.test.web.server.LocalServerPort;
2626

2727
import com.linecorp.armeria.client.WebClient;
2828
import com.linecorp.armeria.client.logging.ContentPreviewingClient;

it/spring/boot2-tomcat9/src/test/java/com/linecorp/armeria/spring/tomcat/ActuatorAutoConfigurationHealthGroupTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@
2222

2323
import org.junit.jupiter.api.BeforeEach;
2424
import org.junit.jupiter.api.Test;
25-
import org.springframework.boot.actuate.autoconfigure.web.server.LocalManagementPort;
2625
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
2726
import org.springframework.boot.test.autoconfigure.actuate.metrics.AutoConfigureMetrics;
2827
import org.springframework.boot.test.context.SpringBootTest;
2928
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
29+
import org.springframework.boot.test.web.server.LocalManagementPort;
3030
import org.springframework.test.annotation.DirtiesContext;
3131
import org.springframework.test.context.ActiveProfiles;
3232

it/spring/webflux-security/src/test/java/com/linecorp/armeria/spring/security/SecureResourceTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import org.junit.jupiter.api.Test;
2323
import org.springframework.boot.test.context.SpringBootTest;
2424
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
25-
import org.springframework.boot.web.server.LocalServerPort;
25+
import org.springframework.boot.test.web.server.LocalServerPort;
2626

2727
import com.linecorp.armeria.client.WebClient;
2828
import com.linecorp.armeria.client.cookie.CookieClient;

settings.gradle

+11
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,23 @@ project(':scalapb_3').projectDir = file('scalapb/scalapb_3')
5050

5151
includeWithFlags ':spring:boot1-autoconfigure', 'java', 'publish', 'relocate', 'no_aggregation'
5252
includeWithFlags ':spring:boot1-starter', 'java', 'publish', 'relocate', 'no_aggregation'
53+
5354
includeWithFlags ':spring:boot2-actuator-autoconfigure', 'java', 'publish', 'relocate'
5455
includeWithFlags ':spring:boot2-actuator-starter', 'java', 'publish', 'relocate'
5556
includeWithFlags ':spring:boot2-autoconfigure', 'java', 'publish', 'relocate'
5657
includeWithFlags ':spring:boot2-starter', 'java', 'publish', 'relocate'
5758
includeWithFlags ':spring:boot2-webflux-autoconfigure', 'java', 'publish', 'relocate'
5859
includeWithFlags ':spring:boot2-webflux-starter', 'java', 'publish', 'relocate'
60+
61+
// TODO(ikhoon): Publish Spring Boot 3 intgretions after refactorying boot2-autoconfigure to implemement
62+
// ServletWebServerFactory.
63+
includeWithFlags ':spring:boot3-actuator-autoconfigure', 'java', 'relocate'
64+
includeWithFlags ':spring:boot3-actuator-starter', 'java', 'relocate'
65+
includeWithFlags ':spring:boot3-autoconfigure', 'java', 'relocate'
66+
includeWithFlags ':spring:boot3-starter', 'java', 'relocate'
67+
includeWithFlags ':spring:boot3-webflux-autoconfigure', 'java', 'relocate'
68+
includeWithFlags ':spring:boot3-webflux-starter', 'java', 'relocate'
69+
5970
includeWithFlags ':dropwizard1', 'java', 'publish', 'relocate', 'no_aggregation'
6071
includeWithFlags ':dropwizard2', 'java', 'publish', 'relocate'
6172
includeWithFlags ':thrift0.9', 'java', 'publish', 'relocate', 'no_aggregation'

spring/boot1-autoconfigure/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ dependencies {
2222
testImplementation libs.spring.boot1.starter
2323
testImplementation libs.spring.boot1.starter.test
2424
// Enables cglib for testing
25-
testImplementation libs.hibernate.validator
25+
testImplementation libs.hibernate.validator6
2626
}
2727

2828
// Use the sources from ':spring:boot2-autoconfigure'.

spring/boot2-actuator-autoconfigure/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ task generateTestSources(type: Copy) {
2323
into "${project.ext.genSrcDir}/test"
2424
include '**/RetryableArmeriaServerGracefulShutdownLifecycle.java'
2525
include '**/RetryableArmeriaServerGracefulShutdownLifecycleConfiguration.java'
26-
include '**/META-INF/spring.factories'
26+
include '**/META-INF/spring'
2727
}
2828

2929
task generateSources(type: Copy) {

spring/boot2-actuator-autoconfigure/src/main/java/com/linecorp/armeria/spring/actuate/ArmeriaSpringActuatorAutoConfiguration.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@
6565
import org.springframework.context.annotation.Configuration;
6666
import org.springframework.core.env.ConfigurableEnvironment;
6767
import org.springframework.core.env.PropertySource;
68-
import org.springframework.util.SocketUtils;
6968
import org.springframework.util.StringUtils;
7069

7170
import com.google.common.annotations.VisibleForTesting;
@@ -80,6 +79,7 @@
8079
import com.linecorp.armeria.common.MediaTypeNames;
8180
import com.linecorp.armeria.common.SessionProtocol;
8281
import com.linecorp.armeria.common.annotation.Nullable;
82+
import com.linecorp.armeria.internal.common.util.PortUtil;
8383
import com.linecorp.armeria.server.HttpService;
8484
import com.linecorp.armeria.server.Route;
8585
import com.linecorp.armeria.server.ServerBuilder;
@@ -256,7 +256,7 @@ private static Integer obtainManagementServerPort(ServerBuilder serverBuilder,
256256
return null;
257257
}
258258
if (port == 0) {
259-
port = SocketUtils.findAvailableTcpPort();
259+
port = PortUtil.unusedTcpPort();
260260
}
261261
// The management port was not configured by ArmeriaAutoConfiguration
262262
final Port managementPort = new Port().setPort(port).setProtocol(SessionProtocol.HTTP);

spring/boot2-actuator-autoconfigure/src/main/resources/META-INF/spring.factories

-2
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
com.linecorp.armeria.spring.actuate.ArmeriaSpringActuatorAutoConfiguration

spring/boot2-actuator-autoconfigure/src/test/java/com/linecorp/armeria/spring/actuate/ArmeriaSpringActuatorAutoConfigurationInternalServiceTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@
2424
import org.junit.jupiter.api.Timeout;
2525
import org.slf4j.Logger;
2626
import org.slf4j.LoggerFactory;
27-
import org.springframework.boot.actuate.autoconfigure.web.server.LocalManagementPort;
2827
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
2928
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
3029
import org.springframework.boot.autoconfigure.SpringBootApplication;
3130
import org.springframework.boot.test.autoconfigure.actuate.metrics.AutoConfigureMetrics;
3231
import org.springframework.boot.test.context.SpringBootTest;
32+
import org.springframework.boot.test.web.server.LocalManagementPort;
3333
import org.springframework.test.annotation.DirtiesContext;
3434
import org.springframework.test.context.ActiveProfiles;
3535

spring/boot2-actuator-autoconfigure/src/test/java/com/linecorp/armeria/spring/actuate/ArmeriaSpringActuatorAutoConfigurationSecureTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@
2424
import org.junit.jupiter.api.Timeout;
2525
import org.slf4j.Logger;
2626
import org.slf4j.LoggerFactory;
27-
import org.springframework.boot.actuate.autoconfigure.web.server.LocalManagementPort;
2827
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
2928
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
3029
import org.springframework.boot.autoconfigure.SpringBootApplication;
3130
import org.springframework.boot.test.autoconfigure.actuate.metrics.AutoConfigureMetrics;
3231
import org.springframework.boot.test.context.SpringBootTest;
32+
import org.springframework.boot.test.web.server.LocalManagementPort;
3333
import org.springframework.test.annotation.DirtiesContext;
3434
import org.springframework.test.context.ActiveProfiles;
3535

0 commit comments

Comments
 (0)