Skip to content

Commit bea733d

Browse files
csvirimetacosm
authored andcommitted
feat: Cloner interface for Custom Resource instead of ObjectMapper (#611)
1 parent 60660ed commit bea733d

File tree

6 files changed

+44
-38
lines changed

6 files changed

+44
-38
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package io.javaoperatorsdk.operator.api.config;
2+
3+
import io.fabric8.kubernetes.client.CustomResource;
4+
5+
public interface Cloner {
6+
7+
CustomResource<?, ?> clone(CustomResource<?, ?> object);
8+
9+
}

Diff for: operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java

+17-7
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,24 @@
99
import io.javaoperatorsdk.operator.Metrics;
1010
import io.javaoperatorsdk.operator.api.ResourceController;
1111

12+
import com.fasterxml.jackson.core.JsonProcessingException;
1213
import com.fasterxml.jackson.databind.ObjectMapper;
1314

1415
/** An interface from which to retrieve configuration information. */
1516
public interface ConfigurationService {
1617

17-
ObjectMapper OBJECT_MAPPER = new ObjectMapper();
18+
Cloner DEFAULT_CLONER = new Cloner() {
19+
private final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
20+
21+
@Override
22+
public CustomResource<?, ?> clone(CustomResource<?, ?> object) {
23+
try {
24+
return OBJECT_MAPPER.readValue(OBJECT_MAPPER.writeValueAsString(object), object.getClass());
25+
} catch (JsonProcessingException e) {
26+
throw new IllegalStateException(e);
27+
}
28+
}
29+
};
1830

1931
/**
2032
* Retrieves the configuration associated with the specified controller
@@ -79,14 +91,12 @@ default int concurrentReconciliationThreads() {
7991
}
8092

8193
/**
82-
* The {@link ObjectMapper} that the operator should use to de-/serialize resources. This is
83-
* particularly useful when frameworks can configure a specific mapper that should also be used by
84-
* the SDK.
85-
*
94+
* Used to clone custom resources.
95+
*
8696
* @return the ObjectMapper to use
8797
*/
88-
default ObjectMapper getObjectMapper() {
89-
return OBJECT_MAPPER;
98+
default Cloner getResourceCloner() {
99+
return DEFAULT_CLONER;
90100
}
91101

92102
int DEFAULT_TERMINATION_TIMEOUT_SECONDS = 10;

Diff for: operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java

+6-8
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,13 @@
77
import io.javaoperatorsdk.operator.Metrics;
88
import io.javaoperatorsdk.operator.api.ResourceController;
99

10-
import com.fasterxml.jackson.databind.ObjectMapper;
11-
1210
public class ConfigurationServiceOverrider {
1311
private final ConfigurationService original;
1412
private Metrics metrics;
1513
private Config clientConfig;
1614
private boolean checkCR;
1715
private int threadNumber;
18-
private ObjectMapper mapper;
16+
private Cloner cloner;
1917
private int timeoutSeconds;
2018

2119
public ConfigurationServiceOverrider(
@@ -24,7 +22,7 @@ public ConfigurationServiceOverrider(
2422
this.clientConfig = original.getClientConfiguration();
2523
this.checkCR = original.checkCRDAndValidateLocalModel();
2624
this.threadNumber = original.concurrentReconciliationThreads();
27-
this.mapper = original.getObjectMapper();
25+
this.cloner = original.getResourceCloner();
2826
this.timeoutSeconds = original.getTerminationTimeoutSeconds();
2927
this.metrics = original.getMetrics();
3028
}
@@ -45,8 +43,8 @@ public ConfigurationServiceOverrider withConcurrentReconciliationThreads(int thr
4543
return this;
4644
}
4745

48-
public ConfigurationServiceOverrider withObjectMapper(ObjectMapper mapper) {
49-
this.mapper = mapper;
46+
public ConfigurationServiceOverrider withResourceCloner(Cloner cloner) {
47+
this.cloner = cloner;
5048
return this;
5149
}
5250

@@ -94,8 +92,8 @@ public int concurrentReconciliationThreads() {
9492
}
9593

9694
@Override
97-
public ObjectMapper getObjectMapper() {
98-
return mapper;
95+
public Cloner getResourceCloner() {
96+
return cloner;
9997
}
10098

10199
@Override

Diff for: operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/internal/CustomResourceEventSource.java

+6-17
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,13 @@
1313
import io.fabric8.kubernetes.client.informers.SharedIndexInformer;
1414
import io.fabric8.kubernetes.client.informers.cache.Cache;
1515
import io.javaoperatorsdk.operator.MissingCRDException;
16+
import io.javaoperatorsdk.operator.api.config.Cloner;
1617
import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
1718
import io.javaoperatorsdk.operator.processing.ConfiguredController;
1819
import io.javaoperatorsdk.operator.processing.ResourceCache;
1920
import io.javaoperatorsdk.operator.processing.event.AbstractEventSource;
2021
import io.javaoperatorsdk.operator.processing.event.CustomResourceID;
2122

22-
import com.fasterxml.jackson.core.JsonProcessingException;
23-
import com.fasterxml.jackson.databind.ObjectMapper;
24-
2523
import static io.javaoperatorsdk.operator.processing.KubernetesResourceUtils.getName;
2624
import static io.javaoperatorsdk.operator.processing.KubernetesResourceUtils.getUID;
2725
import static io.javaoperatorsdk.operator.processing.KubernetesResourceUtils.getVersion;
@@ -40,15 +38,14 @@ public class CustomResourceEventSource<T extends CustomResource<?, ?>> extends A
4038
private final ConfiguredController<T> controller;
4139
private final Map<String, SharedIndexInformer<T>> sharedIndexInformers =
4240
new ConcurrentHashMap<>();
43-
private final ObjectMapper cloningObjectMapper;
41+
4442
private final CustomResourceEventFilter<T> filter;
4543
private final OnceWhitelistEventFilterEventFilter<T> onceWhitelistEventFilterEventFilter;
46-
44+
private final Cloner cloner;
4745

4846
public CustomResourceEventSource(ConfiguredController<T> controller) {
4947
this.controller = controller;
50-
this.cloningObjectMapper =
51-
controller.getConfiguration().getConfigurationService().getObjectMapper();
48+
this.cloner = controller.getConfiguration().getConfigurationService().getResourceCloner();
5249

5350
var filters = new CustomResourceEventFilter[] {
5451
CustomResourceEventFilters.finalizerNeededAndApplied(),
@@ -160,7 +157,7 @@ public Optional<T> getCustomResource(CustomResourceID resourceID) {
160157
if (resource == null) {
161158
return Optional.empty();
162159
} else {
163-
return Optional.of(clone(resource));
160+
return Optional.of((T) (cloner.clone(resource)));
164161
}
165162
}
166163

@@ -176,15 +173,6 @@ public SharedIndexInformer<T> getInformer(String namespace) {
176173
return getInformers().get(Objects.requireNonNullElse(namespace, ANY_NAMESPACE_MAP_KEY));
177174
}
178175

179-
private T clone(T customResource) {
180-
try {
181-
return (T) cloningObjectMapper.readValue(
182-
cloningObjectMapper.writeValueAsString(customResource), customResource.getClass());
183-
} catch (JsonProcessingException e) {
184-
throw new IllegalStateException(e);
185-
}
186-
}
187-
188176
/**
189177
* This will ensure that the next event received after this method is called will not be filtered
190178
* out.
@@ -196,4 +184,5 @@ public void whitelistNextEvent(CustomResourceID customResourceID) {
196184
onceWhitelistEventFilterEventFilter.whitelistNextEvent(customResourceID);
197185
}
198186
}
187+
199188
}

Diff for: operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/internal/CustomResourceEventFilterTest.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,8 @@ public void eventNotFilteredByCustomPredicateIfFinalizerIsRequired() {
103103
oldResource.getStatus().getConfigMapStatus(),
104104
newResource.getStatus().getConfigMapStatus()));
105105

106-
when(config.getConfigurationService().getObjectMapper())
107-
.thenReturn(ConfigurationService.OBJECT_MAPPER);
106+
when(config.getConfigurationService().getResourceCloner())
107+
.thenReturn(ConfigurationService.DEFAULT_CLONER);
108108

109109
var controller = new TestConfiguredController(config);
110110
var eventSource = new CustomResourceEventSource<>(controller);
@@ -142,8 +142,8 @@ public TestControllerConfig(String finalizer, boolean generationAware,
142142
TestCustomResource.class,
143143
mock(ConfigurationService.class));
144144

145-
when(getConfigurationService().getObjectMapper())
146-
.thenReturn(ConfigurationService.OBJECT_MAPPER);
145+
when(getConfigurationService().getResourceCloner())
146+
.thenReturn(ConfigurationService.DEFAULT_CLONER);
147147
}
148148
}
149149

Diff for: operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/internal/CustomResourceEventSourceTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,8 @@ public TestConfiguration(boolean generationAware) {
164164
null,
165165
TestCustomResource.class,
166166
mock(ConfigurationService.class));
167-
when(getConfigurationService().getObjectMapper())
168-
.thenReturn(ConfigurationService.OBJECT_MAPPER);
167+
when(getConfigurationService().getResourceCloner())
168+
.thenReturn(ConfigurationService.DEFAULT_CLONER);
169169
when(getConfigurationService().getMetrics())
170170
.thenReturn(Metrics.NOOP);
171171
}

0 commit comments

Comments
 (0)