JavaModelUtils.java

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

import io.kaumei.jdbc.anno.ProcessorException;
import org.jspecify.annotations.Nullable;

import javax.lang.model.element.*;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import java.util.Objects;

public final class JavaModelUtils {

    private JavaModelUtils() {
    }

    public static ExecutableElement getStaticMethod(Element elem, CharSequence simpleMethodName) {
        ExecutableElement found = null;
        for (var child : elem.getEnclosedElements()) {
            if (child instanceof ExecutableElement method
                    && isStatic(method)
                    && isVisible(method)
                    && method.getSimpleName().contentEquals(simpleMethodName)) {
                if (found == null) {
                    found = method;
                } else {
                    throw new ProcessorException("To many methods found: " + simpleMethodName, elem); // sanity-check
                }
            }
        }
        // sanity-check:on
        if (found == null) {
            throw new ProcessorException("No method found: " + simpleMethodName, elem);
        }
        // sanity-check:off
        return found;
    }

    public static Name getQualifiedClassName(ExecutableElement element) {
        if (element.getEnclosingElement() instanceof TypeElement typeElement) {
            return typeElement.getQualifiedName();
        }
        throw new ProcessorException("Unknown element type: " + element.getClass().getName()); // sanity-check
    }

    public static boolean isVisible(Element element) {
        var modifiers = element.getModifiers();
        return !modifiers.contains(Modifier.PRIVATE) && !modifiers.contains(Modifier.PROTECTED);
    }

    public static boolean isStatic(Element element) {
        var modifiers = element.getModifiers();
        return modifiers.contains(Modifier.STATIC);
    }

    public static boolean isTopLevel(TypeElement element) {
        return element.getEnclosingElement() instanceof PackageElement;
    }

    // ------------------------------------------------------------------------

    public static TypeMirror component(TypeMirror mirror) {
        return Objects.requireNonNull(componentOpt(mirror), "TypeMirror has no component.");
    }

    @Nullable
    public static TypeMirror componentOpt(TypeMirror mirror) {
        if (mirror instanceof DeclaredType declared) {
            if (declared.getTypeArguments().size() == 1) {
                return declared.getTypeArguments().get(0);
            }
        } else if (mirror instanceof ArrayType arrayType) {
            return arrayType.getComponentType();
        }
        return null;
    }
}