EasyAnnotation框架实例化对象注解(二)

537 阅读5分钟

如何成为T型人才,垂直在一个行业中,必须要有一整套知识体系,在这里,就一个字坚持~

前言

开发过程中,经常会运用到一些设计模式,优秀的架构少不了设计模式使用。工厂设计模式属于创建模式之一,当一个类或者接口有多个子类,并且基于输入返回特定的子类,此时会使用工厂设计模式,这种模式负责从客户端到工厂类的实例化。其实原理我们都懂,那如何通过APT技术实现工厂类?接下来直接代码编码,注解理论知识,请移步到 细聊注解知识点。谢谢~

Contents

一、定义实例化对象注解

@ObjectFactory:该注解标识需要加入工厂类的子类。@Retention(RetentionPolicy.CLASS):表示编译时注解。@Target(ElementType.TYPE): 表示修饰类。注解参数定义type变量,表示工厂类Class对象,key变量,表示注解修饰类在工厂类中的标识。

@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface ObjectFactory {

    Class type(); //父类名

    String key();  //标识
}

二、自定义注解处理器

不同注解类型,对应不同注解处理器,注解处理器主要作用就是注解解析。在定义编译时注解,我们需要通过继承AbstractProcessor这个类来创建注解处理器,并重写父类方法,一般只需要重新几个重要方法分别:

1、注解初始化
public synchronized void init(ProcessingEnvironment processingEnvironment)
2、注解解析
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
3、注解版本
public SourceVersion getSupportedSourceVersion()
4、解析类型
public Set<String> getSupportedAnnotationTypes()

2.1、注解处理器初始化

AbstractProcessor注解处理器每次初始化只会调用一次init(ProcessingEnvironment processingEnvironment)方法,所以可以用来初始化工具类。

@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        //注解处理器工具类
        mProcessorUtils = ProcessorUtils.getInstance(processingEnv);
        //根据ObjectFactory.object()类型,存储不同的子类
        mGroupedClassesMap = new LinkedHashMap<>();
        //生产模板对象
        mGenerator = new ObjectFactoryGenerator();
 }

2.2、绑定注解到注解处理器

getSupportedAnnotationTypes()方法是注解处理器能够识别注解类型。这里把注解@ObjectFactory存储到LinkedHashSet数据结构中,并返回集合,标识注解处理器识别目标注解对象。

@Override
public Set<String> getSupportedAnnotationTypes() {
   LinkedHashSet<String> types = new LinkedHashSet<>(1);
   types.add(ObjectFactory.class.getCanonicalName());
    return types;
}

2.3、注解解析处理

RoundEnvironment这个类中提供#getElementsAnnotatedWith()方法,可以根据注解类型返回该类型注解所有信息,通过Element可以获取注解信息。Element.getKind返回注解修饰类型,根据不同类型转换为不同Element子类。#checkValidClass() 主要校验注解是否有效,有效数据根据注解type类型进行区分存储,type标识不同工厂类。解析所有注解信息后,存储到LinkedHashMap集合中,最后遍历集合中数据,循环调用 #generator方法,生成样板代码。

@Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        Set<? extends Element> factoryElements =
                roundEnvironment.getElementsAnnotatedWith(ObjectFactory.class);
        for (Element element : factoryElements) {
            ObjectFactoryClasses classes = null;
            try {
                ElementKind kind = element.getKind();
                if (kind == ElementKind.CLASS) {
                    classes = new ObjectFactoryClasses((TypeElement) element);
                    if (!checkValidClass(classes)) {
                        return true; //检查不符合要求,进行错误日志输出
                    }

                    ObjectFactoryGroupedClasses groupedClasses = mGroupedClassesMap.get(classes.getQualifiedName());
                    if (groupedClasses == null) {
                        groupedClasses = new ObjectFactoryGroupedClasses();
                        mGroupedClassesMap.put(classes.getQualifiedName(), groupedClasses);
                    }

                    groupedClasses.addObjectFactoryClasses(classes);

                }
            } catch (IllegalArgumentException e) {
                mProcessorUtils.eLog(e.getMessage());
                return true;
            } catch (IdAlreadyUsedException e) {
                ObjectFactoryClasses existing = e.getExisting();
                assert classes != null;
                mProcessorUtils.eLog(
                        "Conflict: The class %s is annotated with @%s with id ='%s' but %s already uses the same id",
                        classes.getQualifiedName(), ObjectFactory.class.getSimpleName(),
                        existing.getTypeElement().getQualifiedName().toString());
                return true;
            }
        }

        try {
            //生成模板代码
            for (String objects : mGroupedClassesMap.keySet()) {
                mGenerator.generator(objects, mGroupedClassesMap.get(objects), mProcessorUtils, processingEnv);
            }
            //process()多次调用处理,所以配置信息及时释放
            mGroupedClassesMap.clear();
        } catch (Exception e) {
            mProcessorUtils.eLog(e.getMessage());
        }
        return true;
    }

2.4、注解信息校验

@ObjectFactory注解修饰的类级别,所以主要校验类的限定符,是否抽象类,是否实现同一个父类,这里getQualifiedName()方法通过反射射方式获取共同父类名,在通过不断循环判断是否实现同个父类,同时对构造函数限定符,参数校验。

 /**
     * 类型校验
     * @param classes
     * @return
     */
    private boolean checkValidClass(ObjectFactoryClasses classes) {
        TypeElement typeElement = classes.getTypeElement();

        //检查该类限定符
        if (!typeElement.getModifiers().contains(Modifier.PUBLIC)) {
            mProcessorUtils.eLog("The class $s not public",
                    classes.getQualifiedName());
            return false;
        }

        //检查是否是一个抽象类
        if (typeElement.getModifiers().contains(Modifier.ABSTRACT)) {
            mProcessorUtils.eLog("The class $s is abstract," +
                            "You can't annotate abstract classes with @%s",
                    classes.getQualifiedName(), ObjectFactory.class.getSimpleName());
            return false;
        }

        //检查继承关系,必须是@ObjectFactory.object()类型子类
        TypeElement superTypeElement = mProcessorUtils.processorElementUtils().
                getTypeElement(classes.getQualifiedName());
        //检查是否为接口类型
        if (superTypeElement.getKind() == ElementKind.INTERFACE) {
            if (!typeElement.getInterfaces().contains(superTypeElement.asType())) {
                mProcessorUtils.eLog("The class %s annotated with @%s must implement the interface %s",
                        typeElement.getQualifiedName().toString(), ObjectFactory.class.getSimpleName(),
                        classes.getQualifiedName());
                return false;
            } else {
                TypeElement currentClass = typeElement;
                while (true) {
                    TypeMirror superclassType = currentClass.getSuperclass();
                    if (superclassType.getKind() == TypeKind.NONE) {
                        // 到达了基本类型(java.lang.Object), 所以退出
                        mProcessorUtils.eLog("The class %s annotated with @%s must inherit from %s",
                                typeElement.getQualifiedName().toString(), ObjectFactory.class.getSimpleName(),
                                classes.getQualifiedName());
                        return false;
                    }

                    if (superclassType.toString().equals(classes.getQualifiedName())) {
                        break;
                    }

                    currentClass = (TypeElement) mProcessorUtils.processorTypeUtils().asElement(superclassType);
                }
            }
        }

        for (Element element : typeElement.getEnclosedElements()) {
            if (element.getKind() == ElementKind.CONSTRUCTOR) {
                ExecutableElement constructorElement = (ExecutableElement) element;
                if (constructorElement.getParameters().size() == 0 && constructorElement.getModifiers().contains(Modifier.PUBLIC)) {
                    return true;
                }
            }
        }

        // 没有找到默认构造函数
        mProcessorUtils.eLog("The class %s must provide an public empty default constructor",
                classes.getQualifiedName());

        return false;
    }

三、解析注解信息,生成样板代码

3.1、解析注解信息

在上文roundEnvironment.getElementsAnnotatedWith()获取到@ObjectFactory注解TypeElement对象,通过TypeElement可以获取到注解参数信息。

/**
 * @Author: WeiShuai
 * @Time: 2020/5/12
 * @Description: TypeElements包装类,
 */
public class ObjectFactoryClasses {
    private TypeElement mTypeElement;
    private String mQualifiedName;
    private String mSimpleName;
    private String mKey;

    public ObjectFactoryClasses(TypeElement typeElement) {
        this.mTypeElement = typeElement;

        ObjectFactory factory = mTypeElement.getAnnotation(ObjectFactory.class);
        this.mKey = factory.key();

        if ("".equals(mKey)) {
            throw new IllegalArgumentException(
                    String.format("key() in @%s for class %s is null or empty! that's not allowed",
                            ObjectFactory.class.getSimpleName(), mTypeElement.getQualifiedName().toString()));
        }

        try {
            Class<?> clazz = factory.type();
            mQualifiedName = clazz.getCanonicalName();
            mSimpleName = clazz.getSimpleName();
        } catch (MirroredTypeException mte) {
            DeclaredType classTypeMirror = (DeclaredType) mte.getTypeMirror();
            TypeElement classTypeElement = (TypeElement) classTypeMirror.asElement();
            mQualifiedName = classTypeElement.getQualifiedName().toString();
            mSimpleName = classTypeElement.getSimpleName().toString();
        }
    }

    /**
     * 获取在{@link ObjectFactory#key()}指定的类型合法全名
     *
     * @return
     */
    public String getQualifiedName() {
        return mQualifiedName;
    }

    /**
     * 获取在 {@link ObjectFactory#key()} 中指定的类型的简单名字
     *
     * @return qualified name
     */
    public String getSimpleName() {
        return mSimpleName;
    }

    /**
     * 返回TypeElement
     *
     * @return
     */
    public TypeElement getTypeElement() {
        return mTypeElement;
    }

    /**
     * 获取对象标识
     *
     * @return
     */
    public String getKey() {
        return mKey;
    }

}

3.2、封装注解信息

根据注解@ObjectFactory参数key字段,key表示注解修饰类标识,通过该标识来封装注解信息。

/**
 * @Author: WeiShuai
 * @Time: 2020/5/12
 * @Description: 保存TypeElements对象信息
 */
public class ObjectFactoryGroupedClasses {

    private LinkedHashMap<String, ObjectFactoryClasses> mObjectFactoryMaps = new
            LinkedHashMap<>();

    /**
     * 保存ObjectFactory对象
     */
    public void addObjectFactoryClasses(ObjectFactoryClasses classes) throws IdAlreadyUsedException {
        ObjectFactoryClasses objectFactoryClasses = mObjectFactoryMaps.get(classes.getKey());
        if (objectFactoryClasses != null) {
            throw new IdAlreadyUsedException(objectFactoryClasses);
        }

        mObjectFactoryMaps.put(classes.getKey(), classes);
    }

    /**
     * 获取ObjectFactory对象
     *
     * @param key
     */
    public ObjectFactoryClasses getObjectFactoryClasses(String key) {
        return mObjectFactoryMaps.get(key);
    }

    /**
     * 获取注解信息
     *
     * @return
     */
    public LinkedHashMap<String, ObjectFactoryClasses> getObjectFactoryClassesMaps() {
        return mObjectFactoryMaps;
    }

}

3.3、生成样板代码

public class ObjectFactoryGenerator {

    public void generator(String clazzType,
                          ObjectFactoryGroupedClasses groupedClasses,
                          ProcessorUtils processorUtils,
                          ProcessingEnvironment processingEnv) {

        if ("".equals(clazzType)) {
            throw new NullPointerException(
                    String.format("getQualifiedName()  is null or empty! that's not allowed"));
        }

        TypeElement superTypeElement = processorUtils.processorElementUtils().
                getTypeElement(clazzType);
        String classes = superTypeElement.getSimpleName().toString();

        MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(Constant.METHOD_FACTORY)
                .addModifiers(Modifier.PUBLIC)
                .returns(TypeName.get(superTypeElement.asType()));

        //根据FactoryObject.key()获取对象
        methodBuilder.addParameter(String.class, "id");

        //LinkedHashMap<K,V>,K:注解标识,V:使用注解对应对象信息
        LinkedHashMap<String, ObjectFactoryClasses> classesMaps =
                groupedClasses.getObjectFactoryClassesMaps();
        TypeElement typeElement = null;
        for (String key : classesMaps.keySet()) {
            typeElement = classesMaps.get(key).getTypeElement();
            methodBuilder.addStatement("if( \"" + key + "\".equals(id)){");
            methodBuilder.addStatement("return new " + typeElement.getQualifiedName().toString() + "()");
            methodBuilder.addStatement("}");
        }

        methodBuilder.addStatement("return null");

        if (typeElement != null) {
            processorUtils.writeToFile(classes + Constant.FACTORY_SUFFIX,
                    processorUtils.getPackageName(typeElement),
                    methodBuilder.build(), processingEnv, null);
        }
    }
}

四、功能点测试

4.1、测试代码

  1. 创建抽象BaseFragment类作为共同父类,在HomeFragment、MineFragment类继承父类BaseFragment,实现父类未实现方法。
public abstract class BaseFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View rootView = inflater.inflate(getLayoutId(), null);
        return rootView;
    }

    public abstract int getLayoutId();
}
  1. 创建HomeFragment、MineFragment类这里必须实现共同父类BaseFragment,因为@ObjectFactory注解校验规则限定,注解参数定义type=父类.class,key="类标识"。
@ObjectFactory(type = BaseFragment.class, key = "Home")
public class HomeFragment extends BaseFragment {
    @Override
    public int getLayoutId() {
        return R.layout.fragment_home;
    }
}
@ObjectFactory(type = BaseFragment.class, key = "Mine")
public class MineFragment extends BaseFragment {
    @Override
    public int getLayoutId() {
        return R.layout.fragment_mine;
    }
}

4.2、样板代码

通过解析指定注解信息,通过APT技术构建类、方法、字段,并生成java文件。

public final class BaseFragment$Factory {
  public BaseFragment objectFactory(String id) {
    if( "Home".equals(id)){;
    return new com.linwei.annotation.compile.HomeFragment();
    };
    if( "Mine".equals(id)){;
    return new com.linwei.annotation.compile.MineFragment();
    };
    return null;
  }
}

About me