Maven:代码生成之前的部分编译
tl;dr-edition: 我知道编译会失败,但希望编译后在我的 target/classes
文件夹中仍然可以编译的类子集。我已经配置了
,但没有生成任何类,甚至没有生成独立于除 Object
之外的任何其他类的虚拟类。是否有一些配置可以实现此目的?
我有一个由 Maven 支持的项目,其工作流程基本上由以下(相关)目标组成:
...
init-compile
代码生成器(如下)使用基于反射的配置,因此,在第一遍中,我想尝试编译尽可能多的项目,以便不会在那里抛出 ClassNotFoundException。此编译配置为
以便构建继续。false 不幸的是(你可以称之为设计缺陷),该配置既用于代码生成(指定 OWL 文件和命名空间来打包映射)又用于运行时,因此它还包含代码不需要的其他元素生成器,但仍会被读取,因此需要在类路径上才能成功。
生成模型
在此步骤中,一些模型类是从 OWL-Ontology 生成的,创建的代码使项目的其余部分完全可编译。
默认编译
现在,显然应该编译其余的类
save-model
现在,从本体中读取实例并将其序列化为运行时的文件
- < p>
...
旁注:生成和保存模型都使用 maven-exec-plugin
,但我真诚地认为这根本不重要。
问题:
当我使用mvn -e -U clean package source:jar javadoc:jar install:install
运行构建时,它在generate-model<期间失败/code> 目标是我试图避免的错误。
target/classes
是空的,因此编译器似乎没有吐出它可以/应该能够处理的类的子集。有办法实现这一点吗?
我有两个我都不喜欢的解决方法:
- 在将配置文件“AST”解析为 Java 对象之前编辑它,以便仅解析与代码生成器相关的部分(需要调整我有权访问的代码)但我的项目应该认为是不可变的);
- 并将
init-compile
目标配置为仅包含所需的类(太不灵活,因为 POM 应该/可能是使用相同模型的未来应用程序的模板)。
如果您可以想象另一种方法来解决我的问题,您可以从我的描述中看到,我也很高兴听到它们!
tl;dr-edition: I have a compilation I know that will fail, but want the subset of classes that are still compilable in my target/classes
folder after compilation. I have configured <failOnError>false</failOnError>
, but no classes are generated, not even a dummy class that is independent of any other classes except Object
. Is there some configuration to achieve this?
I have a maven-powered project whose workflow consists of basically the following (relevant) goals:
...
init-compile
The code generator (below) uses a config that is reflection-based, so, in a first pass, I want to try compile as much of the project as possible so that no ClassNotFoundExceptions are thrown there. This compilation is configured with
<failOnError>false</failOnError>
so that the build continues.Unfortunately (you could call it a design flaw), the config is used both for code generation (specifying the OWL file and namespace to package mappings) and at runtime, so it also contains other elements that are not needed for the code generator, but are still read and therefore needed on the classpath to succeed.
generate-model
In this step, some model classes are generated from an OWL-Ontology, creating the code that makes the rest of the project completely compileable.
default-compile
Now, the rest of the classes should be compiled, obviously
save-model
Now, the instances from the ontology are read and serialized to a file for runtime
...
Side note: both generate and save model use maven-exec-plugin
, but I sincerely don't think that matters at all.
Question:
When I run my build with mvn -e -U clean package source:jar javadoc:jar install:install
, it fails during the generate-model
goal with the errors I'm trying to avoid. target/classes
is empty, so it seems that the compiler doesn't spit out the subset of classes it could/should have been able to process. Is there a way to achieve this?
I have two workarounds in mind which I both don't like:
- Editing the config file "AST" before parsing it into Java-Objects, so that only the part relevant for the code generator is parsed (needs tweaking of code that I have access to but should be considered immutable by my project);
- and to configure the
init-compile
goal to only include the needed classes (too inflexible, because the POM should/could be a template for future applications using the same model).
If you can imagine another way to work around my problem that you can see from my description, I would be glad to hear them, too!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先,让我重述一下您的问题,以确保我正确理解了它。
您有一组类,其编译形式的功能是
配置代码生成器和运行时。 (的一个子集
这些与代码生成器相关,但生成会失败
除非存在完整的配置。所以我们可以将其视为
尽管整个配置都是必要的。)
然后您将拥有一组将作为源生成的类
代码。它们有一个生成时间,也许是一个编译时间,以及一个
运行时依赖于配置类。
最后,您还有一些具有编译时依赖性的其他代码
依赖于生成的类,以及运行时依赖
生成的类和配置类。
但是,您的配置类对生成的类或其他代码没有任何编译时依赖性。您没有明确说明这一点,但我假设它,否则您将遇到循环依赖问题。
这是我的建议:将项目划分为多模块(“reactor”)项目。您当前的项目将是reactor项目的一个模块。创建一个名为“config”或类似的新模块,并将您的配置类移入其中。让主模块依赖它。
如果您不喜欢多模块项目,您可以通过声明绑定到生成源阶段的编译插件的额外执行来实现相同的目的。 (你没有说,但我假设你在这个阶段进行代码生成。如果你在 POM 中的代码生成器插件之前声明编译插件,Maven 将以相同的顺序执行它们。)你可以使用编译插件的“include”过滤器仅编译配置类。为此,您需要将配置类与其他所有配置类放在一个单独的包中,无论如何,这是一个很好的做法。
First, let me recapitulate your problem to be sure I've grasped it properly.
You have a set of classes whose function, in their compiled form, is
to configure both the code generator and the runtime. (A subset of
these are relevant to the code generator, but generation will fail
unless the complete configuration is present. So we can treat it as
though the entire configuration were necessary.)
You then have a set of classes which will be generated as source
code. These have a generation-time, perhaps a compile-time, and a
run-time dependency upon the configuration classes.
Finally you have some other code which has a compile-time dependency
upon the generated classes, and a runtime dependency upon both the
generated classes and the configuration classes.
However, your configuration classes don't have any compile-time dependencies upon the generated classes nor upon the other code. You don't explicitly say this, but I'm assuming it, otherwise you've got a circular dependency problem.
Here's my suggestion: Divide the project into a multi-module ("reactor") project. Your current project will be a module of the reactor project. Create a new module called "config" or similar and move your config classes into it. Have the main module depend upon it.
If you don't like multi-module projects, you could achieve the same thing by declaring an extra execution of the compile plugin, bound to the generate-sources phase. (You don't say, but I assume you're doing the code generation in this phase. If you declare the compile plugin before the code generator plugin within the POM, Maven will execute them in the same order.) You would use the "include" filter of the compile plugin to compile only the config classes. For this, you would need to have the config classes in a separate package from all the rest, which is good practice anyway.
有一种非常方便的解决方案 - 使用 Eclipse Java Compiler (EJC) 而不是标准的 Oracle javac! ECJ 相对于 javac 的优点之一是它允许错误,它尝试尽可能多地编译并保留已生成的类文件。 EJC 是为在 IDE 中使用而开发的,用于必须进行部分编译的高度交互工作,但它也可以用作 CLI 或 Maven 插件。 Plexus 人员提供 EJC 作为方便的 Maven 依赖项。
编译器可插入 Maven 中。您可以在一个 POM 中定义多个编译(编译执行),并且可以为每个编译器使用不同的编译器,为开发人员提供广泛的选择。
POM 代码示例:
感谢 Gabriel Axel 的文章 http: //www.gabiaxel.com/2011/10/replacing-javac-with-eclipse-compiler.html
这种方法可以解决一些棘手的问题“源到生成的源到源”循环依赖关系,可能无法通过拆分为单独的模块来解决。
另外,我想以最透明的方式集成源代码生成。必须根据生成源的依赖关系重新整理代码肯定会破坏它。我想根据逻辑设计对我的代码进行分组,而不是因为技术细节。
如果您的代码生成器恰好是 xtext,就像我的情况一样,并且您使用 xtext-maven-plugin,比如说新发布的 2.5.0,您不必像上面的示例中那样配置任何内容,该插件完全按照下面的方式执行引擎盖。
There is one highly convenient solution - use Eclipse Java Compiler (EJC) instead of standard Oracle javac! One of ECJ advantages over javac is that it is permissible of errors, it tries to compile as much as possible and keeps already generated class files. EJC was developed for use in IDE, for highly interactive work where partial compilation is a must, but it can also be used as CLI or Maven plugin. Plexus guys provide EJC as a handy Maven dependency.
Compilers are pluggable in Maven. You can have multiple compilation (compilation executions) defined in one POM and you can use different compilers for each giving the developer broad range of options.
Example POM code:
Credits to Gabriel Axel for his article http://www.gabiaxel.com/2011/10/replacing-javac-with-eclipse-compiler.html
This approach can solve some tricky "source to generated source to source" circular dependencies, potentially unsolvable by splitting into separate modules.
Also, I wanted to integrate source generation in the most transparent way. Having to reshuffle the code based on dependencies on generated sources would definitively break it. I want to group my code based on logical design not because of technicalities.
If you code generator happens to xtext, like in my case, and you use xtext-maven-plugin, let's say freshly released 2.5.0, you don't have to configure nothing like in the example above, the plugin does exactly that under the hood.