diff --git a/README.md b/README.md index 10d53fbc66..bb23272811 100644 --- a/README.md +++ b/README.md @@ -78,8 +78,7 @@ public class Runner { The Controller implements the business logic and describes all the classes needed to handle the CRD. ```java -@Controller(customResourceClass = WebServer.class, - crdName = "webservers.sample.javaoperatorsdk") +@Controller(crdName = "webservers.sample.javaoperatorsdk") public class WebServerController implements ResourceController { @Override diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index a5be06a274..21c628d75e 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -31,6 +31,7 @@ + io.fabric8 @@ -77,10 +78,26 @@ 4.0.3 test + + + com.google.testing.compile + compile-testing + 0.19 + test + + + + com.google.auto.service + auto-service + 1.0-rc2 + compile + + - org.javassist - javassist - 3.27.0-GA + com.squareup + javapoet + 1.13.0 + compile diff --git a/operator-framework/src/main/java/io/javaoperatorsdk/operator/ControllerToCustomResourceMappingsProvider.java b/operator-framework/src/main/java/io/javaoperatorsdk/operator/ControllerToCustomResourceMappingsProvider.java new file mode 100644 index 0000000000..c8491e9598 --- /dev/null +++ b/operator-framework/src/main/java/io/javaoperatorsdk/operator/ControllerToCustomResourceMappingsProvider.java @@ -0,0 +1,56 @@ +package io.javaoperatorsdk.operator; + +import io.fabric8.kubernetes.client.CustomResource; +import io.javaoperatorsdk.operator.api.ResourceController; +import org.apache.commons.lang3.ClassUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.*; +import java.util.stream.Collectors; + + +class ControllerToCustomResourceMappingsProvider { + private static final Logger log = LoggerFactory.getLogger(ControllerUtils.class); + + static Map, Class> provide(final String resourcePath) { + Map, Class> controllerToCustomResourceMappings = new HashMap(); + try { + final Enumeration customResourcesMetadataList = ControllerUtils.class.getClassLoader().getResources(resourcePath); + for (Iterator it = customResourcesMetadataList.asIterator(); it.hasNext(); ) { + URL url = it.next(); + + List classNamePairs = retrieveClassNamePairs(url); + classNamePairs.forEach(clazzPair -> { + try { + final String[] classNames = clazzPair.split(","); + if (classNames.length != 2) { + throw new IllegalStateException(String.format("%s is not valid CustomResource metadata defined in %s", clazzPair, url.toString())); + } + + controllerToCustomResourceMappings.put( + (Class) ClassUtils.getClass(classNames[0]), + (Class) ClassUtils.getClass(classNames[1]) + ); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + }); + } + log.debug("Loaded Controller to CustomResource mappings {}", controllerToCustomResourceMappings); + return controllerToCustomResourceMappings; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static List retrieveClassNamePairs(URL url) throws IOException { + return new BufferedReader( + new InputStreamReader(url.openStream()) + ).lines().collect(Collectors.toList()); + } +} diff --git a/operator-framework/src/main/java/io/javaoperatorsdk/operator/ControllerUtils.java b/operator-framework/src/main/java/io/javaoperatorsdk/operator/ControllerUtils.java index ee55c152f3..fa130fa346 100644 --- a/operator-framework/src/main/java/io/javaoperatorsdk/operator/ControllerUtils.java +++ b/operator-framework/src/main/java/io/javaoperatorsdk/operator/ControllerUtils.java @@ -1,43 +1,49 @@ package io.javaoperatorsdk.operator; -import io.javaoperatorsdk.operator.api.Controller; -import io.javaoperatorsdk.operator.api.ResourceController; -import io.fabric8.kubernetes.api.builder.Function; import io.fabric8.kubernetes.client.CustomResource; import io.fabric8.kubernetes.client.CustomResourceDoneable; -import javassist.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import io.javaoperatorsdk.operator.api.Controller; +import io.javaoperatorsdk.operator.api.ResourceController; -import java.util.HashMap; import java.util.Map; public class ControllerUtils { - private final static double JAVA_VERSION = Double.parseDouble(System.getProperty("java.specification.version")); private static final String FINALIZER_NAME_SUFFIX = "/finalizer"; + public static final String CONTROLLERS_RESOURCE_PATH = "javaoperatorsdk/controllers"; + private static Map, Class> controllerToCustomResourceMappings; - // this is just to support testing, this way we don't try to create class multiple times in memory with same name. - // note that other solution is to add a random string to doneable class name - private static Map, Class>> - doneableClassCache = new HashMap<>(); + static { + controllerToCustomResourceMappings = + ControllerToCustomResourceMappingsProvider + .provide(CONTROLLERS_RESOURCE_PATH); + } static String getFinalizer(ResourceController controller) { final String annotationFinalizerName = getAnnotation(controller).finalizerName(); if (!Controller.NULL.equals(annotationFinalizerName)) { return annotationFinalizerName; } - final String crdName = getAnnotation(controller).crdName() + FINALIZER_NAME_SUFFIX; - return crdName; + return getAnnotation(controller).crdName() + FINALIZER_NAME_SUFFIX; } - static boolean getGenerationEventProcessing(ResourceController controller) { + static boolean getGenerationEventProcessing(ResourceController controller) { return getAnnotation(controller).generationAwareEventProcessing(); } static Class getCustomResourceClass(ResourceController controller) { - return (Class) getAnnotation(controller).customResourceClass(); + final Class customResourceClass = controllerToCustomResourceMappings + .get(controller.getClass()); + if (customResourceClass == null) { + throw new IllegalArgumentException( + String.format( + "No custom resource has been found for controller %s", + controller.getClass().getCanonicalName() + ) + ); + } + return (Class) customResourceClass; } static String getCrdName(ResourceController controller) { @@ -48,38 +54,15 @@ static String getCrdName(ResourceController controller) { public static Class> getCustomResourceDoneableClass(ResourceController controller) { try { - Class customResourceClass = getAnnotation(controller).customResourceClass(); - String className = customResourceClass.getPackage().getName() + "." + customResourceClass.getSimpleName() + "CustomResourceDoneable"; - - if (doneableClassCache.containsKey(customResourceClass)) { - return (Class>) doneableClassCache.get(customResourceClass); - } - - ClassPool pool = ClassPool.getDefault(); - pool.appendClassPath(new LoaderClassPath(Thread.currentThread().getContextClassLoader())); - - CtClass superClass = pool.get(CustomResourceDoneable.class.getName()); - CtClass function = pool.get(Function.class.getName()); - CtClass customResource = pool.get(customResourceClass.getName()); - CtClass[] argTypes = {customResource, function}; - CtClass customDoneable = pool.makeClass(className, superClass); - CtConstructor ctConstructor = CtNewConstructor.make(argTypes, null, "super($1, $2);", customDoneable); - customDoneable.addConstructor(ctConstructor); - - Class> doneableClass; - if (JAVA_VERSION >= 9) { - doneableClass = (Class>) customDoneable.toClass(customResourceClass); - } else { - doneableClass = (Class>) customDoneable.toClass(); - } - doneableClassCache.put(customResourceClass, doneableClass); - return doneableClass; - } catch (CannotCompileException | NotFoundException e) { - throw new IllegalStateException(e); + final Class customResourceClass = getCustomResourceClass(controller); + return (Class>) Class.forName(customResourceClass.getCanonicalName() + "Doneable"); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + return null; } } - private static Controller getAnnotation(ResourceController controller) { + private static Controller getAnnotation(ResourceController controller) { return controller.getClass().getAnnotation(Controller.class); } diff --git a/operator-framework/src/main/java/io/javaoperatorsdk/operator/api/Controller.java b/operator-framework/src/main/java/io/javaoperatorsdk/operator/api/Controller.java index 9edec45c75..87bca2e15a 100644 --- a/operator-framework/src/main/java/io/javaoperatorsdk/operator/api/Controller.java +++ b/operator-framework/src/main/java/io/javaoperatorsdk/operator/api/Controller.java @@ -1,6 +1,5 @@ package io.javaoperatorsdk.operator.api; -import io.fabric8.kubernetes.client.CustomResource; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -14,8 +13,6 @@ String crdName(); - Class customResourceClass(); - /** * Optional finalizer name, if it is not, * the crdName will be used as the name of the finalizer too. diff --git a/operator-framework/src/main/java/io/javaoperatorsdk/operator/processing/ControllerAnnotationProcessor.java b/operator-framework/src/main/java/io/javaoperatorsdk/operator/processing/ControllerAnnotationProcessor.java new file mode 100644 index 0000000000..cc36cb9a2b --- /dev/null +++ b/operator-framework/src/main/java/io/javaoperatorsdk/operator/processing/ControllerAnnotationProcessor.java @@ -0,0 +1,150 @@ +package io.javaoperatorsdk.operator.processing; + +import com.google.auto.service.AutoService; +import com.squareup.javapoet.*; +import io.fabric8.kubernetes.api.builder.Function; +import io.fabric8.kubernetes.client.CustomResourceDoneable; +import io.javaoperatorsdk.operator.api.ResourceController; +import javax.annotation.processing.*; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.*; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.tools.Diagnostic; +import javax.tools.FileObject; +import javax.tools.JavaFileObject; +import javax.tools.StandardLocation; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import static io.javaoperatorsdk.operator.ControllerUtils.CONTROLLERS_RESOURCE_PATH; + +@SupportedAnnotationTypes( + "io.javaoperatorsdk.operator.api.Controller") +@SupportedSourceVersion(SourceVersion.RELEASE_8) +@AutoService(Processor.class) +public class ControllerAnnotationProcessor extends AbstractProcessor { + private FileObject resource; + PrintWriter printWriter = null; + private Set generatedDoneableClassFiles = new HashSet<>(); + + @Override + public synchronized void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + try { + resource = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", CONTROLLERS_RESOURCE_PATH); + } catch (IOException e) { + throw new RuntimeException(e); + } + try { + printWriter = new PrintWriter(resource.openOutputStream()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + try { + for (TypeElement annotation : annotations) { + Set annotatedElements + = roundEnv.getElementsAnnotatedWith(annotation); + annotatedElements.stream().filter(element -> element.getKind().equals(ElementKind.CLASS)) + .map(e -> (TypeElement) e) + .forEach(e -> this.generateDoneableClass(e, printWriter)); + } + } finally { + printWriter.close(); + } + return true; + } + + private void generateDoneableClass(TypeElement controllerClassSymbol, PrintWriter printWriter) { + try { + final TypeMirror resourceType = findResourceType(controllerClassSymbol); + + TypeElement customerResourceTypeElement = processingEnv + .getElementUtils() + .getTypeElement(resourceType.toString()); + + final String doneableClassName = customerResourceTypeElement.getSimpleName() + "Doneable"; + final String destinationClassFileName = customerResourceTypeElement.getQualifiedName() + "Doneable"; + final TypeName customResourceType = TypeName.get(resourceType); + + if (!generatedDoneableClassFiles.add(destinationClassFileName)) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, + String.format( + "%s already exist! adding the mapping to the %s", + destinationClassFileName, + CONTROLLERS_RESOURCE_PATH) + ); + printWriter.println(controllerClassSymbol.getQualifiedName() + "," + customResourceType.toString()); + return; + } + JavaFileObject builderFile = processingEnv.getFiler() + .createSourceFile(destinationClassFileName); + + try (PrintWriter out = new PrintWriter(builderFile.openWriter())) { + printWriter.println(controllerClassSymbol.getQualifiedName() + "," + customResourceType.toString()); + final MethodSpec constructor = MethodSpec.constructorBuilder() + .addModifiers(Modifier.PUBLIC) + .addParameter(customResourceType, "resource") + .addParameter(Function.class, "function") + .addStatement("super(resource,function)") + .build(); + + + final TypeSpec typeSpec = TypeSpec.classBuilder(doneableClassName) + .superclass(ParameterizedTypeName.get(ClassName.get(CustomResourceDoneable.class), customResourceType)) + .addModifiers(Modifier.PUBLIC) + .addMethod(constructor) + .build(); + + final PackageElement packageElement = processingEnv.getElementUtils().getPackageOf(customerResourceTypeElement); + JavaFile file = JavaFile.builder(packageElement.getQualifiedName().toString(), typeSpec) + .build(); + file.writeTo(out); + } + } catch (Exception ioException) { + ioException.printStackTrace(); + } + } + + private TypeMirror findResourceType(TypeElement controllerClassSymbol) throws Exception { + try { + final DeclaredType controllerType = collectAllInterfaces(controllerClassSymbol) + .stream() + .filter(i -> i.toString() + .startsWith(ResourceController.class.getCanonicalName()) + ) + .findFirst() + .orElseThrow(() -> new Exception("ResourceController is not implemented by " + controllerClassSymbol.toString())); + + return controllerType.getTypeArguments().get(0); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + private List collectAllInterfaces(TypeElement element) { + try { + List interfaces = new ArrayList<>(element.getInterfaces()).stream().map(t -> (DeclaredType) t).collect(Collectors.toList()); + TypeElement superclass = ((TypeElement) ((DeclaredType) element.getSuperclass()).asElement()); + while (superclass.getSuperclass().getKind() != TypeKind.NONE) { + interfaces.addAll(superclass.getInterfaces().stream().map(t -> (DeclaredType) t).collect(Collectors.toList())); + superclass = ((TypeElement) ((DeclaredType) superclass.getSuperclass()).asElement()); + } + return interfaces; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/ControllerUtilsTest.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/ControllerUtilsTest.java index 4c8b48a009..3d8decd00d 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/ControllerUtilsTest.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/ControllerUtilsTest.java @@ -25,7 +25,7 @@ public void returnsValuesFromControllerAnnotationFinalizer() { assertTrue(CustomResourceDoneable.class.isAssignableFrom(ControllerUtils.getCustomResourceDoneableClass(new TestCustomResourceController(null)))); } - @Controller(crdName = "test.crd", customResourceClass = TestCustomResource.class, finalizerName = CUSTOM_FINALIZER_NAME) + @Controller(crdName = "test.crd", finalizerName = CUSTOM_FINALIZER_NAME) static class TestCustomFinalizerController implements ResourceController { @Override diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/processing/ControllerAnnotationProcessorTest.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/processing/ControllerAnnotationProcessorTest.java new file mode 100644 index 0000000000..85b29d050c --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/processing/ControllerAnnotationProcessorTest.java @@ -0,0 +1,36 @@ +package io.javaoperatorsdk.operator.processing; + +import com.google.testing.compile.*; +import com.google.testing.compile.Compiler; +import org.junit.jupiter.api.Test; + +import javax.tools.JavaFileObject; + +class ControllerAnnotationProcessorTest { + @Test + public void generateCorrectDoneableClassIfInterfaceIsSecond() { + Compilation compilation = Compiler.javac() + .withProcessors(new ControllerAnnotationProcessor()) + .compile(JavaFileObjects.forResource("ControllerImplemented2Interfaces.java")); + CompilationSubject.assertThat(compilation).succeeded(); + + final JavaFileObject expectedResource = JavaFileObjects.forResource("ControllerImplemented2InterfacesExpected.java"); + JavaFileObjectSubject.assertThat(compilation.generatedSourceFiles().get(0)).hasSourceEquivalentTo(expectedResource); + } + + @Test + public void generateCorrectDoneableClassIfThereIsAbstractBaseController() { + + Compilation compilation = Compiler.javac() + .withProcessors(new ControllerAnnotationProcessor()) + .compile( + JavaFileObjects.forResource("AbstractController.java"), + JavaFileObjects.forResource("ControllerImplementedIntermediateAbstractClass.java") + ); + CompilationSubject.assertThat(compilation).succeeded(); + + final JavaFileObject expectedResource = JavaFileObjects.forResource("ControllerImplementedIntermediateAbstractClassExpected.java"); + JavaFileObjectSubject.assertThat(compilation.generatedSourceFiles().get(0)).hasSourceEquivalentTo(expectedResource); + + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/TestCustomResourceController.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/TestCustomResourceController.java index 9f27896914..982043e711 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/TestCustomResourceController.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/TestCustomResourceController.java @@ -18,8 +18,7 @@ @Controller( generationAwareEventProcessing = false, - crdName = TestCustomResourceController.CRD_NAME, - customResourceClass = TestCustomResource.class) + crdName = TestCustomResourceController.CRD_NAME) public class TestCustomResourceController implements ResourceController, TestExecutionInfoProvider { private static final Logger log = LoggerFactory.getLogger(TestCustomResourceController.class); diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/subresource/SubResourceTestCustomResourceController.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/subresource/SubResourceTestCustomResourceController.java index 9b47305490..a83b3c35ba 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/subresource/SubResourceTestCustomResourceController.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/subresource/SubResourceTestCustomResourceController.java @@ -12,7 +12,6 @@ @Controller( crdName = SubResourceTestCustomResourceController.CRD_NAME, - customResourceClass = SubResourceTestCustomResource.class, generationAwareEventProcessing = false) public class SubResourceTestCustomResourceController implements ResourceController, TestExecutionInfoProvider { diff --git a/operator-framework/src/test/resources/AbstractController.java b/operator-framework/src/test/resources/AbstractController.java new file mode 100644 index 0000000000..e5462316c6 --- /dev/null +++ b/operator-framework/src/test/resources/AbstractController.java @@ -0,0 +1,26 @@ +package io; + +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.client.CustomResourceDoneable; +import io.javaoperatorsdk.operator.api.Context; +import io.javaoperatorsdk.operator.api.Controller; +import io.javaoperatorsdk.operator.api.ResourceController; +import io.javaoperatorsdk.operator.api.UpdateControl; +import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.api.model.SecretBuilder; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.apache.commons.lang3.RandomStringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import java.io.Serializable; + +import static java.lang.String.format; + + +public abstract class AbstractController implements Serializable, ResourceController { + public static class MyCustomResource extends CustomResource { + + } +} diff --git a/operator-framework/src/test/resources/ControllerImplemented2Interfaces.java b/operator-framework/src/test/resources/ControllerImplemented2Interfaces.java new file mode 100644 index 0000000000..c37ee85dbf --- /dev/null +++ b/operator-framework/src/test/resources/ControllerImplemented2Interfaces.java @@ -0,0 +1,36 @@ +package io; + +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.client.CustomResourceDoneable; +import io.javaoperatorsdk.operator.api.Context; +import io.javaoperatorsdk.operator.api.Controller; +import io.javaoperatorsdk.operator.api.ResourceController; +import io.javaoperatorsdk.operator.api.UpdateControl; +import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.api.model.SecretBuilder; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.apache.commons.lang3.RandomStringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import java.io.Serializable; + +import static java.lang.String.format; + +@Controller(crdName = "test.crd") +public class ControllerImplemented2Interfaces implements Serializable, ResourceController { + + public static class MyCustomResource extends CustomResource { + } + + @Override + public UpdateControl createOrUpdateResource(MyCustomResource customResource, Context context) { + return UpdateControl.updateCustomResource(null); + } + + @Override + public boolean deleteResource(MyCustomResource customResource, Context context) { + return false; + } +} diff --git a/operator-framework/src/test/resources/ControllerImplemented2InterfacesExpected.java b/operator-framework/src/test/resources/ControllerImplemented2InterfacesExpected.java new file mode 100644 index 0000000000..88290a5d53 --- /dev/null +++ b/operator-framework/src/test/resources/ControllerImplemented2InterfacesExpected.java @@ -0,0 +1,10 @@ +package io; + +import io.fabric8.kubernetes.api.builder.Function; +import io.fabric8.kubernetes.client.CustomResourceDoneable; + +public class MyCustomResourceDoneable extends CustomResourceDoneable { + public MyCustomResourceDoneable(ControllerImplemented2Interfaces.MyCustomResource resource, Function function) { + super(resource, function); + } +} diff --git a/operator-framework/src/test/resources/ControllerImplementedIntermediateAbstractClass.java b/operator-framework/src/test/resources/ControllerImplementedIntermediateAbstractClass.java new file mode 100644 index 0000000000..9a06ca01aa --- /dev/null +++ b/operator-framework/src/test/resources/ControllerImplementedIntermediateAbstractClass.java @@ -0,0 +1,31 @@ +package io; + +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.client.CustomResourceDoneable; +import io.javaoperatorsdk.operator.api.Context; +import io.javaoperatorsdk.operator.api.Controller; +import io.javaoperatorsdk.operator.api.ResourceController; +import io.javaoperatorsdk.operator.api.UpdateControl; +import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.api.model.SecretBuilder; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.apache.commons.lang3.RandomStringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import java.io.Serializable; + +import static java.lang.String.format; + +@Controller(crdName = "test.crd") +public class ControllerImplementedIntermediateAbstractClass extends AbstractController implements Serializable { + + public UpdateControl createOrUpdateResource(AbstractController.MyCustomResource customResource, Context context) { + return UpdateControl.updateCustomResource(null); + } + + public boolean deleteResource(AbstractController.MyCustomResource customResource, Context context) { + return false; + } +} diff --git a/operator-framework/src/test/resources/ControllerImplementedIntermediateAbstractClassExpected.java b/operator-framework/src/test/resources/ControllerImplementedIntermediateAbstractClassExpected.java new file mode 100644 index 0000000000..f08562f05e --- /dev/null +++ b/operator-framework/src/test/resources/ControllerImplementedIntermediateAbstractClassExpected.java @@ -0,0 +1,10 @@ +package io; + +import io.fabric8.kubernetes.api.builder.Function; +import io.fabric8.kubernetes.client.CustomResourceDoneable; + +public class MyCustomResourceDoneable extends CustomResourceDoneable { + public MyCustomResourceDoneable(AbstractController.MyCustomResource resource, Function function) { + super(resource, function); + } +} diff --git a/samples/common/src/main/java/io/javaoperatorsdk/operator/sample/CustomServiceController.java b/samples/common/src/main/java/io/javaoperatorsdk/operator/sample/CustomServiceController.java index 1f489d81dc..c2a558fed9 100644 --- a/samples/common/src/main/java/io/javaoperatorsdk/operator/sample/CustomServiceController.java +++ b/samples/common/src/main/java/io/javaoperatorsdk/operator/sample/CustomServiceController.java @@ -15,7 +15,7 @@ /** * A very simple sample controller that creates a service with a label. */ -@Controller(customResourceClass = CustomService.class, +@Controller( crdName = "customservices.sample.javaoperatorsdk") public class CustomServiceController implements ResourceController { diff --git a/samples/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaController.java b/samples/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaController.java index bda42ac066..481fb5f7b5 100644 --- a/samples/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaController.java +++ b/samples/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaController.java @@ -21,9 +21,7 @@ import static java.lang.String.format; -@Controller( - crdName = "schemas.mysql.sample.javaoperatorsdk", - customResourceClass = Schema.class) +@Controller(crdName = "schemas.mysql.sample.javaoperatorsdk") public class SchemaController implements ResourceController { static final String USERNAME_FORMAT = "%s-user"; static final String SECRET_FORMAT = "%s-secret"; diff --git a/samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatController.java b/samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatController.java index 1034ce1b39..76a8cffaa8 100644 --- a/samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatController.java +++ b/samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatController.java @@ -26,8 +26,7 @@ import java.util.Objects; import java.util.Optional; -@Controller(customResourceClass = Tomcat.class, - crdName = "tomcats.tomcatoperator.io") +@Controller(crdName = "tomcats.tomcatoperator.io") public class TomcatController implements ResourceController { private final Logger log = LoggerFactory.getLogger(getClass()); @@ -201,4 +200,4 @@ public String toString() { '}'; } } -} \ No newline at end of file +} diff --git a/samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/WebappController.java b/samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/WebappController.java index 4c2083a08d..b66a43597c 100644 --- a/samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/WebappController.java +++ b/samples/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/WebappController.java @@ -16,7 +16,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -@Controller(customResourceClass = Webapp.class, +@Controller( crdName = "webapps.tomcatoperator.io") public class WebappController implements ResourceController { diff --git a/samples/webserver/src/main/java/io/javaoperatorsdk/operator/sample/WebServerController.java b/samples/webserver/src/main/java/io/javaoperatorsdk/operator/sample/WebServerController.java index 984e6d3d43..f3a4894fad 100644 --- a/samples/webserver/src/main/java/io/javaoperatorsdk/operator/sample/WebServerController.java +++ b/samples/webserver/src/main/java/io/javaoperatorsdk/operator/sample/WebServerController.java @@ -21,7 +21,7 @@ import java.util.HashMap; import java.util.Map; -@Controller(customResourceClass = WebServer.class, +@Controller( crdName = "webservers.sample.javaoperatorsdk") public class WebServerController implements ResourceController { diff --git a/spring-boot-starter/src/test/java/io/javaoperatorsdk/operator/springboot/starter/TestController.java b/spring-boot-starter/src/test/java/io/javaoperatorsdk/operator/springboot/starter/TestController.java index b6475c57db..54ba3e721c 100644 --- a/spring-boot-starter/src/test/java/io/javaoperatorsdk/operator/springboot/starter/TestController.java +++ b/spring-boot-starter/src/test/java/io/javaoperatorsdk/operator/springboot/starter/TestController.java @@ -5,12 +5,10 @@ import io.javaoperatorsdk.operator.api.Controller; import io.javaoperatorsdk.operator.api.ResourceController; import io.javaoperatorsdk.operator.api.UpdateControl; -import io.javaoperatorsdk.operator.springboot.starter.model.TestResource; import org.springframework.stereotype.Component; @Component -@Controller(crdName = "name", - customResourceClass = TestResource.class) +@Controller(crdName = "name") public class TestController implements ResourceController { @Override