Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HealthContributor beans managed by a CompositeHealthContributor are recreated on each call #31676

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -31,23 +31,29 @@
* @param <V> the value type
* @param <C> the contributor type
* @author Phillip Webb
* @author Guirong Hu
* @see CompositeHealthContributorMapAdapter
* @see CompositeReactiveHealthContributorMapAdapter
*/
abstract class NamedContributorsMapAdapter<V, C> implements NamedContributors<C> {

private final Map<String, V> map;

private final Function<V, ? extends C> valueAdapter;
private final Map<String, C> namedContributorsMap;

NamedContributorsMapAdapter(Map<String, V> map, Function<V, ? extends C> valueAdapter) {
Assert.notNull(map, "Map must not be null");
Assert.notNull(valueAdapter, "ValueAdapter must not be null");
map.keySet().forEach(this::validateKey);
map.values().stream().map(valueAdapter)
.forEach((value) -> Assert.notNull(value, "Map must not contain null values"));
this.map = Collections.unmodifiableMap(new LinkedHashMap<>(map));
this.valueAdapter = valueAdapter;
this.namedContributorsMap = getContributorsMap(map, valueAdapter);
}

private Map<String, C> getContributorsMap(Map<String, V> map, Function<V, ? extends C> valueAdapter) {
Map<String, C> contributorsMap = new LinkedHashMap<>(map.size());
map.forEach((name, value) -> {
this.validateKey(name);
C contributor = adapt(value, valueAdapter);
Assert.notNull(contributor, "Map must not contain null values");
contributorsMap.put(name, contributor);
});
return Collections.unmodifiableMap(contributorsMap);
}

private void validateKey(String value) {
Expand All @@ -58,7 +64,7 @@ private void validateKey(String value) {

@Override
public Iterator<NamedContributor<C>> iterator() {
Iterator<Entry<String, V>> iterator = this.map.entrySet().iterator();
Iterator<Entry<String, C>> iterator = this.namedContributorsMap.entrySet().iterator();
return new Iterator<NamedContributor<C>>() {

@Override
Expand All @@ -68,20 +74,20 @@ public boolean hasNext() {

@Override
public NamedContributor<C> next() {
Entry<String, V> entry = iterator.next();
return NamedContributor.of(entry.getKey(), adapt(entry.getValue()));
Entry<String, C> entry = iterator.next();
return NamedContributor.of(entry.getKey(), entry.getValue());
}

};
}

@Override
public C getContributor(String name) {
return adapt(this.map.get(name));
return this.namedContributorsMap.get(name);
}

private C adapt(V value) {
return (value != null) ? this.valueAdapter.apply(value) : null;
private C adapt(V value, Function<V, ? extends C> valueAdapter) {
return (value != null) ? valueAdapter.apply(value) : null;
}

}
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -20,6 +20,7 @@
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;

import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -92,6 +93,22 @@ void getContributorReturnsAdaptedEntry() {
assertThat(adapter.getContributor("two")).isEqualTo("owt");
}

@Test
void eachValueAdapterShouldBeCalledOnlyOnce() {
Map<String, String> map = new LinkedHashMap<>();
map.put("one", "one");
map.put("two", "two");
int callCount = map.size();

AtomicInteger counter = new AtomicInteger(0);
TestNamedContributorsMapAdapter<String> adapter = new TestNamedContributorsMapAdapter<>(map,
(name) -> count(name, counter));
assertThat(adapter.getContributor("one")).isEqualTo("eno");
assertThat(counter.get()).isEqualTo(callCount);
assertThat(adapter.getContributor("two")).isEqualTo("owt");
assertThat(counter.get()).isEqualTo(callCount);
}

@Test
void getContributorWhenNotInMapReturnsNull() {
TestNamedContributorsMapAdapter<String> adapter = createAdapter();
Expand All @@ -106,6 +123,11 @@ private TestNamedContributorsMapAdapter<String> createAdapter() {
return adapter;
}

private String count(CharSequence charSequence, AtomicInteger counter) {
counter.incrementAndGet();
return reverse(charSequence);
}

private String reverse(CharSequence charSequence) {
return new StringBuilder(charSequence).reverse().toString();
}
Expand Down