Skip to content

Commit e392924

Browse files
committed
fix: implementation of put should return value instead of Optional
Signed-off-by: Chris Laprun <[email protected]>
1 parent 73688b8 commit e392924

File tree

4 files changed

+58
-62
lines changed

4 files changed

+58
-62
lines changed

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/managed/DefaultManagedDependentResourceContext.java

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,16 @@
33
import java.util.Optional;
44
import java.util.concurrent.ConcurrentHashMap;
55

6+
import org.slf4j.Logger;
7+
import org.slf4j.LoggerFactory;
8+
69
import io.javaoperatorsdk.operator.processing.dependent.workflow.WorkflowCleanupResult;
710
import io.javaoperatorsdk.operator.processing.dependent.workflow.WorkflowReconcileResult;
811

912
@SuppressWarnings("rawtypes")
1013
public class DefaultManagedDependentResourceContext implements ManagedDependentResourceContext {
14+
private static final Logger log =
15+
LoggerFactory.getLogger(DefaultManagedDependentResourceContext.class);
1116
public static final Object RECONCILE_RESULT_KEY = new Object();
1217
public static final Object CLEANUP_RESULT_KEY = new Object();
1318
private final ConcurrentHashMap attributes = new ConcurrentHashMap();
@@ -21,18 +26,27 @@ public <T> Optional<T> get(Object key, Class<T> expectedType) {
2126

2227
@Override
2328
@SuppressWarnings("unchecked")
24-
@Deprecated(forRemoval = true)
2529
public <T> T put(Object key, T value) {
26-
return (T) putOrRemove(key, value);
27-
}
28-
29-
@Override
30-
@SuppressWarnings("unchecked")
31-
public <T> Optional<T> putOrRemove(Object key, T value) {
30+
Object previous;
3231
if (value == null) {
33-
return (Optional<T>) Optional.ofNullable(attributes.remove(key));
32+
return (T) attributes.remove(key);
33+
} else {
34+
previous = attributes.put(key, value);
3435
}
35-
return (Optional<T>) Optional.ofNullable(attributes.put(key, value));
36+
37+
if (previous != null && !previous.getClass().isAssignableFrom(value.getClass())) {
38+
logWarning("Previous value (" + previous +
39+
") for key (" + key +
40+
") was not of type " + value.getClass() +
41+
". This might indicate an issue in your code. If not, use put(" + key +
42+
", null) first to remove the previous value.");
43+
}
44+
return (T) previous;
45+
}
46+
47+
// only for testing purposes
48+
void logWarning(String message) {
49+
log.warn(message);
3650
}
3751

3852
@Override

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/managed/ManagedDependentResourceContext.java

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,31 +30,24 @@ public interface ManagedDependentResourceContext {
3030
* the semantics of this operation is defined as removing the mapping associated with the
3131
* specified key.
3232
*
33-
* @param <T> object type
34-
* @param key the key identifying which contextual object to add or remove from the context
35-
* @param value the value to add to the context or {@code null} to remove an existing entry
36-
* associated with the specified key
37-
* @return an Optional containing the previous value associated with the key or
38-
* {@link Optional#empty()} if none existed
39-
* @deprecated use {@link #putOrRemove(Object, Object)} instead
40-
*/
41-
@SuppressWarnings("unchecked")
42-
@Deprecated(forRemoval = true)
43-
<T> T put(Object key, T value);
44-
45-
/**
46-
* Associates the specified contextual value to the specified key. If the value is {@code null},
47-
* the semantics of this operation is defined as removing the mapping associated with the
48-
* specified key.
33+
* <p>
34+
* Note that, while implementations shouldn't throw a {@link ClassCastException} when the new
35+
* value type differs from the type of the existing value, calling sites might encounter such
36+
* exceptions if they bind the return value to a specific type. Users are either expected to
37+
* disregard the return value (most common case) or "reset" the value type associated with the
38+
* specified key by first calling {@code put(key, null)} if they want to ensure some level of type
39+
* safety in their code (where attempting to store values of different types under the same key
40+
* might be indicative of an issue).
41+
* </p>
4942
*
5043
* @param <T> object type
5144
* @param key the key identifying which contextual object to add or remove from the context
5245
* @param value the value to add to the context or {@code null} to remove an existing entry
5346
* associated with the specified key
54-
* @return an Optional containing the previous value associated with the key or
55-
* {@link Optional#empty()} if none existed
47+
* @return the previous value if one was associated with the specified key, {@code null}
48+
* otherwise.
5649
*/
57-
<T> Optional<T> putOrRemove(Object key, T value);
50+
<T> T put(Object key, T value);
5851

5952
/**
6053
* Retrieves the value associated with the key or fail with an exception if none exists.

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DefaultWorkflow.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public WorkflowReconcileResult reconcile(P primary, Context<P> context) {
9393
new WorkflowReconcileExecutor<>(this, primary, context);
9494
var result = workflowReconcileExecutor.reconcile();
9595
context.managedDependentResourceContext()
96-
.putOrRemove(DefaultManagedDependentResourceContext.RECONCILE_RESULT_KEY, result);
96+
.put(DefaultManagedDependentResourceContext.RECONCILE_RESULT_KEY, result);
9797
if (throwExceptionAutomatically) {
9898
result.throwAggregateExceptionIfErrorsPresent();
9999
}
@@ -106,7 +106,7 @@ public WorkflowCleanupResult cleanup(P primary, Context<P> context) {
106106
new WorkflowCleanupExecutor<>(this, primary, context);
107107
var result = workflowCleanupExecutor.cleanup();
108108
context.managedDependentResourceContext()
109-
.putOrRemove(DefaultManagedDependentResourceContext.CLEANUP_RESULT_KEY, result);
109+
.put(DefaultManagedDependentResourceContext.CLEANUP_RESULT_KEY, result);
110110
if (throwExceptionAutomatically) {
111111
result.throwAggregateExceptionIfErrorsPresent();
112112
}

operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/reconciler/dependent/managed/DefaultManagedDependentResourceContextTest.java

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414

1515
class DefaultManagedDependentResourceContextTest {
1616

17-
private ManagedDependentResourceContext context = new DefaultManagedDependentResourceContext();
17+
private final ManagedDependentResourceContext context =
18+
new DefaultManagedDependentResourceContext();
1819

1920
@Test
2021
void getWhenEmpty() {
@@ -37,26 +38,29 @@ void putNewValueOverwrites() {
3738
assertThat(actual).contains("valueB");
3839
}
3940

40-
@Test
41-
void putOrRemoveNewValueOverwrites() {
42-
context.putOrRemove("key", "value");
43-
context.putOrRemove("key", "valueB");
44-
Optional<String> actual = context.get("key", String.class);
45-
assertThat(actual).contains("valueB");
46-
}
47-
4841
@Test
4942
void putNewValueReturnsPriorValue() {
50-
context.put("key", "value");
51-
Optional<String> actual = (Optional<String>) (Object) context.put("key", "valueB");
52-
assertThat(actual).contains("value");
43+
final var prior = "value";
44+
context.put("key", prior);
45+
String actual = context.put("key", "valueB");
46+
assertThat(actual).isEqualTo(prior);
5347
}
5448

5549
@Test
56-
void putOrRemoveNewValueReturnsPriorValue() {
57-
context.put("key", "value");
58-
Optional<String> actual = context.putOrRemove("key", "valueB");
59-
assertThat(actual).contains("value");
50+
void putNewValueThrowsExceptionIfTypesDiffer() {
51+
// to check that we properly log things without setting up a complex fixture
52+
final String[] messages = new String[1];
53+
var context = new DefaultManagedDependentResourceContext() {
54+
@Override
55+
void logWarning(String message) {
56+
messages[0] = message;
57+
}
58+
};
59+
final var prior = "value";
60+
final var key = "key";
61+
context.put(key, prior);
62+
context.put(key, 10);
63+
assertThat(messages[0]).contains(key).contains(prior).contains("put(" + key + ", null)");
6064
}
6165

6266
@Test
@@ -67,25 +71,11 @@ void putNullRemoves() {
6771
assertThat(actual).isEmpty();
6872
}
6973

70-
@Test
71-
void putOrRemoveNullRemoves() {
72-
context.putOrRemove("key", "value");
73-
context.putOrRemove("key", null);
74-
Optional<String> actual = context.get("key", String.class);
75-
assertThat(actual).isEmpty();
76-
}
7774

7875
@Test
7976
void putNullReturnsPriorValue() {
8077
context.put("key", "value");
81-
Optional<String> actual = context.put("key", null);
82-
assertThat(actual).contains("value");
83-
}
84-
85-
@Test
86-
void putOrRemoveNullReturnsPriorValue() {
87-
context.putOrRemove("key", "value");
88-
Optional<String> actual = context.putOrRemove("key", null);
78+
String actual = context.put("key", null);
8979
assertThat(actual).contains("value");
9080
}
9181

@@ -113,5 +103,4 @@ void getWorkflowReconcileResult() {
113103
Optional<WorkflowReconcileResult> actual = context.getWorkflowReconcileResult();
114104
assertThat(actual).containsSame(result);
115105
}
116-
117106
}

0 commit comments

Comments
 (0)