插件验证在Maven中如何工作,为什么它用无效的版本来构建我的项目? [英] How does plugin validation work in Maven, and why does it build my project with an invalid version?

查看:59
本文介绍了插件验证在Maven中如何工作,为什么它用无效的版本来构建我的项目?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

即使我在POM中指定了一个完全无效的插件,我的Maven项目也能正常运行:

I have a Maven project that builds fine even though I have specified a completely invalid plugin in my POM:

<build>
  <plugins>
    <plugin>
      <groupId>bla</groupId>
      <artifactId>bar</artifactId>
      <version>1.9.553342342343</version>
      <executions>
        <execution>
          <phase>compile</phase>
        </execution>
      </executions>
      <configuration>
        <project>
          <inceptionYear>123123</inceptionYear>
          <contributors>
            asdad
          </contributors>
        </project>
      </configuration>
    </plugin>
  </plugins>
</build>

我也没有在Eclipse中看到任何错误,即使删除了~.m2\repository文件夹,它仍然可以正常运行. Maven验证插件的方式发生了变化吗?还是当我宣布一个目标被炸毁时首先出现?

I also don't see any errors in Eclipse and even after deleting the ~.m2\repository folder, it still builds fine. Has something changed in how Maven validates plugins? Or is it first when I declare a goal that it blows up?

推荐答案

您的问题提出了不同的问题,即Maven执行的不同类型的验证检查以及何时完成验证.坐好,有很多话要说.

Your question raises different matters, namely the different kind of validation checks that are performed by Maven, and when they are actually done. Sit tight, there is a lot to say.

在构建项目模型时,就在构建开始时就进行了第一套验证.此过程由 Model Builder 组件完成,它的目标是将POM文件解析为Model对象(以便以后可以从其中创建完整的MavenProject对象,从而显着执行依赖关系调解).该验证步骤实际上分为两部分:

The first set of validation is done right at the start of the build, when the model of the project is built. This process is done by the Model Builder component, and its goal is to parse the POM file into a Model object (so that later, a full MavenProject object can be created from it, performing notably dependency mediation). This validation step is actually splitted in 2 parts:

  • A raw model validation, which reasons on the POM, before any inheritance or anything is applied. It looks for missing required values, like the presence of a groupId, an artifactId or a version; that repositories have an id; or, in your case here, that a plugin has a groupId and an artifactId. It doesn't actually check if there is a version, because the version could be inherited, and that wasn't done yet.
  • An effective model validation, which is performed after inheritance, interpolation and profile/default injection. At this point, the model should be completely valid. Notably, it must have a packaging, each dependency must have a version, each plugin must have a version as well, etc. And the plugin version you have is actually perfectly valid, in the sense that 1.9.553342342343 is technically an accepted version number. In fact, practically all String qualify as a valid version number; the illegal characters are \\/:\"<>|?*. Also, the <configuration> of a plugin is not validated, simply because it can't: that is specific for each plugin, and one could potentially declare a <project> parameter. For the same reason, it doesn't check whether the plugin actually exists in a remote repository, or if any goals, phase, etc. are specified.

因此,在此步骤结束时,该POM已完全验证并且完全可以.

Therefore, at the end of this step, that POM is fully validated and perfectly OK.

然后是实际上

Then comes the step of actually building the MavenProject from it. Because Maven needs to perform dependency mediation on the dependencies of the project, it first has to download them. So if you have any invalid dependencies (i.e. dependencies that cannot be resolved with the configured remote repositories in the settings or the project itself), that'll stop right here.

但是,如果我们认为依赖关系已正确解决,则构建将继续逐个调用每个插件.重要的一点是,只有在Maven检测到将在构建过程中调用它们时,才解决插件及其各自的依赖项.如果没有,Maven将不会尝试下载任何内容.此外,在实际调用插件并将值注入其中以供其使用时,也将完成插件配置的验证.

But if we imagine that the dependencies are correctly resolved, the build will continue to invoke each plugin one by one. The important point is that plugins, and their respective dependencies, are only resolved if Maven detects that they are going to be invoked during the build. If not, Maven will not try to download anything. Furthermore, the validation of the configuration of the plugin is also done when the plugin is actually invoked and the values are injected into it, to be used by it.

取决于启动的Maven命令,并非POM中声明的所有插件都可以工作.例如,如果用户输入了阶段,例如mvn clean package

Depending on the Maven command that was launched, not all plugins declared in the POM will have work to do. For example, if phases were entered by the user, like mvn clean package, then every plugin bound to a phase of the clean lifecycle, or the default lifecycle up to package, will be invoked; so any plugin bound to the install phase would not be invoked. Also, if the user entered a goal, like mvn org.apache.maven.plugins:maven-clean-plugin:3.0.0:clean then only that specific goal of that specific plugin will be invoked, and all the other plugins will be ignored.

这最后一部分是为什么问题中的POM绝对不会给Maven带来麻烦,这里有很多要点:

This last part is why the POM in the question poses absolutely no trouble to Maven, and here are multiple points about it:

  1. 它绑定到compile阶段,但没有<goal>,因此即使要执行该阶段,插件也无能为力,因为未定义目标. Maven知道这一点,并且不会尝试解决插件工件.
  2. 通过将<goals><goal>foo</goal></goals>添加到插件声明中,将<goal>设置为foo并重新测试.我们在POM中:

  1. It is bound to the compile phase, but it doesn't have a <goal>, so even if that phase were to be executed, there is nothing the plugin could do, since no goals were defined. Maven knows about this, and doesn't try to resolve the plugin artifact.
  2. Let's set a <goal> to foo and re-test, by adding <goals><goal>foo</goal></goals> to the plugin declaration. We have in the POM:

<executions>
  <execution>
    <phase>compile</phase>
    <goals><goal>foo</goal></goals>
  </execution>
</executions>

运行mvn cleanmvn clean validate仍然绝对不会导致任何问题:compile阶段未执行.但是现在,如果我们运行mvn compile,我们最终会得到一个错误:

Running mvn clean, or mvn clean validate would still cause absolutely no issue: the compile phase was not executed. But now, if we run mvn compile, we'll finally get an error:

插件bla:bar:1.9.553342342343或其依赖项之一无法解析

Plugin bla:bar:1.9.553342342343 or one of its dependencies could not be resolved

这毕竟是我们想要的.由于插件声明的阶段为compile,并且所使用的命令将在该阶段运行,因此Maven尝试下载该阶段(但失败).

This is, after all, what we wanted. Since the plugin declaration has a phase of compile, and the command used would run that phase, Maven tries to download it (and fails).

因此,让我们删除该阶段.现在会发生什么?

So let's remove the phase. What would happen now?

<executions>
  <execution>
    <goals><goal>foo</goal></goals>
  </execution>
</executions>

实际上,在特定阶段(例如mvn cleanmvn validate)运行 any 命令现在将使构建失败.原因是插件可以具有默认阶段(另请参见@Mojo带注释的目标上的nofollow noreferrer> defaultPhase 属性).由于每个插件都可以自行决定是否为其目标提供默认阶段,因此Maven必须下载插件工件,并确定此特定插件是否使用默认插件.因此,我们的构建将再次失败,是的!

Actually, running any command with specific phases, like mvn clean or mvn validate, would now fail the build. The reason is that a plugin can have a default phase (see also the defaultPhase attribute on @Mojo annotated goal). Since each plugin has the discretion of providing a default phase to any of its goal, Maven has to download the plugin artifact, and find out if this particular plugin uses a default. So, our build will fail again, yay!

如果用户调用特定目标,情况就不同了.用上面的方法尝试mvn clean:clean,它不会失败.实际上,只会发出警告,指出Maven无法解决插件工件,但这都不是错误,因为调用clean:clean只会调用特定的clean目标. maven-clean-plugin.实际上,从理论上讲,这里不应该有任何警告. Maven不应尝试下载任何内容.这是以下事实的副作用:使用前缀clean要求检查到远程存储库以解决该问题(参见此知道它是如何工作的答案).但是,如果使用mvn org.apache.maven.plugins:maven-clean-plugin:3.0.0:clean完全合格,而无需任何插件前缀解析,那么您的错误/警告将恢复为零.

It's a different story if the user invokes a specific goal. Try mvn clean:clean with the above, and it will not fail. Actually, warnings are just going to get printed that Maven can't resolve the plugin artifact, but none of that is an error, since invoking clean:clean will just invoke the specific clean goal of the maven-clean-plugin. And actually, in theory, there shouldn't be any warnings here; Maven shouldn't try to download anything. It's a side-effect from the fact that using the prefix clean demands to checks to remote repositories in order to resolve it (refer to this answer to know how that works). But if you fully qualify it, without any plugin prefix resolution needed, with mvn org.apache.maven.plugins:maven-clean-plugin:3.0.0:clean, you're back to zero errors/warnings.

最后,如果我们删除所有内容并最终得到

Finally, if we remove everything and end up with

<executions>
  <execution>
  </execution>
</executions>

应该很清楚,您将不做任何操作都将导致错误,因为绝不能执行该插件. (如果使用前缀,您仍然会收到警告.)

it should be pretty clear, that nothing you'll do with result in an errors, because in no way can that plugin ever be executed. (You'll still get warnings if using a prefix).

第3步:插件配置

问题的最后一部分很简单:插件的配置验证.您会注意到,这里根本没有提到这一点.这是因为它仅在实际执行插件时发生.而且,由于它甚至不存在,因此不太可能执行.

Step 3: Plugin configuration

The last part of the question is the simple one: the configuration validation of the plugin. You'll notice that at no point this was mentioned here; this is because it only happens when the plugin is actually executed. And since it doesn't even exist, it's not likely to be executed.

为了解释起见,让我们假设它是.每个插件都配置有特定的它将XML元素映射到类,字段,列表,地图,数组,就像您期望的那样.您可以提供您自己的配置程序,但这并不是一件容易的事.实际上并没有执行任何实际的验证:基本上,如果配置器可以在mojo中连接适当的值,那么就完成了.您可以检查默认情况下存在的不同类型的转换器,但是归结为:未将字符串"foo"指定为期望的整数值;如果插件期望,则传递正确的枚举名称;为自定义类传递正确的XML配置(即,每个字段都有自己的XML元素)...值得指出的是,将"foo"设置为预期的布尔属性不是问题,它将把false连接到值中.

Let's suppose it is, for the sake of the explanation. Each plugin is configured with a specific configurator. By default, it maps the XML elements to classes, fields, lists, maps, arrays, just like you would expect. You could provide your own configurator, but that's not a trivial task. There is actually no real validation performed: basically, if the configurator can wire the proper values in the mojo, it's done. You can check the different types of converters that are present by default, but it comes down to: not specifying a String "foo" to an expected integer value; passing a correct enumeration name if the plugin expects that; passing proper XML configuration for a custom class (i.e. each field with their own XML element)... Worth pointing out that setting "foo" to an expected boolean property is not a problem, it'll wire false into the value.

最后,没有映射到mojo的任何参数的XML配置将被完全忽略,因此,即使bar插件存在并且没有任何参数,在XML配置中传递<project>也会只是被忽略,不会导致任何错误.

And finally, the XML configuration that did not map to any parameter of the mojo are completely ignored, so even if the bar plugin existed and didn't take any parameters, passing a <project> in the XML configuration would just be ignored, and wouldn't cause any errors.

这篇关于插件验证在Maven中如何工作,为什么它用无效的版本来构建我的项目?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆