Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/372.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/190.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java androidstudio中的多模块注释处理_Java_Android_Annotations_Annotation Processing - Fatal编程技术网

Java androidstudio中的多模块注释处理

Java androidstudio中的多模块注释处理,java,android,annotations,annotation-processing,Java,Android,Annotations,Annotation Processing,我在Android Studio中有一个包含多个模块的项目。一个模块可能依赖于另一个模块,例如: 模块PhoneApp->模块功能一->模块服务 我已经将注释处理包含在根模块中,但是android apt注释处理只发生在最顶层(PhoneApp),因此理论上它应该在编译时访问所有模块。然而,我在生成的java文件中看到的只是PhoneApp中注释的类,而不是来自其他模块的类 PhoneApp/build/generated/source/apt/debug/.../GeneratedClass.

我在Android Studio中有一个包含多个模块的项目。一个模块可能依赖于另一个模块,例如:

模块PhoneApp->模块功能一->模块服务

我已经将注释处理包含在根模块中,但是android apt注释处理只发生在最顶层(PhoneApp),因此理论上它应该在编译时访问所有模块。然而,我在生成的java文件中看到的只是PhoneApp中注释的类,而不是来自其他模块的类

PhoneApp/build/generated/source/apt/debug/.../GeneratedClass.java
在其他模块中,我在mediates目录中找到一个生成的文件,该文件只包含来自该模块的注释文件

FeatureOne/build/intermediates/classes/debug/.../GeneratedClass.class
FeatureOne/build/intermediates/classes/debug/.../GeneratedClass.java
我的目标是在PhoneApp中生成一个文件,允许我访问所有模块中的注释文件。不完全确定为什么代码生成过程会针对每个应用程序运行,并且无法在PhoneApp上聚合所有注释。谢谢你的帮助

到目前为止,代码非常简单和直接,因为它工作正常,所以省略了checkIsValid()

批注处理器:

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    try {

        for (Element annotatedElement : roundEnv.getElementsAnnotatedWith(GuiceModule.class)) {
            if (checkIsValid(annotatedElement)) {
                AnnotatedClass annotatedClass = new AnnotatedClass((TypeElement) annotatedElement);
                if (!annotatedClasses.containsKey(annotatedClass.getSimpleTypeName())) {
                    annotatedClasses.put(annotatedClass.getSimpleTypeName(), annotatedClass);
                }
            }
        }

        if (roundEnv.processingOver()) {
            generateCode();
        }

    } catch (ProcessingException e) {
        error(e.getElement(), e.getMessage());
    } catch (IOException e) {
        error(null, e.getMessage());
    }

    return true;
}

private void generateCode() throws IOException {
    PackageElement packageElement = elementUtils.getPackageElement(getClass().getPackage().getName());
    String packageName = packageElement.isUnnamed() ? null : packageElement.getQualifiedName().toString();

    ClassName moduleClass = ClassName.get("com.google.inject", "Module");
    ClassName contextClass = ClassName.get("android.content", "Context");
    TypeName arrayOfModules = ArrayTypeName.of(moduleClass);

    MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("juice")
            .addParameter(contextClass, "context")
            .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
            .returns(arrayOfModules);

    methodBuilder.addStatement("$T<$T> collection = new $T<>()", List.class, moduleClass, ArrayList.class);

    for (String key : annotatedClasses.keySet()) {

        AnnotatedClass annotatedClass = annotatedClasses.get(key);
        ClassName className = ClassName.get(annotatedClass.getElement().getEnclosingElement().toString(),
                annotatedClass.getElement().getSimpleName().toString());

        if (annotatedClass.isContextRequired()) {
            methodBuilder.addStatement("collection.add(new $T(context))", className);
        } else {
            methodBuilder.addStatement("collection.add(new $T())", className);
        }

    }

    methodBuilder.addStatement("return collection.toArray(new $T[collection.size()])", moduleClass);

    TypeSpec classTypeSpec = TypeSpec.classBuilder("FreshlySqueezed")
            .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
            .addMethod(methodBuilder.build())
            .build();

    JavaFile.builder(packageName, classTypeSpec)
            .build()
            .writeTo(filer);
}
@覆盖

公共布尔过程(设置而不是使用Filer保存生成的文件,而是使用常规java文件写入。处理时,您需要将对象序列化为临时文件,因为即使静态变量也不会在模块之间保存。配置gradle以在编译之前删除临时文件。

回答有关此的问题永远不会太晚,所以

在工作中的一项任务中,我也遇到过类似的复杂情况

我能够解决这个问题

短版

关于moduleA中moduleB生成的类,您只需要知道包和类名。它们可以存储在某种
MyClassesRegistrar
生成的类中,放在已知包中。使用后缀避免名称冲突,按包获取注册器。实例化它们并使用其中的数据

Lond版本

首先,您将无法在最顶层的模块中包含仅编译时的依赖项(让我们像您典型的android项目结构那样将其称为“应用程序”模块)。注释处理无法以这种方式工作,而且,据我所知,对此无法采取任何措施

现在来谈谈细节。我的任务是: 我有人工编写的注释类。我将它们命名为“事件”。在编译时,我需要为这些事件生成助手类,以合并它们的结构和内容(静态可用(注释值、常量等)和运行时可用(使用后者时,我将事件对象传递给这些助手).Helper类名称取决于带有后缀的事件类名称,所以直到代码生成完成我才知道它

因此,在生成帮助程序后,我创建一个工厂并生成代码,以根据提供的
MyEvent.class
提供新的帮助程序实例。问题是:我在应用程序模块中只需要一个工厂,但它应该能够为库模块中的事件提供帮助程序-这无法直接完成

我所做的是:

  • 跳过我的应用程序模块所依赖的模块的生成工厂

  • 在非应用程序模块中,生成所谓的HelpersRegister实现:

    –他们都共享相同的软件包(稍后您会知道原因)

    –它们的名称不会因后缀而冲突(见下文)

    –通过用户必须设置的javac
    “-Amylib.suffix=MyModuleName”
    参数区分应用程序模块和库模块-这是一个限制,但是一个较小的限制。不必为应用程序模块指定后缀

    –helpersregistrator生成的实现可以提供未来工厂代码生成所需的所有内容:事件类名、帮助器类名、包(这两个共享包用于帮助器和事件之间的包可见性)-所有字符串,合并到POJO中

  • 在应用程序模块中,我生成helpers——像往常一样,我通过它们的包获取helperRegistrar,实例化它们,运行它们的内容,用代码丰富我的工厂,这些代码提供来自其他模块的helpers。我所需要的只是类名和一个包

  • 瞧!我的工厂可以提供应用程序模块和其他模块的助手实例

  • 剩下的唯一不确定性是在应用程序模块和其他模块中创建和运行处理器类实例的顺序。我没有找到任何可靠的信息,但运行我的示例表明,编译器(以及代码生成)首先在我们依赖的模块中运行,然后在应用程序模块中运行(否则,将对应用程序模块进行编译)。这使我们有理由期望不同模块中的代码处理器执行顺序已知

    另一种稍微相似的方法是:跳过注册器,在所有模块中生成工厂,并在应用程序模块中编写工厂以使用其他工厂,您得到的工厂名称和上面注册器的名称相同

    这里可以看到一个例子:-这是一个我应用这种方法的库(因为我有工厂,所以没有注册器,但对你来说可能不是这样)


    注意:后缀参数可以切换为更简单的“-Amylibraryname.library=true”工厂/注册商的名称可以自动生成/递增

    这是一个好问题。我想如果您在找到解决方案时与他人分享您的解决方案,很多人会很感激,但我还没有。中讨论了处理器限制,这可能被视为不可能实现所需的跨模块注释处理器。由于注释处理器分别为每个模块运行,您可以尝试增量方法,但这取决于您的具体情况。如果您在处理下一个模块后不需要更改整个类,而只向现有类添加新行,则可以使用此方法:1.处理第一个模块时,生成cl