Skip to content

Commit 9ce96fb

Browse files
committed
Document support for java.util.Duration
Closes gh-12244
1 parent 6676967 commit 9ce96fb

File tree

4 files changed

+187
-3
lines changed

4 files changed

+187
-3
lines changed

spring-boot-project/spring-boot-docs/src/main/asciidoc/index.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ Phillip Webb; Dave Syer; Josh Long; Stéphane Nicoll; Rob Winch; Andy Wilkinson;
3636
:dc-spring-boot-test-autoconfigure: {dc-root}/org/springframework/boot/test/autoconfigure
3737
:dependency-management-plugin: https://github.com/spring-gradle-plugins/dependency-management-plugin
3838
:dependency-management-plugin-documentation: {dependency-management-plugin}/blob/master/README.md
39+
:java-javadoc: https://docs.oracle.com/javase/8/docs/api/
3940
:spring-boot-actuator-api: https://docs.spring.io/spring-boot/docs/{spring-boot-docs-version}/actuator-api/
4041
:spring-boot-maven-plugin-site: https://docs.spring.io/spring-boot/docs/{spring-boot-docs-version}/maven-plugin
4142
:spring-boot-gradle-plugin: https://docs.spring.io/spring-boot/docs/{spring-boot-docs-version}/gradle-plugin

spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,8 +1177,8 @@ such as `my.property-name=acme`.
11771177

11781178
[[boot-features-external-config-conversion]]
11791179
==== Properties Conversion
1180-
Spring attempts to coerce the external application properties to the right type when it
1181-
binds to the `@ConfigurationProperties` beans. If you need custom type conversion, you
1180+
Spring Boot attempts to coerce the external application properties to the right type when
1181+
it binds to the `@ConfigurationProperties` beans. If you need custom type conversion, you
11821182
can provide a `ConversionService` bean (with a bean named `conversionService`) or custom
11831183
property editors (through a `CustomEditorConfigurer` bean) or custom `Converters` (with
11841184
bean definitions annotated as `@ConfigurationPropertiesBinding`).
@@ -1191,6 +1191,50 @@ only rely on custom converters qualified with `@ConfigurationPropertiesBinding`.
11911191

11921192

11931193

1194+
[[boot-features-external-config-conversion-duration]]
1195+
===== Converting durations
1196+
Spring Boot has dedicated support for expressing durations. If you expose a
1197+
`java.time.Duration` property, the following formats in application properties are
1198+
available:
1199+
1200+
* A regular `long` representation (using milliseconds as the default unit unless a
1201+
`@DefaultUnit` has been specified)
1202+
* The standard ISO-8601 format
1203+
{java-javadoc}/java/time/Duration.html#parse-java.lang.CharSequence-[used by
1204+
`java.util.Duration`]
1205+
* A more readable format where the value and the unit are coupled (e.g. `10s` means 10
1206+
seconds)
1207+
1208+
Consider the following example:
1209+
1210+
[source,java,indent=0]
1211+
----
1212+
include::{code-examples}/context/properties/bind/AppSystemProperties.java[tag=example]
1213+
----
1214+
1215+
To specify a session timeout of 30 seconds, `30`, `PT30S` and `30s` are all equivalent. A
1216+
read timeout of 500ms can be specified in any of the following form: `500`, `PT0.5S` and
1217+
`500ms`.
1218+
1219+
You can also use any of the supported unit. These are:
1220+
1221+
* `ns` for nanoseconds
1222+
* `ms` for milliseconds
1223+
* `s` for seconds
1224+
* `m` for minutes
1225+
* `h` for hours
1226+
* `d` for days
1227+
1228+
The default unit is milliseconds and can be overridden using `@DefaultUnit` as illustrated
1229+
in the sample above.
1230+
1231+
TIP: If you are upgrading from a previous version that is simply using `Long` to express
1232+
the duration, make sure to define the unit (using `@DefaultUnit`) if it isn't
1233+
milliseconds alongside the switch to `Duration`. Doing so gives a transparent upgrade path
1234+
while supporting a much richer format.
1235+
1236+
1237+
11941238
[[boot-features-external-config-validation]]
11951239
==== @ConfigurationProperties Validation
11961240
Spring Boot attempts to validate `@ConfigurationProperties` classes whenever they are
@@ -1387,7 +1431,7 @@ See "<<boot-features-external-config-profile-specific-properties>>" for details.
13871431
Spring Boot uses http://commons.apache.org/logging[Commons Logging] for all internal
13881432
logging but leaves the underlying log implementation open. Default configurations are
13891433
provided for
1390-
https://docs.oracle.com/javase/8/docs/api/java/util/logging/package-summary.html[Java Util
1434+
{java-javadoc}/java/util/logging/package-summary.html[Java Util
13911435
Logging], http://logging.apache.org/log4j/2.x/[Log4J2], and
13921436
http://logback.qos.ch/[Logback]. In each case, loggers are pre-configured to use console
13931437
output with optional file output also available.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://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,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.docs.context.properties.bind;
18+
19+
import java.time.Duration;
20+
import java.time.temporal.ChronoUnit;
21+
22+
import org.springframework.boot.context.properties.ConfigurationProperties;
23+
import org.springframework.boot.convert.DurationUnit;
24+
25+
/**
26+
* A {@link ConfigurationProperties} example that uses {@link Duration}.
27+
*
28+
* @author Stephane Nicoll
29+
*/
30+
// tag::example[]
31+
@ConfigurationProperties("app.system")
32+
public class AppSystemProperties {
33+
34+
@DurationUnit(ChronoUnit.SECONDS)
35+
private Duration sessionTimeout = Duration.ofSeconds(30);
36+
37+
private Duration readTimeout = Duration.ofMillis(1000);
38+
39+
public Duration getSessionTimeout() {
40+
return this.sessionTimeout;
41+
}
42+
43+
public void setSessionTimeout(Duration sessionTimeout) {
44+
this.sessionTimeout = sessionTimeout;
45+
}
46+
47+
public Duration getReadTimeout() {
48+
return this.readTimeout;
49+
}
50+
51+
public void setReadTimeout(Duration readTimeout) {
52+
this.readTimeout = readTimeout;
53+
}
54+
55+
}
56+
// end::example[]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://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,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.docs.context.properties.bind;
18+
19+
import java.time.Duration;
20+
import java.util.function.Consumer;
21+
22+
import org.junit.Test;
23+
24+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
25+
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
26+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
27+
import org.springframework.boot.test.context.runner.ContextConsumer;
28+
import org.springframework.context.annotation.Configuration;
29+
30+
import static org.assertj.core.api.Assertions.assertThat;
31+
32+
/**
33+
* Tests for {@link AppSystemProperties}.
34+
*
35+
* @author Stephane Nicoll
36+
*/
37+
public class AppSystemPropertiesTests {
38+
39+
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
40+
.withUserConfiguration(Config.class);
41+
42+
@Test
43+
public void bindWithDefaultUnit() {
44+
this.contextRunner.withPropertyValues("app.system.session-timeout=40",
45+
"app.system.read-timeout=5000").run(assertBinding(p -> {
46+
assertThat(p.getSessionTimeout()).isEqualTo(Duration.ofSeconds(40));
47+
assertThat(p.getReadTimeout()).isEqualTo(Duration.ofMillis(5000));
48+
}));
49+
}
50+
51+
@Test
52+
public void bindWithExplicitUnit() {
53+
this.contextRunner.withPropertyValues("app.system.session-timeout=1h",
54+
"app.system.read-timeout=5s").run(assertBinding(p -> {
55+
assertThat(p.getSessionTimeout()).isEqualTo(Duration.ofMinutes(60));
56+
assertThat(p.getReadTimeout()).isEqualTo(Duration.ofMillis(5000));
57+
}));
58+
}
59+
60+
@Test
61+
public void bindWithIso8601Format() {
62+
this.contextRunner.withPropertyValues("app.system.session-timeout=PT15S",
63+
"app.system.read-timeout=PT0.5S").run(assertBinding(p -> {
64+
assertThat(p.getSessionTimeout()).isEqualTo(Duration.ofSeconds(15));
65+
assertThat(p.getReadTimeout()).isEqualTo(Duration.ofMillis(500));
66+
}));
67+
}
68+
69+
private ContextConsumer<AssertableApplicationContext> assertBinding(
70+
Consumer<AppSystemProperties> appSystemProperties) {
71+
return (context) -> {
72+
assertThat(context).hasSingleBean(AppSystemProperties.class);
73+
appSystemProperties.accept(context.getBean(AppSystemProperties.class));
74+
};
75+
}
76+
77+
@Configuration
78+
@EnableConfigurationProperties(AppSystemProperties.class)
79+
static class Config {
80+
81+
}
82+
83+
}

0 commit comments

Comments
 (0)