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

cn.wjybxx.dsonapt.SchemaGenerator 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.AbstractGenerator;
import cn.wjybxx.apt.AptUtils;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;

import javax.lang.model.element.Modifier;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.*;
import javax.tools.Diagnostic;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 方法对象
 *
 * @author wjybxx
 * date - 2023/12/10
 */
class SchemaGenerator extends AbstractGenerator {

    private final Context context;
    private final ClassName typeInfoRawTypeName;

    public SchemaGenerator(CodecProcessor processor, Context context) {
        super(processor, context.typeElement);
        this.context = context;
        this.typeInfoRawTypeName = processor.typeNameTypeInfo;
    }

    @Override
    public void execute() {
        final List allSerialFields = context.dsonSerialFields;
        final List allAptTypeInfos = new ArrayList<>(allSerialFields.size());
        for (VariableElement variableElement : allSerialFields) {
            allAptTypeInfos.add(parseTypeArgMirrors(variableElement));
        }

        final List typesFields = genTypeFields(allSerialFields, allAptTypeInfos);
        final List factoryFields = genFactoryFields(allSerialFields, allAptTypeInfos);
        final List namesSpec = genNames();
        context.typeBuilder.addFields(typesFields)
                .addFields(factoryFields)
                .addFields(namesSpec);
    }

    // region typeArgs

    private List genTypeFields(List allSerialFields, List allAptTypeInfos) {
        List typeFieldList = new ArrayList<>(allSerialFields.size() * 2);
        for (int i = 0; i < allSerialFields.size(); i++) {
            VariableElement variableElement = allSerialFields.get(i);
            AptTypeInfo aptTypeInfo = allAptTypeInfos.get(i);
            typeFieldList.add(genTypeField(variableElement, aptTypeInfo));
        }
        return typeFieldList;
    }

    private List genFactoryFields(List allSerialFields, List allAptTypeInfos) {
        List typeFieldList = new ArrayList<>(allSerialFields.size() * 2);
        for (int i = 0; i < allSerialFields.size(); i++) {
            VariableElement variableElement = allSerialFields.get(i);
            AptTypeInfo aptTypeInfo = allAptTypeInfos.get(i);
            if (aptTypeInfo.impl != null) {
                typeFieldList.add(genFactoryField(variableElement, aptTypeInfo));
            }
        }
        return typeFieldList;
    }

    private FieldSpec genFactoryField(VariableElement variableElement, AptTypeInfo aptTypeInfo) {
        // 暂不擦除泛型 -- 我们约定禁止字段出现未定义泛型,如:List
        ParameterizedTypeName fieldTypeName = ParameterizedTypeName.get(AptUtils.CLSNAME_SUPPLIER,
                TypeName.get(variableElement.asType()));
        String filedName = "factories_" + variableElement.getSimpleName().toString();
        FieldSpec.Builder builder = FieldSpec.builder(fieldTypeName, filedName, AptUtils.PUBLIC_STATIC_FINAL);

        if (aptTypeInfo.type == AptTypeInfo.TYPE_MAP) {
            if (processor.isEnumMap(aptTypeInfo.impl)) {
                builder.initializer("() -> new EnumMap<>($T.class)",
                        TypeName.get(typeUtils.erasure(aptTypeInfo.typeArgs.get(0))));
            } else {
                builder.initializer("$T::new",
                        TypeName.get(typeUtils.erasure(aptTypeInfo.impl)));
            }
        } else if (aptTypeInfo.type == AptTypeInfo.TYPE_COLLECTION) {
            if (processor.isEnumSet(aptTypeInfo.impl)) {
                builder.initializer("() -> EnumSet.noneOf($T.class)",
                        TypeName.get(typeUtils.erasure(aptTypeInfo.typeArgs.get(0))));
            } else {
                builder.initializer("$T::new",
                        TypeName.get(typeUtils.erasure(aptTypeInfo.impl)));
            }
        } else {
            // 其它类型字段
            builder.initializer("$T::new",
                    TypeName.get(typeUtils.erasure(aptTypeInfo.impl)));
        }
        return builder.build();
    }

    private FieldSpec genTypeField(VariableElement variableElement, AptTypeInfo aptTypeInfo) {
        ParameterizedTypeName fieldTypeName;
        if (variableElement.asType().getKind().isPrimitive()) {
            // 基础类型不能做泛型参数...
            fieldTypeName = ParameterizedTypeName.get(typeInfoRawTypeName,
                    TypeName.get(variableElement.asType()).box());
        } else {
            // TypeInfo的泛型T最好不带泛型参数,兼容性很差
            fieldTypeName = ParameterizedTypeName.get(typeInfoRawTypeName,
                    TypeName.get(typeUtils.erasure(variableElement.asType())));
        }
        String filedName = "types_" + variableElement.getSimpleName().toString();
        FieldSpec.Builder builder = FieldSpec.builder(fieldTypeName, filedName, AptUtils.PUBLIC_STATIC_FINAL);
        switch (aptTypeInfo.typeArgs.size()) {
            case 0: {
                builder.initializer("$T.of($T.class)",
                        typeInfoRawTypeName,
                        TypeName.get(typeUtils.erasure(aptTypeInfo.declared)));
                break;
            }
            case 1: {
                builder.initializer("$T.of($T.class, $T.class)",
                        typeInfoRawTypeName,
                        TypeName.get(typeUtils.erasure(aptTypeInfo.declared)),
                        TypeName.get(typeUtils.erasure(aptTypeInfo.typeArgs.get(0))));
                break;
            }
            case 2: {
                builder.initializer("$T.of($T.class, $T.class, $T.class)",
                        typeInfoRawTypeName,
                        TypeName.get(typeUtils.erasure(aptTypeInfo.declared)),
                        TypeName.get(typeUtils.erasure(aptTypeInfo.typeArgs.get(0))),
                        TypeName.get(typeUtils.erasure(aptTypeInfo.typeArgs.get(1))));
                break;
            }
            default: {
                // 超过2个泛型参数时,使用List.of
                StringBuilder format = new StringBuilder("$T.of($T.class, List.Of(");
                List params = new ArrayList<>(aptTypeInfo.typeArgs.size() + 2);
                params.add(typeInfoRawTypeName);
                params.add(TypeName.get(typeUtils.erasure(aptTypeInfo.declared)));
                for (int i = 0; i < aptTypeInfo.typeArgs.size(); i++) {
                    if (i > 0) {
                        format.append(", ");
                    }
                    TypeMirror typeArg = aptTypeInfo.typeArgs.get(i);
                    format.append("$T.class");
                    params.add(typeUtils.erasure(typeArg));
                }
                format.append(")");
                builder.initializer(format.toString(), params.toArray());
                break;
            }
        }
        return builder.build();
    }

    private AptTypeInfo parseTypeArgMirrors(VariableElement variableElement) {
        TypeMirror typeMirror = variableElement.asType();
        // 普通类型字段 -- 也需要解析泛型参数
        if (typeMirror.getKind().isPrimitive()) {
            return AptTypeInfo.of(typeMirror, null);
        }
        // 数组支持impl
        AptFieldProps properties = context.fieldPropsMap.get(variableElement);
        if (typeMirror.getKind() == TypeKind.ARRAY) {
            return AptTypeInfo.of(variableElement.asType(), properties.implMirror);
        }
        if (processor.isMap(typeMirror)) {
            return parseMapTypeArgs(variableElement, properties);
        }
        if (processor.isCollection(typeMirror)) {
            return parseCollectionTypeArgs(variableElement, properties);
        }
        final DeclaredType declaredType = (DeclaredType) typeMirror;
        final List typeArguments = erasureTypeArguments(declaredType.getTypeArguments());
        return AptTypeInfo.of(declaredType, typeArguments, properties.implMirror);
    }

    /** 解析map的类型信息 */
    private AptTypeInfo parseMapTypeArgs(VariableElement variableElement, AptFieldProps properties) {
        // 查找传递给Map接口的KV泛型参数
//        final DeclaredType superTypeMirror = AptUtils.upwardToSuperTypeMirror(typeUtils, variableElement.asType(), processor.mapTypeMirror);
//        List typeArguments = erasureTypeArguments(superTypeMirror.getTypeArguments());
//        if (typeArguments.size() != 2) {
//            messager.printMessage(Diagnostic.Kind.ERROR, "Can't find key or value type of map", variableElement);
//        }
        final DeclaredType declaredType = (DeclaredType) variableElement.asType();
        final List typeArguments = erasureTypeArguments(declaredType.getTypeArguments());
        final TypeMirror realImplMirror = parseMapVarImpl(variableElement, properties);
        return AptTypeInfo.ofMap(variableElement.asType(), typeArguments, realImplMirror);
    }

    /** 解析Collection的类型信息 */
    private AptTypeInfo parseCollectionTypeArgs(VariableElement variableElement, AptFieldProps properties) {
        // 查找传递给Collection接口的E泛型参数
//        final DeclaredType superTypeMirror = AptUtils.upwardToSuperTypeMirror(typeUtils, variableElement.asType(), processor.collectionTypeMirror);
//        final List typeArguments = erasureTypeArguments(superTypeMirror.getTypeArguments());
//        if (typeArguments.size() != 1) {
//            messager.printMessage(Diagnostic.Kind.ERROR, "Can't find element type of collection", variableElement);
//        }
        final DeclaredType declaredType = (DeclaredType) variableElement.asType();
        final List typeArguments = erasureTypeArguments(declaredType.getTypeArguments());
        TypeMirror realImplMirror = parseCollectionVarImpl(variableElement, properties);
        return AptTypeInfo.ofCollection(variableElement.asType(), typeArguments, realImplMirror);
    }

    /** 解析map的实现类 */
    private TypeMirror parseMapVarImpl(VariableElement variableElement, AptFieldProps properties) {
        if (!AptUtils.isBlank(properties.readProxy)) {
            return null; // 有读代理,不需要解析
        }
        TypeMirror typeMirror = variableElement.asType();
        if (processor.isEnumMap(typeMirror)) {
            return processor.enumMapRawTypeMirror; // EnumMap不需要解析
        }

        final DeclaredType declaredType = AptUtils.findDeclaredType(variableElement.asType());
        assert declaredType != null;
        // 具体类和抽象类都可以指定实现类
        if (properties.implMirror != null
                && AptUtils.isSubTypeIgnoreTypeParameter(typeUtils, properties.implMirror, variableElement.asType())) {
            return properties.implMirror;
        }
        // 是具体类型-可直接构造
        if (!declaredType.asElement().getModifiers().contains(Modifier.ABSTRACT)) {
            return declaredType;
        }
        // 如果是抽象的,并且不是LinkedHashMap的超类,则抛出异常
        checkDefaultImpl(variableElement, processor.linkedHashMapTypeMirror);
        return null;
    }

    /** 解析collection的实现类 */
    private TypeMirror parseCollectionVarImpl(VariableElement variableElement, AptFieldProps properties) {
        if (!AptUtils.isBlank(properties.readProxy)) {
            return null; // 有读代理,不需要解析
        }
        TypeMirror typeMirror1 = variableElement.asType();
        if (processor.isEnumSet(typeMirror1)) {
            return processor.enumSetRawTypeMirror; // EnumSet不需要解析
        }

        final DeclaredType declaredType = AptUtils.findDeclaredType(variableElement.asType());
        assert declaredType != null;
        // 具体类和抽象类都可以指定实现类
        if (properties.implMirror != null
                && AptUtils.isSubTypeIgnoreTypeParameter(typeUtils, properties.implMirror, variableElement.asType())) {
            return properties.implMirror;
        }
        // 是具体类型-可直接构造
        if (!declaredType.asElement().getModifiers().contains(Modifier.ABSTRACT)) {
            return declaredType;
        }
        // 如果是抽象的,并且不是ArrayList/LinkedHashSet的超类,则抛出异常
        TypeMirror typeMirror = variableElement.asType();
        if (processor.isSet(typeMirror)) {
            checkDefaultImpl(variableElement, processor.linkedHashSetTypeMirror);
        } else {
            checkDefaultImpl(variableElement, processor.arrayListTypeMirror);
        }
        return null;
    }

    /** 擦除泛型参数 */
    private List erasureTypeArguments(List typeArguments) {
        List result = new ArrayList<>(typeArguments.size());
        for (TypeMirror typeArgument : typeArguments) {
            if (typeArgument.getKind() == TypeKind.WILDCARD) {
                // 通配符 —— ? extends XXX,其上界就可以看做声明类型
                WildcardType wildcardType = (WildcardType) typeArgument;
                if (wildcardType.getExtendsBound() != null) {
                    result.add(typeUtils.erasure(wildcardType.getExtendsBound()));
                } else {
                    result.add(processor.objectTypeMirror);
                }

            } else if (typeArgument.getKind() == TypeKind.TYPEVAR) {
                // 泛型变量 —— T extends XXX,其上界就可以看做声明类型
                TypeVariable typeVariable = (TypeVariable) typeArgument;
                result.add(typeUtils.erasure(typeVariable.getUpperBound()));
            } else {
                result.add(typeUtils.erasure(typeArgument));
            }
        }
        return result;
    }

    /** 检查字段是否是默认实现类型的超类 */
    private void checkDefaultImpl(VariableElement variableElement, TypeMirror defImpl) {
        if (!AptUtils.isSubTypeIgnoreTypeParameter(typeUtils, defImpl, variableElement.asType())) {
            messager.printMessage(Diagnostic.Kind.ERROR,
                    "Unknown abstract Map or Collection must contains impl annotation " + CodecProcessor.CNAME_PROPERTY,
                    variableElement);
        }
    }

    // endregion

    // region names

    private List genNames() {
        final List serialFields = context.dsonSerialFields;
        final Set dsonNameSet = new HashSet<>((int) (serialFields.size() * 1.35f));
        final List fieldSpecList = new ArrayList<>(serialFields.size());

        for (VariableElement variableElement : serialFields) {
            AptFieldProps properties = context.fieldPropsMap.get(variableElement);
            String fieldName = variableElement.getSimpleName().toString();
            String dsonName;
            if (!AptUtils.isBlank(properties.name)) {
                dsonName = properties.name.trim();
            } else {
                dsonName = fieldName;
            }
            if (!dsonNameSet.add(dsonName)) {
                messager.printMessage(Diagnostic.Kind.ERROR,
                        String.format("dsonName is duplicate, dsonName %s", dsonName),
                        variableElement);
                continue;
            }
            fieldSpecList.add(FieldSpec.builder(AptUtils.CLSNAME_STRING, "names_" + fieldName, AptUtils.PUBLIC_STATIC_FINAL)
                    .initializer("$S", dsonName)
                    .build()
            );
        }
        return fieldSpecList;
    }

    // endregion

}