KaumeiClassBuilder.java

/*
 * SPDX-FileCopyrightText: 2025 kaumei.io
 * SPDX-License-Identifier: Apache-2.0
 */
package io.kaumei.jdbc.anno.gen;

import com.palantir.javapoet.*;
import io.kaumei.jdbc.JdbcConnectionProvider;
import io.kaumei.jdbc.anno.ProcessorException;
import io.kaumei.jdbc.anno.ctx.Context;
import org.jspecify.annotations.Nullable;

import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import java.util.HashMap;
import java.util.Map;

import static io.kaumei.jdbc.anno.Processor.GENERATED;

public class KaumeiClassBuilder implements KaumeiBuilder {
    // ----- state
    private final TypeElement iface;
    private final String packageName;
    private final TypeSpec.Builder typeSpecBuilder;
    private final Map<String, TargetMethod> classNames = new HashMap<>();

    KaumeiClassBuilder(Context ctx, String packageName, TypeElement iface) {
        this.iface = iface;
        this.packageName = packageName;
        var simpleName = iface.getSimpleName() + ctx.kaumeiConfig.generatedClassSuffix();

        var generationAnno = ctx.JDBC_GENERATION.getAnnoOpt(iface);

        this.typeSpecBuilder = TypeSpec.classBuilder(simpleName)
                .addModifiers(Modifier.PUBLIC)
                .addSuperinterface(ClassName.get(iface));

        this.typeSpecBuilder.addAnnotation(GENERATED);
        // ----- copy all annotations
        for (var mirror : iface.getAnnotationMirrors()) {
            var spec = ctx.kaumeiJdbcGenerator.annotationSpec(mirror);
            if (spec != null) {
                typeSpecBuilder.addAnnotation(AnnotationSpec.get(mirror));
            }
        }
        // ----- add additional specified annotations
        if (generationAnno != null) {
            for (TypeMirror anno : generationAnno.classAnnotations()) {
                this.typeSpecBuilder.addAnnotation(ClassName.get(ctx.asTypeElement(anno)));
            }
        }

        // ----- Add supplier field
        typeSpecBuilder.addField(
                FieldSpec.builder(JdbcConnectionProvider.class, "supplier", Modifier.PRIVATE, Modifier.FINAL).build());


        var constructor = MethodSpec.constructorBuilder()
                .addModifiers(Modifier.PUBLIC)
                .addParameter(JdbcConnectionProvider.class, "supplier")
                .addStatement("this.supplier = $L", KaumeiLib.requireNonNull("supplier"));
        // ----- add additional specified annotations
        if (generationAnno != null) {
            for (var anno : generationAnno.constructorAnnotations()) {

                constructor.addAnnotation(ClassName.get(ctx.asTypeElement(anno)));
            }
        }

        // ----- Add constructor
        this.typeSpecBuilder.addMethod(constructor.build());
    }

    @Override
    public TypeElement type() {
        return this.iface;
    }

    @Override
    public TypeSpec build() {
        return this.typeSpecBuilder.build();
    }

    public String packageName() {
        return packageName;
    }

    @Nullable TargetMethod containsClass(String name) {
        return classNames.get(name);
    }

    void addClass(String name, TypeSpec typeSpec, TargetMethod targetMethod) {
        if (classNames.put(name, targetMethod) != null) { // sanity-check
            throw new ProcessorException("Name already known: " + name); // sanity-check
        }
        this.typeSpecBuilder.addType(typeSpec);
    }

    public void addMethod(MethodSpec methodSpec) {
        this.typeSpecBuilder.addMethod(methodSpec);
    }

}