io.micronaut.kubernetes.client.processor.KubernetesApisProcessor Maven / Gradle / Ivy
/*
* Copyright 2017-2021 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.kubernetes.client.processor;
import com.squareup.javapoet.*;
import io.micronaut.annotation.processing.AnnotationUtils;
import io.micronaut.annotation.processing.GenericUtils;
import io.micronaut.annotation.processing.ModelUtils;
import io.micronaut.annotation.processing.PublicMethodVisitor;
import io.micronaut.annotation.processing.visitor.JavaVisitorContext;
import io.micronaut.context.annotation.BootstrapContextCompatible;
import io.micronaut.context.annotation.Factory;
import io.micronaut.context.annotation.Requires;
import io.micronaut.core.convert.value.MutableConvertibleValues;
import io.micronaut.core.naming.NameUtils;
import javax.annotation.processing.*;
import io.micronaut.inject.visitor.TypeElementVisitor;
import jakarta.inject.Singleton;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
/**
* An annotation processor that generates the Kubernetes APIs factories. Based on {@code io.micronaut.kubernetes.client.Apis}
* annotation field {@code kind} either {@code Async}, {@code RxJava2} or {@code Reactor} client factories are generated.
*
* @author Pavol Gressa
* @since 2.2
*/
@SupportedAnnotationTypes("io.micronaut.kubernetes.client.Apis")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class KubernetesApisProcessor extends AbstractProcessor {
public static final String KUBERNETES_APIS_PACKAGE = "io.kubernetes.client.openapi.apis";
public static final String MICRONAUT_APIS_PACKAGE = "io.micronaut.kubernetes.client";
private Filer filer;
private Messager messager;
private Elements elements;
private Types types;
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
this.filer = processingEnv.getFiler();
this.messager = processingEnv.getMessager();
this.elements = processingEnv.getElementUtils();
this.types = processingEnv.getTypeUtils();
}
@Override
public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (TypeElement annotation : annotations) {
final Set extends Element> element = roundEnv.getElementsAnnotatedWith(annotation);
for (Element e : element) {
final List apisNames = resolveClientNames(e);
final String t = resolveClientType(e);
for (String clientName : apisNames) {
final String packageName = NameUtils.getPackageName(clientName);
final String simpleName = NameUtils.getSimpleName(clientName);
switch (t) {
case "RXJAVA2":
writeRxJava2Clients(e, packageName, simpleName);
break;
case "RXJAVA3":
writeRxJava3Clients(e, packageName, simpleName);
break;
case "REACTOR":
writeReactorClients(e, packageName, simpleName);
break;
case "ASYNC":
writeClientFactory(e, packageName, simpleName);
break;
default:
break;
}
}
}
}
return false;
}
private void writeClientFactory(Element e, String packageName, String simpleName) {
final String factoryName = simpleName + "Factory";
final String factoryPackageName = packageName.replace(KUBERNETES_APIS_PACKAGE, MICRONAUT_APIS_PACKAGE);
final TypeSpec.Builder builder = TypeSpec.classBuilder(factoryName);
builder.addAnnotation(Factory.class);
final MethodSpec.Builder buildMethod = MethodSpec.methodBuilder("build");
buildMethod.returns(ClassName.get(packageName, simpleName))
.addParameter(ClassName.get("io.kubernetes.client.openapi", "ApiClient"), "apiClient")
.addAnnotation(Singleton.class)
.addModifiers(Modifier.PROTECTED)
.addCode("return new " + simpleName + "(apiClient);");
builder.addMethod(buildMethod.build());
if (Objects.equals(simpleName, "CoreV1Api")) {
builder.addAnnotation(BootstrapContextCompatible.class);
buildMethod.addAnnotation(BootstrapContextCompatible.class);
}
final JavaFile javaFile = JavaFile.builder(factoryPackageName, builder.build()).build();
try {
final JavaFileObject javaFileObject = filer.createSourceFile(factoryPackageName + "." + factoryName, e);
try (Writer writer = javaFileObject.openWriter()) {
javaFile.writeTo(writer);
}
} catch (IOException ioException) {
messager.printMessage(Diagnostic.Kind.ERROR, "Error occurred generating Kubernetes " + simpleName + " factory: " + ioException.getMessage(), e);
}
}
private void writeReactorClients(Element e, String packageName, String simpleName) {
final String reactorClientName = simpleName + "ReactorClient";
final String reactorPackageName = packageName.replace(KUBERNETES_APIS_PACKAGE, MICRONAUT_APIS_PACKAGE + ".reactor");
ClassName cn = ClassName.get(reactorPackageName, reactorClientName);
TypeSpec.Builder builder = TypeSpec.classBuilder(cn);
ClassName clientType = ClassName.get(packageName, simpleName);
ClassName reactorMonoType = ClassName.get("reactor.core.publisher", "Mono");
final AnnotationSpec.Builder requiresSpec =
AnnotationSpec.builder(Requires.class)
.addMember("beans", "{$T.class}", clientType);
builder.addAnnotation(requiresSpec.build());
builder.addAnnotation(Singleton.class);
if (Objects.equals(simpleName, "CoreV1Api")) {
builder.addAnnotation(BootstrapContextCompatible.class);
}
builder.addModifiers(Modifier.PUBLIC);
builder.addField(clientType, "client", Modifier.FINAL, Modifier.PRIVATE);
builder.addMethod(MethodSpec.constructorBuilder()
.addParameter(clientType, "client")
.addCode("this.client = client;")
.build());
TypeElement typeElement = elements.getTypeElement(clientType.reflectionName());
if (typeElement != null) {
ModelUtils modelUtils = new ModelUtils(elements, types) {
};
GenericUtils genericUtils = new GenericUtils(elements, types, modelUtils) {
};
AnnotationUtils annotationUtils = new AnnotationUtils(processingEnv, elements, messager, types, modelUtils, genericUtils, filer) {
};
JavaVisitorContext visitorContext = new JavaVisitorContext(
processingEnv,
messager,
elements,
annotationUtils,
types,
modelUtils,
genericUtils,
filer,
MutableConvertibleValues.of(new LinkedHashMap<>()),
TypeElementVisitor.VisitorKind.ISOLATING);
typeElement.asType().accept(new PublicMethodVisitor
© 2015 - 2025 Weber Informatics LLC | Privacy Policy