Search code examples
javamavenmaven-3checkstylemaven-checkstyle-plugin

How to configure a multi-module Apache Maven project to use a Checkstyle config project that consists of multiple XML files that reference each other?


I would like to configure the Apache Maven Checkstyle Plugin v3.3.0 with Apache Maven v3.9.3 in a multi-module project to use the palantir-java-format style.

I've read both Multimodule Configuration and Using Custom Developed Checkstyle Checks of the official plugin documentation. As recommended in the documentation I created a separate jar Maven project example-company-config. The single purpose of example-company-config is to provide the Checkstyle config files as resources in a JAR file. B ydoing that the Checkstyle config can be shared across many Maven projects.

  • I was able to make it work with a standalone (i.e. no references to other XML files) checkstyle.xml file.
  • But here is the problem: The palantir-java-format Checkstyle config uses three files and the checkstyle.xml references the other files with a property config_loc.

I found out how to to set that property. The following is a snippet of my Aggregator POM.

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-checkstyle-plugin</artifactId>
                <version>3.3.0</version>
                <dependencies>
                    <dependency>
                        <groupId>io.github.florianwolters</groupId>
                        <artifactId>example-company-config</artifactId>
                        <version>0.1.0</version>
                        <type>jar</type>
                        <scope>compile</scope>
                    </dependency>
                </dependencies>
                    <configLocation>io.github.florianwolters/checkstyle/palantir/checkstyle.xml</configLocation>
                    <propertyExpansion>config_loc=.</propertyExpansion>
                </configuration>
            </plugin>
        <plugins>
    <pluginManagement>
<build>

But: Since all three Checkstyle files of palantir-java-format are stored inside the JAR file of the example-company-config project, this does not work.

I identified three possible solutions:

  1. Qualify a XML file from another XML file inside the same archive file with a "special syntax". I don't think that this syntax exists and therefore that this is not possible.

  2. Extract the JAR file of example-company-config during the build process and reference to it using an absolute file path.

    Maybe this is possible with the Apache Maven Dependency Plugin.

  3. Turn the example-company-config from type jar to type pom and install the Checkstyle config files manually.

    Maybe this is possible with the Apache Maven Assembly Plugin.

Notes:

  • I consider modification of the three Checkstyle config files a non-solution.
  • I'm aware that the Spotless for Maven plugin exists. I do not want to fail the build (yet) in case of formatting violations. Therefore I want to use the palantir-java-format style with the Checkstyle tool. I may migrate from Checkstyle to Spotless later.

Do you have a solution or some guidance for the problem I've described?

Related resources:


Solution

  • I was able to solve this on my own, by utilizing the Apache Maven Dependency Plugin.

    The following excerpt from my pom.xml for the Company POM project should contain all the relevant stuff to make this work. Note that the Company POM uses the example-checkstyle-config project as recommended by the documentation linked in the OP. The JAR file of the separate example-checkstyle-config project is extracted during the build of all child projects (note that the Company POM itself has to be exclude, otherwise I'd have a cyclic dependency (in addition its useless work, because a Company POM does not have source code).

    By doing all this this an absolute file path can be injected via the <propertyExpansion> element and everything works as expected.

    But: I had to modify the palantir-java-format Checkstyle config:

    1. The custom-suppressions.xml file suppresses all warnings.
    2. The checkstyle-suppressions.xml files suppresses warnings in test files. I'd like to have warnings for all source files.

    Therefore, my requirements in the OP was not met. Nonetheless, do I think, that I've found a neat solution for the problem (and similar problems that can be solved by "simply" extracting a dependency to the own build tree directory).

    <properties>
        <io.github.florianwolters.build.unpackDirectory>${project.build.directory}/unpack</io.github.florianwolters.build.unpackDirectory>
        <io.github.florianwolters.checkstyle.unpackDirectory>${io.github.florianwolters.build.unpackDirectory}/checkstyle-config</io.github.florianwolters.checkstyle.unpackDirectory>
        <io.github.florianwolters.checkstyle.configDirectory>${io.github.florianwolters.checkstyle.unpackDirectory}/${project.groupId}/checkstyle/palantir</io.github.florianwolters.checkstyle.configDirectory>
    
        <io.github.florianwolters.version.company-checkstyle-config>0.1.0</io.github.florianwolters.version.company-checkstyle-config>
        <io.github.florianwolters.version.maven-checkstyle-plugin>3.3.0</io.github.florianwolters.version.maven-checkstyle-plugin>
        <io.github.florianwolters.version.checkstyle>10.12.1</io.github.florianwolters.version.checkstyle>
    </properties>
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-checkstyle-plugin</artifactId>
                    <version>${io.github.florianwolters.version.maven-checkstyle-plugin}</version>
                    <dependencies>
                        <dependency>
                            <groupId>com.puppycrawl.tools</groupId>
                            <artifactId>checkstyle</artifactId>
                            <version>${io.github.florianwolters.version.checkstyle}</version>
                            <type>jar</type>
                            <scope>compile</scope>
                        </dependency>
                        <dependency>
                            <groupId>${project.groupId}</groupId>
                            <artifactId>example-checkstyle-config</artifactId>
                            <version>${io.github.florianwolters.version.company-checkstyle-config}</version>
                            <type>jar</type>
                            <scope>compile</scope>
                        </dependency>
                    </dependencies>
                    <configuration>
                        <configLocation>${io.github.florianwolters.checkstyle.configDirectory}/checkstyle.xml</configLocation>
                        <consoleOutput>true</consoleOutput>
                        <enableFilesSummary>true</enableFilesSummary>
                        <enableRulesSummary>true</enableRulesSummary>
                        <enableSeveritySummary>true</enableSeveritySummary>
                        <failOnViolation>false</failOnViolation>
                        <linkXRef>true</linkXRef>
                        <propertyExpansion>config_loc=${io.github.florianwolters.checkstyle.configDirectory}</propertyExpansion>
                        <skip>${checkstyle.skip}</skip>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-dependency-plugin</artifactId>
                    <version>${io.github.florianwolters.version.maven-dependency-plugin}</version>
                    <executions>
                        <execution>
                            <id>dependency.unpack.company-checkstyle-config</id>
                            <phase>validate</phase>
                            <configuration>
                                <artifactItems>
                                    <artifactItem>
                                        <groupId>${project.groupId}</groupId>
                                        <artifactId>example-checkstyle-config</artifactId>
                                        <version>${io.github.florianwolters.version.company-checkstyle-config}</version>
                                        <type>jar</type>
                                        <outputDirectory>${io.github.florianwolters.checkstyle.unpackDirectory}</outputDirectory>
                                        <overWrite>false</overWrite>
                                    </artifactItem>
                                </artifactItems>
                                <overWriteIfNewer>true</overWriteIfNewer>
                                <overWriteReleases>false</overWriteReleases>
                                <overWriteSnapshots>true</overWriteSnapshots>
                            </configuration>
                            <goals>
                                <goal>unpack</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <!-- Skip the execution for the parent Maven project. -->
                    <execution>
                        <id>dependency.unpack.company-checkstyle-config</id>
                        <inherited>false</inherited>
                        <phase>none</phase>
                    </execution>
                </executions>
            </plugin>
    </build>