Skip to content

Commit 85ad4bf

Browse files
xstefankcsviri
authored andcommitted
feat: automatically derive the the dependent resource type if not specified
Signed-off-by: xstefank <xstefank122@gmail.com>
1 parent 63bbec5 commit 85ad4bf

File tree

76 files changed

+142
-315
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+142
-315
lines changed

bootstrapper-maven-plugin/src/main/resources/templates/ConfigMapDependentResource.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,6 @@ public class ConfigMapDependentResource
1717

1818
public static final String KEY = "key";
1919

20-
public ConfigMapDependentResource() {
21-
super(ConfigMap.class);
22-
}
23-
2420
@Override
2521
protected ConfigMap desired({{artifactClassId}}CustomResource primary,
2622
Context<{{artifactClassId}}CustomResource> context) {

docs/content/en/docs/documentation/dependent-resource-and-workflows/dependent-resources.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,6 @@ Deleted (or set to be garbage collected). The following example shows how to cre
136136
@KubernetesDependent(labelSelector = WebPageManagedDependentsReconciler.SELECTOR)
137137
class DeploymentDependentResource extends CRUDKubernetesDependentResource<Deployment, WebPage> {
138138

139-
public DeploymentDependentResource() {
140-
super(Deployment.class);
141-
}
142-
143139
@Override
144140
protected Deployment desired(WebPage webPage, Context<WebPage> context) {
145141
var deploymentName = deploymentName(webPage);

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/Utils.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,39 @@ public static Class<?> getTypeArgumentFromExtendedClassByIndex(Class<?> clazz, i
134134
}
135135
}
136136

137+
public static Class<?> getTypeArgumentFromHierarchyByIndex(Class<?> clazz, int index) {
138+
return getTypeArgumentFromHierarchyByIndex(clazz, null, index);
139+
}
140+
141+
public static Class<?> getTypeArgumentFromHierarchyByIndex(
142+
Class<?> clazz, Class<?> expectedImplementedInterface, int index) {
143+
Class<?> c = clazz;
144+
while (!(c.getGenericSuperclass() instanceof ParameterizedType)) {
145+
c = c.getSuperclass();
146+
}
147+
Class<?> actualTypeArgument =
148+
(Class<?>) ((ParameterizedType) c.getGenericSuperclass()).getActualTypeArguments()[index];
149+
if (expectedImplementedInterface != null
150+
&& !expectedImplementedInterface.isAssignableFrom(actualTypeArgument)) {
151+
throw new IllegalArgumentException(
152+
GENERIC_PARAMETER_TYPE_ERROR_PREFIX
153+
+ clazz.getName()
154+
+ "because it doesn't extend a class that is parametrized with the type that"
155+
+ " implements "
156+
+ expectedImplementedInterface.getSimpleName()
157+
+ ". Please provide the resource type in the constructor (e.g.,"
158+
+ " super(Deployment.class).");
159+
} else if (expectedImplementedInterface == null && actualTypeArgument.equals(Object.class)) {
160+
throw new IllegalArgumentException(
161+
GENERIC_PARAMETER_TYPE_ERROR_PREFIX
162+
+ clazz.getName()
163+
+ " because it doesn't extend a class that is parametrized with the type we want to"
164+
+ " retrieve or because it's Object.class. Please provide the resource type in the "
165+
+ "constructor (e.g., super(Deployment.class).");
166+
}
167+
return actualTypeArgument;
168+
}
169+
137170
public static Class<?> getFirstTypeArgumentFromInterface(
138171
Class<?> clazz, Class<?> expectedImplementedInterface) {
139172
return getTypeArgumentFromInterfaceByIndex(clazz, expectedImplementedInterface, 0);

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.util.Optional;
44

55
import io.fabric8.kubernetes.api.model.HasMetadata;
6+
import io.javaoperatorsdk.operator.api.config.Utils;
67
import io.javaoperatorsdk.operator.api.reconciler.Context;
78
import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext;
89
import io.javaoperatorsdk.operator.api.reconciler.Ignore;
@@ -23,13 +24,22 @@ public abstract class AbstractEventSourceHolderDependentResource<
2324
private boolean isCacheFillerEventSource;
2425
protected String eventSourceNameToUse;
2526

27+
@SuppressWarnings("unchecked")
28+
protected AbstractEventSourceHolderDependentResource() {
29+
this(null, null);
30+
}
31+
2632
protected AbstractEventSourceHolderDependentResource(Class<R> resourceType) {
2733
this(resourceType, null);
2834
}
2935

3036
protected AbstractEventSourceHolderDependentResource(Class<R> resourceType, String name) {
3137
super(name);
32-
this.resourceType = resourceType;
38+
if (resourceType == null) {
39+
this.resourceType = (Class<R>) Utils.getTypeArgumentFromHierarchyByIndex(getClass(), 0);
40+
} else {
41+
this.resourceType = resourceType;
42+
}
3343
}
3444

3545
/**

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ public abstract class AbstractExternalDependentResource<
2121

2222
private InformerEventSource<?, P> externalStateEventSource;
2323

24+
protected AbstractExternalDependentResource() {}
25+
2426
@SuppressWarnings("unchecked")
2527
protected AbstractExternalDependentResource(Class<R> resourceType) {
2628
super(resourceType);

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractPollingDependentResource.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ public abstract class AbstractPollingDependentResource<R, P extends HasMetadata>
1616
public static final Duration DEFAULT_POLLING_PERIOD = Duration.ofMillis(5000);
1717
private Duration pollingPeriod;
1818

19+
protected AbstractPollingDependentResource() {}
20+
1921
protected AbstractPollingDependentResource(Class<R> resourceType) {
2022
this(resourceType, DEFAULT_POLLING_PERIOD);
2123
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ public abstract class PerResourcePollingDependentResource<R, P extends HasMetada
1414
extends AbstractPollingDependentResource<R, P>
1515
implements PerResourcePollingEventSource.ResourceFetcher<R, P> {
1616

17+
public PerResourcePollingDependentResource() {}
18+
1719
public PerResourcePollingDependentResource(Class<R> resourceType) {
1820
super(resourceType);
1921
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/CRUDKubernetesDependentResource.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ public abstract class CRUDKubernetesDependentResource<R extends HasMetadata, P e
1818
extends KubernetesDependentResource<R, P>
1919
implements Creator<R, P>, Updater<R, P>, GarbageCollected<P> {
2020

21+
public CRUDKubernetesDependentResource() {}
22+
2123
public CRUDKubernetesDependentResource(Class<R> resourceType) {
2224
super(resourceType);
2325
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/CRUDNoGCKubernetesDependentResource.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
public class CRUDNoGCKubernetesDependentResource<R extends HasMetadata, P extends HasMetadata>
2121
extends KubernetesDependentResource<R, P> implements Creator<R, P>, Updater<R, P>, Deleter<P> {
2222

23+
public CRUDNoGCKubernetesDependentResource() {}
24+
2325
public CRUDNoGCKubernetesDependentResource(Class<R> resourceType) {
2426
super(resourceType);
2527
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ public abstract class KubernetesDependentResource<R extends HasMetadata, P exten
4242
private KubernetesDependentResourceConfig<R> kubernetesDependentResourceConfig;
4343
private volatile Boolean useSSA;
4444

45+
public KubernetesDependentResource() {}
46+
4547
public KubernetesDependentResource(Class<R> resourceType) {
4648
this(resourceType, null);
4749
}

operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverriderTest.java

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -359,21 +359,11 @@ public UpdateControl<ConfigMap> reconcile(ConfigMap resource, Context<ConfigMap>
359359
}
360360

361361
public static class ReadOnlyDependent extends KubernetesDependentResource<ConfigMap, ConfigMap>
362-
implements GarbageCollected<ConfigMap> {
363-
364-
public ReadOnlyDependent() {
365-
super(ConfigMap.class);
366-
}
367-
}
362+
implements GarbageCollected<ConfigMap> {}
368363

369364
@KubernetesDependent(informer = @Informer(namespaces = Constants.WATCH_ALL_NAMESPACES))
370365
public static class WatchAllNSDependent extends KubernetesDependentResource<ConfigMap, ConfigMap>
371-
implements GarbageCollected<ConfigMap> {
372-
373-
public WatchAllNSDependent() {
374-
super(ConfigMap.class);
375-
}
376-
}
366+
implements GarbageCollected<ConfigMap> {}
377367

378368
@Workflow(dependents = @Dependent(type = OverriddenNSDependent.class))
379369
@ControllerConfiguration(
@@ -394,10 +384,6 @@ public static class OverriddenNSDependent
394384
implements GarbageCollected<ConfigMap> {
395385

396386
private static final String DEP_NS = "dependentNS";
397-
398-
public OverriddenNSDependent() {
399-
super(ConfigMap.class);
400-
}
401387
}
402388

403389
@Workflow(
@@ -415,12 +401,7 @@ public UpdateControl<ConfigMap> reconcile(ConfigMap resource, Context<ConfigMap>
415401

416402
private static class NamedDependentResource
417403
extends KubernetesDependentResource<ConfigMap, ConfigMap>
418-
implements GarbageCollected<ConfigMap> {
419-
420-
public NamedDependentResource() {
421-
super(ConfigMap.class);
422-
}
423-
}
404+
implements GarbageCollected<ConfigMap> {}
424405

425406
private static class ExternalDependentResource
426407
implements DependentResource<Object, ConfigMap>,

operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/UtilsTest.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,5 @@ public UpdateControl<ConfigMap> reconcile(ConfigMap resource, Context<ConfigMap>
118118
}
119119

120120
public static class TestKubernetesDependentResource
121-
extends KubernetesDependentResource<Deployment, TestCustomResource> {
122-
123-
public TestKubernetesDependentResource() {
124-
super(Deployment.class);
125-
}
126-
}
121+
extends KubernetesDependentResource<Deployment, TestCustomResource> {}
127122
}

operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/dependent/DependentResourceConfigurationResolverTest.java

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -144,20 +144,10 @@ public UpdateControl<ConfigMap> reconcile(ConfigMap resource, Context<ConfigMap>
144144
}
145145

146146
public static class ConfigMapDep extends KubernetesDependentResource<ConfigMap, ConfigMap>
147-
implements GarbageCollected<ConfigMap> {
148-
149-
public ConfigMapDep() {
150-
super(ConfigMap.class);
151-
}
152-
}
147+
implements GarbageCollected<ConfigMap> {}
153148

154149
public static class ServiceDep extends KubernetesDependentResource<Service, ConfigMap>
155-
implements GarbageCollected<ConfigMap> {
156-
157-
public ServiceDep() {
158-
super(Service.class);
159-
}
160-
}
150+
implements GarbageCollected<ConfigMap> {}
161151

162152
@CustomAnnotation(value = CustomAnnotatedDep.PROVIDED_VALUE)
163153
@Configured(

operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcherTest.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,6 @@ HasMetadata createPrimary(String caseName) {
186186
private static class ServiceAccountDR
187187
extends KubernetesDependentResource<ServiceAccount, HasMetadata> {
188188

189-
public ServiceAccountDR() {
190-
super(ServiceAccount.class);
191-
}
192-
193189
@Override
194190
protected ServiceAccount desired(HasMetadata primary, Context<HasMetadata> context) {
195191
return new ServiceAccountBuilder()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package io.javaoperatorsdk.operator.processing.dependent.kubernetes;
2+
3+
import org.junit.jupiter.api.Test;
4+
import org.junit.jupiter.params.ParameterizedTest;
5+
import org.junit.jupiter.params.provider.ValueSource;
6+
7+
import io.fabric8.kubernetes.api.model.apps.Deployment;
8+
import io.javaoperatorsdk.operator.sample.simple.TestCustomResource;
9+
10+
import static io.javaoperatorsdk.operator.api.config.Utils.GENERIC_PARAMETER_TYPE_ERROR_PREFIX;
11+
import static org.assertj.core.api.Assertions.assertThat;
12+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
13+
14+
class KubernetesDependentResourceTest {
15+
16+
@ParameterizedTest
17+
@ValueSource(
18+
classes = {
19+
TestDeploymentDependentResource.class,
20+
ChildTestDeploymentDependentResource.class,
21+
GrandChildTestDeploymentDependentResource.class,
22+
ChildTypeWithValidKubernetesDependentResource.class,
23+
ConstructorOverridedCorrectDeployementDependentResource.class
24+
})
25+
void checkResourceTypeDerivationWithInheritance(Class<?> clazz) throws Exception {
26+
KubernetesDependentResource<?, ?> dependentResource =
27+
(KubernetesDependentResource<?, ?>) clazz.getDeclaredConstructor().newInstance();
28+
assertThat(dependentResource).isInstanceOf(KubernetesDependentResource.class);
29+
assertThat(dependentResource.resourceType()).isEqualTo(Deployment.class);
30+
}
31+
32+
private static class TestDeploymentDependentResource
33+
extends KubernetesDependentResource<Deployment, TestCustomResource> {}
34+
35+
private static class ChildTestDeploymentDependentResource
36+
extends TestDeploymentDependentResource {}
37+
38+
private static class GrandChildTestDeploymentDependentResource
39+
extends ChildTestDeploymentDependentResource {}
40+
41+
private static class ChildTypeWithValidKubernetesDependentResource<P, T>
42+
extends KubernetesDependentResource<Deployment, TestCustomResource> {}
43+
44+
private static class ConstructorOverridedCorrectDeployementDependentResource
45+
extends KubernetesDependentResource<Deployment, TestCustomResource> {
46+
public ConstructorOverridedCorrectDeployementDependentResource() {
47+
super(Deployment.class);
48+
}
49+
}
50+
51+
@Test
52+
void validateInvalidTypeDerivationTypesThrowException() {
53+
assertThatThrownBy(() -> new InvalidChildTestDeploymentDependentResource())
54+
.isInstanceOf(IllegalArgumentException.class)
55+
.hasMessage(
56+
GENERIC_PARAMETER_TYPE_ERROR_PREFIX
57+
+ InvalidChildTestDeploymentDependentResource.class.getName()
58+
+ " because it doesn't extend a class that is parametrized with the type we want to"
59+
+ " retrieve or because it's Object.class. Please provide the resource type in the "
60+
+ "constructor (e.g., super(Deployment.class).");
61+
assertThatThrownBy(() -> new InvalidGrandChildTestDeploymentDependentResource())
62+
.isInstanceOf(IllegalArgumentException.class)
63+
.hasMessage(
64+
GENERIC_PARAMETER_TYPE_ERROR_PREFIX
65+
+ InvalidGrandChildTestDeploymentDependentResource.class.getName()
66+
+ " because it doesn't extend a class that is parametrized with the type we want to"
67+
+ " retrieve or because it's Object.class. Please provide the resource type in the "
68+
+ "constructor (e.g., super(Deployment.class).");
69+
}
70+
71+
private static class InvalidChildTestDeploymentDependentResource
72+
extends ChildTypeWithValidKubernetesDependentResource<Object, Object> {}
73+
74+
private static class InvalidGrandChildTestDeploymentDependentResource
75+
extends InvalidChildTestDeploymentDependentResource {}
76+
}

operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/unmodifiabledependentpart/UnmodifiablePartConfigMapDependent.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,6 @@ public class UnmodifiablePartConfigMapDependent
1414
public static final String UNMODIFIABLE_INITIAL_DATA_KEY = "initialDataKey";
1515
public static final String ACTUAL_DATA_KEY = "actualDataKey";
1616

17-
public UnmodifiablePartConfigMapDependent() {
18-
super(ConfigMap.class);
19-
}
20-
2117
@Override
2218
protected ConfigMap desired(
2319
UnmodifiableDependentPartCustomResource primary,

operator-framework/src/test/java/io/javaoperatorsdk/operator/config/BaseConfigurationServiceTest.java

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -414,12 +414,7 @@ public UpdateControl<ConfigMapReader> reconcile(
414414

415415
@KubernetesDependent(useSSA = BooleanWithUndefined.TRUE)
416416
public static class WithAnnotation
417-
extends CRUDKubernetesDependentResource<ConfigMap, ConfigMapReader> {
418-
419-
public WithAnnotation() {
420-
super(ConfigMap.class);
421-
}
422-
}
417+
extends CRUDKubernetesDependentResource<ConfigMap, ConfigMapReader> {}
423418
}
424419

425420
public static class MissingAnnotationReconciler implements Reconciler<ConfigMap> {
@@ -443,18 +438,10 @@ public UpdateControl<ConfigMap> reconcile(ConfigMap resource, Context<ConfigMap>
443438
}
444439

445440
private static class DefaultDependent
446-
extends KubernetesDependentResource<ConfigMapReader, ConfigMap> {
447-
public DefaultDependent() {
448-
super(ConfigMapReader.class);
449-
}
450-
}
441+
extends KubernetesDependentResource<ConfigMapReader, ConfigMap> {}
451442

452443
@KubernetesDependent(useSSA = BooleanWithUndefined.FALSE)
453-
private static class NonSSADependent extends KubernetesDependentResource<Service, ConfigMap> {
454-
public NonSSADependent() {
455-
super(Service.class);
456-
}
457-
}
444+
private static class NonSSADependent extends KubernetesDependentResource<Service, ConfigMap> {}
458445
}
459446

460447
public static class TestRetry implements Retry, AnnotationConfigurable<TestRetryConfiguration> {

operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/ConfigMapDeleterBulkDependentResource.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,6 @@ public class ConfigMapDeleterBulkDependentResource
2121
public static final String ADDITIONAL_DATA_KEY = "additionalData";
2222
public static final String INDEX_DELIMITER = "-";
2323

24-
public ConfigMapDeleterBulkDependentResource() {
25-
super(ConfigMap.class);
26-
}
27-
2824
@Override
2925
public Map<String, ConfigMap> desiredResources(
3026
BulkDependentTestCustomResource primary, Context<BulkDependentTestCustomResource> context) {

operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/readonly/ReadOnlyBulkDependentResource.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,6 @@ public class ReadOnlyBulkDependentResource
2323

2424
public static final String INDEX_DELIMITER = "-";
2525

26-
public ReadOnlyBulkDependentResource() {
27-
super(ConfigMap.class);
28-
}
29-
3026
@Override
3127
public Map<String, ConfigMap> getSecondaryResources(
3228
BulkDependentTestCustomResource primary, Context<BulkDependentTestCustomResource> context) {

operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/cleanermanageddependent/ConfigMapDependentResource.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,6 @@ public class ConfigMapDependentResource
1919

2020
private static final AtomicInteger numberOfCleanupExecutions = new AtomicInteger(0);
2121

22-
public ConfigMapDependentResource() {
23-
super(ConfigMap.class);
24-
}
25-
2622
@Override
2723
protected ConfigMap desired(
2824
CleanerForManagedDependentCustomResource primary,

0 commit comments

Comments
 (0)