【问题标题】:How to externalize pieces of maven build file?如何外部化 Maven 构建文件?
【发布时间】:2010-10-04 10:59:29
【问题描述】:

我遇到了如何以 XML 格式对配置文件进行版本控制的问题。最简单的方法是编写 XSLT 更新。应用程序的每个版本都有自己的 XSLT 更新。所有这些更新文件都足够小,可以由 IDE 管理,尤其是它的 DIFF 工具。

由于该项目已经开发为 Maven2,Java 逻辑解决方案是通过 maven 构建文件触发这些更新。

这是应用一组更新的部分今天的样子:

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>xml-maven-plugin</artifactId>
  <executions>
    <execution>
    <phase>compile</phase>
      <goals>
        <goal>transform</goal>
      </goals>
    </execution>
  </executions>
  <configuration>
    <transformationSets>
      <transformationSet>
        <dir>config/xsltUpdates/input</dir>
        <stylesheet>config/xsltUpdates/update1-8-3.xsl</stylesheet>
        <outputDir>config/xsltUpdates/update1-8-3</outputDir>
      </transformationSet>
      <transformationSet>
         <dir>config/xsltUpdates/update1-8-3</dir>
         <stylesheet>config/xsltUpdates/update1-8-9.xsl</stylesheet>
         <outputDir>config/xsltUpdates/update1-8-9</outputDir>
      </transformationSet>
      <transformationSet>
        <dir>config/xsltUpdates/update1-8-9</dir>
        <stylesheet>config/xsltUpdates/update1-9-0.xsl</stylesheet>
        <outputDir>config/xsltUpdates/update1-9-0</outputDir>
      </transformationSet>
      <transformationSet>
        <dir>config/xsltUpdates/update1-9-0</dir>
        <stylesheet>config/xsltUpdates/update1-10-0.xsl</stylesheet>
        <outputDir>config/xsltUpdates/update1-10-0</outputDir>
      </transformationSet>
      <transformationSet>
        <dir>config/xsltUpdates/update1-10-0</dir>
        <stylesheet>config/xsltUpdates/update1-10-0-1.xsl</stylesheet>
        <outputDir>config/xsltUpdates/update1-10-0-1</outputDir>
      </transformationSet>
      <transformationSet>
        <dir>config/xsltUpdates/update1-10-0-1</dir>
        <stylesheet>config/xsltUpdates/update1-10-0-2.xsl</stylesheet>
        <outputDir>config/xsltUpdates/update1-10-0-2</outputDir>
      </transformationSet>
      <transformationSet>
        <dir>config/xsltUpdates/update1-10-0-2</dir>
        <stylesheet>config/xsltUpdates/updateCurrent.xsl</stylesheet>
        <outputDir>config/xsltUpdates/output</outputDir>
      </transformationSet>
    </transformationSets>
  </configuration>
  <dependencies>
    <dependency>
      <groupId>net.sf.saxon</groupId>
      <artifactId>saxon</artifactId>
      <version>8.7</version>
    </dependency>
  </dependencies>
</plugin>

我想在某些属性/xml 文件导入中外部化有关 transformationSet 的信息。我的 pom.xml 文件将更干净,更易于维护。

我该怎么做?

我可以在构建文件中使用一些迭代控制语句吗?有没有办法从某个外部文件导入数据?

【问题讨论】:

    标签: java maven-2 refactoring maven-plugin


    【解决方案1】:

    一些插件允许您使用外部描述符(例如maven-assembly-plugin)。不幸的是,xml-maven-plugin 还不是其中之一。

    一种选择是从 xml-maven-plugin 复制相关目标并将 maven-shared-io 中的处理硬塞到目标中。我一直在寻找自己这样做,以期针对各种插件提出请求以使用描述符文件和 LocatorStrategy 方法来查找描述符。这是一些将修改 xml-maven-plugin 以允许使用描述符的处理。请注意,所涉及的文件几乎没有验证,因此它有点脆弱,但它确实有效。

    1) 使用以下依赖项创建一个新的 maven-plugin 项目(例如称为 xml-ext-maven-plugin):

    <dependencies>
      <dependency>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>xml-maven-plugin</artifactId>
        <version>1.0-beta-2</version>
      </dependency>
      <dependency>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>2.2-beta-2</version>
      </dependency>
    </dependencies>
    

    2) 从 xml-maven-plugin 复制 TransformMojo 和 AbstractXmlMojo .java 文件(您需要父 mojo 从其 javadoc 继承属性)。

    3) 向 TransformMojo 添加 descriptors 属性:

    /**
     * A list of descriptor files to obtain the transformation sets from
     * 
     * @parameter
     */
    private String[] descriptors;
    

    4) 修改execute()方法,读取transformationSets的描述符

    public void execute() throws MojoExecutionException, MojoFailureException {
        //insert at start of method to resolve transformationSets fronm descriptors
        if (descriptors != null && descriptors.length > 0) {
            transformationSets = readDescriptors(descriptors);
        }
    
        ...
    

    5) 实现 readDescriptors() 以允许您在类路径或项目内定位描述符(读取器处理主要从程序集插件的 DefaultAssemblyReader 提升)。请注意,此实现中几乎没有验证,适当的插件会检查是否设置了值等。

    private TransformationSet[] readDescriptors(String[] descriptors)
            throws MojoExecutionException {
    
        List descriptorSets = new ArrayList();
        // add all the existing transformationSets
        if (transformationSets != null && transformationSets.length != 0) {
            descriptorSets.addAll(Arrays.asList(transformationSets));
        }
    
        for (int i = 0; i < descriptors.length; i++) {
            getLog().info(
                    "Reading transformation descriptor: " + descriptors[i]);
    
            Location location = getLocation(descriptors[i]);
    
            Reader reader = null;
            try {
                reader = new InputStreamReader(location.getInputStream(),
                        "UTF-8");
    
                Xpp3Dom dom = Xpp3DomBuilder.build(reader);
    
                descriptorSets.addAll(parseTransformationSets(dom));
            } catch (IOException e) {
                throw new MojoExecutionException(
                        "Error reading transformation descriptor: "
                                + descriptors[i], e);
            } catch (XmlPullParserException e) {
                throw new MojoExecutionException(
                        "Error parsing transformation descriptor: "
                                + descriptors[i], e);
            } finally {
                IOUtil.close(reader);
            }
        }
    
        return (TransformationSet[]) descriptorSets
                .toArray(new TransformationSet[descriptorSets.size()]);
    }
    
    /**
     * Create transformationSets from the Xpp3Dom.
     * TODO use plexus utilities to resolve these elegantly?
     */
    private List parseTransformationSets(Xpp3Dom dom) {
        // TODO validation of the input files!
        Xpp3Dom[] setDoms = dom.getChildren("transformationSet");
    
        List sets = new ArrayList();
        for (int i = 0; i < setDoms.length; i++) {
            TransformationSet set = new TransformationSet();
            set.setDir(new File(setDoms[i].getChild("dir").getValue()));
            set.setStylesheet(new File(setDoms[i].getChild("stylesheet")
                    .getValue()));
    
            Xpp3Dom outDom = setDoms[i].getChild("outputDir");
    
            if (outDom != null) {
                set.setOutputDir(new File(outDom.getValue()));
            }
    
            sets.add(set);
        }
        return sets;
    }
    

    6) 实现 getLocation() 以使用各种策略以相对路径、url 或类路径来发现文件。

    private Location getLocation(String path) {
        List strategies = new ArrayList();
        strategies.add(new RelativeFileLocatorStrategy(getBasedir()));
        strategies.add(new ClasspathResourceLocatorStrategy());
        strategies.add(new FileLocatorStrategy());
        strategies.add(new URLLocatorStrategy());
    
        List refStrategies = new ArrayList();
        refStrategies.add(classpathStrategy);
    
        Locator locator = new Locator();
    
        locator.setStrategies(strategies);
    
        Location location = locator.resolve(path);
        return location;
    }
    

    7) 覆盖 asAbsoluteFile() 以使用定位器策略解析文件(允许我们在描述符项目中定义 xsl 文件)。

    protected File asAbsoluteFile(File f) {
        String path = f.getPath();
    
        // ensure we're getting a path in the form that URL can handle
        if (path != null) {
            path = path.replaceAll("\\\\", "/");
        }
        Location location = getLocation(path);
    
        if (location == null) {
            //can't find the file, let the parent implementation have a try
            return super.asAbsoluteFile(f);
        }
        try {
            return location.getFile();
        } catch (IOException e) {
            throw new RuntimeException("unable to read file " + f.getPath(), e);
        }
    }
    

    8) 将插件安装到您的存储库。

    9) 创建一个新的 maven 项目来托管您的转换集(例如称为 xml-ext-test-descriptor)。过程与assembly-plugin的shared descriptors相同,即创建一个项目,在src/main/resources下添加一些xml文件,然后安装项目。 xml 文件采用标准 transformationSets 配置的形式。例如在 src/main/resources/transformations1.xml 中放置几个​​转换:

    <transformationSets>
      <transformationSet>
        <!--the config directory is in the root of the project -->
        <dir>config/xsltUpdates/input</dir>
        <!-- the stylesheet can be in the descriptor project-->
        <stylesheet>/stylesheets/update1-8-3.xsl</stylesheet>       
        <outputDir>config/xsltUpdates/update1-8-3</outputDir>
      </transformationSet>
      <transformationSet>
         <dir>config/xsltUpdates/update1-8-3</dir>
         <stylesheet>/stylesheets/update1-8-9.xsl</stylesheet>
         <outputDir>config/xsltUpdates/update1-8-9</outputDir>
      </transformationSet>
    </transformationSets>
    

    10) 将您的 xsl 文件放入描述符项目中,例如src/main/resources/stylesheets/update1-8-3.xsl

    11)在你的项目中配置新插件,将描述符项目作为依赖引用,将xml文件作为描述符引用:

    <plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>xml-maven-plugin</artifactId>
      <executions>
        <execution>
          <phase>compile</phase>
          <goals>
            <goal>transform</goal>
          </goals>
        </execution>
      </executions>
      <dependencies>
        <dependency>
          <groupId>name.seller.rich</groupId>
          <artifactId>xml-ext-test-descriptor</artifactId>
          <version>0.0.1</version>
        </dependency>
      </dependencies>
      <configuration>
       <descriptors>
         <!-- will be resolved from xml-ext-test-descriptor -->
         <descriptor>/transformationSet1.xml</descriptor>
       </descriptors>
     </plugin>
    

    如果上述所有步骤都有效,则自定义插件在执行时将从 xml-ext-test-descriptor 依赖项解析 transformationSet1.xml 和您的 xsl 文件,并正常处理它们。

    【讨论】:

      【解决方案2】:

      可能还有其他方法可以做到这一点,但您可以在父 pom 中有一个 pluginManagement 部分。

      pluginManagement: 是一个可以在侧面插件中看到的元素。插件管理以几乎相同的方式包含插件元素,除了不是为这个特定的项目构建配置插件信息,它旨在配置从这个项目继承的项目构建。但是,这仅配置子级的 plugins 元素中实际引用的插件。孩子们有权覆盖 pluginManagement 定义。

      例如:

      父项目 POM(需要运行 mvn install 以确保它对您的子项目可见)

      <project xmlns="http://maven.apache.org/POM/4.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
          http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>org.nkl</groupId>
        <artifactId>parent</artifactId>
        <packaging>pom</packaging>
        <version>0.0.1-SNAPSHOT</version>
        <build>
          <pluginManagement>
            <plugins>
              <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>xml-maven-plugin</artifactId>
                <executions>
                  <execution>
                    <phase>compile</phase>
                    <goals>
                      <goal>transform</goal>
                    </goals>
                  </execution>
                </executions>
                <configuration>
                  <transformationSets>
                    <transformationSet>
                      <dir>config/xsltUpdates/input</dir>
                      <stylesheet>config/xsltUpdates/update1-8-3.xsl</stylesheet>
                      <outputDir>config/xsltUpdates/update1-8-3</outputDir>
                    </transformationSet>
                    <transformationSet>
                      <dir>config/xsltUpdates/update1-8-3</dir>
                      <stylesheet>config/xsltUpdates/update1-8-9.xsl</stylesheet>
                      <outputDir>config/xsltUpdates/update1-8-9</outputDir>
                    </transformationSet>
                    <transformationSet>
                      <dir>config/xsltUpdates/update1-8-9</dir>
                      <stylesheet>config/xsltUpdates/update1-9-0.xsl</stylesheet>
                      <outputDir>config/xsltUpdates/update1-9-0</outputDir>
                    </transformationSet>
                    <transformationSet>
                      <dir>config/xsltUpdates/update1-9-0</dir>
                      <stylesheet>config/xsltUpdates/update1-10-0.xsl</stylesheet>
                      <outputDir>config/xsltUpdates/update1-10-0</outputDir>
                    </transformationSet>
                    <transformationSet>
                      <dir>config/xsltUpdates/update1-10-0</dir>
                      <stylesheet>config/xsltUpdates/update1-10-0-1.xsl</stylesheet>
                      <outputDir>config/xsltUpdates/update1-10-0-1</outputDir>
                    </transformationSet>
                    <transformationSet>
                      <dir>config/xsltUpdates/update1-10-0-1</dir>
                      <stylesheet>config/xsltUpdates/update1-10-0-2.xsl</stylesheet>
                      <outputDir>config/xsltUpdates/update1-10-0-2</outputDir>
                    </transformationSet>
                    <transformationSet>
                      <dir>config/xsltUpdates/update1-10-0-2</dir>
                      <stylesheet>config/xsltUpdates/updateCurrent.xsl</stylesheet>
                      <outputDir>config/xsltUpdates/output</outputDir>
                    </transformationSet>
                  </transformationSets>
                </configuration>
                <dependencies>
                  <dependency>
                    <groupId>net.sf.saxon</groupId>
                    <artifactId>saxon</artifactId>
                    <version>8.7</version>
                  </dependency>
                </dependencies>
              </plugin>
            </plugins>
          </pluginManagement>
        </build>
      </project>
      

      子项目POM

      <project xmlns="http://maven.apache.org/POM/4.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
          http://maven.apache.org/maven-v4_0_0.xsd">
        <parent>
          <artifactId>parent</artifactId>
          <groupId>org.nkl</groupId>
          <version>0.0.1-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
        <groupId>org.nkl</groupId>
        <artifactId>child</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <build>
          <plugins>
            <plugin>
              <groupId>org.codehaus.mojo</groupId>
              <artifactId>xml-maven-plugin</artifactId>
            </plugin>
          </plugins>
        </build>
      </project>
      

      【讨论】:

      • 当前 pom 已经有一个父文件。 Maven2 不允许多重继承。我可以让我的 pom 成为其当前父级的孙子,并在其间添加一个新的父级,其中将保存外部化数据...
      • ...问题是外部化将超出我想避免的项目范围
      • 对不起,我不能再帮鲍里斯了。
      猜你喜欢
      • 2021-12-28
      • 2014-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多