All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.longdt.vertxservice.processor.ServiceProxyHandlerWriter Maven / Gradle / Ivy

Go to download

A lightweight replacement for vertx-service-proxy. This library is highly optimized for vertx java

There is a newer version: 1.1.1
Show newest version
package com.github.longdt.vertxservice.processor;

import com.github.longdt.vertxservice.util.Arguments;
import com.squareup.javapoet.*;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.eventbus.Message;
import io.vertx.serviceproxy.HelperUtils;
import io.vertx.serviceproxy.ServiceException;

import javax.annotation.processing.Filer;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import java.io.IOException;

import static com.google.auto.common.GeneratedAnnotationSpecs.generatedAnnotationSpec;
import static com.squareup.javapoet.TypeSpec.classBuilder;
import static javax.lang.model.element.Modifier.PUBLIC;

public class ServiceProxyHandlerWriter {
    private final Filer filer;
    private final Elements elements;
    private final SourceVersion sourceVersion;
    private final Types types;

    ServiceProxyHandlerWriter(ProcessingEnvironment processingEnv) {
        this.filer = processingEnv.getFiler();
        this.elements = processingEnv.getElementUtils();
        this.sourceVersion = processingEnv.getSourceVersion();
        this.types = processingEnv.getTypeUtils();
    }

    void writeServiceProxyHandler(ServiceDeclaration serviceDeclaration) throws IOException {
        String serviceProxy = serviceDeclaration.target().getSimpleName().toString() + Constant.PROXY_HANDLER;
        TypeSpec.Builder builder =
                classBuilder(serviceProxy)
                        .addOriginatingElement(serviceDeclaration.target());
        generatedAnnotationSpec(
                elements,
                sourceVersion,
                Service4JProcessor.class,
                "Do not edit this file")
                .ifPresent(builder::addAnnotation);
        builder.addModifiers(Modifier.PUBLIC);
        addSuperinterface(builder);
        addFields(builder, serviceDeclaration);
        addConstructor(builder, serviceDeclaration);
        addMethods(builder, serviceDeclaration);
        JavaFile.builder(elements.getPackageOf(serviceDeclaration.target()).getQualifiedName().toString(), builder.build())
                .skipJavaLangImports(true)
                .build()
                .writeTo(filer);
    }

    private void addMethods(TypeSpec.Builder builder, ServiceDeclaration serviceDeclaration) {
        MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("handle")
                .addParameter(ParameterizedTypeName.get(Message.class, Object.class), Constant.MESSAGE_VARIABLE)
                .addModifiers(PUBLIC)
                .addAnnotation(Override.class)
                .returns(void.class);
        CodeBlock.Builder codeBlockBuilder = CodeBlock.builder();
        codeBlockBuilder.beginControlFlow("try");
        codeBlockBuilder.addStatement("var $1L = $2L.headers().get($1S)", Constant.ACTION, Constant.MESSAGE_VARIABLE);
        codeBlockBuilder.beginControlFlow("if ($L == null)", Constant.ACTION)
                .addStatement("throw new $T(\"action not specified\")", IllegalStateException.class)
                .endControlFlow();
        codeBlockBuilder.beginControlFlow("switch ($L)", Constant.ACTION);
        serviceDeclaration.methods().forEach(e -> addCase(codeBlockBuilder, e));
        codeBlockBuilder.beginControlFlow("default:")
                .addStatement("throw new $T(\"Invalid action: \" + $L)", IllegalStateException.class, Constant.ACTION)
                .endControlFlow();
        codeBlockBuilder.endControlFlow();
        codeBlockBuilder.nextControlFlow("catch ($T e)", Exception.class);
        codeBlockBuilder.beginControlFlow("if ($L)", Constant.INCLUDE_DEBUG_INFO_VARIABLE)
                .addStatement("$L.reply(new $T(500, e.getMessage(), $T.generateDebugInfo(e)))", Constant.MESSAGE_VARIABLE, ServiceException.class, HelperUtils.class)
                .nextControlFlow("else")
                .addStatement("$L.reply(new $T(500, e.getMessage()))", Constant.MESSAGE_VARIABLE, ServiceException.class)
                .endControlFlow();
        codeBlockBuilder.endControlFlow();
        methodBuilder.addCode(codeBlockBuilder.build());
        builder.addMethod(methodBuilder.build());
    }

    private void addCase(CodeBlock.Builder codeBlockBuilder, ExecutableElement element) {
        var params = element.getParameters();
        if (params.isEmpty()) {
            new NoParamMethodProxyHandlerWriter(types).writeInvocation(codeBlockBuilder, element);
        } else if (params.size() == 1) {
            new SingleParamMethodProxyHandlerWriter(types).writeInvocation(codeBlockBuilder, element);
        } else {
            new MultiParamMethodProxyHandlerWriter(types).writeInvocation(codeBlockBuilder, element);
        }
    }

    private void addConstructor(TypeSpec.Builder builder, ServiceDeclaration serviceDeclaration) {
        MethodSpec.Builder constructor = MethodSpec.constructorBuilder();
        constructor.addModifiers(PUBLIC);
        constructor.addParameter(TypeName.get(Vertx.class), Constant.VERTX_VARIABLE);
        constructor.addParameter(TypeName.get(serviceDeclaration.target().asType()), Constant.SERVICE_VARIABLE);
        constructor.addParameter(TypeName.get(boolean.class), Constant.INCLUDE_DEBUG_INFO_VARIABLE);
        constructor.addStatement("this.$1L = $1L", Constant.VERTX_VARIABLE);
        constructor.addStatement("this.$1L = $1L", Constant.SERVICE_VARIABLE);
        constructor.addStatement("this.$1L = $1L", Constant.INCLUDE_DEBUG_INFO_VARIABLE);
        builder.addMethod(constructor.build());
    }

    private void addFields(TypeSpec.Builder builder, ServiceDeclaration serviceDeclaration) {
        builder.addField(
                FieldSpec.builder(Vertx.class, Constant.VERTX_VARIABLE, Modifier.PRIVATE, Modifier.FINAL)
                        .build());
        builder.addField(
                FieldSpec.builder(TypeName.get(serviceDeclaration.target().asType()), Constant.SERVICE_VARIABLE, Modifier.PRIVATE, Modifier.FINAL)
                        .build());
        builder.addField(
                FieldSpec.builder(boolean.class, Constant.INCLUDE_DEBUG_INFO_VARIABLE, Modifier.PRIVATE, Modifier.FINAL)
                        .build());
    }

    private void addSuperinterface(TypeSpec.Builder builder) {
        builder.addSuperinterface(ParameterizedTypeName.get(
                ClassName.get(Handler.class),
                ParameterizedTypeName.get(Message.class, Object.class)));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy