From 23fdf200299ec577f2edf26bdd39b7c70fceaab9 Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Fri, 28 Jan 2022 19:11:55 +0100 Subject: [PATCH 1/2] fix: do not call default resource class resolution logic by default --- .../operator/api/config/DefaultResourceConfiguration.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultResourceConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultResourceConfiguration.java index 7b80416433..d7b5f76815 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultResourceConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultResourceConfiguration.java @@ -23,8 +23,7 @@ public DefaultResourceConfiguration(String labelSelector, Class resourceClass public DefaultResourceConfiguration(String labelSelector, Class resourceClass, Set namespaces) { this.labelSelector = labelSelector; - this.resourceClass = resourceClass == null ? ResourceConfiguration.super.getResourceClass() - : resourceClass; + this.resourceClass = resourceClass; this.namespaces = namespaces != null ? namespaces : Collections.emptySet(); this.watchAllNamespaces = this.namespaces.isEmpty(); } From 04cc4dddf3ab8c79c23fdd09a534e64d524f5344 Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Sat, 29 Jan 2022 00:15:35 +0100 Subject: [PATCH 2/2] fix: do not create DependentResources directly from configuration The idea is to delay instantiation until needed and rely on DependentResourceControllerFactory for this purpose instead. Not sure if we actually need to use an interface there or not. --- .../api/config/ControllerConfiguration.java | 2 +- .../DefaultControllerConfiguration.java | 6 +- .../DependentResourceConfiguration.java | 10 ++ .../DependentResourceController.java | 11 ++- .../DependentResourceControllerFactory.java | 24 +++-- ...ernetesDependentResourceConfiguration.java | 65 +++++++++---- ...KubernetesDependentResourceController.java | 10 +- .../dependent/DependentResourceManager.java | 9 +- .../informer/InformerConfiguration.java | 92 +++++++++++-------- .../runtime/AnnotationConfiguration.java | 55 +++++------ 10 files changed, 180 insertions(+), 104 deletions(-) create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DependentResourceConfiguration.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfiguration.java index d4739f8267..7e44a45de9 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfiguration.java @@ -48,7 +48,7 @@ default ResourceEventFilter getEventFilter() { return ResourceEventFilters.passthrough(); } - default List getDependentResources() { + default List getDependentResources() { return Collections.emptyList(); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultControllerConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultControllerConfiguration.java index 0a3c68c70b..25ff5a5315 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultControllerConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultControllerConfiguration.java @@ -18,7 +18,7 @@ public class DefaultControllerConfiguration private final boolean generationAware; private final RetryConfiguration retryConfiguration; private final ResourceEventFilter resourceEventFilter; - private final List dependents; + private final List dependents; // NOSONAR constructor is meant to provide all information public DefaultControllerConfiguration( @@ -33,7 +33,7 @@ public DefaultControllerConfiguration( ResourceEventFilter resourceEventFilter, Class resourceClass, ConfigurationService service, - List dependents) { + List dependents) { super(labelSelector, resourceClass, namespaces); this.associatedControllerClassName = associatedControllerClassName; this.name = name; @@ -96,7 +96,7 @@ public ResourceEventFilter getEventFilter() { } @Override - public List getDependentResources() { + public List getDependentResources() { return dependents; } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DependentResourceConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DependentResourceConfiguration.java new file mode 100644 index 0000000000..15911e0418 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DependentResourceConfiguration.java @@ -0,0 +1,10 @@ +package io.javaoperatorsdk.operator.api.config; + +import io.fabric8.kubernetes.api.model.HasMetadata; + +public interface DependentResourceConfiguration { + + Class> getDependentResourceClass(); + + Class getResourceClass(); +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResourceController.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResourceController.java index 043aec2f53..21cd16a32f 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResourceController.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResourceController.java @@ -2,11 +2,12 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.config.DependentResource; +import io.javaoperatorsdk.operator.api.config.DependentResourceConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; import io.javaoperatorsdk.operator.processing.event.source.EventSource; -public class DependentResourceController +public class DependentResourceController> implements DependentResource, Builder, Updater, Persister, Cleaner { @@ -15,14 +16,16 @@ public class DependentResourceController private final Cleaner cleaner; private final Persister persister; private final DependentResource delegate; + private final C configuration; @SuppressWarnings("unchecked") - public DependentResourceController(DependentResource delegate) { + public DependentResourceController(DependentResource delegate, C configuration) { this.delegate = delegate; builder = (delegate instanceof Builder) ? (Builder) delegate : null; updater = (delegate instanceof Updater) ? (Updater) delegate : null; cleaner = (delegate instanceof Cleaner) ? (Cleaner) delegate : null; persister = initPersister(delegate); + this.configuration = configuration; } @SuppressWarnings("unchecked") @@ -84,4 +87,8 @@ public void createOrReplace(R dependentResource, Context context) { public R getFor(P primary, Context context) { return persister.getFor(primary, context); } + + public C getConfiguration() { + return configuration; + } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResourceControllerFactory.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResourceControllerFactory.java index f814cd7a1a..dd11a7a706 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResourceControllerFactory.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResourceControllerFactory.java @@ -1,14 +1,26 @@ package io.javaoperatorsdk.operator.api.reconciler.dependent; +import java.lang.reflect.InvocationTargetException; + import io.fabric8.kubernetes.api.model.HasMetadata; -import io.javaoperatorsdk.operator.api.config.DependentResource; +import io.javaoperatorsdk.operator.api.config.DependentResourceConfiguration; public interface DependentResourceControllerFactory

{ - default DependentResourceController from(DependentResource dependent) { - // todo: this needs to be cleaned-up / redesigned - return dependent instanceof DependentResourceController - ? (DependentResourceController) dependent - : new DependentResourceController<>(dependent); + default , R, C extends DependentResourceConfiguration> T from( + C config) { + try { + final var dependentResource = config.getDependentResourceClass().getConstructor() + .newInstance(); + if (config instanceof KubernetesDependentResourceConfiguration) { + return (T) new KubernetesDependentResourceController(dependentResource, + (KubernetesDependentResourceConfiguration) config); + } else { + return (T) new DependentResourceController(dependentResource, config); + } + } catch (NoSuchMethodException | InvocationTargetException | InstantiationException + | IllegalAccessException e) { + throw new IllegalArgumentException(e); + } } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResourceConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResourceConfiguration.java index dad9411d2d..23d37881b4 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResourceConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResourceConfiguration.java @@ -4,35 +4,64 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.config.ConfigurationService; +import io.javaoperatorsdk.operator.api.config.DependentResource; +import io.javaoperatorsdk.operator.api.config.DependentResourceConfiguration; import io.javaoperatorsdk.operator.processing.event.source.AssociatedSecondaryResourceIdentifier; import io.javaoperatorsdk.operator.processing.event.source.PrimaryResourcesRetriever; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerConfiguration; -public class KubernetesDependentResourceConfiguration - extends InformerConfiguration { +public interface KubernetesDependentResourceConfiguration + extends InformerConfiguration, DependentResourceConfiguration { - private final boolean owned; + class DefaultKubernetesDependentResourceConfiguration + extends DefaultInformerConfiguration + implements KubernetesDependentResourceConfiguration { - protected KubernetesDependentResourceConfiguration( - ConfigurationService service, - String labelSelector, Class resourceClass, - PrimaryResourcesRetriever secondaryToPrimaryResourcesIdSet, - AssociatedSecondaryResourceIdentifier

associatedWith, - boolean skipUpdateEventPropagationIfNoChange, Set namespaces, boolean owned) { - super(service, labelSelector, resourceClass, secondaryToPrimaryResourcesIdSet, associatedWith, - skipUpdateEventPropagationIfNoChange, namespaces); - this.owned = owned; + private final boolean owned; + private final Class> dependentResourceClass; + + protected DefaultKubernetesDependentResourceConfiguration( + ConfigurationService service, + String labelSelector, Class resourceClass, + PrimaryResourcesRetriever secondaryToPrimaryResourcesIdSet, + AssociatedSecondaryResourceIdentifier

associatedWith, + boolean skipUpdateEventPropagationIfNoChange, Set namespaces, boolean owned, + Class> dependentResourceClass) { + super(service, labelSelector, resourceClass, secondaryToPrimaryResourcesIdSet, associatedWith, + skipUpdateEventPropagationIfNoChange, namespaces); + this.owned = owned; + this.dependentResourceClass = dependentResourceClass; + } + + public boolean isOwned() { + return owned; + } + + @Override + public Class> getDependentResourceClass() { + return dependentResourceClass; + } + + @Override + public Class getResourceClass() { + return super.getResourceClass(); + } } - public static KubernetesDependentResourceConfiguration from( - InformerConfiguration cfg, boolean owned) { - return new KubernetesDependentResourceConfiguration<>(cfg.getConfigurationService(), + static KubernetesDependentResourceConfiguration from( + InformerConfiguration cfg, boolean owned, + Class dependentResourceClass) { + return new DefaultKubernetesDependentResourceConfiguration(cfg.getConfigurationService(), cfg.getLabelSelector(), cfg.getResourceClass(), cfg.getPrimaryResourcesRetriever(), cfg.getAssociatedResourceIdentifier(), cfg.isSkipUpdateEventPropagationIfNoChange(), - cfg.getNamespaces(), owned); + cfg.getNamespaces(), owned, + (Class>) dependentResourceClass); } - public boolean isOwned() { - return owned; + boolean isOwned(); + + @Override + default Class getResourceClass() { + return InformerConfiguration.super.getResourceClass(); } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResourceController.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResourceController.java index 015b60f4bb..172e9cb0d9 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResourceController.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResourceController.java @@ -12,7 +12,8 @@ import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; public class KubernetesDependentResourceController - extends DependentResourceController { + extends DependentResourceController> { + private final KubernetesDependentResourceConfiguration configuration; private KubernetesClient client; private InformerEventSource informer; @@ -20,7 +21,7 @@ public class KubernetesDependentResourceController delegate, KubernetesDependentResourceConfiguration configuration) { - super(delegate); + super(delegate, configuration); // todo: check if we can validate that types actually match properly final var associatedPrimaries = (delegate instanceof PrimaryResourcesRetriever) @@ -36,7 +37,8 @@ public KubernetesDependentResourceController(DependentResource delegate, .withAssociatedSecondaryResourceIdentifier(associatedSecondary) .build(); this.configuration = - KubernetesDependentResourceConfiguration.from(augmented, configuration.isOwned()); + KubernetesDependentResourceConfiguration.from(augmented, configuration.isOwned(), + configuration.getDependentResourceClass()); } @Override @@ -69,6 +71,6 @@ public R getFor(P primary, Context context) { } public boolean owned() { - return configuration.isOwned(); + return getConfiguration().isOwned(); } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java index 30e92e3d63..911805b396 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java @@ -8,7 +8,7 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.config.ControllerConfiguration; -import io.javaoperatorsdk.operator.api.config.DependentResource; +import io.javaoperatorsdk.operator.api.config.DependentResourceConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.ContextInitializer; import io.javaoperatorsdk.operator.api.reconciler.DeleteControl; @@ -42,13 +42,14 @@ public DependentResourceManager(Controller controller) { @Override public List prepareEventSources(EventSourceContext context) { - final List configured = configuration.getDependentResources(); + final List configured = configuration.getDependentResources(); dependents = new ArrayList<>(configured.size()); List sources = new ArrayList<>(configured.size() + 5); configured.forEach(dependent -> { - dependents.add(configuration.dependentFactory().from(dependent)); - sources.add(dependent.initEventSource(context)); + final var dependentResourceController = configuration.dependentFactory().from(dependent); + dependents.add(dependentResourceController); + sources.add(dependentResourceController.initEventSource(context)); }); return sources; diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerConfiguration.java index 0c06698327..49b7ae7654 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerConfiguration.java @@ -7,45 +7,57 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.config.ConfigurationService; import io.javaoperatorsdk.operator.api.config.DefaultResourceConfiguration; +import io.javaoperatorsdk.operator.api.config.ResourceConfiguration; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.AssociatedSecondaryResourceIdentifier; import io.javaoperatorsdk.operator.processing.event.source.PrimaryResourcesRetriever; -public class InformerConfiguration - extends DefaultResourceConfiguration { - - private final PrimaryResourcesRetriever secondaryToPrimaryResourcesIdSet; - private final AssociatedSecondaryResourceIdentifier

associatedWith; - private final boolean skipUpdateEventPropagationIfNoChange; - - protected InformerConfiguration(ConfigurationService service, String labelSelector, - Class resourceClass, - PrimaryResourcesRetriever secondaryToPrimaryResourcesIdSet, - AssociatedSecondaryResourceIdentifier

associatedWith, - boolean skipUpdateEventPropagationIfNoChange, Set namespaces) { - super(labelSelector, resourceClass, namespaces); - setConfigurationService(service); - this.secondaryToPrimaryResourcesIdSet = - Objects.requireNonNullElse(secondaryToPrimaryResourcesIdSet, Mappers.fromOwnerReference()); - this.associatedWith = - Objects.requireNonNullElseGet(associatedWith, () -> ResourceID::fromResource); - this.skipUpdateEventPropagationIfNoChange = skipUpdateEventPropagationIfNoChange; - } +public interface InformerConfiguration + extends ResourceConfiguration { + + class DefaultInformerConfiguration extends + DefaultResourceConfiguration implements InformerConfiguration { + + private final PrimaryResourcesRetriever secondaryToPrimaryResourcesIdSet; + private final AssociatedSecondaryResourceIdentifier

associatedWith; + private final boolean skipUpdateEventPropagationIfNoChange; + + protected DefaultInformerConfiguration(ConfigurationService service, String labelSelector, + Class resourceClass, + PrimaryResourcesRetriever secondaryToPrimaryResourcesIdSet, + AssociatedSecondaryResourceIdentifier

associatedWith, + boolean skipUpdateEventPropagationIfNoChange, Set namespaces) { + super(labelSelector, resourceClass, namespaces); + setConfigurationService(service); + this.secondaryToPrimaryResourcesIdSet = + Objects.requireNonNullElse(secondaryToPrimaryResourcesIdSet, + Mappers.fromOwnerReference()); + this.associatedWith = + Objects.requireNonNullElseGet(associatedWith, () -> ResourceID::fromResource); + this.skipUpdateEventPropagationIfNoChange = skipUpdateEventPropagationIfNoChange; + } - public PrimaryResourcesRetriever getPrimaryResourcesRetriever() { - return secondaryToPrimaryResourcesIdSet; - } + public PrimaryResourcesRetriever getPrimaryResourcesRetriever() { + return secondaryToPrimaryResourcesIdSet; + } - public AssociatedSecondaryResourceIdentifier

getAssociatedResourceIdentifier() { - return associatedWith; - } + public AssociatedSecondaryResourceIdentifier

getAssociatedResourceIdentifier() { + return associatedWith; + } - public boolean isSkipUpdateEventPropagationIfNoChange() { - return skipUpdateEventPropagationIfNoChange; + public boolean isSkipUpdateEventPropagationIfNoChange() { + return skipUpdateEventPropagationIfNoChange; + } } - public static class InformerConfigurationBuilder { + PrimaryResourcesRetriever getPrimaryResourcesRetriever(); + + AssociatedSecondaryResourceIdentifier

getAssociatedResourceIdentifier(); + + boolean isSkipUpdateEventPropagationIfNoChange(); + + class InformerConfigurationBuilder { private PrimaryResourcesRetriever secondaryToPrimaryResourcesIdSet; private AssociatedSecondaryResourceIdentifier

associatedWith; @@ -101,32 +113,32 @@ public InformerConfigurationBuilder withLabelSelector(String labelSelector } public InformerConfiguration build() { - return new InformerConfiguration<>(configurationService, labelSelector, resourceClass, + return new DefaultInformerConfiguration<>(configurationService, labelSelector, resourceClass, secondaryToPrimaryResourcesIdSet, associatedWith, skipUpdateEventPropagationIfNoChange, namespaces); } } - public static InformerConfigurationBuilder from( + static InformerConfigurationBuilder from( EventSourceContext

context, Class resourceClass) { return new InformerConfigurationBuilder<>(resourceClass, context.getConfigurationService()); } - public static InformerConfigurationBuilder from(ConfigurationService configurationService, + static InformerConfigurationBuilder from(ConfigurationService configurationService, Class resourceClass) { return new InformerConfigurationBuilder<>(resourceClass, configurationService); } - public static InformerConfigurationBuilder from( + static InformerConfigurationBuilder from( InformerConfiguration configuration) { return new InformerConfigurationBuilder(configuration.getResourceClass(), configuration.getConfigurationService()) - .withNamespaces(configuration.getNamespaces()) - .withLabelSelector(configuration.getLabelSelector()) - .skippingEventPropagationIfUnchanged( - configuration.isSkipUpdateEventPropagationIfNoChange()) - .withAssociatedSecondaryResourceIdentifier( - configuration.getAssociatedResourceIdentifier()) - .withPrimaryResourcesRetriever(configuration.getPrimaryResourcesRetriever()); + .withNamespaces(configuration.getNamespaces()) + .withLabelSelector(configuration.getLabelSelector()) + .skippingEventPropagationIfUnchanged( + configuration.isSkipUpdateEventPropagationIfNoChange()) + .withAssociatedSecondaryResourceIdentifier( + configuration.getAssociatedResourceIdentifier()) + .withPrimaryResourcesRetriever(configuration.getPrimaryResourcesRetriever()); } } diff --git a/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/AnnotationConfiguration.java b/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/AnnotationConfiguration.java index 30d2600cfe..1ffde6de36 100644 --- a/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/AnnotationConfiguration.java +++ b/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/AnnotationConfiguration.java @@ -1,6 +1,5 @@ package io.javaoperatorsdk.operator.config.runtime; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -12,11 +11,11 @@ import io.javaoperatorsdk.operator.api.config.ConfigurationService; import io.javaoperatorsdk.operator.api.config.Dependent; import io.javaoperatorsdk.operator.api.config.DependentResource; +import io.javaoperatorsdk.operator.api.config.DependentResourceConfiguration; import io.javaoperatorsdk.operator.api.config.KubernetesDependent; import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResourceConfiguration; -import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResourceController; import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilter; import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilters; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerConfiguration; @@ -28,7 +27,7 @@ public class AnnotationConfiguration private final Reconciler reconciler; private final ControllerConfiguration annotation; private ConfigurationService service; - private List dependents; + private List dependentConfigurations; public AnnotationConfiguration(Reconciler reconciler) { this.reconciler = reconciler; @@ -121,27 +120,20 @@ public ResourceEventFilter getEventFilter() { } @Override - public List getDependentResources() { - if (dependents == null) { - final var dependentConfigs = valueOrDefault(annotation, - ControllerConfiguration::dependents, new Dependent[] {}); - if (dependentConfigs.length > 0) { - dependents = new ArrayList<>(dependentConfigs.length); - for (Dependent dependentConfig : dependentConfigs) { - final Class dependentType = dependentConfig.type(); - DependentResource dependent; - try { - dependent = dependentType.getConstructor().newInstance(); - } catch (NoSuchMethodException | InvocationTargetException | InstantiationException - | IllegalAccessException e) { - throw new IllegalArgumentException(e); - } + public List getDependentResources() { + if (dependentConfigurations == null) { + final var dependents = valueOrDefault(annotation, ControllerConfiguration::dependents, + new Dependent[]{}); + if (dependents.length > 0) { + dependentConfigurations = new ArrayList<>(dependents.length); + for (Dependent dependent : dependents) { + final Class dependentType = dependent.type(); + final var resourceType = dependent.resourceType(); - final var resourceType = dependentConfig.resourceType(); if (HasMetadata.class.isAssignableFrom(resourceType)) { final var kubeDependent = dependentType.getAnnotation(KubernetesDependent.class); final var namespaces = - valueOrDefault(kubeDependent, KubernetesDependent::namespaces, new String[] {}); + valueOrDefault(kubeDependent, KubernetesDependent::namespaces, new String[]{}); final var labelSelector = valueOrDefault(kubeDependent, KubernetesDependent::labelSelector, null); final var owned = valueOrDefault(kubeDependent, KubernetesDependent::owned, @@ -154,17 +146,28 @@ public List getDependentResources() { .skippingEventPropagationIfUnchanged(skipIfUnchanged) .withNamespaces(namespaces) .build(); - dependent = new KubernetesDependentResourceController(dependent, - KubernetesDependentResourceConfiguration.from(configuration, owned)); - } - dependents.add(dependent); + dependentConfigurations.add( + KubernetesDependentResourceConfiguration.from(configuration, owned, dependentType)); + } else { + dependentConfigurations.add(new DependentResourceConfiguration() { + @Override + public Class getDependentResourceClass() { + return dependentType; + } + + @Override + public Class getResourceClass() { + return resourceType; + } + }); + } } } else { - dependents = Collections.emptyList(); + dependentConfigurations = Collections.emptyList(); } } - return dependents; + return dependentConfigurations; } private static T valueOrDefault(C annotation, Function mapper, T defaultValue) {