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

cn.wjybxx.dsonapt.CodecProcessor Maven / Gradle / Ivy

There is a newer version: 2.2.0
Show newest version
/*
 * Copyright 2023-2024 wjybxx([email protected])
 *
 * 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
 *
 *     http://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 cn.wjybxx.dsonapt;

import cn.wjybxx.apt.AptUtils;
import cn.wjybxx.apt.BeanUtils;
import cn.wjybxx.apt.MyAbstractProcessor;
import com.google.auto.service.AutoService;
import com.squareup.javapoet.*;

import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
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 java.util.*;

/**
 * @author wjybxx
 * date 2023/4/13
 */
@AutoService(Processor.class)
public class CodecProcessor extends MyAbstractProcessor {

    // region 常量
    public static final String CNAME_WireType = "cn.wjybxx.dson.WireType";
    public static final String CNAME_NumberStyle = "cn.wjybxx.dson.text.NumberStyle";
    public static final String CNAME_StringStyle = "cn.wjybxx.dson.text.StringStyle";
    public static final String CNAME_ObjectStyle = "cn.wjybxx.dson.text.ObjectStyle";
    public static final String CNAME_TypeInfo = "cn.wjybxx.dsoncodec.TypeInfo";
    public static final String CNAME_Options = "cn.wjybxx.dsoncodec.ConverterOptions";

    // Dson
    private static final String CNAME_SERIALIZABLE = "cn.wjybxx.dsoncodec.annotations.DsonSerializable";
    public static final String CNAME_PROPERTY = "cn.wjybxx.dsoncodec.annotations.DsonProperty";
    private static final String CNAME_DSON_IGNORE = "cn.wjybxx.dsoncodec.annotations.DsonIgnore";
    private static final String CNAME_DSON_READER = "cn.wjybxx.dsoncodec.DsonObjectReader";
    private static final String CNAME_DSON_WRITER = "cn.wjybxx.dsoncodec.DsonObjectWriter";
    private static final String CNAME_DSON_SCAN_IGNORE = "cn.wjybxx.dsoncodec.annotations.DsonCodecScanIgnore";
    // Linker
    private static final String CNAME_CODEC_LINKER_GROUP = "cn.wjybxx.dsoncodec.annotations.DsonCodecLinkerGroup";
    private static final String CNAME_CODEC_LINKER = "cn.wjybxx.dsoncodec.annotations.DsonCodecLinker";
    private static final String CNAME_CODEC_LINKER_BEAN = "cn.wjybxx.dsoncodec.annotations.DsonCodecLinkerBean";
    private static final String MNAME_OUTPUT = "outputPackage";
    private static final String MNAME_CLASS_PROPS = "props";

    // Codec
    public static final String CNAME_CODEC = "cn.wjybxx.dsoncodec.DsonCodec";
    public static final String MNAME_READ_OBJECT = "readObject";
    public static final String MNAME_WRITE_OBJECT = "writeObject";
    // AbstractCodec
    private static final String CNAME_ABSTRACT_CODEC = "cn.wjybxx.dsoncodec.AbstractDsonCodec";
    public static final String MNAME_GET_ENCODER_CLASS = "getEncoderClass";
    public static final String MNAME_BEFORE_ENCODE = "beforeEncode";
    public static final String MNAME_WRITE_FIELDS = "writeFields";
    public static final String MNAME_NEW_INSTANCE = "newInstance";
    public static final String MNAME_READ_FIELDS = "readFields";
    public static final String MNAME_AFTER_DECODE = "afterDecode";
    // EnumCode
    private static final String CNAME_ENUM_CODEC = "cn.wjybxx.dsoncodec.codecs.EnumCodec";
    public static final String CNAME_ENUM_LITE = "cn.wjybxx.base.EnumLite";
    public static final String MNAME_FOR_NUMBER = "forNumber";
    public static final String MNAME_GET_NUMBER = "getNumber";

    //endregion

    // region 字段
    public ClassName typeNameTypeInfo;
    public ClassName typeNameWireType;
    public ClassName typeNameNumberStyle;
    public ClassName typeNameStringStyle;
    public ClassName typeNameObjectStyle;
    public TypeMirror optionsTypeMirror;

    // Dson
    public TypeElement anno_dsonSerializable;
    public TypeMirror anno_dsonProperty;
    public TypeMirror anno_dsonIgnore;
    public TypeMirror dsonReaderTypeMirror;
    public TypeMirror dsonWriterTypeMirror;
    public AnnotationSpec dsonScanIgnoreAnnoSpec;

    // linker
    public TypeElement anno_codecLinkerGroup;
    public TypeElement anno_codecLinker;
    public TypeElement anno_codecLinkerBean;

    // abstractCodec
    public TypeElement abstractCodecTypeElement;
    public ExecutableElement getEncoderClassMethod;
    public ExecutableElement newInstanceMethod;
    public ExecutableElement readFieldsMethod;
    public ExecutableElement afterDecodeMethod;
    public ExecutableElement writeObjectMethod;
    public ExecutableElement beforeEncodeMethod;
    public ExecutableElement writeFieldsMethod;

    // enumCodec
    public TypeElement enumCodecTypeElement;

    // 特殊类型依赖
    // 基础类型
    public TypeMirror stringTypeMirror;
    public TypeMirror enumLiteTypeMirror;
    public TypeMirror objectTypeMirror;

    // 集合类型
    public TypeMirror mapTypeMirror;
    public TypeMirror collectionTypeMirror;
    public TypeMirror setTypeMirror;
    public TypeMirror enumSetRawTypeMirror;
    public TypeMirror enumMapRawTypeMirror;
    public TypeMirror linkedHashMapTypeMirror;
    public TypeMirror linkedHashSetTypeMirror;
    public TypeMirror arrayListTypeMirror;

    // endregion

    public CodecProcessor() {
    }

    @Override
    public Set getSupportedAnnotationTypes() {
        return Set.of(CNAME_SERIALIZABLE, CNAME_CODEC_LINKER_GROUP, CNAME_CODEC_LINKER_BEAN);
    }

    @Override
    protected void ensureInited() {
        if (typeNameWireType != null) return;
        // common
        optionsTypeMirror = elementUtils.getTypeElement(CNAME_Options).asType();
        typeNameTypeInfo = ClassName.get(elementUtils.getTypeElement(CNAME_TypeInfo));
        typeNameWireType = AptUtils.classNameOfCanonicalName(CNAME_WireType);
        typeNameNumberStyle = AptUtils.classNameOfCanonicalName(CNAME_NumberStyle);
        typeNameStringStyle = AptUtils.classNameOfCanonicalName(CNAME_StringStyle);
        typeNameObjectStyle = AptUtils.classNameOfCanonicalName(CNAME_ObjectStyle);

        // dson
        anno_dsonSerializable = elementUtils.getTypeElement(CNAME_SERIALIZABLE);
        anno_dsonProperty = elementUtils.getTypeElement(CNAME_PROPERTY).asType();
        anno_dsonIgnore = elementUtils.getTypeElement(CNAME_DSON_IGNORE).asType();
        dsonReaderTypeMirror = elementUtils.getTypeElement(CNAME_DSON_READER).asType();
        dsonWriterTypeMirror = elementUtils.getTypeElement(CNAME_DSON_WRITER).asType();
        dsonScanIgnoreAnnoSpec = AnnotationSpec.builder(ClassName.get(elementUtils.getTypeElement(CNAME_DSON_SCAN_IGNORE)))
                .build();
        // linker
        anno_codecLinkerGroup = elementUtils.getTypeElement(CNAME_CODEC_LINKER_GROUP);
        anno_codecLinker = elementUtils.getTypeElement(CNAME_CODEC_LINKER);
        anno_codecLinkerBean = elementUtils.getTypeElement(CNAME_CODEC_LINKER_BEAN);

        // Codec
        TypeElement codecTypeElement = elementUtils.getTypeElement(CNAME_CODEC);
        getEncoderClassMethod = AptUtils.findMethodByName(codecTypeElement, MNAME_GET_ENCODER_CLASS);
        // abstractCodec
        abstractCodecTypeElement = elementUtils.getTypeElement(CNAME_ABSTRACT_CODEC);
        {
            List allMethodsWithInherit = BeanUtils.getAllMethodsWithInherit(abstractCodecTypeElement);
            // dson
            newInstanceMethod = findCodecMethod(allMethodsWithInherit, MNAME_NEW_INSTANCE, dsonReaderTypeMirror);
            readFieldsMethod = findCodecMethod(allMethodsWithInherit, MNAME_READ_FIELDS, dsonReaderTypeMirror);
            afterDecodeMethod = findCodecMethod(allMethodsWithInherit, MNAME_AFTER_DECODE, dsonReaderTypeMirror);
            writeObjectMethod = findCodecMethod(allMethodsWithInherit, MNAME_WRITE_OBJECT, dsonWriterTypeMirror);
            beforeEncodeMethod = findCodecMethod(allMethodsWithInherit, MNAME_BEFORE_ENCODE, dsonWriterTypeMirror);
            writeFieldsMethod = findCodecMethod(allMethodsWithInherit, MNAME_WRITE_FIELDS, dsonWriterTypeMirror);
        }
        // enumLiteCodec
        enumCodecTypeElement = elementUtils.getTypeElement(CNAME_ENUM_CODEC);

        // 特殊类型依赖
        // 基础类型
        stringTypeMirror = elementUtils.getTypeElement(String.class.getCanonicalName()).asType();
        enumLiteTypeMirror = elementUtils.getTypeElement(CNAME_ENUM_LITE).asType();
        objectTypeMirror = elementUtils.getTypeElement(Object.class.getCanonicalName()).asType();
        // 集合
        mapTypeMirror = elementUtils.getTypeElement(Map.class.getCanonicalName()).asType();
        collectionTypeMirror = elementUtils.getTypeElement(Collection.class.getCanonicalName()).asType();
        setTypeMirror = elementUtils.getTypeElement(Set.class.getCanonicalName()).asType();
        enumSetRawTypeMirror = typeUtils.erasure(AptUtils.getTypeMirrorOfClass(elementUtils, EnumSet.class));
        enumMapRawTypeMirror = typeUtils.erasure(AptUtils.getTypeMirrorOfClass(elementUtils, EnumMap.class));
        linkedHashMapTypeMirror = typeUtils.erasure(AptUtils.getTypeMirrorOfClass(elementUtils, LinkedHashMap.class));
        linkedHashSetTypeMirror = typeUtils.erasure(AptUtils.getTypeMirrorOfClass(elementUtils, LinkedHashSet.class));
        arrayListTypeMirror = typeUtils.erasure(AptUtils.getTypeMirrorOfClass(elementUtils, ArrayList.class));
    }

    private ExecutableElement findCodecMethod(List allMethodsWithInherit,
                                              String methodName, TypeMirror firstArg) {
        return allMethodsWithInherit.stream()
                .filter(e -> e.getKind() == ElementKind.METHOD && e.getSimpleName().toString().equals(methodName))
                .filter(e -> e.getParameters().size() > 0
                        && AptUtils.isSameTypeIgnoreTypeParameter(typeUtils, e.getParameters().get(0).asType(), firstArg)
                )
                .findFirst()
                .orElseThrow(() -> new RuntimeException("method is absent, methodName: " + methodName));
    }

    @Override
    protected boolean doProcess(Set annotations, RoundEnvironment roundEnv) {
        final Set allTypeElements = AptUtils.selectSourceFileAny(roundEnv, elementUtils,
                anno_dsonSerializable, anno_codecLinkerGroup, anno_codecLinkerBean);
        for (TypeElement typeElement : allTypeElements) {
            try {
                // 各种缓存,避免频繁解析类型信息
                Context context = new Context(typeElement);
                context.dsonSerialAnnoMirror = AptUtils.findAnnotation(typeUtils, typeElement, anno_dsonSerializable.asType())
                        .orElse(null);
                context.linkerGroupAnnoMirror = AptUtils.findAnnotation(typeUtils, typeElement, anno_codecLinkerGroup.asType())
                        .orElse(null);
                context.linkerBeanAnnoMirror = AptUtils.findAnnotation(typeUtils, typeElement, anno_codecLinkerBean.asType())
                        .orElse(null);

                context.aptClassProps = AptClassProps.parse(typeUtils, typeElement, anno_dsonSerializable.asType());
                cacheFields(context);

                // 判断是哪类注解
                if (context.linkerGroupAnnoMirror != null) {
                    // 不是为自己生成,而是为字段生成
                    processLinkerGroup(context);
                } else if (context.linkerBeanAnnoMirror != null) {
                    // 不是为自己生成,当前类是Codec配置类
                    processLinkerBean(context);
                } else {
                    processDirectType(context);
                }
            } catch (Throwable e) {
                messager.printMessage(Diagnostic.Kind.ERROR, AptUtils.getStackTrace(e), typeElement);
            }
        }
        return true;
    }

    private void processLinkerBean(Context linkerBeanContext) {
        final AnnotationMirror linkerBeanAnnoMirror = linkerBeanContext.linkerBeanAnnoMirror;
        final String outPackage = getOutputPackage(linkerBeanContext.typeElement, linkerBeanAnnoMirror);

        DeclaredType declaredType; // 被投影的类型
        {
            AnnotationValue annotationValue = AptUtils.getAnnotationValue(linkerBeanAnnoMirror, "value");
            Objects.requireNonNull(annotationValue, "classProps");
            declaredType = AptUtils.findDeclaredType(AptUtils.getAnnotationValueTypeMirror(annotationValue));
            Objects.requireNonNull(declaredType);
        }
        AnnotationValue classPropsAnnoValue = AptUtils.getAnnotationValue(linkerBeanAnnoMirror, MNAME_CLASS_PROPS);
        AptClassProps aptClassProps = classPropsAnnoValue == null ?
                new AptClassProps() : AptClassProps.parse(typeUtils, (AnnotationMirror) classPropsAnnoValue.getValue());

        // 创建模拟数据
        TypeElement typeElement = (TypeElement) declaredType.asElement();
        Context context = new Context(typeElement);
        context.linkerBeanAddAnnotations = getAdditionalAnnotations(aptClassProps);
        // 模拟为dson数据
        context.dsonSerialAnnoMirror = linkerBeanAnnoMirror;
        context.dsonAddAnnotations = context.linkerBeanAddAnnotations;
        context.outPackage = outPackage;

        context.aptClassProps = aptClassProps;
        cacheFields(context);
        // 修正ClassProps注解
        {
            TypeMirror linkerBeanTypeMirror = linkerBeanContext.typeElement.asType();
            aptClassProps.codecProxyTypeElement = linkerBeanContext.typeElement;
            aptClassProps.codecProxyClassName = TypeName.get(typeUtils.erasure(linkerBeanTypeMirror));
            aptClassProps.codecProxyEnclosedElements = linkerBeanContext.typeElement.getEnclosedElements();
        }
        // 修正字段的FieldProps注解 —— 将LinkerBean上的注解信息转移到目标类
        {
            cacheFieldProps(linkerBeanContext);
            context.fieldPropsMap.clear();

            // 按name缓存,提高效率
            Map fieldName2FieldPropsMap = HashMap.newHashMap(linkerBeanContext.fieldPropsMap.size());
            linkerBeanContext.fieldPropsMap.forEach((k, v) -> {
                fieldName2FieldPropsMap.put(k.getSimpleName().toString(), v);
            });
            for (VariableElement field : context.allFields) {
                AptFieldProps aptFieldProps = fieldName2FieldPropsMap.get(field.getSimpleName().toString());
                if (aptFieldProps == null) aptFieldProps = new AptFieldProps();
                context.fieldPropsMap.put(field, aptFieldProps);
            }
        }
        // dson
        {
            context.serialTypeElement = anno_dsonSerializable;
            context.ignoreTypeMirror = anno_dsonIgnore;
            context.readerTypeMirror = dsonReaderTypeMirror;
            context.writerTypeMirror = dsonWriterTypeMirror;

            context.serialFields = new ArrayList<>();
            checkTypeElement(context);
            context.dsonSerialFields.addAll(context.serialFields);
        }
        generateCodec(context);
    }

    private void processLinkerGroup(Context groupContext) {
        final String outPackage = getOutputPackage(groupContext.typeElement, groupContext.linkerGroupAnnoMirror);
        for (VariableElement variableElement : groupContext.allFields) {
            AnnotationMirror linkerAnnoMirror = AptUtils.findAnnotation(typeUtils, variableElement, anno_codecLinker.asType())
                    .orElse(null);
            if (linkerAnnoMirror == null) { // 不需要链接的字段
                continue;
            }
            DeclaredType declaredType = AptUtils.findDeclaredType(variableElement.asType());
            if (declaredType == null) {
                messager.printMessage(Diagnostic.Kind.ERROR, "Bad Linker Target", variableElement);
                continue;
            }

            AnnotationValue classPropsAnnoValue = AptUtils.getAnnotationValue(linkerAnnoMirror, MNAME_CLASS_PROPS);
            AptClassProps aptClassProps = classPropsAnnoValue == null ?
                    new AptClassProps() : AptClassProps.parse(typeUtils, (AnnotationMirror) classPropsAnnoValue.getValue());

            // 创建模拟数据
            TypeElement typeElement = (TypeElement) declaredType.asElement();
            Context context = new Context(typeElement);
            context.linkerAddAnnotations = getAdditionalAnnotations(aptClassProps);
            // 模拟为dson数据
            context.dsonSerialAnnoMirror = linkerAnnoMirror;
            context.dsonAddAnnotations = context.linkerAddAnnotations;
            context.outPackage = outPackage;

            context.aptClassProps = aptClassProps;
            cacheFields(context);
            cacheFieldProps(context);
            // dson
            {
                context.serialTypeElement = anno_dsonSerializable;
                context.ignoreTypeMirror = anno_dsonIgnore;
                context.readerTypeMirror = dsonReaderTypeMirror;
                context.writerTypeMirror = dsonWriterTypeMirror;

                context.serialFields = new ArrayList<>();
                checkTypeElement(context);
                context.dsonSerialFields.addAll(context.serialFields);
            }
            generateCodec(context);
        }
    }

    private void processDirectType(Context context) {
        cacheFieldProps(context);
        // dson
        if (context.dsonSerialAnnoMirror != null) {
            context.dsonAddAnnotations = getAdditionalAnnotations(context.aptClassProps);
            context.serialTypeElement = anno_dsonSerializable;
            context.ignoreTypeMirror = anno_dsonIgnore;
            context.readerTypeMirror = dsonReaderTypeMirror;
            context.writerTypeMirror = dsonWriterTypeMirror;

            context.serialFields = new ArrayList<>();
            checkTypeElement(context);
            context.dsonSerialFields.addAll(context.serialFields);
        }
        generateCodec(context);
    }

    private void generateCodec(Context context) {
        TypeElement typeElement = context.typeElement;
        if (isEnumLite(typeElement.asType())) {
            DeclaredType superDeclaredType = typeUtils.getDeclaredType(enumCodecTypeElement, typeUtils.erasure(typeElement.asType()));
            initTypeBuilder(context, typeElement, superDeclaredType);
            //
            new EnumCodecGenerator(this, typeElement, context).execute();
        } else {
            DeclaredType superDeclaredType = typeUtils.getDeclaredType(abstractCodecTypeElement, typeUtils.erasure(typeElement.asType()));
            initTypeBuilder(context, typeElement, superDeclaredType);
            // 先生成常量字段
            SchemaGenerator schemaGenerator = new SchemaGenerator(this, context);
            schemaGenerator.execute();
            // 不论注解是否存在,所有方法都要实现
            // dson
            {
                context.serialAnnoMirror = context.dsonSerialAnnoMirror;
                context.scanIgnoreAnnoSpec = dsonScanIgnoreAnnoSpec;
                context.additionalAnnotations = context.dsonAddAnnotations;

                context.serialTypeElement = anno_dsonSerializable;
                context.ignoreTypeMirror = anno_dsonIgnore;
                context.readerTypeMirror = dsonReaderTypeMirror;
                context.writerTypeMirror = dsonWriterTypeMirror;
                context.serialFields = context.dsonSerialFields;
                context.serialNameAccess = "names_";
                new PojoCodecGenerator(this, context).execute();
            }
        }
        // 写入文件
        if (context.outPackage != null) {
            AptUtils.writeToFile(typeElement, context.typeBuilder, context.outPackage, messager, filer);
        } else {
            AptUtils.writeToFile(typeElement, context.typeBuilder, elementUtils, messager, filer);
        }
    }

    // region

    private void cacheFields(Context context) {
        context.allFieldsAndMethodWithInherit = BeanUtils.getAllFieldsAndMethodsWithInherit(context.typeElement);
        context.allFields = context.allFieldsAndMethodWithInherit.stream()
                .filter(e -> e.getKind() == ElementKind.FIELD && !e.getModifiers().contains(Modifier.STATIC))
                .map(e -> (VariableElement) e)
                .toList();
    }

    private void cacheFieldProps(Context context) {
        context.allFields.forEach(variableElement -> {
            AptFieldProps aptFieldProps = AptFieldProps.parse(typeUtils, variableElement, anno_dsonProperty);
            // dsonIgnore
            AptUtils.findAnnotation(typeUtils, variableElement, anno_dsonIgnore)
                    .ifPresent(ignoreAnnoMirror -> aptFieldProps.dsonIgnore = AptUtils.getAnnotationValueValue(ignoreAnnoMirror, "value"));
            context.fieldPropsMap.put(variableElement, aptFieldProps);
        });
    }

    /** 获取输出目录 -- 默认为配置类的路径 */
    private String getOutputPackage(TypeElement typeElement, AnnotationMirror annotationMirror) {
        String outPackage = AptUtils.getAnnotationValueValue(annotationMirror, MNAME_OUTPUT);
        if (AptUtils.isBlank(outPackage)) {
            return elementUtils.getPackageOf(typeElement).getQualifiedName().toString();
        }
        return outPackage;
    }

    /** 获取为生成的Codec附加的注解 */
    private List getAdditionalAnnotations(AptClassProps aptClassProps) {
        if (aptClassProps.additionalAnnotations.isEmpty()) {
            return List.of();
        }
        List result = new ArrayList<>(aptClassProps.additionalAnnotations.size());
        for (TypeMirror typeMirror : aptClassProps.additionalAnnotations) {
            final ClassName className = (ClassName) ClassName.get(typeMirror);
            result.add(AnnotationSpec.builder(className)
                    .build());
        }
        return result;
    }

    private void initTypeBuilder(Context context, TypeElement typeElement, DeclaredType superDeclaredType) {
        context.superDeclaredType = superDeclaredType;
        context.typeBuilder = TypeSpec.classBuilder(getCodecName(typeElement))
                .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
                .addAnnotation(AptUtils.SUPPRESS_UNCHECKED_RAWTYPES)
                .addAnnotation(processorInfoAnnotation)
                .superclass(TypeName.get(superDeclaredType));
    }

    private String getCodecName(TypeElement typeElement) {
        return AptUtils.getProxyClassName(elementUtils, typeElement, "Codec");
    }

    // endregion

    private void checkTypeElement(Context context) {
        TypeElement typeElement = context.typeElement;
        if (!isClassOrEnum(typeElement)) {
            messager.printMessage(Diagnostic.Kind.ERROR, "unsupported type", typeElement);
            return;
        }
        if (typeElement.getKind() == ElementKind.ENUM) {
            checkEnum(typeElement);
        } else {
            checkNormalClass(context);
        }
    }

    // region 枚举检查

    /**
     * 检查枚举 - 要自动序列化的枚举,必须实现EnumLite接口且提供forNumber方法。
     */
    private void checkEnum(TypeElement typeElement) {
        if (!isEnumLite(typeElement.asType())) {
            messager.printMessage(Diagnostic.Kind.ERROR,
                    "serializable enum must implement EnumLite",
                    typeElement);
            return;
        }
        if (!containNotPrivateStaticForNumberMethod(typeElement)) {
            messager.printMessage(Diagnostic.Kind.ERROR,
                    "serializable enum must contains a not private 'static T forNumber(int)' method!",
                    typeElement);
        }
    }

    /**
     * 是否包含静态的非private的forNumber方法
     */
    private boolean containNotPrivateStaticForNumberMethod(TypeElement typeElement) {
        return typeElement.getEnclosedElements().stream()
                .filter(e -> e.getKind() == ElementKind.METHOD)
                .map(e -> (ExecutableElement) e)
                .anyMatch(e -> e.getModifiers().contains(Modifier.PUBLIC)
                        && e.getModifiers().contains(Modifier.STATIC)
                        && e.getParameters().size() == 1
                        && e.getSimpleName().toString().equals(MNAME_FOR_NUMBER)
                        && e.getParameters().get(0).asType().getKind() == TypeKind.INT);
    }
    // endregion

    // region 普通类检查

    private void checkNormalClass(Context context) {
        final AptClassProps aptClassProps = context.aptClassProps;
        if (aptClassProps.isSingleton()) {
            return;
        }
        TypeElement typeElement = context.typeElement;
        checkConstructor(typeElement, context.readerTypeMirror);

        final List allFieldsAndMethodWithInherit = context.allFieldsAndMethodWithInherit;
        final List instMethodList = context.allFieldsAndMethodWithInherit.stream()
                .filter(e -> e.getKind() == ElementKind.METHOD && !e.getModifiers().contains(Modifier.STATIC))
                .toList();

        for (Element element : allFieldsAndMethodWithInherit) {
            if (element.getKind() != ElementKind.FIELD) {
                continue;
            }
            final VariableElement variableElement = (VariableElement) element;
            final AptFieldProps aptFieldProps = context.fieldPropsMap.get(variableElement);
            if (!isSerializableField(variableElement, instMethodList, aptFieldProps)) {
                continue;
            }
            context.serialFields.add(variableElement);

            if (isAutoWriteField(variableElement, aptClassProps, aptFieldProps)) {
                if (aptFieldProps.hasWriteProxy()) {
                    continue;
                }
                // 工具写:需要提供可直接取值或包含非private的getter方法
                if (AptUtils.isBlank(aptFieldProps.getter)
                        && !canGetDirectly(variableElement, typeElement)
                        && findNotPrivateGetter(variableElement, allFieldsAndMethodWithInherit) == null) {
                    messager.printMessage(Diagnostic.Kind.ERROR,
                            String.format("serializable field (%s) must contains a not private getter or canGetDirectly", variableElement.getSimpleName()),
                            typeElement); // 可能无法定位到超类字段,因此打印到Type
                    continue;
                }
            }
            if (isAutoReadField(variableElement, aptClassProps, aptFieldProps)) {
                if (aptFieldProps.hasReadProxy()) {
                    continue;
                }
                // 工具读:需要提供可直接赋值或非private的setter方法
                if (AptUtils.isBlank(aptFieldProps.setter)
                        && !canSetDirectly(variableElement, typeElement)
                        && findNotPrivateSetter(variableElement, allFieldsAndMethodWithInherit) == null) {
                    messager.printMessage(Diagnostic.Kind.ERROR,
                            String.format("serializable field (%s) must contains a not private setter or canSetDirectly", variableElement.getSimpleName()),
                            typeElement); // 可能无法定位到超类字段,因此打印到Type
                    continue;
                }
            }
        }
    }

    /** 检查是否包含无参构造方法或解析构造方法 */
    private void checkConstructor(TypeElement typeElement, TypeMirror readerTypeMirror) {
        if (typeElement.getModifiers().contains(Modifier.ABSTRACT)) {
            return;
        }
        if (BeanUtils.containsNoArgsConstructor(typeElement)
                || containsReaderConstructor(typeElement, readerTypeMirror)
                || containsNewInstanceMethod(typeElement, readerTypeMirror)) {
            return;
        }
        messager.printMessage(Diagnostic.Kind.ERROR,
                "SerializableClass %s must contains no-args constructor or reader-args constructor!",
                typeElement);
    }

    // region 钩子方法检查

    /** 是否包含 T(Reader reader) 构造方法 */
    public boolean containsReaderConstructor(TypeElement typeElement, TypeMirror readerTypeMirror) {
        return BeanUtils.containsOneArgsConstructor(typeUtils, typeElement, readerTypeMirror);
    }

    /** 是否包含 newInstance 静态解码方法 -- 只能从当前类型查询 */
    public boolean containsNewInstanceMethod(TypeElement typeElement, TypeMirror readerTypeMirror) {
        return containsHookMethod(typeElement.getEnclosedElements(), MNAME_NEW_INSTANCE, readerTypeMirror);
    }

    /** 是否包含 readerObject 实例方法 */
    public boolean containsReadObjectMethod(List allFieldsAndMethodWithInherit, TypeMirror readerTypeMirror) {
        return containsHookMethod(allFieldsAndMethodWithInherit, MNAME_READ_OBJECT, readerTypeMirror);
    }

    /** 是否包含 writeObject 实例方法 */
    public boolean containsWriteObjectMethod(List allFieldsAndMethodWithInherit, TypeMirror writerTypeMirror) {
        return containsHookMethod(allFieldsAndMethodWithInherit, MNAME_WRITE_OBJECT, writerTypeMirror);
    }

    /** 是否包含 beforeEncode 实例方法 */
    public boolean containsBeforeEncodeMethod(List allFieldsAndMethodWithInherit) {
        return containsHookMethod(allFieldsAndMethodWithInherit, MNAME_BEFORE_ENCODE, optionsTypeMirror);
    }

    /** 是否包含 afterDecode 实例方法 */
    public boolean containsAfterDecodeMethod(List allFieldsAndMethodWithInherit) {
        return containsHookMethod(allFieldsAndMethodWithInherit, MNAME_AFTER_DECODE, optionsTypeMirror);
    }

    private boolean containsHookMethod(List allFieldsAndMethodWithInherit, String methodName, TypeMirror argTypeMirror) {
        return allFieldsAndMethodWithInherit.stream()
                .filter(e -> e.getKind() == ElementKind.METHOD)
                .map(e -> (ExecutableElement) e)
                .anyMatch(e -> e.getModifiers().contains(Modifier.PUBLIC)
                        && e.getParameters().size() == 1
                        && e.getSimpleName().toString().equals(methodName)
                        && AptUtils.isSameTypeIgnoreTypeParameter(typeUtils, e.getParameters().get(0).asType(), argTypeMirror));
    }

    // endregion

    // region 字段检查

    /**
     * 测试{@link TypeElement}是否可以直接读取字段。
     * (这里需要考虑继承问题)
     *
     * @param variableElement 类字段,可能是继承的字段
     * @return 如果可直接取值,则返回true
     */
    public boolean canGetDirectly(final VariableElement variableElement, TypeElement typeElement) {
        return variableElement.getModifiers().contains(Modifier.PUBLIC);
    }

    /**
     * 测试{@link TypeElement}是否可以直接写字段。
     * (这里需要考虑继承问题)
     *
     * @param variableElement 类字段,可能是继承的字段
     * @return 如果可直接赋值,则返回true
     */
    public boolean canSetDirectly(final VariableElement variableElement, TypeElement typeElement) {
        if (variableElement.getModifiers().contains(Modifier.FINAL)) {
            return false;
        }
        return variableElement.getModifiers().contains(Modifier.PUBLIC);
    }

    /** 字段是否是类的成员或同包类的成员 -- 兼容性不好,生成的Codec可能在其它包 */
    @Deprecated
    private boolean isMemberOrPackageMember(VariableElement variableElement, TypeElement typeElement) {
        final TypeElement enclosingElement = (TypeElement) variableElement.getEnclosingElement();
        if (enclosingElement.equals(typeElement)) {
            return true;
        }
        return elementUtils.getPackageOf(enclosingElement).equals(elementUtils.getPackageOf(typeElement));
    }

    /**
     * 查找非private的getter方法
     *
     * @param allMethodWithInherit 所有的字段和方法,可能在父类中
     */
    public ExecutableElement findNotPrivateGetter(final VariableElement variableElement, final List allMethodWithInherit) {
        return BeanUtils.findNotPrivateGetter(typeUtils, variableElement, allMethodWithInherit);
    }

    /**
     * 查找非private的setter方法
     *
     * @param allMethodWithInherit 所有的字段和方法,可能在父类中
     */
    public ExecutableElement findNotPrivateSetter(final VariableElement variableElement, final List allMethodWithInherit) {
        return BeanUtils.findNotPrivateSetter(typeUtils, variableElement, allMethodWithInherit);
    }

    /** 是否是可序列化的字段 */
    private boolean isSerializableField(VariableElement variableElement, List instMethodList, AptFieldProps aptFieldProps) {
        if (variableElement.getModifiers().contains(Modifier.STATIC)) {
            return false;
        }
        // 有注解的情况下,取决于注解的值
        Boolean ignore = aptFieldProps.dsonIgnore;
        if (ignore != null) return ignore;
        // 无注解的情况下,默认忽略 transient 字段
        if (variableElement.getModifiers().contains(Modifier.TRANSIENT)) {
            return false;
        }
        // 判断public和getter
        if (variableElement.getModifiers().contains(Modifier.PUBLIC)) {
            return true;
        }
        return BeanUtils.containsNotPrivateGetter(typeUtils, variableElement, instMethodList);
    }

    /** 是否是托管写的字段 */
    boolean isAutoWriteField(VariableElement variableElement, AptClassProps aptClassProps, AptFieldProps aptFieldProps) {
        if (aptClassProps.isSingleton()) {
            return false;
        }
        // 优先判断skip属性
        if (isSkipFields(variableElement, aptClassProps)) {
            return false;
        }
        return true;
    }

    /** 是否是托管写的字段 */
    boolean isAutoReadField(VariableElement variableElement, AptClassProps aptClassProps, AptFieldProps aptFieldProps) {
        if (aptClassProps.isSingleton()) {
            return false;
        }
        // final必定或构造方法读
        if (variableElement.getModifiers().contains(Modifier.FINAL)) {
            return false;
        }
        // 优先判断skip属性
        if (isSkipFields(variableElement, aptClassProps)) {
            return false;
        }
        return true;
    }

    private boolean isSkipFields(VariableElement variableElement, AptClassProps aptClassProps) {
        if (aptClassProps.skipFields.isEmpty()) {
            return false;
        }
        String fieldName = variableElement.getSimpleName().toString();
        if (aptClassProps.skipFields.contains(fieldName)) {
            return true;
        }
        if (!aptClassProps.clippedSkipFields.contains(fieldName)) {
            return false;
        }
        // 测试SimpleClassName和FullClassName
        TypeElement declaredTypeElement = (TypeElement) variableElement.getEnclosingElement();
        String simpleClassName = declaredTypeElement.getSimpleName().toString();
        if (aptClassProps.skipFields.contains(simpleClassName + "." + fieldName)) {
            return true;
        }
        String fullClassName = declaredTypeElement.getQualifiedName().toString();
        if (aptClassProps.skipFields.contains(fullClassName + "." + fieldName)) {
            return true;
        }
        return false;
    }
    // endregion

    // endregion

    // region 类型测试
    protected boolean isClassOrEnum(TypeElement typeElement) {
        return typeElement.getKind() == ElementKind.CLASS
                || typeElement.getKind() == ElementKind.ENUM;
    }

    protected boolean isString(TypeMirror typeMirror) {
        return typeUtils.isSameType(typeMirror, stringTypeMirror);
    }

    protected boolean isByteArray(TypeMirror typeMirror) {
        return AptUtils.isByteArray(typeMirror);
    }

    protected boolean isEnumLite(TypeMirror typeMirror) {
        return AptUtils.isSubTypeIgnoreTypeParameter(typeUtils, typeMirror, enumLiteTypeMirror);
    }

    protected boolean isMap(TypeMirror typeMirror) {
        return AptUtils.isSubTypeIgnoreTypeParameter(typeUtils, typeMirror, mapTypeMirror);
    }

    protected boolean isCollection(TypeMirror typeMirror) {
        return AptUtils.isSubTypeIgnoreTypeParameter(typeUtils, typeMirror, collectionTypeMirror);
    }

    protected boolean isSet(TypeMirror typeMirror) {
        return AptUtils.isSubTypeIgnoreTypeParameter(typeUtils, typeMirror, setTypeMirror);
    }

    protected boolean isEnumSet(TypeMirror typeMirror) {
        return typeMirror == enumSetRawTypeMirror || AptUtils.isSameTypeIgnoreTypeParameter(typeUtils, typeMirror, enumSetRawTypeMirror);
    }

    protected boolean isEnumMap(TypeMirror typeMirror) {
        return typeMirror == enumMapRawTypeMirror || AptUtils.isSameTypeIgnoreTypeParameter(typeUtils, typeMirror, enumMapRawTypeMirror);
    }
    // endregion

    // region overriding util

    public MethodSpec newGetEncoderClassMethod(DeclaredType superDeclaredType, TypeName rawTypeName) {
        return MethodSpec.overriding(getEncoderClassMethod, superDeclaredType, typeUtils)
                .addStatement("return $T.class", rawTypeName)
                .addAnnotation(AptUtils.ANNOTATION_NONNULL)
                .build();
    }

    public MethodSpec.Builder newNewInstanceMethodBuilder(DeclaredType superDeclaredType) {
        return MethodSpec.overriding(newInstanceMethod, superDeclaredType, typeUtils);
    }

    public MethodSpec.Builder newReadFieldsMethodBuilder(DeclaredType superDeclaredType) {
        return MethodSpec.overriding(readFieldsMethod, superDeclaredType, typeUtils);
    }

    public MethodSpec.Builder newAfterDecodeMethodBuilder(DeclaredType superDeclaredType) {
        return MethodSpec.overriding(afterDecodeMethod, superDeclaredType, typeUtils);
    }

    public MethodSpec.Builder newWriteObjectMethodBuilder(DeclaredType superDeclaredType) {
        return MethodSpec.overriding(writeObjectMethod, superDeclaredType, typeUtils);
    }

    public MethodSpec.Builder newBeforeEncodeMethodBuilder(DeclaredType superDeclaredType) {
        return MethodSpec.overriding(beforeEncodeMethod, superDeclaredType, typeUtils);
    }

    public MethodSpec.Builder newWriteFieldsMethodBuilder(DeclaredType superDeclaredType) {
        return MethodSpec.overriding(writeFieldsMethod, superDeclaredType, typeUtils);
    }

    // endregion

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy