Skip to content

Commit c6d5dd5

Browse files
committed
feat: allow context keys to be any type
Since we are going from String to Object this will not break code.
1 parent 8b2782e commit c6d5dd5

3 files changed

Lines changed: 59 additions & 23 deletions

File tree

implementation/revapi.json

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,42 @@
5151
"criticality" : "highlight",
5252
"minSeverity" : "POTENTIALLY_BREAKING",
5353
"minCriticality" : "documented",
54-
"differences" : [ ]
54+
"differences" : [ {
55+
"code" : "java.method.parameterTypeChanged",
56+
"old" : "parameter boolean io.smallrye.mutiny.Context::contains(===java.lang.String===)",
57+
"new" : "parameter boolean io.smallrye.mutiny.Context::contains(===java.lang.Object===)",
58+
"justification" : "Context keys changed from String to Object"
59+
}, {
60+
"code" : "java.method.parameterTypeChanged",
61+
"old" : "parameter io.smallrye.mutiny.Context io.smallrye.mutiny.Context::delete(===java.lang.String===)",
62+
"new" : "parameter io.smallrye.mutiny.Context io.smallrye.mutiny.Context::delete(===java.lang.Object===)",
63+
"justification" : "Context keys changed from String to Object"
64+
}, {
65+
"code" : "java.method.parameterTypeChanged",
66+
"old" : "parameter <T> T io.smallrye.mutiny.Context::get(===java.lang.String===) throws java.util.NoSuchElementException",
67+
"new" : "parameter <T> T io.smallrye.mutiny.Context::get(===java.lang.Object===) throws java.util.NoSuchElementException",
68+
"justification" : "Context keys changed from String to Object"
69+
}, {
70+
"code" : "java.method.parameterTypeChanged",
71+
"old" : "parameter <T> T io.smallrye.mutiny.Context::getOrElse(===java.lang.String===, java.util.function.Supplier<? extends T>)",
72+
"new" : "parameter <T> T io.smallrye.mutiny.Context::getOrElse(===java.lang.Object===, java.util.function.Supplier<? extends T>)",
73+
"justification" : "Context keys changed from String to Object"
74+
}, {
75+
"code" : "java.method.parameterTypeChanged",
76+
"old" : "parameter io.smallrye.mutiny.Context io.smallrye.mutiny.Context::put(===java.lang.String===, java.lang.Object)",
77+
"new" : "parameter io.smallrye.mutiny.Context io.smallrye.mutiny.Context::put(===java.lang.Object===, java.lang.Object)",
78+
"justification" : "Context keys changed from String to Object"
79+
}, {
80+
"code" : "java.method.parameterTypeParameterChanged",
81+
"old" : "parameter io.smallrye.mutiny.Context io.smallrye.mutiny.Context::from(===java.util.Map<java.lang.String, ?>===)",
82+
"new" : "parameter io.smallrye.mutiny.Context io.smallrye.mutiny.Context::from(===java.util.Map<?, ?>===)",
83+
"justification" : "Context keys changed from String to Object"
84+
}, {
85+
"code" : "java.method.returnTypeTypeParametersChanged",
86+
"old" : "method java.util.Set<java.lang.String> io.smallrye.mutiny.Context::keys()",
87+
"new" : "method java.util.Set<java.lang.Object> io.smallrye.mutiny.Context::keys()",
88+
"justification" : "Context keys changed from String to Object"
89+
} ]
5590
}
5691
}, {
5792
"extension" : "revapi.reporter.json",
@@ -70,4 +105,4 @@
70105
"minCriticality" : "documented",
71106
"output" : "out"
72107
}
73-
} ]
108+
} ]

implementation/src/main/java/io/smallrye/mutiny/Context.java

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
* A context is provided by a {@link io.smallrye.mutiny.subscription.UniSubscriber} or {@link Flow.Subscriber}
1717
* that implements {@link io.smallrye.mutiny.subscription.ContextSupport}.
1818
* <p>
19-
* Context keys are represented as {@link String} while values can be from heterogeneous types.
19+
* Context keys and values can be from heterogeneous types.
20+
* Keys must have proper {@link Object#equals(Object)} and {@link Object#hashCode()} implementations.
2021
* <p>
2122
* {@link Context} instances are thread-safe.
2223
* Internal storage is not allocated until the first entry is being added.
@@ -57,9 +58,9 @@ public static Context of(Object... entries) {
5758
if (entries.length % 2 != 0) {
5859
throw new IllegalArgumentException("Arguments must be balanced to form (key, value) pairs");
5960
}
60-
HashMap<String, Object> map = new HashMap<>();
61+
HashMap<Object, Object> map = new HashMap<>();
6162
for (int i = 0; i < entries.length; i = i + 2) {
62-
String key = nonNull(entries[i], "key").toString();
63+
Object key = nonNull(entries[i], "key");
6364
Object value = nonNull(entries[i + 1], "value");
6465
map.put(key, value);
6566
}
@@ -73,17 +74,17 @@ public static Context of(Object... entries) {
7374
* @return the new context
7475
* @throws NullPointerException when {@code entries} is null
7576
*/
76-
public static Context from(Map<String, ?> entries) {
77+
public static Context from(Map<?, ?> entries) {
7778
return new Context(requireNonNull(entries, "The entries map cannot be null"));
7879
}
7980

80-
private volatile ConcurrentHashMap<String, Object> entries;
81+
private volatile ConcurrentHashMap<Object, Object> entries;
8182

8283
private Context() {
8384
this.entries = null;
8485
}
8586

86-
private Context(Map<String, ?> initialEntries) {
87+
private Context(Map<?, ?> initialEntries) {
8788
this.entries = new ConcurrentHashMap<>(initialEntries);
8889
}
8990

@@ -93,7 +94,7 @@ private Context(Map<String, ?> initialEntries) {
9394
* @param key the key
9495
* @return {@code true} when there is an entry for {@code key}, {@code false} otherwise
9596
*/
96-
public boolean contains(String key) {
97+
public boolean contains(Object key) {
9798
if (entries == null) {
9899
return false;
99100
} else {
@@ -110,7 +111,7 @@ public boolean contains(String key) {
110111
* @throws NoSuchElementException when there is no entry for {@code key}
111112
*/
112113
@SuppressWarnings("unchecked")
113-
public <T> T get(String key) throws NoSuchElementException {
114+
public <T> T get(Object key) throws NoSuchElementException {
114115
if (entries == null) {
115116
throw new NoSuchElementException("The context is empty");
116117
}
@@ -130,7 +131,7 @@ public <T> T get(String key) throws NoSuchElementException {
130131
* @return the value
131132
*/
132133
@SuppressWarnings("unchecked")
133-
public <T> T getOrElse(String key, Supplier<? extends T> alternativeSupplier) {
134+
public <T> T getOrElse(Object key, Supplier<? extends T> alternativeSupplier) {
134135
if (entries != null) {
135136
T value = (T) entries.get(key);
136137
if (value != null) {
@@ -147,7 +148,7 @@ public <T> T getOrElse(String key, Supplier<? extends T> alternativeSupplier) {
147148
* @param value the value, cannot be {@code null}
148149
* @return this context
149150
*/
150-
public Context put(String key, Object value) {
151+
public Context put(Object key, Object value) {
151152
if (entries == null) {
152153
synchronized (this) {
153154
if (entries == null) {
@@ -165,7 +166,7 @@ public Context put(String key, Object value) {
165166
* @param key the key
166167
* @return this context
167168
*/
168-
public Context delete(String key) {
169+
public Context delete(Object key) {
169170
if (entries != null) {
170171
entries.remove(key);
171172
}
@@ -188,12 +189,12 @@ public boolean isEmpty() {
188189
*
189190
* @return the set of keys
190191
*/
191-
public Set<String> keys() {
192+
public Set<Object> keys() {
192193
if (this.entries == null) {
193194
return Collections.emptySet();
194195
}
195-
HashSet<String> set = new HashSet<>();
196-
Enumeration<String> enumeration = entries.keys();
196+
HashSet<Object> set = new HashSet<>();
197+
Enumeration<Object> enumeration = entries.keys();
197198
while (enumeration.hasMoreElements()) {
198199
set.add(enumeration.nextElement());
199200
}

implementation/src/test/java/io/smallrye/mutiny/ContextTest.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,9 @@ void getOnMissingKey() {
162162
@Test
163163
void keysetIsACopy() {
164164
Context context = Context.of("foo", "bar", "123", 456);
165-
Set<String> k1 = context.keys();
165+
Set<Object> k1 = context.keys();
166166
context.put("bar", "baz");
167-
Set<String> k2 = context.keys();
167+
Set<Object> k2 = context.keys();
168168
assertThat(k1).isNotSameAs(k2);
169169
}
170170
}
@@ -312,20 +312,20 @@ void joinAllAndAttachContext() {
312312
Context context = Context.of("foo", "bar", "baz", "baz");
313313

314314
Uni<Integer> a = Uni.createFrom().item(58)
315-
.withContext((uni, ctx) -> uni.onItem().invoke(n -> ctx.put(n.toString(), n)));
315+
.withContext((uni, ctx) -> uni.onItem().invoke(n -> ctx.put(n, n)));
316316

317317
Uni<Integer> b = Uni.createFrom().item(63)
318-
.withContext((uni, ctx) -> uni.onItem().invoke(n -> ctx.put(n.toString(), n)));
318+
.withContext((uni, ctx) -> uni.onItem().invoke(n -> ctx.put(n, n)));
319319

320320
Uni<Integer> c = Uni.createFrom().item(69)
321-
.withContext((uni, ctx) -> uni.onItem().invoke(n -> ctx.put(n.toString(), n)));
321+
.withContext((uni, ctx) -> uni.onItem().invoke(n -> ctx.put(n, n)));
322322

323323
UniAssertSubscriber<String> sub = Uni.join().all(a, b, c).andFailFast()
324324
.attachContext()
325325
.onItem().transform(itemsWithContext -> {
326326
Context ctx = itemsWithContext.context();
327-
return itemsWithContext.get().toString() + "::" + ctx.get("58") + "::" + ctx.get("63") + "::"
328-
+ ctx.get("69");
327+
return itemsWithContext.get().toString() + "::" + ctx.get(58) + "::" + ctx.get(63) + "::"
328+
+ ctx.get(69);
329329
})
330330
.subscribe().withSubscriber(UniAssertSubscriber.create(context));
331331

0 commit comments

Comments
 (0)