使用地图的地图作为 Maven 插件参数

Rol*_*Huß 4 maven-plugin maven

是否可以使用地图的地图作为 Maven 插件参数?,例如

@Parameter
private Map<String, Map<String, String>> converters;
Run Code Online (Sandbox Code Playgroud)

然后像这样使用它

<converters>
  <json>
     <indent>true</indent>
     <strict>true</strict>
  </json>
  <yaml>
      <stripComments>false</stripComments>
  </yaml>
<converters>
Run Code Online (Sandbox Code Playgroud)

如果我像这样使用它,converters则仅包含键jsonyaml以 null 作为值。

我知道可以将复杂的对象作为值,但是是否也可以像本示例中那样使用映射作为变量元素值?

Tun*_*aki 6

This is apparently a limitation of the sisu.plexus project internally used by the Mojo API. If you peek inside the MapConverter source, you'll find out that it first tries to fetch the value of the map by trying to interpret the configuration as a String (invoking fromExpression), and when this fails, looks up the expected type of the value. However this method doesn't check for parameterized types, which is our case here (since the type of the map value is Map<String, String>). I filed the bug 498757 on the Bugzilla of this project to track this.

Using a custom wrapper object

One workaround would be to not use a Map<String, String> as value but use a custom object:

@Parameter
private Map<String, Converter> converters;
Run Code Online (Sandbox Code Playgroud)

with a class Converter, located in the same package as the Mojo, being:

public class Converter {

    @Parameter
    private Map<String, String> properties;

    @Override
    public String toString() { return properties.toString(); } // to test

}
Run Code Online (Sandbox Code Playgroud)

You can then configure your Mojo with:

<converters>
  <json>
    <properties>
      <indent>true</indent>
      <strict>true</strict>
    </properties>
  </json>
  <yaml>
    <properties>
      <stripComments>false</stripComments>
    </properties>
  </yaml>
</converters>
Run Code Online (Sandbox Code Playgroud)

此配置将正确地将值注入内部映射中。它还保留了可变方面:该对象仅作为内部映射的包装器引入。我用一个简单的测试魔力对此进行了测试

<converters>
  <json>
    <properties>
      <indent>true</indent>
      <strict>true</strict>
    </properties>
  </json>
  <yaml>
    <properties>
      <stripComments>false</stripComments>
    </properties>
  </yaml>
</converters>
Run Code Online (Sandbox Code Playgroud)

并且输出是预期的{json={indent=true, strict=true}, yaml={stripComments=false}}

使用自定义配置器

Map<String, Map<String, String>>我还找到了一种通过使用自定义来保留 a 的方法ComponentConfigurator

所以我们想MapConverter通过继承来修复,问题是如何注册这个新的FixedMapConverter。默认情况下,Maven 使用 aBasicComponentConfigurator来配置 Mojo,并且它依赖于 aDefaultConverterLookup来查找用于特定类的转换器。在这种情况下,我们希望提供一个自定义转换,Map它将返回我们的固定版本。因此,我们需要扩展这个基本配置器并注册我们的新转换器。

public void execute() throws MojoExecutionException, MojoFailureException {
    getLog().info(converters.toString());
}
Run Code Online (Sandbox Code Playgroud)

然后我们需要告诉 Maven 使用这个新的配置器而不是基本的配置器。这是一个 2 步过程:

  1. 在 Maven 插件中,创建一个src/main/resources/META-INF/plexus/components.xml注册新组件的文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <component-set>
      <components>
        <component>
          <role>org.codehaus.plexus.component.configurator.ComponentConfigurator</role>
          <role-hint>custom-basic</role-hint>
          <implementation>package.to.CustomBasicComponentConfigurator</implementation>
        </component>
      </components>
    </component-set>
    
    Run Code Online (Sandbox Code Playgroud)

    请注意一些事情:我们声明一个具有hint的新组件"custom-basic",这将用作引用它的id,并且<implementation>引用我们的配置器的完全限定类名。

  2. 告诉我们的 Mojo 使用这个配置器和注释configurator的属性@Mojo

    import org.codehaus.plexus.classworlds.realm.ClassRealm;
    import org.codehaus.plexus.component.configurator.BasicComponentConfigurator;
    import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
    import org.codehaus.plexus.component.configurator.ConfigurationListener;
    import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
    import org.codehaus.plexus.configuration.PlexusConfiguration;
    
    public class CustomBasicComponentConfigurator extends BasicComponentConfigurator {
        @Override
        public void configureComponent(final Object component, final PlexusConfiguration configuration,
                final ExpressionEvaluator evaluator, final ClassRealm realm, final ConfigurationListener listener)
                throws ComponentConfigurationException {
            converterLookup.registerConverter(new FixedMapConverter());
            super.configureComponent(component, configuration, evaluator, realm, listener);
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    这里传递的配置器对应于上面指定的角色提示components.xml

有了这样的设置,你终于可以声明了

<?xml version="1.0" encoding="UTF-8"?>
<component-set>
  <components>
    <component>
      <role>org.codehaus.plexus.component.configurator.ComponentConfigurator</role>
      <role-hint>custom-basic</role-hint>
      <implementation>package.to.CustomBasicComponentConfigurator</implementation>
    </component>
  </components>
</component-set>
Run Code Online (Sandbox Code Playgroud)

并且所有内容都会正确注入:Maven 将使用我们的自定义配置器,它将注册我们的固定版本的地图转换器并正确转换内部地图。


完整代码FixedMapConverter(几乎是复制粘贴的MapConverter,因为我们无法覆盖错误的方法):

@Mojo(name = "test", configurator = "custom-basic")
Run Code Online (Sandbox Code Playgroud)