Polish
This commit is contained in:
parent
ad4ce9cf57
commit
f1c5fc41b4
|
|
@ -246,9 +246,8 @@ public class EndpointAutoConfiguration {
|
||||||
}
|
}
|
||||||
Map<String, HealthIndicator> allIndicators = new LinkedHashMap<>(
|
Map<String, HealthIndicator> allIndicators = new LinkedHashMap<>(
|
||||||
healthIndicators);
|
healthIndicators);
|
||||||
reactiveHealthIndicators.forEach((beanName, indicator) -> {
|
reactiveHealthIndicators.forEach((beanName, indicator) -> allIndicators
|
||||||
allIndicators.computeIfAbsent(beanName, n -> adapt(indicator));
|
.computeIfAbsent(beanName, n -> adapt(indicator)));
|
||||||
});
|
|
||||||
return allIndicators;
|
return allIndicators;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,4 +67,3 @@ public class CompositeReactiveHealthIndicatorConfiguration<H extends ReactiveHea
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,7 @@ public class ReactiveHealthIndicatorsConfiguration {
|
||||||
@ConditionalOnBean(ReactiveRedisConnectionFactory.class)
|
@ConditionalOnBean(ReactiveRedisConnectionFactory.class)
|
||||||
@ConditionalOnEnabledHealthIndicator("redis")
|
@ConditionalOnEnabledHealthIndicator("redis")
|
||||||
static class RedisHealthIndicatorConfiguration extends
|
static class RedisHealthIndicatorConfiguration extends
|
||||||
CompositeReactiveHealthIndicatorConfiguration<RedisReactiveHealthIndicator,
|
CompositeReactiveHealthIndicatorConfiguration<RedisReactiveHealthIndicator, ReactiveRedisConnectionFactory> {
|
||||||
ReactiveRedisConnectionFactory> {
|
|
||||||
|
|
||||||
private final Map<String, ReactiveRedisConnectionFactory> redisConnectionFactories;
|
private final Map<String, ReactiveRedisConnectionFactory> redisConnectionFactories;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ public class HealthReactiveWebEndpointExtension {
|
||||||
|
|
||||||
@ReadOperation
|
@ReadOperation
|
||||||
public Mono<WebEndpointResponse<Health>> health() {
|
public Mono<WebEndpointResponse<Health>> health() {
|
||||||
return this.delegate.health().map(health -> {
|
return this.delegate.health().map((health) -> {
|
||||||
Integer status = this.statusHttpMapper.mapStatus(health.getStatus());
|
Integer status = this.statusHttpMapper.mapStatus(health.getStatus());
|
||||||
return new WebEndpointResponse<>(health, status);
|
return new WebEndpointResponse<>(health, status);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -47,10 +47,10 @@ public class StatusReactiveWebEndpointExtension {
|
||||||
|
|
||||||
@ReadOperation
|
@ReadOperation
|
||||||
public Mono<WebEndpointResponse<Health>> health() {
|
public Mono<WebEndpointResponse<Health>> health() {
|
||||||
return this.delegate.health().map(health -> {
|
return this.delegate.health().map((health) -> {
|
||||||
Integer status = this.statusHttpMapper.mapStatus(health.getStatus());
|
Integer status = this.statusHttpMapper.mapStatus(health.getStatus());
|
||||||
return new WebEndpointResponse<>(
|
return new WebEndpointResponse<>(Health.status(health.getStatus()).build(),
|
||||||
Health.status(health.getStatus()).build(), status);
|
status);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,18 +25,17 @@ import reactor.core.publisher.Mono;
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractReactiveHealthIndicator
|
public abstract class AbstractReactiveHealthIndicator implements ReactiveHealthIndicator {
|
||||||
implements ReactiveHealthIndicator {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final Mono<Health> health() {
|
public final Mono<Health> health() {
|
||||||
return doHealthCheck(new Health.Builder())
|
return doHealthCheck(new Health.Builder())
|
||||||
.onErrorResume(ex -> Mono.just(new Health.Builder().down(ex).build()));
|
.onErrorResume((ex) -> Mono.just(new Health.Builder().down(ex).build()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Actual health check logic. If an error occurs in the pipeline it will be
|
* Actual health check logic. If an error occurs in the pipeline it will be handled
|
||||||
* handled automatically.
|
* automatically.
|
||||||
* @param builder the {@link Health.Builder} to report health status and details
|
* @param builder the {@link Health.Builder} to report health status and details
|
||||||
* @return a {@link Mono} that provides the {@link Health}
|
* @return a {@link Mono} that provides the {@link Health}
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,8 @@ public class CompositeHealthIndicatorFactory {
|
||||||
* @return a {@link HealthIndicator} that delegates to the specified
|
* @return a {@link HealthIndicator} that delegates to the specified
|
||||||
* {@code healthIndicators}.
|
* {@code healthIndicators}.
|
||||||
*/
|
*/
|
||||||
public CompositeHealthIndicator createHealthIndicator(HealthAggregator healthAggregator,
|
public CompositeHealthIndicator createHealthIndicator(
|
||||||
|
HealthAggregator healthAggregator,
|
||||||
Map<String, HealthIndicator> healthIndicators) {
|
Map<String, HealthIndicator> healthIndicators) {
|
||||||
Assert.notNull(healthAggregator, "HealthAggregator must not be null");
|
Assert.notNull(healthAggregator, "HealthAggregator must not be null");
|
||||||
Assert.notNull(healthIndicators, "HealthIndicators must not be null");
|
Assert.notNull(healthIndicators, "HealthIndicators must not be null");
|
||||||
|
|
|
||||||
|
|
@ -57,9 +57,8 @@ public class CompositeReactiveHealthIndicator implements ReactiveHealthIndicator
|
||||||
Assert.notNull(indicators, "Indicators must not be null");
|
Assert.notNull(indicators, "Indicators must not be null");
|
||||||
this.indicators = new LinkedHashMap<>(indicators);
|
this.indicators = new LinkedHashMap<>(indicators);
|
||||||
this.healthAggregator = healthAggregator;
|
this.healthAggregator = healthAggregator;
|
||||||
this.timeoutCompose = mono -> this.timeout != null ?
|
this.timeoutCompose = (mono) -> this.timeout != null ? mono.timeout(
|
||||||
mono.timeout(Duration.ofMillis(this.timeout), Mono.just(this.timeoutHealth)) :
|
Duration.ofMillis(this.timeout), Mono.just(this.timeoutHealth)) : mono;
|
||||||
mono;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -77,9 +76,10 @@ public class CompositeReactiveHealthIndicator implements ReactiveHealthIndicator
|
||||||
/**
|
/**
|
||||||
* Specify an alternative timeout {@link Health} if an {@link HealthIndicator} failed
|
* Specify an alternative timeout {@link Health} if an {@link HealthIndicator} failed
|
||||||
* to reply after specified {@code timeout}.
|
* to reply after specified {@code timeout}.
|
||||||
* @param timeout number of milliseconds to wait before using the {@code timeoutHealth}
|
* @param timeout number of milliseconds to wait before using the
|
||||||
|
* {@code timeoutHealth}
|
||||||
* @param timeoutHealth the {@link Health} to use if an health indicator reached the
|
* @param timeoutHealth the {@link Health} to use if an health indicator reached the
|
||||||
* {@code} timeout
|
* {@code timeout}
|
||||||
* @return this instance
|
* @return this instance
|
||||||
*/
|
*/
|
||||||
public CompositeReactiveHealthIndicator timeoutStrategy(long timeout,
|
public CompositeReactiveHealthIndicator timeoutStrategy(long timeout,
|
||||||
|
|
@ -93,7 +93,7 @@ public class CompositeReactiveHealthIndicator implements ReactiveHealthIndicator
|
||||||
@Override
|
@Override
|
||||||
public Mono<Health> health() {
|
public Mono<Health> health() {
|
||||||
return Flux.fromIterable(this.indicators.entrySet())
|
return Flux.fromIterable(this.indicators.entrySet())
|
||||||
.flatMap(entry -> Mono.just(entry.getKey())
|
.flatMap((entry) -> Mono.just(entry.getKey())
|
||||||
.and(entry.getValue().health().compose(this.timeoutCompose)))
|
.and(entry.getValue().health().compose(this.timeoutCompose)))
|
||||||
.collectMap(Tuple2::getT1, Tuple2::getT2)
|
.collectMap(Tuple2::getT1, Tuple2::getT2)
|
||||||
.map(this.healthAggregator::aggregate);
|
.map(this.healthAggregator::aggregate);
|
||||||
|
|
|
||||||
|
|
@ -60,13 +60,15 @@ public class CompositeReactiveHealthIndicatorFactory {
|
||||||
Map<String, ReactiveHealthIndicator> reactiveHealthIndicators,
|
Map<String, ReactiveHealthIndicator> reactiveHealthIndicators,
|
||||||
Map<String, HealthIndicator> healthIndicators) {
|
Map<String, HealthIndicator> healthIndicators) {
|
||||||
Assert.notNull(healthAggregator, "HealthAggregator must not be null");
|
Assert.notNull(healthAggregator, "HealthAggregator must not be null");
|
||||||
Assert.notNull(reactiveHealthIndicators, "ReactiveHealthIndicators must not be null");
|
Assert.notNull(reactiveHealthIndicators,
|
||||||
|
"ReactiveHealthIndicators must not be null");
|
||||||
CompositeReactiveHealthIndicator healthIndicator = new CompositeReactiveHealthIndicator(
|
CompositeReactiveHealthIndicator healthIndicator = new CompositeReactiveHealthIndicator(
|
||||||
healthAggregator);
|
healthAggregator);
|
||||||
merge(reactiveHealthIndicators, healthIndicators).forEach((beanName, indicator) -> {
|
merge(reactiveHealthIndicators, healthIndicators)
|
||||||
String name = this.healthIndicatorNameFactory.apply(beanName);
|
.forEach((beanName, indicator) -> {
|
||||||
healthIndicator.addHealthIndicator(name, indicator);
|
String name = this.healthIndicatorNameFactory.apply(beanName);
|
||||||
});
|
healthIndicator.addHealthIndicator(name, indicator);
|
||||||
|
});
|
||||||
return healthIndicator;
|
return healthIndicator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,8 +82,8 @@ public class CompositeReactiveHealthIndicatorFactory {
|
||||||
reactiveHealthIndicators);
|
reactiveHealthIndicators);
|
||||||
healthIndicators.forEach((beanName, indicator) -> {
|
healthIndicators.forEach((beanName, indicator) -> {
|
||||||
String name = this.healthIndicatorNameFactory.apply(beanName);
|
String name = this.healthIndicatorNameFactory.apply(beanName);
|
||||||
allIndicators.computeIfAbsent(name, n ->
|
allIndicators.computeIfAbsent(name,
|
||||||
new HealthIndicatorReactiveAdapter(indicator));
|
(n) -> new HealthIndicatorReactiveAdapter(indicator));
|
||||||
});
|
});
|
||||||
return allIndicators;
|
return allIndicators;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@ import reactor.core.scheduler.Schedulers;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adapts a {@link HealthIndicator} to a {@link ReactiveHealthIndicator} so that it can
|
* Adapts a {@link HealthIndicator} to a {@link ReactiveHealthIndicator} so that it can be
|
||||||
* be safely invoked in a reactive environment.
|
* safely invoked in a reactive environment.
|
||||||
*
|
*
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
|
|
@ -40,8 +40,7 @@ public class HealthIndicatorReactiveAdapter implements ReactiveHealthIndicator {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Health> health() {
|
public Mono<Health> health() {
|
||||||
return Mono.create((sink) ->
|
return Mono.create((sink) -> Schedulers.elastic().schedule(() -> invoke(sink)));
|
||||||
Schedulers.elastic().schedule(() -> invoke(sink)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void invoke(MonoSink<Health> sink) {
|
private void invoke(MonoSink<Health> sink) {
|
||||||
|
|
|
||||||
|
|
@ -42,11 +42,11 @@ public class RedisReactiveHealthIndicator extends AbstractReactiveHealthIndicato
|
||||||
ReactiveRedisConnection connection = this.connectionFactory
|
ReactiveRedisConnection connection = this.connectionFactory
|
||||||
.getReactiveConnection();
|
.getReactiveConnection();
|
||||||
return connection.serverCommands().info()
|
return connection.serverCommands().info()
|
||||||
.map(info -> builder.up()
|
.map((info) -> builder.up()
|
||||||
.withDetail(RedisHealthIndicator.VERSION,
|
.withDetail(RedisHealthIndicator.VERSION,
|
||||||
info.getProperty(RedisHealthIndicator.REDIS_VERSION))
|
info.getProperty(RedisHealthIndicator.REDIS_VERSION))
|
||||||
.build())
|
.build())
|
||||||
.doFinally(signal -> connection.close());
|
.doFinally((signal) -> connection.close());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,37 +47,38 @@ public class EndpointAutoConfigurationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void healthEndpointAdaptReactiveHealthIndicator() {
|
public void healthEndpointAdaptReactiveHealthIndicator() {
|
||||||
this.contextRunner.withUserConfiguration(
|
this.contextRunner
|
||||||
ReactiveHealthIndicatorConfiguration.class).run((context) -> {
|
.withUserConfiguration(ReactiveHealthIndicatorConfiguration.class)
|
||||||
ReactiveHealthIndicator reactiveHealthIndicator = context.getBean(
|
.run((context) -> {
|
||||||
"reactiveHealthIndicator", ReactiveHealthIndicator.class);
|
ReactiveHealthIndicator reactiveHealthIndicator = context.getBean(
|
||||||
verify(reactiveHealthIndicator, times(0)).health();
|
"reactiveHealthIndicator", ReactiveHealthIndicator.class);
|
||||||
Health health = context.getBean(HealthEndpoint.class).health();
|
verify(reactiveHealthIndicator, times(0)).health();
|
||||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
Health health = context.getBean(HealthEndpoint.class).health();
|
||||||
assertThat(health.getDetails()).containsOnlyKeys("reactive");
|
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||||
verify(reactiveHealthIndicator, times(1)).health();
|
assertThat(health.getDetails()).containsOnlyKeys("reactive");
|
||||||
});
|
verify(reactiveHealthIndicator, times(1)).health();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void healthEndpointMergeRegularAndReactive() {
|
public void healthEndpointMergeRegularAndReactive() {
|
||||||
this.contextRunner.withUserConfiguration(HealthIndicatorConfiguration.class,
|
this.contextRunner.withUserConfiguration(HealthIndicatorConfiguration.class,
|
||||||
ReactiveHealthIndicatorConfiguration.class).run((context) -> {
|
ReactiveHealthIndicatorConfiguration.class).run((context) -> {
|
||||||
HealthIndicator simpleHealthIndicator = context.getBean(
|
HealthIndicator simpleHealthIndicator = context
|
||||||
"simpleHealthIndicator", HealthIndicator.class);
|
.getBean("simpleHealthIndicator", HealthIndicator.class);
|
||||||
ReactiveHealthIndicator reactiveHealthIndicator = context.getBean(
|
ReactiveHealthIndicator reactiveHealthIndicator = context.getBean(
|
||||||
"reactiveHealthIndicator", ReactiveHealthIndicator.class);
|
"reactiveHealthIndicator", ReactiveHealthIndicator.class);
|
||||||
verify(simpleHealthIndicator, times(0)).health();
|
verify(simpleHealthIndicator, times(0)).health();
|
||||||
verify(reactiveHealthIndicator, times(0)).health();
|
verify(reactiveHealthIndicator, times(0)).health();
|
||||||
Health health = context.getBean(HealthEndpoint.class).health();
|
Health health = context.getBean(HealthEndpoint.class).health();
|
||||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||||
assertThat(health.getDetails()).containsOnlyKeys("simple", "reactive");
|
assertThat(health.getDetails()).containsOnlyKeys("simple",
|
||||||
verify(simpleHealthIndicator, times(1)).health();
|
"reactive");
|
||||||
verify(reactiveHealthIndicator, times(1)).health();
|
verify(simpleHealthIndicator, times(1)).health();
|
||||||
});
|
verify(reactiveHealthIndicator, times(1)).health();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
static class HealthIndicatorConfiguration {
|
static class HealthIndicatorConfiguration {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,17 +43,16 @@ public class ReactiveHealthIndicatorsConfigurationTests {
|
||||||
@Test
|
@Test
|
||||||
public void redisHealthIndicator() {
|
public void redisHealthIndicator() {
|
||||||
this.contextRunner
|
this.contextRunner
|
||||||
.withConfiguration(AutoConfigurations.of(
|
.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
|
||||||
RedisAutoConfiguration.class))
|
|
||||||
.withPropertyValues("management.health.diskspace.enabled:false")
|
.withPropertyValues("management.health.diskspace.enabled:false")
|
||||||
.run(hasSingleReactiveHealthIndicator(RedisReactiveHealthIndicator.class));
|
.run(hasSingleReactiveHealthIndicator(
|
||||||
|
RedisReactiveHealthIndicator.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ContextConsumer<AssertableApplicationContext> hasSingleReactiveHealthIndicator(
|
private ContextConsumer<AssertableApplicationContext> hasSingleReactiveHealthIndicator(
|
||||||
Class<? extends ReactiveHealthIndicator> type) {
|
Class<? extends ReactiveHealthIndicator> type) {
|
||||||
return (context) -> assertThat(context).getBeans(ReactiveHealthIndicator.class)
|
return (context) -> assertThat(context).getBeans(ReactiveHealthIndicator.class)
|
||||||
.hasSize(1)
|
.hasSize(1).hasValueSatisfying(
|
||||||
.hasValueSatisfying(
|
|
||||||
new Condition<>((indicator) -> indicator.getClass().equals(type),
|
new Condition<>((indicator) -> indicator.getClass().equals(type),
|
||||||
"Wrong indicator type"));
|
"Wrong indicator type"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,6 @@ public class LiquibaseEndpointTests {
|
||||||
LiquibaseAutoConfiguration.class))
|
LiquibaseAutoConfiguration.class))
|
||||||
.withPropertyValues("spring.datasource.generate-unique-name=true");
|
.withPropertyValues("spring.datasource.generate-unique-name=true");
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void liquibaseReportIsReturned() throws Exception {
|
public void liquibaseReportIsReturned() throws Exception {
|
||||||
this.contextRunner.withUserConfiguration(Config.class)
|
this.contextRunner.withUserConfiguration(Config.class)
|
||||||
|
|
|
||||||
|
|
@ -69,8 +69,9 @@ public class HealthEndpointWebIntegrationTests {
|
||||||
@Bean
|
@Bean
|
||||||
public HealthEndpoint healthEndpoint(
|
public HealthEndpoint healthEndpoint(
|
||||||
Map<String, HealthIndicator> healthIndicators) {
|
Map<String, HealthIndicator> healthIndicators) {
|
||||||
return new HealthEndpoint(new CompositeHealthIndicatorFactory().createHealthIndicator(
|
return new HealthEndpoint(
|
||||||
new OrderedHealthAggregator(), healthIndicators));
|
new CompositeHealthIndicatorFactory().createHealthIndicator(
|
||||||
|
new OrderedHealthAggregator(), healthIndicators));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|
|
||||||
|
|
@ -67,8 +67,9 @@ public class StatusEndpointWebIntegrationTests {
|
||||||
@Bean
|
@Bean
|
||||||
public StatusEndpoint statusEndpoint(
|
public StatusEndpoint statusEndpoint(
|
||||||
Map<String, HealthIndicator> healthIndicators) {
|
Map<String, HealthIndicator> healthIndicators) {
|
||||||
return new StatusEndpoint(new CompositeHealthIndicatorFactory().createHealthIndicator(
|
return new StatusEndpoint(
|
||||||
new OrderedHealthAggregator(), healthIndicators));
|
new CompositeHealthIndicatorFactory().createHealthIndicator(
|
||||||
|
new OrderedHealthAggregator(), healthIndicators));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ public class CompositeReactiveHealthIndicatorFactoryTests {
|
||||||
public void noHealthIndicator() {
|
public void noHealthIndicator() {
|
||||||
ReactiveHealthIndicator healthIndicator = createHealthIndicator(
|
ReactiveHealthIndicator healthIndicator = createHealthIndicator(
|
||||||
Collections.singletonMap("test", () -> Mono.just(UP)), null);
|
Collections.singletonMap("test", () -> Mono.just(UP)), null);
|
||||||
StepVerifier.create(healthIndicator.health()).consumeNextWith(h -> {
|
StepVerifier.create(healthIndicator.health()).consumeNextWith((h) -> {
|
||||||
assertThat(h.getStatus()).isEqualTo(Status.UP);
|
assertThat(h.getStatus()).isEqualTo(Status.UP);
|
||||||
assertThat(h.getDetails()).containsOnlyKeys("test");
|
assertThat(h.getDetails()).containsOnlyKeys("test");
|
||||||
}).verifyComplete();
|
}).verifyComplete();
|
||||||
|
|
@ -53,10 +53,9 @@ public class CompositeReactiveHealthIndicatorFactoryTests {
|
||||||
@Test
|
@Test
|
||||||
public void defaultHealthIndicatorNameFactory() {
|
public void defaultHealthIndicatorNameFactory() {
|
||||||
ReactiveHealthIndicator healthIndicator = new CompositeReactiveHealthIndicatorFactory()
|
ReactiveHealthIndicator healthIndicator = new CompositeReactiveHealthIndicatorFactory()
|
||||||
.createReactiveHealthIndicator(new OrderedHealthAggregator(),
|
.createReactiveHealthIndicator(new OrderedHealthAggregator(), Collections
|
||||||
Collections.singletonMap("myHealthIndicator", () -> Mono.just(UP)),
|
.singletonMap("myHealthIndicator", () -> Mono.just(UP)), null);
|
||||||
null);
|
StepVerifier.create(healthIndicator.health()).consumeNextWith((h) -> {
|
||||||
StepVerifier.create(healthIndicator.health()).consumeNextWith(h -> {
|
|
||||||
assertThat(h.getStatus()).isEqualTo(Status.UP);
|
assertThat(h.getStatus()).isEqualTo(Status.UP);
|
||||||
assertThat(h.getDetails()).containsOnlyKeys("my");
|
assertThat(h.getDetails()).containsOnlyKeys("my");
|
||||||
}).verifyComplete();
|
}).verifyComplete();
|
||||||
|
|
@ -67,7 +66,7 @@ public class CompositeReactiveHealthIndicatorFactoryTests {
|
||||||
ReactiveHealthIndicator healthIndicator = createHealthIndicator(
|
ReactiveHealthIndicator healthIndicator = createHealthIndicator(
|
||||||
Collections.singletonMap("test", () -> Mono.just(UP)),
|
Collections.singletonMap("test", () -> Mono.just(UP)),
|
||||||
Collections.singletonMap("regular", () -> DOWN));
|
Collections.singletonMap("regular", () -> DOWN));
|
||||||
StepVerifier.create(healthIndicator.health()).consumeNextWith(h -> {
|
StepVerifier.create(healthIndicator.health()).consumeNextWith((h) -> {
|
||||||
assertThat(h.getStatus()).isEqualTo(Status.DOWN);
|
assertThat(h.getStatus()).isEqualTo(Status.DOWN);
|
||||||
assertThat(h.getDetails()).containsOnlyKeys("test", "regular");
|
assertThat(h.getDetails()).containsOnlyKeys("test", "regular");
|
||||||
}).verifyComplete();
|
}).verifyComplete();
|
||||||
|
|
@ -75,14 +74,15 @@ public class CompositeReactiveHealthIndicatorFactoryTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void reactiveHealthIndicatorTakesPrecedence() {
|
public void reactiveHealthIndicatorTakesPrecedence() {
|
||||||
ReactiveHealthIndicator reactivehealthIndicator = mock(ReactiveHealthIndicator.class);
|
ReactiveHealthIndicator reactivehealthIndicator = mock(
|
||||||
|
ReactiveHealthIndicator.class);
|
||||||
given(reactivehealthIndicator.health()).willReturn(Mono.just(UP));
|
given(reactivehealthIndicator.health()).willReturn(Mono.just(UP));
|
||||||
HealthIndicator regularHealthIndicator = mock(HealthIndicator.class);
|
HealthIndicator regularHealthIndicator = mock(HealthIndicator.class);
|
||||||
given(regularHealthIndicator.health()).willReturn(UP);
|
given(regularHealthIndicator.health()).willReturn(UP);
|
||||||
ReactiveHealthIndicator healthIndicator = createHealthIndicator(
|
ReactiveHealthIndicator healthIndicator = createHealthIndicator(
|
||||||
Collections.singletonMap("test", reactivehealthIndicator),
|
Collections.singletonMap("test", reactivehealthIndicator),
|
||||||
Collections.singletonMap("test", regularHealthIndicator));
|
Collections.singletonMap("test", regularHealthIndicator));
|
||||||
StepVerifier.create(healthIndicator.health()).consumeNextWith(h -> {
|
StepVerifier.create(healthIndicator.health()).consumeNextWith((h) -> {
|
||||||
assertThat(h.getStatus()).isEqualTo(Status.UP);
|
assertThat(h.getStatus()).isEqualTo(Status.UP);
|
||||||
assertThat(h.getDetails()).containsOnlyKeys("test");
|
assertThat(h.getDetails()).containsOnlyKeys("test");
|
||||||
}).verifyComplete();
|
}).verifyComplete();
|
||||||
|
|
@ -93,7 +93,7 @@ public class CompositeReactiveHealthIndicatorFactoryTests {
|
||||||
private ReactiveHealthIndicator createHealthIndicator(
|
private ReactiveHealthIndicator createHealthIndicator(
|
||||||
Map<String, ReactiveHealthIndicator> reactiveHealthIndicators,
|
Map<String, ReactiveHealthIndicator> reactiveHealthIndicators,
|
||||||
Map<String, HealthIndicator> healthIndicators) {
|
Map<String, HealthIndicator> healthIndicators) {
|
||||||
return new CompositeReactiveHealthIndicatorFactory(n -> n)
|
return new CompositeReactiveHealthIndicatorFactory((n) -> n)
|
||||||
.createReactiveHealthIndicator(new OrderedHealthAggregator(),
|
.createReactiveHealthIndicator(new OrderedHealthAggregator(),
|
||||||
reactiveHealthIndicators, healthIndicators);
|
reactiveHealthIndicators, healthIndicators);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,13 +38,13 @@ public class CompositeReactiveHealthIndicatorTests {
|
||||||
|
|
||||||
private OrderedHealthAggregator healthAggregator = new OrderedHealthAggregator();
|
private OrderedHealthAggregator healthAggregator = new OrderedHealthAggregator();
|
||||||
|
|
||||||
private CompositeReactiveHealthIndicator indicator =
|
private CompositeReactiveHealthIndicator indicator = new CompositeReactiveHealthIndicator(
|
||||||
new CompositeReactiveHealthIndicator(this.healthAggregator);
|
this.healthAggregator);
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void singleIndicator() {
|
public void singleIndicator() {
|
||||||
this.indicator.addHealthIndicator("test", () -> Mono.just(HEALTHY));
|
this.indicator.addHealthIndicator("test", () -> Mono.just(HEALTHY));
|
||||||
StepVerifier.create(this.indicator.health()).consumeNextWith(h -> {
|
StepVerifier.create(this.indicator.health()).consumeNextWith((h) -> {
|
||||||
assertThat(h.getStatus()).isEqualTo(Status.UP);
|
assertThat(h.getStatus()).isEqualTo(Status.UP);
|
||||||
assertThat(h.getDetails()).containsOnlyKeys("test");
|
assertThat(h.getDetails()).containsOnlyKeys("test");
|
||||||
assertThat(h.getDetails().get("test")).isEqualTo(HEALTHY);
|
assertThat(h.getDetails().get("test")).isEqualTo(HEALTHY);
|
||||||
|
|
@ -54,17 +54,14 @@ public class CompositeReactiveHealthIndicatorTests {
|
||||||
@Test
|
@Test
|
||||||
public void longHealth() {
|
public void longHealth() {
|
||||||
for (int i = 0; i < 50; i++) {
|
for (int i = 0; i < 50; i++) {
|
||||||
this.indicator.addHealthIndicator(
|
this.indicator.addHealthIndicator("test" + i,
|
||||||
"test" + i, new TimeoutHealth(10000, Status.UP));
|
new TimeoutHealth(10000, Status.UP));
|
||||||
}
|
}
|
||||||
StepVerifier.withVirtualTime(this.indicator::health)
|
StepVerifier.withVirtualTime(this.indicator::health).expectSubscription()
|
||||||
.expectSubscription()
|
.thenAwait(Duration.ofMillis(10000)).consumeNextWith((h) -> {
|
||||||
.thenAwait(Duration.ofMillis(10000))
|
|
||||||
.consumeNextWith(h -> {
|
|
||||||
assertThat(h.getStatus()).isEqualTo(Status.UP);
|
assertThat(h.getStatus()).isEqualTo(Status.UP);
|
||||||
assertThat(h.getDetails()).hasSize(50);
|
assertThat(h.getDetails()).hasSize(50);
|
||||||
})
|
}).verifyComplete();
|
||||||
.verifyComplete();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -73,7 +70,7 @@ public class CompositeReactiveHealthIndicatorTests {
|
||||||
this.indicator.addHealthIndicator("slow", new TimeoutHealth(10000, Status.UP))
|
this.indicator.addHealthIndicator("slow", new TimeoutHealth(10000, Status.UP))
|
||||||
.addHealthIndicator("fast", new TimeoutHealth(10, Status.UP))
|
.addHealthIndicator("fast", new TimeoutHealth(10, Status.UP))
|
||||||
.timeoutStrategy(100, UNKNOWN_HEALTH);
|
.timeoutStrategy(100, UNKNOWN_HEALTH);
|
||||||
StepVerifier.create(this.indicator.health()).consumeNextWith(h -> {
|
StepVerifier.create(this.indicator.health()).consumeNextWith((h) -> {
|
||||||
assertThat(h.getStatus()).isEqualTo(Status.UP);
|
assertThat(h.getStatus()).isEqualTo(Status.UP);
|
||||||
assertThat(h.getDetails()).containsOnlyKeys("slow", "fast");
|
assertThat(h.getDetails()).containsOnlyKeys("slow", "fast");
|
||||||
assertThat(h.getDetails().get("slow")).isEqualTo(UNKNOWN_HEALTH);
|
assertThat(h.getDetails().get("slow")).isEqualTo(UNKNOWN_HEALTH);
|
||||||
|
|
@ -86,16 +83,13 @@ public class CompositeReactiveHealthIndicatorTests {
|
||||||
this.indicator.addHealthIndicator("slow", new TimeoutHealth(10000, Status.UP))
|
this.indicator.addHealthIndicator("slow", new TimeoutHealth(10000, Status.UP))
|
||||||
.addHealthIndicator("fast", new TimeoutHealth(10, Status.UP))
|
.addHealthIndicator("fast", new TimeoutHealth(10, Status.UP))
|
||||||
.timeoutStrategy(20000, null);
|
.timeoutStrategy(20000, null);
|
||||||
StepVerifier.withVirtualTime(this.indicator::health)
|
StepVerifier.withVirtualTime(this.indicator::health).expectSubscription()
|
||||||
.expectSubscription()
|
.thenAwait(Duration.ofMillis(10000)).consumeNextWith((h) -> {
|
||||||
.thenAwait(Duration.ofMillis(10000))
|
|
||||||
.consumeNextWith(h -> {
|
|
||||||
assertThat(h.getStatus()).isEqualTo(Status.UP);
|
assertThat(h.getStatus()).isEqualTo(Status.UP);
|
||||||
assertThat(h.getDetails()).containsOnlyKeys("slow", "fast");
|
assertThat(h.getDetails()).containsOnlyKeys("slow", "fast");
|
||||||
assertThat(h.getDetails().get("slow")).isEqualTo(HEALTHY);
|
assertThat(h.getDetails().get("slow")).isEqualTo(HEALTHY);
|
||||||
assertThat(h.getDetails().get("fast")).isEqualTo(HEALTHY);
|
assertThat(h.getDetails().get("fast")).isEqualTo(HEALTHY);
|
||||||
})
|
}).verifyComplete();
|
||||||
.verifyComplete();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class TimeoutHealth implements ReactiveHealthIndicator {
|
static class TimeoutHealth implements ReactiveHealthIndicator {
|
||||||
|
|
@ -112,7 +106,7 @@ public class CompositeReactiveHealthIndicatorTests {
|
||||||
@Override
|
@Override
|
||||||
public Mono<Health> health() {
|
public Mono<Health> health() {
|
||||||
return Mono.delay(Duration.ofMillis(this.timeout))
|
return Mono.delay(Duration.ofMillis(this.timeout))
|
||||||
.map(l -> Health.status(this.status).build());
|
.map((l) -> Health.status(this.status).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,8 @@ public class HealthIndicatorReactiveAdapterTests {
|
||||||
@Test
|
@Test
|
||||||
public void delegateReturnsHealth() {
|
public void delegateReturnsHealth() {
|
||||||
HealthIndicator delegate = mock(HealthIndicator.class);
|
HealthIndicator delegate = mock(HealthIndicator.class);
|
||||||
HealthIndicatorReactiveAdapter adapter = new HealthIndicatorReactiveAdapter(delegate);
|
HealthIndicatorReactiveAdapter adapter = new HealthIndicatorReactiveAdapter(
|
||||||
|
delegate);
|
||||||
Health status = Health.up().build();
|
Health status = Health.up().build();
|
||||||
given(delegate.health()).willReturn(status);
|
given(delegate.health()).willReturn(status);
|
||||||
StepVerifier.create(adapter.health()).expectNext(status).verifyComplete();
|
StepVerifier.create(adapter.health()).expectNext(status).verifyComplete();
|
||||||
|
|
@ -41,7 +42,8 @@ public class HealthIndicatorReactiveAdapterTests {
|
||||||
@Test
|
@Test
|
||||||
public void delegateThrowError() {
|
public void delegateThrowError() {
|
||||||
HealthIndicator delegate = mock(HealthIndicator.class);
|
HealthIndicator delegate = mock(HealthIndicator.class);
|
||||||
HealthIndicatorReactiveAdapter adapter = new HealthIndicatorReactiveAdapter(delegate);
|
HealthIndicatorReactiveAdapter adapter = new HealthIndicatorReactiveAdapter(
|
||||||
|
delegate);
|
||||||
given(delegate.health()).willThrow(new IllegalStateException("Expected"));
|
given(delegate.health()).willThrow(new IllegalStateException("Expected"));
|
||||||
StepVerifier.create(adapter.health()).expectError(IllegalStateException.class);
|
StepVerifier.create(adapter.health()).expectError(IllegalStateException.class);
|
||||||
}
|
}
|
||||||
|
|
@ -49,9 +51,12 @@ public class HealthIndicatorReactiveAdapterTests {
|
||||||
@Test
|
@Test
|
||||||
public void delegateRunsOnTheElasticScheduler() {
|
public void delegateRunsOnTheElasticScheduler() {
|
||||||
String currentThread = Thread.currentThread().getName();
|
String currentThread = Thread.currentThread().getName();
|
||||||
HealthIndicator delegate = () -> Health.status(Thread.currentThread().getName()
|
HealthIndicator delegate = () -> Health
|
||||||
.equals(currentThread) ? Status.DOWN : Status.UP).build();
|
.status(Thread.currentThread().getName().equals(currentThread)
|
||||||
HealthIndicatorReactiveAdapter adapter = new HealthIndicatorReactiveAdapter(delegate);
|
? Status.DOWN : Status.UP)
|
||||||
|
.build();
|
||||||
|
HealthIndicatorReactiveAdapter adapter = new HealthIndicatorReactiveAdapter(
|
||||||
|
delegate);
|
||||||
StepVerifier.create(adapter.health()).expectNext(Health.status(Status.UP).build())
|
StepVerifier.create(adapter.health()).expectNext(Health.status(Status.UP).build())
|
||||||
.verifyComplete();
|
.verifyComplete();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,9 +47,10 @@ public class RedisReactiveHealthIndicatorTests {
|
||||||
ReactiveRedisConnection redisConnection = mock(ReactiveRedisConnection.class);
|
ReactiveRedisConnection redisConnection = mock(ReactiveRedisConnection.class);
|
||||||
ReactiveServerCommands commands = mock(ReactiveServerCommands.class);
|
ReactiveServerCommands commands = mock(ReactiveServerCommands.class);
|
||||||
given(commands.info()).willReturn(Mono.just(info));
|
given(commands.info()).willReturn(Mono.just(info));
|
||||||
RedisReactiveHealthIndicator healthIndicator = createHealthIndicator(redisConnection, commands);
|
RedisReactiveHealthIndicator healthIndicator = createHealthIndicator(
|
||||||
|
redisConnection, commands);
|
||||||
Mono<Health> health = healthIndicator.health();
|
Mono<Health> health = healthIndicator.health();
|
||||||
StepVerifier.create(health).consumeNextWith(h -> {
|
StepVerifier.create(health).consumeNextWith((h) -> {
|
||||||
assertThat(h.getStatus()).isEqualTo(Status.UP);
|
assertThat(h.getStatus()).isEqualTo(Status.UP);
|
||||||
assertThat(h.getDetails()).containsOnlyKeys("version");
|
assertThat(h.getDetails()).containsOnlyKeys("version");
|
||||||
assertThat(h.getDetails().get("version")).isEqualTo("2.8.9");
|
assertThat(h.getDetails().get("version")).isEqualTo("2.8.9");
|
||||||
|
|
@ -60,19 +61,21 @@ public class RedisReactiveHealthIndicatorTests {
|
||||||
@Test
|
@Test
|
||||||
public void redisIsDown() throws Exception {
|
public void redisIsDown() throws Exception {
|
||||||
ReactiveServerCommands commands = mock(ReactiveServerCommands.class);
|
ReactiveServerCommands commands = mock(ReactiveServerCommands.class);
|
||||||
given(commands.info()).willReturn(Mono.error(
|
given(commands.info()).willReturn(
|
||||||
new RedisConnectionFailureException("Connection failed")));
|
Mono.error(new RedisConnectionFailureException("Connection failed")));
|
||||||
ReactiveRedisConnection redisConnection = mock(ReactiveRedisConnection.class);
|
ReactiveRedisConnection redisConnection = mock(ReactiveRedisConnection.class);
|
||||||
RedisReactiveHealthIndicator healthIndicator = createHealthIndicator(redisConnection, commands);
|
RedisReactiveHealthIndicator healthIndicator = createHealthIndicator(
|
||||||
|
redisConnection, commands);
|
||||||
Mono<Health> health = healthIndicator.health();
|
Mono<Health> health = healthIndicator.health();
|
||||||
StepVerifier.create(health).consumeNextWith(h -> {
|
StepVerifier.create(health)
|
||||||
assertThat(h.getStatus()).isEqualTo(Status.DOWN);
|
.consumeNextWith((h) -> assertThat(h.getStatus()).isEqualTo(Status.DOWN))
|
||||||
}).verifyComplete();
|
.verifyComplete();
|
||||||
verify(redisConnection).close();
|
verify(redisConnection).close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private RedisReactiveHealthIndicator createHealthIndicator(
|
private RedisReactiveHealthIndicator createHealthIndicator(
|
||||||
ReactiveRedisConnection redisConnection, ReactiveServerCommands serverCommands) {
|
ReactiveRedisConnection redisConnection,
|
||||||
|
ReactiveServerCommands serverCommands) {
|
||||||
|
|
||||||
ReactiveRedisConnectionFactory redisConnectionFactory = mock(
|
ReactiveRedisConnectionFactory redisConnectionFactory = mock(
|
||||||
ReactiveRedisConnectionFactory.class);
|
ReactiveRedisConnectionFactory.class);
|
||||||
|
|
|
||||||
|
|
@ -76,16 +76,16 @@ public class ConfigurationPropertiesBinder {
|
||||||
* @throws ConfigurationPropertiesBindingException if the binding failed
|
* @throws ConfigurationPropertiesBindingException if the binding failed
|
||||||
*/
|
*/
|
||||||
public void bind(Object target) {
|
public void bind(Object target) {
|
||||||
ConfigurationProperties annotation = AnnotationUtils.findAnnotation(
|
ConfigurationProperties annotation = AnnotationUtils
|
||||||
target.getClass(), ConfigurationProperties.class);
|
.findAnnotation(target.getClass(), ConfigurationProperties.class);
|
||||||
if (annotation != null) {
|
if (annotation != null) {
|
||||||
bind(target, annotation);
|
bind(target, annotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind the specified {@code target} object using the configuration defined by
|
* Bind the specified {@code target} object using the configuration defined by the
|
||||||
* the specified {@code annotation}.
|
* specified {@code annotation}.
|
||||||
* @param target the target to bind the configuration property sources to
|
* @param target the target to bind the configuration property sources to
|
||||||
* @param annotation the binding configuration
|
* @param annotation the binding configuration
|
||||||
* @throws ConfigurationPropertiesBindingException if the binding failed
|
* @throws ConfigurationPropertiesBindingException if the binding failed
|
||||||
|
|
@ -154,10 +154,9 @@ public class ConfigurationPropertiesBinder {
|
||||||
return details.toString();
|
return details.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link Validator} extension to be implemented to signal that that validator can
|
* {@link Validator} extension to be implemented to signal that that validator can be
|
||||||
* be destroyed once the binder is no longer in use.
|
* destroyed once the binder is no longer in use.
|
||||||
*/
|
*/
|
||||||
interface InternalValidator extends Validator {
|
interface InternalValidator extends Validator {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,8 @@ import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.validation.Validator;
|
import org.springframework.validation.Validator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder for creating {@link ConfigurationPropertiesBinder} based on the state of
|
* Builder for creating {@link ConfigurationPropertiesBinder} based on the state of the
|
||||||
* the {@link ApplicationContext}.
|
* {@link ApplicationContext}.
|
||||||
*
|
*
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
|
|
@ -46,7 +46,10 @@ public class ConfigurationPropertiesBinderBuilder {
|
||||||
*/
|
*/
|
||||||
public static final String VALIDATOR_BEAN_NAME = "configurationPropertiesValidator";
|
public static final String VALIDATOR_BEAN_NAME = "configurationPropertiesValidator";
|
||||||
|
|
||||||
private static final String CONVERSION_SERVICE_BEAN_NAME = ConfigurableApplicationContext.CONVERSION_SERVICE_BEAN_NAME;
|
/**
|
||||||
|
* The bean name of the configuration properties conversion service.
|
||||||
|
*/
|
||||||
|
public static final String CONVERSION_SERVICE_BEAN_NAME = ConfigurableApplicationContext.CONVERSION_SERVICE_BEAN_NAME;
|
||||||
|
|
||||||
private static final String[] VALIDATOR_CLASSES = { "javax.validation.Validator",
|
private static final String[] VALIDATOR_CLASSES = { "javax.validation.Validator",
|
||||||
"javax.validation.ValidatorFactory" };
|
"javax.validation.ValidatorFactory" };
|
||||||
|
|
@ -87,7 +90,7 @@ public class ConfigurationPropertiesBinderBuilder {
|
||||||
/**
|
/**
|
||||||
* Specify the {@link Validator} to use or {@code null} to use the default.
|
* Specify the {@link Validator} to use or {@code null} to use the default.
|
||||||
* <p>
|
* <p>
|
||||||
* By default, use a {@link Validator} bean named {@value VALIDATOR_BEAN_NAME} if
|
* By default, use a {@link Validator} bean named {@value #VALIDATOR_BEAN_NAME} if
|
||||||
* any. If not, create a JSR 303 Validator if the necessary libraries are available.
|
* any. If not, create a JSR 303 Validator if the necessary libraries are available.
|
||||||
* No validation occurs otherwise.
|
* No validation occurs otherwise.
|
||||||
* @param validator the validator to use or {@code null}
|
* @param validator the validator to use or {@code null}
|
||||||
|
|
@ -111,8 +114,8 @@ public class ConfigurationPropertiesBinderBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specify the {@link ConfigurableEnvironment Environment} to use, use all
|
* Specify the {@link ConfigurableEnvironment Environment} to use, use all available
|
||||||
* available {@link PropertySource}.
|
* {@link PropertySource}.
|
||||||
* @param environment the environment to use
|
* @param environment the environment to use
|
||||||
* @return this instance
|
* @return this instance
|
||||||
* @see #withPropertySources(Iterable)
|
* @see #withPropertySources(Iterable)
|
||||||
|
|
@ -136,7 +139,8 @@ public class ConfigurationPropertiesBinderBuilder {
|
||||||
if (this.validator != null) {
|
if (this.validator != null) {
|
||||||
return this.validator;
|
return this.validator;
|
||||||
}
|
}
|
||||||
Validator defaultValidator = getOptionalBean(VALIDATOR_BEAN_NAME, Validator.class);
|
Validator defaultValidator = getOptionalBean(VALIDATOR_BEAN_NAME,
|
||||||
|
Validator.class);
|
||||||
if (defaultValidator != null) {
|
if (defaultValidator != null) {
|
||||||
return defaultValidator;
|
return defaultValidator;
|
||||||
}
|
}
|
||||||
|
|
@ -160,7 +164,8 @@ public class ConfigurationPropertiesBinderBuilder {
|
||||||
|
|
||||||
private ConversionService createDefaultConversionService() {
|
private ConversionService createDefaultConversionService() {
|
||||||
ConversionServiceFactory conversionServiceFactory = this.applicationContext
|
ConversionServiceFactory conversionServiceFactory = this.applicationContext
|
||||||
.getAutowireCapableBeanFactory().createBean(ConversionServiceFactory.class);
|
.getAutowireCapableBeanFactory()
|
||||||
|
.createBean(ConversionServiceFactory.class);
|
||||||
return conversionServiceFactory.createConversionService();
|
return conversionServiceFactory.createConversionService();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ import org.springframework.core.NestedExceptionUtils;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exception thrown when a {@code @ConfigurationProperties} annotated object failed
|
* Exception thrown when a {@code @ConfigurationProperties} annotated object failed to be
|
||||||
* to be bound.
|
* bound.
|
||||||
*
|
*
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
|
|
@ -30,8 +30,8 @@ public class ConfigurationPropertiesBindingException extends RuntimeException {
|
||||||
|
|
||||||
private final Class<?> targetClass;
|
private final Class<?> targetClass;
|
||||||
|
|
||||||
public ConfigurationPropertiesBindingException(Class<?> targetClass,
|
public ConfigurationPropertiesBindingException(Class<?> targetClass, String message,
|
||||||
String message, Throwable cause) {
|
Throwable cause) {
|
||||||
super("Could not bind properties to '" + ClassUtils.getShortName(targetClass)
|
super("Could not bind properties to '" + ClassUtils.getShortName(targetClass)
|
||||||
+ "': " + message, cause);
|
+ "': " + message, cause);
|
||||||
this.targetClass = targetClass;
|
this.targetClass = targetClass;
|
||||||
|
|
|
||||||
|
|
@ -233,10 +233,10 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
|
||||||
|
|
||||||
private ConfigurationPropertiesBinder getBinder() {
|
private ConfigurationPropertiesBinder getBinder() {
|
||||||
if (this.configurationPropertiesBinder == null) {
|
if (this.configurationPropertiesBinder == null) {
|
||||||
this.configurationPropertiesBinder = new ConfigurationPropertiesBinderBuilder(this.applicationContext)
|
this.configurationPropertiesBinder = new ConfigurationPropertiesBinderBuilder(
|
||||||
.withConversionService(this.conversionService)
|
this.applicationContext).withConversionService(this.conversionService)
|
||||||
.withValidator(this.validator)
|
.withValidator(this.validator)
|
||||||
.withPropertySources(this.propertySources).build();
|
.withPropertySources(this.propertySources).build();
|
||||||
}
|
}
|
||||||
return this.configurationPropertiesBinder;
|
return this.configurationPropertiesBinder;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,8 @@ class ValidatedLocalValidatorFactoryBean extends LocalValidatorFactoryBean
|
||||||
if (AnnotatedElementUtils.hasAnnotation(type, Validated.class)) {
|
if (AnnotatedElementUtils.hasAnnotation(type, Validated.class)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (type.getPackage() != null && type.getPackage().getName()
|
if (type.getPackage() != null
|
||||||
.startsWith("org.springframework.boot")) {
|
&& type.getPackage().getName().startsWith("org.springframework.boot")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (getConstraintsForClass(type).isBeanConstrained()) {
|
if (getConstraintsForClass(type).isBeanConstrained()) {
|
||||||
|
|
|
||||||
|
|
@ -276,9 +276,8 @@ public class WebEndpointReactiveHandlerMapping extends RequestMappingInfoHandler
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object invoke(Map<String, Object> arguments) {
|
public Object invoke(Map<String, Object> arguments) {
|
||||||
return Mono.create((sink) -> {
|
return Mono.create((sink) -> Schedulers.elastic()
|
||||||
Schedulers.elastic().schedule(() -> invoke(arguments, sink));
|
.schedule(() -> invoke(arguments, sink)));
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void invoke(Map<String, Object> arguments, MonoSink<Object> sink) {
|
private void invoke(Map<String, Object> arguments, MonoSink<Object> sink) {
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,8 @@ public class ConfigurationPropertiesBinderBuilderTests {
|
||||||
|
|
||||||
private final StaticApplicationContext applicationContext = new StaticApplicationContext();
|
private final StaticApplicationContext applicationContext = new StaticApplicationContext();
|
||||||
|
|
||||||
private final ConfigurationPropertiesBinderBuilder builder =
|
private final ConfigurationPropertiesBinderBuilder builder = new ConfigurationPropertiesBinderBuilder(
|
||||||
new ConfigurationPropertiesBinderBuilder(this.applicationContext);
|
this.applicationContext);
|
||||||
|
|
||||||
private final MockEnvironment environment = new MockEnvironment();
|
private final MockEnvironment environment = new MockEnvironment();
|
||||||
|
|
||||||
|
|
@ -78,8 +78,8 @@ public class ConfigurationPropertiesBinderBuilderTests {
|
||||||
DefaultConversionService.class);
|
DefaultConversionService.class);
|
||||||
ConfigurationPropertiesBinder binder = this.builder
|
ConfigurationPropertiesBinder binder = this.builder
|
||||||
.withEnvironment(this.environment).build();
|
.withEnvironment(this.environment).build();
|
||||||
assertThat(ReflectionTestUtils.getField(binder, "conversionService")).isSameAs(
|
assertThat(ReflectionTestUtils.getField(binder, "conversionService"))
|
||||||
this.applicationContext.getBean("conversionService"));
|
.isSameAs(this.applicationContext.getBean("conversionService"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -97,8 +97,7 @@ public class ConfigurationPropertiesBinderBuilderTests {
|
||||||
public void useCustomValidator() {
|
public void useCustomValidator() {
|
||||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||||
ConfigurationPropertiesBinder binder = this.builder
|
ConfigurationPropertiesBinder binder = this.builder
|
||||||
.withEnvironment(this.environment)
|
.withEnvironment(this.environment).withValidator(validator).build();
|
||||||
.withValidator(validator).build();
|
|
||||||
assertThat(ReflectionTestUtils.getField(binder, "validator")).isSameAs(validator);
|
assertThat(ReflectionTestUtils.getField(binder, "validator")).isSameAs(validator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -124,8 +123,9 @@ public class ConfigurationPropertiesBinderBuilderTests {
|
||||||
public void validationWithJsr303() {
|
public void validationWithJsr303() {
|
||||||
ConfigurationPropertiesBinder binder = this.builder
|
ConfigurationPropertiesBinder binder = this.builder
|
||||||
.withEnvironment(this.environment).build();
|
.withEnvironment(this.environment).build();
|
||||||
assertThat(bindWithValidationErrors(binder, new PropertyWithJSR303())
|
assertThat(
|
||||||
.getAllErrors()).hasSize(2);
|
bindWithValidationErrors(binder, new PropertyWithJSR303()).getAllErrors())
|
||||||
|
.hasSize(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,8 @@ public class ConfigurationPropertiesBinderTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindToEnum(String property) {
|
private void bindToEnum(String property) {
|
||||||
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, property);
|
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,
|
||||||
|
property);
|
||||||
ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder(
|
ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder(
|
||||||
this.environment.getPropertySources(), null, null);
|
this.environment.getPropertySources(), null, null);
|
||||||
PropertyWithEnum target = new PropertyWithEnum();
|
PropertyWithEnum target = new PropertyWithEnum();
|
||||||
|
|
@ -129,7 +130,8 @@ public class ConfigurationPropertiesBinderTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindToEnumSet(String property, FooEnum... expected) {
|
private void bindToEnumSet(String property, FooEnum... expected) {
|
||||||
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, property);
|
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,
|
||||||
|
property);
|
||||||
ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder(
|
ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder(
|
||||||
this.environment.getPropertySources(), null, null);
|
this.environment.getPropertySources(), null, null);
|
||||||
PropertyWithEnum target = new PropertyWithEnum();
|
PropertyWithEnum target = new PropertyWithEnum();
|
||||||
|
|
@ -237,11 +239,9 @@ public class ConfigurationPropertiesBinderTests {
|
||||||
public void validationWithCustomValidator() {
|
public void validationWithCustomValidator() {
|
||||||
CustomPropertyValidator validator = spy(new CustomPropertyValidator());
|
CustomPropertyValidator validator = spy(new CustomPropertyValidator());
|
||||||
ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder(
|
ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder(
|
||||||
this.environment.getPropertySources(), null,
|
this.environment.getPropertySources(), null, validator);
|
||||||
validator);
|
|
||||||
PropertyWithCustomValidator target = new PropertyWithCustomValidator();
|
PropertyWithCustomValidator target = new PropertyWithCustomValidator();
|
||||||
assertThat(bindWithValidationErrors(binder, target)
|
assertThat(bindWithValidationErrors(binder, target).getAllErrors()).hasSize(1);
|
||||||
.getAllErrors()).hasSize(1);
|
|
||||||
verify(validator).validate(eq(target), any(Errors.class));
|
verify(validator).validate(eq(target), any(Errors.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -251,8 +251,7 @@ public class ConfigurationPropertiesBinderTests {
|
||||||
"test.foo=bar");
|
"test.foo=bar");
|
||||||
CustomPropertyValidator validator = spy(new CustomPropertyValidator());
|
CustomPropertyValidator validator = spy(new CustomPropertyValidator());
|
||||||
ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder(
|
ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder(
|
||||||
this.environment.getPropertySources(), null,
|
this.environment.getPropertySources(), null, validator);
|
||||||
validator);
|
|
||||||
PropertyWithValidatingSetter target = new PropertyWithValidatingSetter();
|
PropertyWithValidatingSetter target = new PropertyWithValidatingSetter();
|
||||||
binder.bind(target);
|
binder.bind(target);
|
||||||
assertThat(target.getFoo()).isEqualTo("bar");
|
assertThat(target.getFoo()).isEqualTo("bar");
|
||||||
|
|
@ -431,7 +430,6 @@ public class ConfigurationPropertiesBinderTests {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ConfigurationProperties(prefix = "test")
|
@ConfigurationProperties(prefix = "test")
|
||||||
public static class PropertyWithValidatingSetter {
|
public static class PropertyWithValidatingSetter {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -249,7 +249,8 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void genericConverterIsFound() {
|
public void genericConverterIsFound() {
|
||||||
prepareConverterContext(GenericConverterConfiguration.class, PersonProperty.class);
|
prepareConverterContext(GenericConverterConfiguration.class,
|
||||||
|
PersonProperty.class);
|
||||||
this.context.refresh();
|
this.context.refresh();
|
||||||
Person person = this.context.getBean(PersonProperty.class).getPerson();
|
Person person = this.context.getBean(PersonProperty.class).getPerson();
|
||||||
assertThat(person.firstName).isEqualTo("John");
|
assertThat(person.firstName).isEqualTo("John");
|
||||||
|
|
@ -356,7 +357,6 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableConfigurationProperties
|
@EnableConfigurationProperties
|
||||||
@ConfigurationProperties(prefix = "test")
|
@ConfigurationProperties(prefix = "test")
|
||||||
|
|
@ -381,7 +381,6 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableConfigurationProperties
|
@EnableConfigurationProperties
|
||||||
public static class PrototypePropertiesConfig {
|
public static class PrototypePropertiesConfig {
|
||||||
|
|
@ -427,7 +426,6 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
// Must be a raw type
|
// Must be a raw type
|
||||||
static class FactoryBeanTester implements FactoryBean, InitializingBean {
|
static class FactoryBeanTester implements FactoryBean, InitializingBean {
|
||||||
|
|
@ -454,7 +452,6 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableConfigurationProperties(PropertyWithoutConfigurationPropertiesAnnotation.class)
|
@EnableConfigurationProperties(PropertyWithoutConfigurationPropertiesAnnotation.class)
|
||||||
public static class ConfigurationPropertiesWithoutAnnotation {
|
public static class ConfigurationPropertiesWithoutAnnotation {
|
||||||
|
|
@ -553,13 +550,13 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
public Object convert(@Nullable Object source, TypeDescriptor sourceType,
|
||||||
|
TypeDescriptor targetType) {
|
||||||
String[] content = StringUtils.split((String) source, " ");
|
String[] content = StringUtils.split((String) source, " ");
|
||||||
return new Person(content[0], content[1]);
|
return new Person(content[0], content[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableConfigurationProperties
|
@EnableConfigurationProperties
|
||||||
@ConfigurationProperties(prefix = "test")
|
@ConfigurationProperties(prefix = "test")
|
||||||
|
|
|
||||||
|
|
@ -63,8 +63,8 @@ public class AnnotationEndpointDiscovererTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void endpointIsInParentContextIsDiscovered() {
|
public void endpointIsInParentContextIsDiscovered() {
|
||||||
AnnotationConfigApplicationContext parent =
|
AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext(
|
||||||
new AnnotationConfigApplicationContext(TestEndpointConfiguration.class);
|
TestEndpointConfiguration.class);
|
||||||
loadWithParent(parent, EmptyConfiguration.class, hasTestEndpoint());
|
loadWithParent(parent, EmptyConfiguration.class, hasTestEndpoint());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -125,7 +125,7 @@ public class AnnotationEndpointDiscovererTests {
|
||||||
Map<String, EndpointInfo<TestEndpointOperation>> endpoints = mapEndpoints(
|
Map<String, EndpointInfo<TestEndpointOperation>> endpoints = mapEndpoints(
|
||||||
new TestAnnotationEndpointDiscoverer(context,
|
new TestAnnotationEndpointDiscoverer(context,
|
||||||
(endpointId) -> new CachingConfiguration(0))
|
(endpointId) -> new CachingConfiguration(0))
|
||||||
.discoverEndpoints());
|
.discoverEndpoints());
|
||||||
assertThat(endpoints).containsOnlyKeys("test");
|
assertThat(endpoints).containsOnlyKeys("test");
|
||||||
Map<Method, TestEndpointOperation> operations = mapOperations(
|
Map<Method, TestEndpointOperation> operations = mapOperations(
|
||||||
endpoints.get("test"));
|
endpoints.get("test"));
|
||||||
|
|
@ -139,7 +139,7 @@ public class AnnotationEndpointDiscovererTests {
|
||||||
public void endpointMainReadOperationIsNotCachedWithNonMatchingId() {
|
public void endpointMainReadOperationIsNotCachedWithNonMatchingId() {
|
||||||
Function<String, CachingConfiguration> cachingConfigurationFactory = (
|
Function<String, CachingConfiguration> cachingConfigurationFactory = (
|
||||||
endpointId) -> (endpointId.equals("foo") ? new CachingConfiguration(500)
|
endpointId) -> (endpointId.equals("foo") ? new CachingConfiguration(500)
|
||||||
: new CachingConfiguration(0));
|
: new CachingConfiguration(0));
|
||||||
load(TestEndpointConfiguration.class, (context) -> {
|
load(TestEndpointConfiguration.class, (context) -> {
|
||||||
Map<String, EndpointInfo<TestEndpointOperation>> endpoints = mapEndpoints(
|
Map<String, EndpointInfo<TestEndpointOperation>> endpoints = mapEndpoints(
|
||||||
new TestAnnotationEndpointDiscoverer(context,
|
new TestAnnotationEndpointDiscoverer(context,
|
||||||
|
|
@ -157,7 +157,7 @@ public class AnnotationEndpointDiscovererTests {
|
||||||
public void endpointMainReadOperationIsCachedWithMatchingId() {
|
public void endpointMainReadOperationIsCachedWithMatchingId() {
|
||||||
Function<String, CachingConfiguration> cachingConfigurationFactory = (
|
Function<String, CachingConfiguration> cachingConfigurationFactory = (
|
||||||
endpointId) -> (endpointId.equals("test") ? new CachingConfiguration(500)
|
endpointId) -> (endpointId.equals("test") ? new CachingConfiguration(500)
|
||||||
: new CachingConfiguration(0));
|
: new CachingConfiguration(0));
|
||||||
load(TestEndpointConfiguration.class, (context) -> {
|
load(TestEndpointConfiguration.class, (context) -> {
|
||||||
Map<String, EndpointInfo<TestEndpointOperation>> endpoints = mapEndpoints(
|
Map<String, EndpointInfo<TestEndpointOperation>> endpoints = mapEndpoints(
|
||||||
new TestAnnotationEndpointDiscoverer(context,
|
new TestAnnotationEndpointDiscoverer(context,
|
||||||
|
|
@ -174,10 +174,10 @@ public class AnnotationEndpointDiscovererTests {
|
||||||
.isEqualTo(500);
|
.isEqualTo(500);
|
||||||
assertThat(operations.get(ReflectionUtils.findMethod(TestEndpoint.class,
|
assertThat(operations.get(ReflectionUtils.findMethod(TestEndpoint.class,
|
||||||
"getOne", String.class)).getInvoker())
|
"getOne", String.class)).getInvoker())
|
||||||
.isNotInstanceOf(CachingOperationInvoker.class);
|
.isNotInstanceOf(CachingOperationInvoker.class);
|
||||||
assertThat(operations.get(ReflectionUtils.findMethod(TestEndpoint.class,
|
assertThat(operations.get(ReflectionUtils.findMethod(TestEndpoint.class,
|
||||||
"update", String.class, String.class)).getInvoker())
|
"update", String.class, String.class)).getInvoker())
|
||||||
.isNotInstanceOf(CachingOperationInvoker.class);
|
.isNotInstanceOf(CachingOperationInvoker.class);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,8 +69,8 @@ public class JerseyWebEndpointIntegrationTests extends
|
||||||
@Bean
|
@Bean
|
||||||
public ServletRegistrationBean<ServletContainer> servletContainer(
|
public ServletRegistrationBean<ServletContainer> servletContainer(
|
||||||
ResourceConfig resourceConfig) {
|
ResourceConfig resourceConfig) {
|
||||||
return new ServletRegistrationBean<>(
|
return new ServletRegistrationBean<>(new ServletContainer(resourceConfig),
|
||||||
new ServletContainer(resourceConfig), "/*");
|
"/*");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue