自定义APT终极—>生成有参抽象工程

7 篇文章 1 订阅

接着上篇 自定义apt实战之一>抽象工厂

在和Java后台的同事聊天的时候,发现他们经常使用Data-Map来存放类名,然后通过反射来初始化。我在想为什么不用抽象工厂呢?抽象工厂和策略反射相比较:
优点
抽象工厂无反射,性能相对较高;
Data-Map每次增加 一个类,都需要在Data_Map里面进行注册,一不小心还有可能key重复;
缺点:
抽象工厂强依赖,不符合高内聚低耦合的设计思想;
抽象工厂要写很多if-else,不够优雅,每次新增类都要增加if-else;

特别是针对我现在工作内容,各种协议,每个协议都有很多子项。有时候做程序员,要有懒人精神。不会偷懒的程序员不是好程序员,所谓懒人,通俗点就是要少写代码,在后续扩展时,尽量不触及之前的代码(低耦合)。

要做到吸收上面两种方式的优点,同时避免缺点。使用APT去生成这个抽象工厂,之前已经完成了无参的抽象工厂。可以通过在基类接口里面定义抽象方法来进行传参。但是在后续的使用中发现有些类的基类构造方法限定了在实例化对象的时候必须要传参。比如View,必须传入Context。所以就想着给抽象工厂增加有参的produce方法。

基本思路:在重写工厂接口的@produce修饰的方法是,判断该方法有多少个参数,把这些参数存到集合里面,在实例化对象时,把这些参数传进去。废话不多说,直接上代码:

@AutoService(Processor.class)
public class FactoryProcessor extends BaseProcessor
{
    // 所有要要处理的抽象工厂
    private List<FactoryBean> mFactoryList = new ArrayList<>();
    // <父类名, 子类集合>
    private Map<String,List<TypeElement>> productsMap = new HashMap<>();

    private boolean dealed;

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)
    {
        try
        {
//            mLogUtil.d("-----FactoryProcessor---process-----id:" + FactoryProcessor.this);
            if (dealed) return false;
            filterAnnotations(roundEnv);

            Iterator<FactoryBean> iterator = mFactoryList.iterator();
            while (iterator.hasNext()){
                generateJavaFile(iterator.next());
            }
            dealed = true;
        } catch (Exception e)
        {
            e.printStackTrace();
            mLogUtil.e(e);
        }
        return true;
    }

    /**
     * 筛选注解
     */
    private boolean filterAnnotations(RoundEnvironment roundEnv) throws ClassNotFoundException
    {
        Set<? extends Element> factoryElements = roundEnv.getElementsAnnotatedWith(AbstractFactory.class);
        Set<? extends Element> productElements = roundEnv.getElementsAnnotatedWith(Product.class);
//        Set<? extends Element> produceElements = roundEnv.getElementsAnnotatedWith(Produce.class);
        // 筛选产品
        Iterator<? extends Element> productIterator = productElements.iterator();
        while (productIterator.hasNext())
        {
            TypeElement productElement = (TypeElement) productIterator.next();
            if (!ProcessorUtil.isValidClass(productElement, mMessager, Product.class.getName())){
                continue;
            }
//            Product product = productElement.getAnnotation(Product.class);
            // 获取要转化的类名
            String superName = "null";
            try
            {
                for (AnnotationMirror m: productElement.getAnnotationMirrors())
                {
                    if (m.getAnnotationType().toString().equals(Product.class.getName())){
                        for (Map.Entry e : m.getElementValues().entrySet())
                        {
                            ExecutableElement key = (ExecutableElement) e.getKey();
                            if (key.getSimpleName().toString().equals("superClass")){
                                AnnotationValue value = (AnnotationValue) e.getValue();
                                superName = value.getValue().toString();
                            }
                        }
                    }
                }
            } catch (Exception e)
            {
                e.printStackTrace();
            }
            // 当前类名
//            String childName = productElement.getQualifiedName().toString();
            // 存入
            List<TypeElement> childClassNames;
            if (productsMap.containsKey(superName)){
                childClassNames = productsMap.get(superName);
            }else {
                childClassNames = new ArrayList<>();
            }
            childClassNames.add(productElement);
            productsMap.put(superName, childClassNames);
        }
        //生成抽象工厂类
        Iterator<? extends Element> factoryIterator = factoryElements.iterator();
        while (factoryIterator.hasNext()){
            Element itemElement = factoryIterator.next();

            // 判断当前类是否是抽象类或者接口
            if (itemElement.getKind() != ElementKind.INTERFACE && !itemElement.getModifiers().contains(Modifier.ABSTRACT)){
                mLogUtil.e("@AbstractFactory 只能作用于接口或者抽象类");
                return false;
            }
            TypeElement factoryElement = (TypeElement) itemElement;
            List<ExecutableElement> methodList = new ArrayList<>();
            // 获取该类的所有抽象方法
            for (Element element: factoryElement.getEnclosedElements())
            {
                if (element.getAnnotation(Produce.class) != null
                        && element.getModifiers().contains(Modifier.ABSTRACT)
                        && element.getModifiers().contains(Modifier.PUBLIC)
                        && element.getKind().equals(ElementKind.METHOD)){
                    if (((ExecutableElement)element).getParameters().size() == 0 ||
                            !((ExecutableElement)element).getParameters().get(0).asType().toString().equals("java.lang.String"))
                    {
                        mLogUtil.e("@Produce 作用的方法最少有 一个java.lang.String类型的参数,且String类型参数必须是第一个参数");
                        return false;
                    }
                    methodList.add((ExecutableElement) element);
                }
            }
            if (methodList.size() > 0){
                FactoryBean factory = new FactoryBean();
                factory.setFactoryImp(factoryElement);
                factory.setMethods(methodList);
                mFactoryList.add(factory);
            }
        }
        return true;
    }

    /**
     * 生成java文件
     */
    private void generateJavaFile(FactoryBean factoryBean){
//        mLogUtil.d("-----generateJavaFile----");
        AbstractFactory factory = factoryBean.getFactoryImp().getAnnotation(AbstractFactory.class);
        String createClassName = factory.name();
        String superClassName = factoryBean.getFactoryImp().getQualifiedName().toString();
        // 新建一个类
        TypeSpec.Builder typeSpecBuilder = TypeSpec.classBuilder(createClassName);
        typeSpecBuilder.addModifiers(Modifier.PUBLIC);
//        typeSpecBuilder.addOriginatingElement()
        ClassName superInterface = ClassName.get(ProcessorUtil.getPackageName(factoryBean.factoryImp), factoryBean.factoryImp.getSimpleName().toString());
        // 增加实现接口
        if (factoryBean.getFactoryImp().getKind() == ElementKind.INTERFACE){
            typeSpecBuilder.addSuperinterface(superInterface);
        } else {// 增加继承类
            typeSpecBuilder.superclass(superInterface);
        }

        // 重写方法
        for (ExecutableElement methodE : factoryBean.methods)
        {
            if (methodE.getParameters().size() == 0) continue;
            MethodSpec.Builder methodSpecBuilder = MethodSpec.methodBuilder(methodE.getSimpleName().toString());
            // 方法的参数部分, 第一个string 类型的key参数
            List<ParameterSpec> paramTypeNames = new ArrayList<>();
            List<? extends VariableElement> paramElements = methodE.getParameters();
            for (int i = 0; i < paramElements.size(); i ++){
                VariableElement itemParamElement = paramElements.get(i);
//                TypeName typeName = new TypeName(itemParamElement.asType().toString());
//                Type type = itemParamElement.asType();

                String itemClassName = itemParamElement.asType().toString();
                if (itemClassName != null && itemClassName.length() > 0 && itemClassName.contains(".")){
                    String paramsPackageName = itemClassName.substring(0, itemClassName.lastIndexOf("."));
                    String paramsName = itemClassName.substring(itemClassName.lastIndexOf(".") + 1);
                    TypeName itemTypeName = ClassName.get(paramsPackageName,paramsName);
                    ParameterSpec parameterSpec2 = ParameterSpec.builder(itemTypeName, itemParamElement.getSimpleName().toString()).build();
                    paramTypeNames.add(parameterSpec2);
                }
            }

            String param = methodE.getParameters().get(0).toString();
//            ParameterSpec parameterSpec = ParameterSpec.builder(String.class, param)
//                    .build();
//            paramTypeNames.add(parameterSpec);
//
//            // 参数的类型名
//            String paramsClassName = ProcessorUtil.getClassName(methodE, Produce.class.getName(), "paramas");
//            TypeName paramsTymeName = null;
//            if (paramsClassName != null && paramsClassName.length() > 0 && paramsClassName.contains(".")){
//                String paramsPackageName = paramsClassName.substring(0, paramsClassName.lastIndexOf("."));
//                String paramsName = paramsClassName.substring(paramsClassName.lastIndexOf(".") + 1);
//                paramsTymeName = ClassName.get(paramsPackageName,paramsName);
//                ParameterSpec parameterSpec2 = ParameterSpec.builder(paramsTymeName, "parames").build();
//                paramTypeNames.add(parameterSpec2);
//            }

            // 方法的返回类型
            TypeMirror returnTypeMirror = methodE.getReturnType();
            // 所有要if-else实例化的对象
            List<TypeElement> entities = productsMap.get(returnTypeMirror.toString());

            if (entities == null || entities.size() == 0) continue;
//            TypeName textUtilName = ClassName.get("android.text","TextUtils");

            for (int i = 0; i < entities.size(); i ++)
            {
                TypeElement element =  entities.get(i);
                String key = element.getAnnotation(Product.class).key();
                TypeName backEntity = ClassName.get(ProcessorUtil.getPackageName(element), element.getSimpleName().toString());
                if (i == 0){
//                    methodSpecBuilder.beginControlFlow("if ($T.equals($S, $L))", textUtilName, key, param);
                    methodSpecBuilder.beginControlFlow("if ($S != null && $S.equals($L))", key, key, param);

                }else {
//                    methodSpecBuilder.nextControlFlow("else if ($T.equals($S, $L))", textUtilName, key, param);
                    methodSpecBuilder.nextControlFlow("else if ($S != null && $S.equals($L))", key, key, param);

                }
                if (paramTypeNames.size() > 1){
                    StringBuilder builder = new StringBuilder("return new $T(");
                    Iterator<ParameterSpec> iterator = paramTypeNames.iterator();
                    iterator.next();
                    Object paramFiledNames[] = new Object[paramTypeNames.size()];
                    paramFiledNames[0] = backEntity;
                    for (int k = 1; k < paramTypeNames.size(); k ++){
                        builder.append("$L");
                        if (k != paramTypeNames.size() - 1){
                            builder.append(",");
                        }
                       paramFiledNames[k] = paramTypeNames.get(k).name;
                    }
                    builder.append(")");
                    methodSpecBuilder.addStatement(builder.toString(), paramFiledNames);
                }else {
                    methodSpecBuilder.addStatement("return new $T()", backEntity);
                }
//                methodSpecBuilder.endControlFlow();
            }
            methodSpecBuilder.endControlFlow()
                    .addStatement("return null");

            MethodSpec methodSpec = methodSpecBuilder.returns(TypeName.get(returnTypeMirror))
                                        .addParameters(paramTypeNames)
                                        .addAnnotation(Override.class)
                                        .addModifiers(Modifier.PUBLIC)
                                        .build();

            typeSpecBuilder.addMethod(methodSpec);
        }

        // 生成.java文件
        JavaFile javaFile = JavaFile.builder(PACKAGE_NAME, typeSpecBuilder.build()).build();
        try
        {
            javaFile.writeTo(mFiler);
        } catch (Exception e)
        {
            e.printStackTrace();
            mLogUtil.e(e);
        }
    }

    @Override
    public Set<String> getSupportedAnnotationTypes()
    {
        Set set =  super.getSupportedAnnotationTypes();
        set.add(AbstractFactory.class.getCanonicalName());
        set.add(Produce.class.getCanonicalName());
        set.add(Product.class.getCanonicalName());
        return set;
    }

    /**
     * 抽象工厂模型
     */
    class FactoryBean
    {
        // 工厂
        TypeElement factoryImp;
        // 生产的方法
        List<ExecutableElement> methods;

        public TypeElement getFactoryImp()
        {
            return factoryImp;
        }

        public void setFactoryImp(TypeElement factoryImp)
        {
            this.factoryImp = factoryImp;
        }

        public List<ExecutableElement> getMethods()
        {
            return methods;
        }

        public void setMethods(List<ExecutableElement> methods)
        {
            this.methods = methods;
        }
    }
}

下面开始使用了:
1.新建产品杯子(或者基类)

public abstract class ICup
{
    int price;

    public ICup(int price)
    {
        this.price = price;
    }
}

2.增加红杯子和蓝杯子:

@Product(key = "1", superClass = ICup.class)
public class RedCup extends ICup
{
    public RedCup(int price)
    {
        super(price);
    }
}

@Product(key = "2", superClass = ICup.class)
public class BuleCup extends ICup
{
    public BuleCup(int price)
    {
        super(price);
    }
}

3.新建杯子工厂接口:

@AbstractFactory(name = "CupFactory")
public interface ICupFactory
{
    @Produce
    ICup createCup(String key, Integer price);
}

这里尤其要注意一下,工厂里@Produce修饰的方法的参数不能是基本数据类型(这里对应createCup方法),因为在apt里面是通过类的类名来找到这个类的,即String为java.lang.String,而基本数据类型不是类,无法查找

4.开始编译。编译完成后:

public class CupFactory implements ICupFactory {
  @Override
  public ICup createCup(String key, Integer price) {
    if ("2" != null && "2".equals(key)) {
      return new BuleCup(price);
    } else if ("1" != null && "1".equals(key)) {
      return new RedCup(price);
    }
    return null;
  }
}

这样整个apt自动生成抽象工厂已经完结了。都已上传到jitpack仓库。
使用步骤:
1.增加仓库地址:

allprojects {
    repositories {
	...
        maven { url 'https://jitpack.io' }
    }
}

2.增加注解的依赖和增加注解库依赖:

 implementation 'com.github.wengliuhu:Arc_annotation:1.5.0'
annotationProcessor 'com.github.wengliuhu:Arc_complier:1.5.0'

这里吐槽一下jcenter。之前google android开发主推用jcenter,之前的库也是放在binary的jcenter仓库,但是从今年5月1号开始,binary将关闭jcenter仓库了。所以转到了jitpack.io,但是jitpack用户体验是在太差,虽然简单,但是一个项目只能打一个包。所以只能把之前的项目拆分。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值