Skip to content

Commit c574021

Browse files
authored
Add support for creating KeyValues from any iterable (#3503)
Add new `of` and `and` methods that allow `KeyValues` to be created from any iterable.
1 parent e36a4b7 commit c574021

File tree

3 files changed

+91
-0
lines changed

3 files changed

+91
-0
lines changed

micrometer-commons/src/main/java/io/micrometer/common/KeyValue.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package io.micrometer.common;
1717

18+
import java.util.function.Function;
1819
import java.util.function.Predicate;
1920

2021
import io.micrometer.common.docs.KeyName;
@@ -57,6 +58,18 @@ static KeyValue of(KeyName keyName, String value) {
5758
return KeyValue.of(keyName.asString(), value);
5859
}
5960

61+
/**
62+
* Creates a {@link KeyValue} for the given {@code element} by extracting a key and
63+
* value from it.
64+
* @param element the source element
65+
* @param keyExtractor function to extract the key from the element
66+
* @param valueExtractor function to extract the value from the element
67+
* @return KeyValue
68+
*/
69+
static <E> KeyValue of(E element, Function<E, String> keyExtractor, Function<E, String> valueExtractor) {
70+
return KeyValue.of(keyExtractor.apply(element), valueExtractor.apply(element));
71+
}
72+
6073
/**
6174
* Creates a {@link KeyValue} for the given key and value and additionally validates
6275
* it with the {@link Predicate}.

micrometer-commons/src/main/java/io/micrometer/common/KeyValues.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import io.micrometer.common.lang.Nullable;
1919

2020
import java.util.*;
21+
import java.util.function.Function;
2122
import java.util.stream.Stream;
2223
import java.util.stream.StreamSupport;
2324

@@ -106,6 +107,24 @@ public KeyValues and(@Nullable KeyValue... keyValues) {
106107
return new KeyValues(newKeyValues);
107108
}
108109

110+
/**
111+
* Return a new {@code KeyValues} instance by merging this collection and the key
112+
* values extracted from the given elements.
113+
* @param elements the source elements
114+
* @param keyExtractor function to extract the key from the element
115+
* @param valueExtractor function to extract the value from the element
116+
* @return a new {@code KeyValues} instance
117+
*/
118+
public <E> KeyValues and(@Nullable Iterable<E> elements, Function<E, String> keyExtractor,
119+
Function<E, String> valueExtractor) {
120+
if (elements == null || !elements.iterator().hasNext()) {
121+
return this;
122+
}
123+
Function<E, KeyValue> mapper = element -> KeyValue.of(element, keyExtractor, valueExtractor);
124+
Iterable<KeyValue> keyValues = () -> StreamSupport.stream(elements.spliterator(), false).map(mapper).iterator();
125+
return and(keyValues);
126+
}
127+
109128
/**
110129
* Return a new {@code KeyValues} instance by merging this collection and the
111130
* specified key values.
@@ -217,6 +236,19 @@ public static KeyValues concat(@Nullable Iterable<? extends KeyValue> keyValues,
217236
return KeyValues.of(keyValues).and(otherKeyValues);
218237
}
219238

239+
/**
240+
* Return a new {@code KeyValues} instance containing key values extracted from the
241+
* given elements.
242+
* @param elements the source elements
243+
* @param keyExtractor function to extract the key from the element
244+
* @param valueExtractor function to extract the value from the element
245+
* @return a new {@code KeyValues} instance
246+
*/
247+
public static <E> KeyValues of(@Nullable Iterable<E> elements, Function<E, String> keyExtractor,
248+
Function<E, String> valueExtractor) {
249+
return empty().and(elements, keyExtractor, valueExtractor);
250+
}
251+
220252
/**
221253
* Return a new {@code KeyValues} instance containing key values constructed from the
222254
* specified source key values.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2022 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+
* 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,
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 io.micrometer.common;
18+
19+
import java.util.Map;
20+
21+
import org.junit.jupiter.api.Test;
22+
23+
import static org.assertj.core.api.Assertions.assertThat;
24+
25+
/**
26+
* Tests for {@link KeyValues}.
27+
*/
28+
class KeyValuesTest {
29+
30+
@Test
31+
void ofExtractingFromElementsReturnsKeyValues() {
32+
Map<String, String> map = Map.of("micrometer", "tracing", "can", "trace");
33+
KeyValues keyValues = KeyValues.of(map.entrySet(), Map.Entry::getKey, Map.Entry::getValue);
34+
assertThat(keyValues).containsExactlyInAnyOrder(KeyValue.of("micrometer", "tracing"),
35+
KeyValue.of("can", "trace"));
36+
}
37+
38+
@Test
39+
void andExtractingFromElementsReturnsKeyValues() {
40+
Map<String, String> map = Map.of("micrometer", "tracing", "can", "trace");
41+
KeyValues keyValues = KeyValues.of("no", "way").and(map.entrySet(), Map.Entry::getKey, Map.Entry::getValue);
42+
assertThat(keyValues).containsExactlyInAnyOrder(KeyValue.of("no", "way"), KeyValue.of("micrometer", "tracing"),
43+
KeyValue.of("can", "trace"));
44+
}
45+
46+
}

0 commit comments

Comments
 (0)