├── .gitattributes
├── .github
└── workflows
│ ├── maven.yml
│ └── site.yml
├── .gitignore
├── .mvn
├── extensions.xml
├── maven.config
└── wrapper
│ ├── MavenWrapperDownloader.java
│ └── maven-wrapper.properties
├── LICENSE
├── LICENSE_HEADER
├── README.md
├── format.xml
├── mvnw
├── mvnw.cmd
├── pom.xml
├── renovate.json
└── src
├── main
├── java
│ └── au
│ │ └── com
│ │ └── acegi
│ │ └── xmlformat
│ │ ├── AbstractXmlPlugin.java
│ │ ├── BlankLinesWriter.java
│ │ ├── FormatUtil.java
│ │ ├── IOUtil.java
│ │ ├── LineEnding.java
│ │ ├── XmlCheckPlugin.java
│ │ ├── XmlFormatPlugin.java
│ │ ├── XmlOutputFormat.java
│ │ └── package-info.java
└── resources
│ └── META-INF
│ └── m2e
│ └── lifecycle-mapping-metadata.xml
├── site
├── markdown
│ ├── history.md.vm
│ ├── index.md
│ └── usage.md.vm
└── site.xml
└── test
├── java
└── au
│ └── com
│ └── acegi
│ └── xmlformat
│ ├── FormatUtilTest.java
│ ├── IOTest.java
│ ├── TestUtil.java
│ ├── XmlCheckPluginTest.java
│ ├── XmlFormatPluginTest.java
│ └── package-info.java
└── resources
├── invalid.xml
├── test1-in.xml
├── test1-out-kbl.xml
├── test1-out.xml
├── test2-in.xml
├── test2-out-kbl.xml
├── test2-out.xml
├── test3-in.xml
├── test3-out.xml
├── test4-in.xml
├── test4-out-kbl.xml
├── test4-out.xml
├── test5-in.xml
├── test5-out-kbl.xml
├── test5-out.xml
├── test6-in.xml
├── test6-out-kbl.xml
└── test6-out.xml
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto eol=lf
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 | *.sln merge=union
7 | *.csproj merge=union
8 | *.vbproj merge=union
9 | *.fsproj merge=union
10 | *.dbproj merge=union
11 |
12 | # Standard to msysgit
13 | *.doc diff=astextplain
14 | *.DOC diff=astextplain
15 | *.docx diff=astextplain
16 | *.DOCX diff=astextplain
17 | *.dot diff=astextplain
18 | *.DOT diff=astextplain
19 | *.pdf diff=astextplain
20 | *.PDF diff=astextplain
21 | *.rtf diff=astextplain
22 | *.RTF diff=astextplain
23 |
--------------------------------------------------------------------------------
/.github/workflows/maven.yml:
--------------------------------------------------------------------------------
1 | name: Maven Build and Deployment
2 |
3 | on: [push, pull_request]
4 |
5 | permissions: read-all
6 |
7 | jobs:
8 | build:
9 | name: Java Latest LTS Build and Verify
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 | - name: Check out Git repository
14 | uses: actions/checkout@v4
15 |
16 | - name: Set up Java and Maven
17 | uses: actions/setup-java@v4
18 | with:
19 | distribution: zulu
20 | java-version: 21
21 | cache: maven
22 |
23 | - name: Build with Maven
24 | run: ./mvnw -B -V verify --no-transfer-progress
25 |
26 | - name: Upload code coverage to Codecov
27 | uses: codecov/codecov-action@v5
28 |
29 | compatibility-checks:
30 | runs-on: ubuntu-latest
31 |
32 | strategy:
33 | matrix:
34 | java: [17, 21, 24, 25-ea]
35 |
36 | name: Java ${{ matrix.java }} Compatibility
37 |
38 | steps:
39 | - name: Check out Git repository
40 | uses: actions/checkout@v4
41 |
42 | - name: Set up Java and Maven
43 | uses: actions/setup-java@v4
44 | with:
45 | distribution: temurin
46 | java-version: ${{ matrix.java }}
47 | cache: maven
48 |
49 | - name: Test with Maven
50 | run: ./mvnw -B -V test
51 |
52 | compatibility-checks-java17-maven363:
53 | runs-on: ubuntu-latest
54 |
55 | strategy:
56 | matrix:
57 | java: [17]
58 |
59 | name: Java ${{ matrix.java }} Compatibility with Maven 3.6.3
60 |
61 | steps:
62 | - name: Check out Git repository
63 | uses: actions/checkout@v4
64 |
65 | - name: Set up Java and Maven
66 | uses: actions/setup-java@v4
67 | with:
68 | distribution: zulu
69 | java-version: ${{ matrix.java }}
70 | cache: maven
71 |
72 | - name: Load Maven 3.6.3
73 | run: mvn -B -V org.apache.maven.plugins::maven-wrapper-plugin:3.3.2:wrapper -Dmaven=3.6.3 --no-transfer-progress
74 |
75 | - name: Test with Maven
76 | run: ./mvnw -B -V test -Dmaven.min-version=3.6.3
77 |
78 | compatibility-checks-java21-maven400:
79 | runs-on: ubuntu-latest
80 |
81 | strategy:
82 | matrix:
83 | java: [21]
84 |
85 | name: Java ${{ matrix.java }} Compatibility with Maven 4.0.0-beta-4
86 |
87 | steps:
88 | - name: Check out Git repository
89 | uses: actions/checkout@v4
90 |
91 | - name: Set up Java and Maven
92 | uses: actions/setup-java@v4
93 | with:
94 | distribution: zulu
95 | java-version: ${{ matrix.java }}
96 | cache: maven
97 |
98 | - name: Load Maven 4.0.0-beta-4
99 | run: mvn -B -V org.apache.maven.plugins::maven-wrapper-plugin:3.3.2:wrapper -Dmaven=4.0.0-beta-4 --no-transfer-progress
100 |
101 | - name: Test with Maven
102 | run: ./mvnw -B -V test
103 |
104 | deploy:
105 | name: Deploy to OSSRH
106 | needs: [build, compatibility-checks]
107 | if: github.event_name == 'push' && github.repository_owner == 'acegi'
108 | runs-on: ubuntu-latest
109 |
110 | steps:
111 | - name: Check out Git repository
112 | uses: actions/checkout@v4
113 |
114 | - name: Set up Java and Maven
115 | uses: actions/setup-java@v4
116 | with:
117 | distribution: zulu
118 | java-version: 21
119 | cache: maven
120 |
121 | - name: Set up Java and Maven
122 | uses: actions/setup-java@v4
123 | with:
124 | distribution: zulu
125 | java-version: 21
126 | cache: maven
127 | server-id: ossrh
128 | server-username: MAVEN_USERNAME
129 | server-password: MAVEN_CENTRAL_TOKEN
130 | gpg-private-key: ${{ secrets.gpg_private_key }}
131 | gpg-passphrase: MAVEN_GPG_PASSPHRASE
132 |
133 | - name: Publish Maven package
134 | run: ./mvnw -B -V -Possrh-deploy deploy --no-transfer-progress
135 | env:
136 | MAVEN_GPG_PASSPHRASE: ${{ secrets.gpg_passphrase }}
137 | MAVEN_USERNAME: ${{ secrets.nexus_username }}
138 | MAVEN_CENTRAL_TOKEN: ${{ secrets.nexus_password }}
139 |
--------------------------------------------------------------------------------
/.github/workflows/site.yml:
--------------------------------------------------------------------------------
1 | name: Maven Site Generation and Publication to GitHub Pages
2 |
3 | on:
4 | push:
5 | tags:
6 | - '**'
7 |
8 | permissions:
9 | contents: write
10 |
11 | jobs:
12 | build:
13 | name: Generate Site
14 | if: github.repository_owner == 'acegi'
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - name: Check out Git repository
19 | uses: actions/checkout@v4
20 |
21 | - name: Set up Java and Maven
22 | uses: actions/setup-java@v4
23 | with:
24 | distribution: zulu
25 | java-version: 21
26 | cache: maven
27 |
28 | - name: Build with Maven
29 | run: ./mvnw -B -V site --no-transfer-progress
30 |
31 | - name: Publish site to GitHub Pages
32 | uses: peaceiris/actions-gh-pages@v4
33 | with:
34 | github_token: ${{ secrets.GITHUB_TOKEN }}
35 | publish_dir: ./target/site
36 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 | bin
3 | .classpath
4 | .project
5 | .settings
6 | .idea
7 | *.iml
8 | *~
9 | *.releaseBackup
10 | secrets.tar
11 | gpg-sign.json
12 | mvn-sync.json
13 | .mvn/wrapper/maven-wrapper.jar
14 | release.properties
15 | .checkstyle
16 | .factorypath
17 | .fbExcludeFilterFile
18 | .pmd
19 | .pmdruleset.xml
20 |
--------------------------------------------------------------------------------
/.mvn/extensions.xml:
--------------------------------------------------------------------------------
1 |
2 |
21 |
22 |
23 | fr.jcgay.maven
24 | maven-profiler
25 | 3.3
26 |
27 |
28 |
--------------------------------------------------------------------------------
/.mvn/maven.config:
--------------------------------------------------------------------------------
1 | -Daether.checksums.algorithms=SHA-512,SHA-256,SHA-1,MD5
2 | -Daether.connector.smartChecksums=false
3 |
--------------------------------------------------------------------------------
/.mvn/wrapper/MavenWrapperDownloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * https://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | import java.io.IOException;
21 | import java.io.InputStream;
22 | import java.net.Authenticator;
23 | import java.net.PasswordAuthentication;
24 | import java.net.URI;
25 | import java.net.URL;
26 | import java.nio.file.Files;
27 | import java.nio.file.Path;
28 | import java.nio.file.Paths;
29 | import java.nio.file.StandardCopyOption;
30 | import java.util.concurrent.ThreadLocalRandom;
31 |
32 | public final class MavenWrapperDownloader {
33 | private static final String WRAPPER_VERSION = "3.3.2";
34 |
35 | private static final boolean VERBOSE = Boolean.parseBoolean(System.getenv("MVNW_VERBOSE"));
36 |
37 | public static void main(String[] args) {
38 | log("Apache Maven Wrapper Downloader " + WRAPPER_VERSION);
39 |
40 | if (args.length != 2) {
41 | System.err.println(" - ERROR wrapperUrl or wrapperJarPath parameter missing");
42 | System.exit(1);
43 | }
44 |
45 | try {
46 | log(" - Downloader started");
47 | final URL wrapperUrl = URI.create(args[0]).toURL();
48 | final String jarPath = args[1].replace("..", ""); // Sanitize path
49 | final Path wrapperJarPath = Paths.get(jarPath).toAbsolutePath().normalize();
50 | downloadFileFromURL(wrapperUrl, wrapperJarPath);
51 | log("Done");
52 | } catch (IOException e) {
53 | System.err.println("- Error downloading: " + e.getMessage());
54 | if (VERBOSE) {
55 | e.printStackTrace();
56 | }
57 | System.exit(1);
58 | }
59 | }
60 |
61 | private static void downloadFileFromURL(URL wrapperUrl, Path wrapperJarPath)
62 | throws IOException {
63 | log(" - Downloading to: " + wrapperJarPath);
64 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
65 | final String username = System.getenv("MVNW_USERNAME");
66 | final char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
67 | Authenticator.setDefault(new Authenticator() {
68 | @Override
69 | protected PasswordAuthentication getPasswordAuthentication() {
70 | return new PasswordAuthentication(username, password);
71 | }
72 | });
73 | }
74 | Path temp = wrapperJarPath
75 | .getParent()
76 | .resolve(wrapperJarPath.getFileName() + "."
77 | + Long.toUnsignedString(ThreadLocalRandom.current().nextLong()) + ".tmp");
78 | try (InputStream inStream = wrapperUrl.openStream()) {
79 | Files.copy(inStream, temp, StandardCopyOption.REPLACE_EXISTING);
80 | Files.move(temp, wrapperJarPath, StandardCopyOption.REPLACE_EXISTING);
81 | } finally {
82 | Files.deleteIfExists(temp);
83 | }
84 | log(" - Downloader complete");
85 | }
86 |
87 | private static void log(String msg) {
88 | if (VERBOSE) {
89 | System.out.println(msg);
90 | }
91 | }
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | # Licensed to the Apache Software Foundation (ASF) under one
2 | # or more contributor license agreements. See the NOTICE file
3 | # distributed with this work for additional information
4 | # regarding copyright ownership. The ASF licenses this file
5 | # to you under the Apache License, Version 2.0 (the
6 | # "License"); you may not use this file except in compliance
7 | # with the License. You may obtain a copy of the License at
8 | #
9 | # https://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 | wrapperVersion=3.3.2
18 | distributionType=source
19 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
20 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/LICENSE_HEADER:
--------------------------------------------------------------------------------
1 | XML Format Maven Plugin (https://github.com/acegi/xml-format-maven-plugin)
2 |
3 | Copyright ${license.git.copyrightYears} Acegi Technology Pty Limited.
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | https://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/acegi/xml-format-maven-plugin/actions)
2 | [](https://codecov.io/gh/acegi/xml-format-maven-plugin)
3 | [](http://www.javadoc.io/doc/au.com.acegi/xml-format-maven-plugin)
4 | [](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22au.com.acegi%22%20AND%20a%3A%22xml-format-maven-plugin%22)
5 | [](http://www.apache.org/licenses/LICENSE-2.0.txt)
6 |
7 | # XML Format Maven Plugin
8 |
9 | Take a look at the [Project Web Site](https://acegi.github.io/xml-format-maven-plugin/)
10 | for full information.
11 |
12 | ## Snapshots
13 |
14 | Snapshot releases are available in the
15 | [OSS Sonatype Snapshots Repository](https://oss.sonatype.org/content/repositories/snapshots/au/com/acegi/xml-format-maven-plugin).
16 |
17 | ## Releasing
18 |
19 | Prepare release locally then push to the release branch which will finish the release.
20 |
21 | - mvn release:clean
22 | - mvn release:prepare
23 |
--------------------------------------------------------------------------------
/format.xml:
--------------------------------------------------------------------------------
1 |
2 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # https://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Apache Maven Wrapper startup batch script, version 3.3.2
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | # e.g. to debug Maven itself, use
32 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | # ----------------------------------------------------------------------------
35 |
36 | if [ -z "$MAVEN_SKIP_RC" ]; then
37 |
38 | if [ -f /usr/local/etc/mavenrc ]; then
39 | . /usr/local/etc/mavenrc
40 | fi
41 |
42 | if [ -f /etc/mavenrc ]; then
43 | . /etc/mavenrc
44 | fi
45 |
46 | if [ -f "$HOME/.mavenrc" ]; then
47 | . "$HOME/.mavenrc"
48 | fi
49 |
50 | fi
51 |
52 | # OS specific support. $var _must_ be set to either true or false.
53 | cygwin=false
54 | darwin=false
55 | mingw=false
56 | case "$(uname)" in
57 | CYGWIN*) cygwin=true ;;
58 | MINGW*) mingw=true ;;
59 | Darwin*)
60 | darwin=true
61 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
62 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
63 | if [ -z "$JAVA_HOME" ]; then
64 | if [ -x "/usr/libexec/java_home" ]; then
65 | JAVA_HOME="$(/usr/libexec/java_home)"
66 | export JAVA_HOME
67 | else
68 | JAVA_HOME="/Library/Java/Home"
69 | export JAVA_HOME
70 | fi
71 | fi
72 | ;;
73 | esac
74 |
75 | if [ -z "$JAVA_HOME" ]; then
76 | if [ -r /etc/gentoo-release ]; then
77 | JAVA_HOME=$(java-config --jre-home)
78 | fi
79 | fi
80 |
81 | # For Cygwin, ensure paths are in UNIX format before anything is touched
82 | if $cygwin; then
83 | [ -n "$JAVA_HOME" ] \
84 | && JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
85 | [ -n "$CLASSPATH" ] \
86 | && CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
87 | fi
88 |
89 | # For Mingw, ensure paths are in UNIX format before anything is touched
90 | if $mingw; then
91 | [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] \
92 | && JAVA_HOME="$(
93 | cd "$JAVA_HOME" || (
94 | echo "cannot cd into $JAVA_HOME." >&2
95 | exit 1
96 | )
97 | pwd
98 | )"
99 | fi
100 |
101 | if [ -z "$JAVA_HOME" ]; then
102 | javaExecutable="$(which javac)"
103 | if [ -n "$javaExecutable" ] && ! [ "$(expr "$javaExecutable" : '\([^ ]*\)')" = "no" ]; then
104 | # readlink(1) is not available as standard on Solaris 10.
105 | readLink=$(which readlink)
106 | if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then
107 | if $darwin; then
108 | javaHome="$(dirname "$javaExecutable")"
109 | javaExecutable="$(cd "$javaHome" && pwd -P)/javac"
110 | else
111 | javaExecutable="$(readlink -f "$javaExecutable")"
112 | fi
113 | javaHome="$(dirname "$javaExecutable")"
114 | javaHome=$(expr "$javaHome" : '\(.*\)/bin')
115 | JAVA_HOME="$javaHome"
116 | export JAVA_HOME
117 | fi
118 | fi
119 | fi
120 |
121 | if [ -z "$JAVACMD" ]; then
122 | if [ -n "$JAVA_HOME" ]; then
123 | if [ -x "$JAVA_HOME/jre/sh/java" ]; then
124 | # IBM's JDK on AIX uses strange locations for the executables
125 | JAVACMD="$JAVA_HOME/jre/sh/java"
126 | else
127 | JAVACMD="$JAVA_HOME/bin/java"
128 | fi
129 | else
130 | JAVACMD="$(
131 | \unset -f command 2>/dev/null
132 | \command -v java
133 | )"
134 | fi
135 | fi
136 |
137 | if [ ! -x "$JAVACMD" ]; then
138 | echo "Error: JAVA_HOME is not defined correctly." >&2
139 | echo " We cannot execute $JAVACMD" >&2
140 | exit 1
141 | fi
142 |
143 | if [ -z "$JAVA_HOME" ]; then
144 | echo "Warning: JAVA_HOME environment variable is not set." >&2
145 | fi
146 |
147 | # traverses directory structure from process work directory to filesystem root
148 | # first directory with .mvn subdirectory is considered project base directory
149 | find_maven_basedir() {
150 | if [ -z "$1" ]; then
151 | echo "Path not specified to find_maven_basedir" >&2
152 | return 1
153 | fi
154 |
155 | basedir="$1"
156 | wdir="$1"
157 | while [ "$wdir" != '/' ]; do
158 | if [ -d "$wdir"/.mvn ]; then
159 | basedir=$wdir
160 | break
161 | fi
162 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
163 | if [ -d "${wdir}" ]; then
164 | wdir=$(
165 | cd "$wdir/.." || exit 1
166 | pwd
167 | )
168 | fi
169 | # end of workaround
170 | done
171 | printf '%s' "$(
172 | cd "$basedir" || exit 1
173 | pwd
174 | )"
175 | }
176 |
177 | # concatenates all lines of a file
178 | concat_lines() {
179 | if [ -f "$1" ]; then
180 | # Remove \r in case we run on Windows within Git Bash
181 | # and check out the repository with auto CRLF management
182 | # enabled. Otherwise, we may read lines that are delimited with
183 | # \r\n and produce $'-Xarg\r' rather than -Xarg due to word
184 | # splitting rules.
185 | tr -s '\r\n' ' ' <"$1"
186 | fi
187 | }
188 |
189 | log() {
190 | if [ "$MVNW_VERBOSE" = true ]; then
191 | printf '%s\n' "$1"
192 | fi
193 | }
194 |
195 | BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
196 | if [ -z "$BASE_DIR" ]; then
197 | exit 1
198 | fi
199 |
200 | MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
201 | export MAVEN_PROJECTBASEDIR
202 | log "$MAVEN_PROJECTBASEDIR"
203 |
204 | ##########################################################################################
205 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
206 | # This allows using the maven wrapper in projects that prohibit checking in binary data.
207 | ##########################################################################################
208 | wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
209 | if [ -r "$wrapperJarPath" ]; then
210 | log "Found $wrapperJarPath"
211 | else
212 | log "Couldn't find $wrapperJarPath, downloading it ..."
213 |
214 | if [ -n "$MVNW_REPOURL" ]; then
215 | wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar"
216 | else
217 | wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar"
218 | fi
219 | while IFS="=" read -r key value; do
220 | # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
221 | safeValue=$(echo "$value" | tr -d '\r')
222 | case "$key" in wrapperUrl)
223 | wrapperUrl="$safeValue"
224 | break
225 | ;;
226 | esac
227 | done <"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
228 | log "Downloading from: $wrapperUrl"
229 |
230 | if $cygwin; then
231 | wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
232 | fi
233 |
234 | if command -v wget >/dev/null; then
235 | log "Found wget ... using wget"
236 | [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
237 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
238 | wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
239 | else
240 | wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
241 | fi
242 | elif command -v curl >/dev/null; then
243 | log "Found curl ... using curl"
244 | [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
245 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
246 | curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
247 | else
248 | curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
249 | fi
250 | else
251 | log "Falling back to using Java to download"
252 | javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
253 | javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
254 | # For Cygwin, switch paths to Windows format before running javac
255 | if $cygwin; then
256 | javaSource=$(cygpath --path --windows "$javaSource")
257 | javaClass=$(cygpath --path --windows "$javaClass")
258 | fi
259 | if [ -e "$javaSource" ]; then
260 | if [ ! -e "$javaClass" ]; then
261 | log " - Compiling MavenWrapperDownloader.java ..."
262 | ("$JAVA_HOME/bin/javac" "$javaSource")
263 | fi
264 | if [ -e "$javaClass" ]; then
265 | log " - Running MavenWrapperDownloader.java ..."
266 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
267 | fi
268 | fi
269 | fi
270 | fi
271 | ##########################################################################################
272 | # End of extension
273 | ##########################################################################################
274 |
275 | # If specified, validate the SHA-256 sum of the Maven wrapper jar file
276 | wrapperSha256Sum=""
277 | while IFS="=" read -r key value; do
278 | case "$key" in wrapperSha256Sum)
279 | wrapperSha256Sum=$value
280 | break
281 | ;;
282 | esac
283 | done <"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
284 | if [ -n "$wrapperSha256Sum" ]; then
285 | wrapperSha256Result=false
286 | if command -v sha256sum >/dev/null; then
287 | if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c >/dev/null 2>&1; then
288 | wrapperSha256Result=true
289 | fi
290 | elif command -v shasum >/dev/null; then
291 | if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c >/dev/null 2>&1; then
292 | wrapperSha256Result=true
293 | fi
294 | else
295 | echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
296 | echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." >&2
297 | exit 1
298 | fi
299 | if [ $wrapperSha256Result = false ]; then
300 | echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2
301 | echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2
302 | echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2
303 | exit 1
304 | fi
305 | fi
306 |
307 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
308 |
309 | # For Cygwin, switch paths to Windows format before running java
310 | if $cygwin; then
311 | [ -n "$JAVA_HOME" ] \
312 | && JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
313 | [ -n "$CLASSPATH" ] \
314 | && CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
315 | [ -n "$MAVEN_PROJECTBASEDIR" ] \
316 | && MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
317 | fi
318 |
319 | # Provide a "standardized" way to retrieve the CLI args that will
320 | # work with both Windows and non-Windows executions.
321 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*"
322 | export MAVEN_CMD_LINE_ARGS
323 |
324 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
325 |
326 | # shellcheck disable=SC2086 # safe args
327 | exec "$JAVACMD" \
328 | $MAVEN_OPTS \
329 | $MAVEN_DEBUG_OPTS \
330 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
331 | "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
332 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
333 |
--------------------------------------------------------------------------------
/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM https://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Apache Maven Wrapper startup batch script, version 3.3.2
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
28 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
29 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
30 | @REM e.g. to debug Maven itself, use
31 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
32 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
33 | @REM ----------------------------------------------------------------------------
34 |
35 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
36 | @echo off
37 | @REM set title of command window
38 | title %0
39 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
40 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
41 |
42 | @REM set %HOME% to equivalent of $HOME
43 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
44 |
45 | @REM Execute a user defined script before this one
46 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
47 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
48 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
49 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
50 | :skipRcPre
51 |
52 | @setlocal
53 |
54 | set ERROR_CODE=0
55 |
56 | @REM To isolate internal variables from possible post scripts, we use another setlocal
57 | @setlocal
58 |
59 | @REM ==== START VALIDATION ====
60 | if not "%JAVA_HOME%" == "" goto OkJHome
61 |
62 | echo. >&2
63 | echo Error: JAVA_HOME not found in your environment. >&2
64 | echo Please set the JAVA_HOME variable in your environment to match the >&2
65 | echo location of your Java installation. >&2
66 | echo. >&2
67 | goto error
68 |
69 | :OkJHome
70 | if exist "%JAVA_HOME%\bin\java.exe" goto init
71 |
72 | echo. >&2
73 | echo Error: JAVA_HOME is set to an invalid directory. >&2
74 | echo JAVA_HOME = "%JAVA_HOME%" >&2
75 | echo Please set the JAVA_HOME variable in your environment to match the >&2
76 | echo location of your Java installation. >&2
77 | echo. >&2
78 | goto error
79 |
80 | @REM ==== END VALIDATION ====
81 |
82 | :init
83 |
84 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
85 | @REM Fallback to current working directory if not found.
86 |
87 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
88 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
89 |
90 | set EXEC_DIR=%CD%
91 | set WDIR=%EXEC_DIR%
92 | :findBaseDir
93 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
94 | cd ..
95 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
96 | set WDIR=%CD%
97 | goto findBaseDir
98 |
99 | :baseDirFound
100 | set MAVEN_PROJECTBASEDIR=%WDIR%
101 | cd "%EXEC_DIR%"
102 | goto endDetectBaseDir
103 |
104 | :baseDirNotFound
105 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
106 | cd "%EXEC_DIR%"
107 |
108 | :endDetectBaseDir
109 |
110 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
111 |
112 | @setlocal EnableExtensions EnableDelayedExpansion
113 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
114 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
115 |
116 | :endReadAdditionalConfig
117 |
118 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
121 |
122 | set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar"
123 |
124 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
125 | IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
126 | )
127 |
128 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
129 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data.
130 | if exist %WRAPPER_JAR% (
131 | if "%MVNW_VERBOSE%" == "true" (
132 | echo Found %WRAPPER_JAR%
133 | )
134 | ) else (
135 | if not "%MVNW_REPOURL%" == "" (
136 | SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar"
137 | )
138 | if "%MVNW_VERBOSE%" == "true" (
139 | echo Couldn't find %WRAPPER_JAR%, downloading it ...
140 | echo Downloading from: %WRAPPER_URL%
141 | )
142 |
143 | powershell -Command "&{"^
144 | "$webclient = new-object System.Net.WebClient;"^
145 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
146 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
147 | "}"^
148 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
149 | "}"
150 | if "%MVNW_VERBOSE%" == "true" (
151 | echo Finished downloading %WRAPPER_JAR%
152 | )
153 | )
154 | @REM End of extension
155 |
156 | @REM If specified, validate the SHA-256 sum of the Maven wrapper jar file
157 | SET WRAPPER_SHA_256_SUM=""
158 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
159 | IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B
160 | )
161 | IF NOT %WRAPPER_SHA_256_SUM%=="" (
162 | powershell -Command "&{"^
163 | "Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash;"^
164 | "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
165 | "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
166 | " Write-Error 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
167 | " Write-Error 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
168 | " Write-Error 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
169 | " exit 1;"^
170 | "}"^
171 | "}"
172 | if ERRORLEVEL 1 goto error
173 | )
174 |
175 | @REM Provide a "standardized" way to retrieve the CLI args that will
176 | @REM work with both Windows and non-Windows executions.
177 | set MAVEN_CMD_LINE_ARGS=%*
178 |
179 | %MAVEN_JAVA_EXE% ^
180 | %JVM_CONFIG_MAVEN_PROPS% ^
181 | %MAVEN_OPTS% ^
182 | %MAVEN_DEBUG_OPTS% ^
183 | -classpath %WRAPPER_JAR% ^
184 | "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
185 | %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
186 | if ERRORLEVEL 1 goto error
187 | goto end
188 |
189 | :error
190 | set ERROR_CODE=1
191 |
192 | :end
193 | @endlocal & set ERROR_CODE=%ERROR_CODE%
194 |
195 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
196 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
197 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
198 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
199 | :skipRcPost
200 |
201 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
202 | if "%MAVEN_BATCH_PAUSE%"=="on" pause
203 |
204 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
205 |
206 | cmd /C exit /B %ERROR_CODE%
207 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
21 |
22 |
23 | 4.0.0
24 |
25 |
26 | com.github.hazendaz
27 | base-parent
28 | 51
29 |
30 |
31 |
32 | au.com.acegi
33 | xml-format-maven-plugin
34 | 4.1.1-SNAPSHOT
35 | maven-plugin
36 |
37 | XML Format Maven Plugin
38 | Automatically formats XML files in a project.
39 | 2011
40 |
41 |
42 | 3.6.3
43 |
44 |
45 |
46 | scm:git:ssh://github.com/acegi/xml-format-maven-plugin.git
47 | scm:git:ssh://git@github.com/acegi/xml-format-maven-plugin.git
48 | HEAD
49 | https://github.com/acegi/xml-format-maven-plugin
50 |
51 |
52 | Github
53 | https://github.com/acegi/xml-format-maven-plugin/issues
54 |
55 |
56 | Github
57 | https://github.com/acegi/xml-format-maven-plugin/actions
58 |
59 |
60 |
61 | gh-pages-scm
62 | GitHub Pages
63 | scm:git:ssh://git@github.com/acegi/xml-format-maven-plugin.git
64 |
65 |
66 |
67 |
68 |
69 | 8
70 | 8
71 | 8
72 |
73 |
74 | 3.15.1
75 |
76 |
77 | 1.17.5
78 | 2.1.4
79 | 3.0
80 | 5.12.2
81 | 3.17.0
82 | 3.9.9
83 | 5.17.0
84 | 4.0.2
85 | 4.8.6
86 |
87 |
88 | true
89 | true
90 | true
91 | true
92 | true
93 | true
94 |
95 |
96 | true
97 |
98 |
99 | -javaagent:${settings.localRepository}/net/bytebuddy/byte-buddy-agent/${byte-buddy.version}/byte-buddy-agent-${byte-buddy.version}.jar
100 |
101 |
102 |
103 |
104 | org.apache.commons
105 | commons-lang3
106 | ${lang.version}
107 | compile
108 |
109 |
110 | org.apache.maven
111 | maven-artifact
112 | ${maven.version}
113 | provided
114 |
115 |
116 | org.apache.maven
117 | maven-core
118 | ${maven.version}
119 | provided
120 |
121 |
122 | org.apache.maven
123 | maven-plugin-api
124 | ${maven.version}
125 | provided
126 |
127 |
128 | org.apache.maven.plugin-tools
129 | maven-plugin-annotations
130 | ${maven-plugin.version}
131 | provided
132 |
133 |
134 | org.codehaus.plexus
135 | plexus-utils
136 | ${plexus-utils.version}
137 | compile
138 |
139 |
140 | org.dom4j
141 | dom4j
142 | ${dom4j.version}
143 | compile
144 |
145 |
146 | org.hamcrest
147 | hamcrest
148 | ${hamcrest.version}
149 | test
150 |
151 |
152 | org.junit.jupiter
153 | junit-jupiter-api
154 | ${junit.version}
155 | test
156 |
157 |
158 | org.mockito
159 | mockito-core
160 | ${mockito.version}
161 | test
162 |
163 |
164 | net.bytebuddy
165 | byte-buddy
166 | ${byte-buddy.version}
167 | test
168 |
169 |
170 | net.bytebuddy
171 | byte-buddy-agent
172 | ${byte-buddy.version}
173 | test
174 |
175 |
176 |
177 |
178 |
179 |
180 | org.apache.maven.plugins
181 | maven-plugin-plugin
182 | ${maven-plugin.version}
183 |
184 |
185 | default-descriptor
186 |
187 | descriptor
188 |
189 |
190 |
191 | help-goal
192 |
193 | helpmojo
194 |
195 |
196 |
197 |
198 |
199 |
200 | com.mycila
201 | license-maven-plugin
202 |
203 |
204 |
205 |
206 |
207 | .fbExcludeFilterFile
208 | **/test*.xml
209 | **/invalid.xml
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 | org.apache.maven.plugins
222 | maven-plugin-report-plugin
223 | ${maven-plugin.version}
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 | ossrh-deploy
232 |
233 |
234 |
235 | org.sonatype.plugins
236 | nexus-staging-maven-plugin
237 | 1.7.0
238 | true
239 |
240 | ossrh
241 | https://oss.sonatype.org/
242 | true
243 |
244 |
245 |
246 | org.apache.maven.plugins
247 | maven-gpg-plugin
248 |
249 |
250 | sign-artifacts
251 |
252 | sign
253 |
254 | verify
255 |
256 |
257 | --pinentry-mode
258 | loopback
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3 | "extends": [
4 | "config:recommended"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/src/main/java/au/com/acegi/xmlformat/AbstractXmlPlugin.java:
--------------------------------------------------------------------------------
1 | /*
2 | * XML Format Maven Plugin (https://github.com/acegi/xml-format-maven-plugin)
3 | *
4 | * Copyright 2011-2025 Acegi Technology Pty Limited.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * https://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package au.com.acegi.xmlformat;
19 |
20 | import java.io.File;
21 | import java.io.IOException;
22 | import java.util.ArrayList;
23 | import java.util.Arrays;
24 | import java.util.List;
25 |
26 | import org.apache.maven.plugin.AbstractMojo;
27 | import org.apache.maven.plugin.MojoExecutionException;
28 | import org.apache.maven.plugin.MojoFailureException;
29 | import org.apache.maven.plugins.annotations.Parameter;
30 | import org.codehaus.plexus.util.DirectoryScanner;
31 | import org.dom4j.DocumentException;
32 |
33 | /**
34 | * Common infrastructure for the various plugin goals.
35 | */
36 | @SuppressWarnings("DesignForExtension")
37 | public abstract class AbstractXmlPlugin extends AbstractMojo {
38 |
39 | /**
40 | * Quote character to use when writing attributes.
41 | */
42 | @Parameter(property = "attributeQuoteChar", defaultValue = "\"")
43 | @SuppressWarnings("PMD.ImmutableField")
44 | private char attributeQuoteChar = '"';
45 |
46 | /**
47 | * The base directory of the project.
48 | */
49 | @Parameter(defaultValue = ".", readonly = true, required = true, property = "project.basedir")
50 | private File baseDirectory;
51 |
52 | /**
53 | * The encoding format.
54 | */
55 | @Parameter(property = "encoding", defaultValue = "UTF-8")
56 | @SuppressWarnings("PMD.ImmutableField")
57 | private String encoding = "UTF-8";
58 |
59 | /**
60 | * A set of file patterns that allow you to exclude certain files/folders from the formatting. In addition to these
61 | * exclusions, the project build directory (typically target
) is always excluded if skipTargetFolder is
62 | * true.
63 | */
64 | @Parameter(property = "excludes")
65 | private String[] excludes;
66 |
67 | /**
68 | * Whether or not to expand empty elements to <tagName></tagName>.
69 | */
70 | @Parameter(property = "expandEmptyElements", defaultValue = "false")
71 | private boolean expandEmptyElements;
72 |
73 | /**
74 | * A set of file patterns that dictate which files should be included in the formatting with each file pattern being
75 | * relative to the base directory.
76 | */
77 | @Parameter(property = "includes")
78 | private String[] includes;
79 |
80 | /**
81 | * Indicates the number of spaces to apply when indenting.
82 | */
83 | @Parameter(property = "indentSize", defaultValue = "2")
84 | private int indentSize;
85 |
86 | /**
87 | * Use tabs instead of spaces for indents. If set to true
, indentSize
will be ignored.
88 | */
89 | @Parameter(property = "tabIndent", defaultValue = "false")
90 | private boolean tabIndent;
91 |
92 | /**
93 | * Sets the line-ending of files after formatting. Valid values are:
94 | *
95 | * - "SYSTEM" - Use line endings of current system
96 | * - "LF" - Use Unix and Mac style line endings
97 | * - "CRLF" - Use DOS and Windows style line endings
98 | * - "CR" - Use early Mac style line endings
99 | *
100 | * This property is only used if {@link #lineSeparator} has its default value. Do not set any value for
101 | * {@link #lineSeparator}.
102 | */
103 | @Parameter(property = "lineEnding", defaultValue = "LF")
104 | @SuppressWarnings("PMD.ImmutableField")
105 | private LineEnding lineEnding = LineEnding.LF;
106 |
107 | /**
108 | * New line separator.
109 | *
110 | * @deprecated Please do not set this value; use {@link #lineEnding} instead
111 | */
112 | @Parameter(property = "lineSeparator", defaultValue = "\n")
113 | @SuppressWarnings("PMD.ImmutableField")
114 | @Deprecated
115 | private String lineSeparator = "\n";
116 |
117 | /**
118 | * Whether or not to print new line after the XML declaration.
119 | */
120 | @Parameter(property = "newLineAfterDeclaration", defaultValue = "false")
121 | private boolean newLineAfterDeclaration;
122 |
123 | /**
124 | * Controls when to output a line.separator every so many tags in case of no lines and total text trimming.
125 | */
126 | @Parameter(property = "newLineAfterNTags", defaultValue = "0")
127 | private int newLineAfterNTags;
128 |
129 | /**
130 | * The default new line flag, set to do new lines only as in original document.
131 | */
132 | @Parameter(property = "newlines", defaultValue = "true")
133 | private boolean newlines;
134 |
135 | /**
136 | * Whether or not to output the encoding in the XML declaration.
137 | */
138 | @Parameter(property = "omitEncoding", defaultValue = "false")
139 | private boolean omitEncoding;
140 |
141 | /**
142 | * Pad string-element boundaries with whitespace.
143 | */
144 | @Parameter(property = "padText", defaultValue = "false")
145 | private boolean padText;
146 |
147 | /**
148 | * Skip XML formatting.
149 | */
150 | @Parameter(property = "xml-format.skip", defaultValue = "false")
151 | private boolean skip;
152 |
153 | /**
154 | * In addition to the exclusions, the project build directory (typically target
) is always excluded if
155 | * true.
156 | */
157 | @Parameter(property = "skipTargetFolder", defaultValue = "true")
158 | private boolean skipTargetFolder = true;
159 |
160 | /**
161 | * Whether or not to suppress the XML declaration.
162 | */
163 | @Parameter(property = "suppressDeclaration", defaultValue = "false")
164 | private boolean suppressDeclaration;
165 |
166 | /**
167 | * The project target directory. This is always excluded from formatting.
168 | */
169 | @Parameter(defaultValue = "${project.build.directory}", readonly = true, required = true)
170 | private File targetDirectory;
171 |
172 | /**
173 | * Should we preserve whitespace or not in text nodes.
174 | */
175 | @Parameter(property = "trimText", defaultValue = "true")
176 | private boolean trimText;
177 |
178 | /**
179 | * Whether or not to use XHTML standard.
180 | */
181 | @Parameter(property = "xhtml", defaultValue = "false")
182 | private boolean xhtml;
183 |
184 | /**
185 | * Whether to keep blank lines. A maximum of one line is preserved between each tag.
186 | */
187 | @Parameter(property = "keepBlankLines", defaultValue = "false")
188 | private boolean keepBlankLines;
189 |
190 | @Override
191 | public void execute() throws MojoExecutionException, MojoFailureException {
192 | assert baseDirectory != null;
193 | assert targetDirectory != null;
194 |
195 | if (skip) {
196 | getLog().info("[xml-format] Skipped");
197 | return;
198 | }
199 |
200 | initializeIncludes();
201 | initializeExcludes();
202 |
203 | final XmlOutputFormat fmt = buildFormatter();
204 |
205 | boolean success = true;
206 | boolean neededFormatting = false;
207 | for (final String inputName : find()) {
208 | final File input = new File(baseDirectory, inputName);
209 | try {
210 | neededFormatting |= processFile(input, fmt);
211 | } catch (final DocumentException | IOException ex) {
212 | success = false;
213 | getLog().error("[xml-format] Error for " + input, ex);
214 | }
215 | }
216 |
217 | if (!success) {
218 | throw new MojoFailureException("[xml-format] Failed)");
219 | }
220 | afterAllProcessed(neededFormatting);
221 | }
222 |
223 | /**
224 | * Processes a single file found in the project.
225 | *
226 | * @param input
227 | * the file to process
228 | * @param fmt
229 | * the formatting options
230 | *
231 | * @return true if the file required changes to match the formatting style
232 | *
233 | * @throws DocumentException
234 | * if input XML could not be parsed
235 | * @throws IOException
236 | * if output XML stream could not be written
237 | */
238 | protected abstract boolean processFile(File input, XmlOutputFormat fmt) throws DocumentException, IOException;
239 |
240 | /**
241 | * Invoked after all files in the project have been processed.
242 | *
243 | * @param neededFormatting
244 | * whether any processed file required changes to match the formatting style
245 | *
246 | * @throws MojoExecutionException
247 | * if the build must be failed
248 | */
249 | protected abstract void afterAllProcessed(boolean neededFormatting) throws MojoExecutionException;
250 |
251 | void setBaseDirectory(final File baseDirectory) {
252 | this.baseDirectory = baseDirectory;
253 | }
254 |
255 | void setExcludes(final String... excludes) {
256 | this.excludes = excludes == null ? null : Arrays.copyOf(excludes, excludes.length);
257 | }
258 |
259 | void setIncludes(final String... includes) {
260 | this.includes = includes == null ? null : Arrays.copyOf(includes, includes.length);
261 | }
262 |
263 | void setSkip(final boolean skip) {
264 | this.skip = skip;
265 | }
266 |
267 | void setSkipTargetFolder(final boolean skipTargetFolder) {
268 | this.skipTargetFolder = skipTargetFolder;
269 | }
270 |
271 | void setTargetDirectory(final File targetDirectory) {
272 | this.targetDirectory = targetDirectory;
273 | }
274 |
275 | private XmlOutputFormat buildFormatter() {
276 | final XmlOutputFormat fmt = new XmlOutputFormat();
277 | fmt.setAttributeQuoteCharacter(attributeQuoteChar);
278 | fmt.setEncoding(encoding);
279 | fmt.setExpandEmptyElements(expandEmptyElements);
280 | if (tabIndent) {
281 | fmt.setIndent("\t");
282 | } else {
283 | fmt.setIndentSize(indentSize);
284 | }
285 | fmt.setLineSeparator(determineLineSeparator());
286 | fmt.setNewLineAfterDeclaration(newLineAfterDeclaration);
287 | fmt.setNewLineAfterNTags(newLineAfterNTags);
288 | fmt.setNewlines(newlines);
289 | fmt.setOmitEncoding(omitEncoding);
290 | fmt.setPadText(padText);
291 | fmt.setSuppressDeclaration(suppressDeclaration);
292 | fmt.setTrimText(trimText);
293 | fmt.setXHTML(xhtml);
294 | fmt.setKeepBlankLines(keepBlankLines);
295 | return fmt;
296 | }
297 |
298 | private String determineLineSeparator() {
299 | return "\n".equals(lineSeparator) ? lineEnding.getChars() : lineSeparator;
300 | }
301 |
302 | private String[] find() {
303 | final DirectoryScanner dirScanner = new DirectoryScanner();
304 | dirScanner.setBasedir(baseDirectory);
305 | dirScanner.setIncludes(includes);
306 |
307 | final List exclude = new ArrayList<>(Arrays.asList(excludes));
308 | if (skipTargetFolder && baseDirectory.equals(targetDirectory.getParentFile())) {
309 | exclude.add(targetDirectory.getName() + "/**");
310 | }
311 | final String[] excluded = new String[exclude.size()];
312 | dirScanner.setExcludes(exclude.toArray(excluded));
313 |
314 | dirScanner.scan();
315 | return dirScanner.getIncludedFiles();
316 | }
317 |
318 | private void initializeExcludes() {
319 | if (excludes == null || excludes.length == 0) {
320 | excludes = new String[0];
321 | }
322 | }
323 |
324 | private void initializeIncludes() {
325 | if (includes == null || includes.length == 0) {
326 | includes = new String[] { "**/*.xml" };
327 | }
328 | }
329 | }
330 |
--------------------------------------------------------------------------------
/src/main/java/au/com/acegi/xmlformat/BlankLinesWriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * XML Format Maven Plugin (https://github.com/acegi/xml-format-maven-plugin)
3 | *
4 | * Copyright 2011-2025 Acegi Technology Pty Limited.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * https://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package au.com.acegi.xmlformat;
19 |
20 | import java.io.IOException;
21 | import java.io.OutputStream;
22 | import java.io.UnsupportedEncodingException;
23 | import java.util.StringTokenizer;
24 |
25 | import org.apache.commons.lang3.StringUtils;
26 | import org.dom4j.Node;
27 | import org.dom4j.io.XMLWriter;
28 |
29 | /**
30 | * Subclass of {@link XMLWriter} that preserves blank lines in outupt (at most one of them, among two subsequent tags).
31 | */
32 | class BlankLinesWriter extends XMLWriter {
33 |
34 | BlankLinesWriter(final OutputStream out, final XmlOutputFormat fmt) throws UnsupportedEncodingException {
35 | super(out, fmt);
36 | }
37 |
38 | @Override
39 | protected void writeString(final String text) throws IOException {
40 | if (text == null || text.length() == 0) {
41 | return;
42 | }
43 |
44 | String input = text;
45 | if (isEscapeText()) {
46 | input = escapeElementEntities(text);
47 | }
48 |
49 | if (getOutputFormat().isTrimText()) {
50 | boolean first = true;
51 | final StringTokenizer tokenizer = new StringTokenizer(input, " \t\r\f");
52 |
53 | final NewLinesHandler newLinesHandler = new NewLinesHandler();
54 | while (tokenizer.hasMoreTokens()) {
55 | final String token = tokenizer.nextToken();
56 |
57 | // Only if more tokens exist, continue
58 | if (newLinesHandler.processToken(token, tokenizer.hasMoreTokens())) {
59 | continue;
60 | }
61 |
62 | if (first) {
63 | first = false;
64 | if (lastOutputNodeType == Node.TEXT_NODE) {
65 | writer.write(" ");
66 | }
67 | } else {
68 | writer.write(" ");
69 | }
70 |
71 | writer.write(token.trim());
72 | lastOutputNodeType = Node.TEXT_NODE;
73 | }
74 | newLinesHandler.finished();
75 | } else {
76 | lastOutputNodeType = Node.TEXT_NODE;
77 | writer.write(input);
78 | }
79 | }
80 |
81 | private final class NewLinesHandler {
82 | private int newLinesCount;
83 |
84 | /**
85 | * Processes the token, counting the newlines and producing at most one in output.
86 | *
87 | * @param token
88 | * The token to be written
89 | * @param hasMoreTokens
90 | * Does more tokens exist
91 | *
92 | * @return True if the token needs to be skipped (it's a newline or a set of newlines)
93 | *
94 | * @throws IOException
95 | * If an I/O error occurs.
96 | */
97 | private boolean processToken(final String token, final boolean hasMoreTokens) throws IOException {
98 | final int tokenNewLines = StringUtils.countMatches(token, '\n');
99 | if (tokenNewLines > 0) {
100 | newLinesCount += tokenNewLines;
101 | return hasMoreTokens;
102 | }
103 | if (newLinesCount > 1) {
104 | writer.write("\n");
105 | newLinesCount = 0;
106 | }
107 | return false;
108 | }
109 |
110 | /**
111 | * Marks the end of token streams, allows to emit a last newlines if the last tokens were all newlines.
112 | *
113 | * @throws IOException
114 | * If an I/O error occurs.
115 | */
116 | private void finished() throws IOException {
117 | if (newLinesCount > 1) {
118 | writer.write("\n");
119 | }
120 | }
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/src/main/java/au/com/acegi/xmlformat/FormatUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * XML Format Maven Plugin (https://github.com/acegi/xml-format-maven-plugin)
3 | *
4 | * Copyright 2011-2025 Acegi Technology Pty Limited.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * https://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package au.com.acegi.xmlformat;
19 |
20 | import static java.io.File.createTempFile;
21 | import static java.nio.file.Files.copy;
22 | import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
23 |
24 | import static au.com.acegi.xmlformat.IOUtil.hash;
25 |
26 | import java.io.File;
27 | import java.io.IOException;
28 | import java.io.InputStream;
29 | import java.io.OutputStream;
30 | import java.io.StringReader;
31 | import java.io.UnsupportedEncodingException;
32 | import java.nio.file.Files;
33 | import java.nio.file.Path;
34 |
35 | import org.dom4j.Document;
36 | import org.dom4j.DocumentException;
37 | import org.dom4j.io.SAXReader;
38 | import org.dom4j.io.XMLWriter;
39 | import org.xml.sax.EntityResolver;
40 | import org.xml.sax.InputSource;
41 | import org.xml.sax.SAXException;
42 |
43 | /**
44 | * Utility methods private to the package.
45 | */
46 | final class FormatUtil {
47 |
48 | private static final String TMP_FILE_PREFIX = FormatUtil.class.getSimpleName();
49 |
50 | private FormatUtil() {
51 | }
52 |
53 | /**
54 | * Ingest an input stream, writing formatted XML to the output stream. The caller is responsible for closing the
55 | * input and output streams. Any errors in the input stream will cause an exception and the output stream should not
56 | * be relied upon.
57 | *
58 | * @param in
59 | * input XML stream
60 | * @param out
61 | * output XML stream
62 | * @param fmt
63 | * format configuration to apply
64 | *
65 | * @throws DocumentException
66 | * if input XML could not be parsed
67 | * @throws IOException
68 | * if output XML stream could not be written
69 | */
70 | static void format(final InputStream in, final OutputStream out, final XmlOutputFormat fmt)
71 | throws DocumentException, IOException {
72 | final SAXReader reader = new SAXReader();
73 | reader.setEntityResolver(new EntityResolver() {
74 | @Override
75 | public InputSource resolveEntity(final String publicId, final String systemId)
76 | throws SAXException, IOException {
77 | return new InputSource(new StringReader(""));
78 | }
79 | });
80 | final Document xmlDoc = reader.read(in);
81 |
82 | final XMLWriter xmlWriter = getXmlWriter(out, fmt);
83 | xmlWriter.write(xmlDoc);
84 | xmlWriter.flush();
85 | }
86 |
87 | private static XMLWriter getXmlWriter(final OutputStream out, final XmlOutputFormat fmt)
88 | throws UnsupportedEncodingException {
89 | final XMLWriter xmlWriter;
90 | if (fmt.isKeepBlankLines()) {
91 | xmlWriter = new BlankLinesWriter(out, fmt);
92 | } else {
93 | xmlWriter = new XMLWriter(out, fmt);
94 | }
95 | return xmlWriter;
96 | }
97 |
98 | /**
99 | * Formats the input file, overwriting the input file with the new content if the formatted content differs.
100 | *
101 | * @param file
102 | * to read and then potentially overwrite
103 | * @param fmt
104 | * format configuration to apply
105 | *
106 | * @return true if the file was overwritten
107 | *
108 | * @throws DocumentException
109 | * if input XML could not be parsed
110 | * @throws IOException
111 | * if output XML stream could not be written
112 | */
113 | static boolean formatInPlace(final File file, final XmlOutputFormat fmt) throws DocumentException, IOException {
114 | if (file.length() == 0) {
115 | return false;
116 | }
117 |
118 | final File tmpFile = createTempFile(TMP_FILE_PREFIX, ".xml");
119 | tmpFile.deleteOnExit();
120 |
121 | try (InputStream in = Files.newInputStream(file.toPath());
122 | OutputStream out = Files.newOutputStream(tmpFile.toPath())) {
123 | format(in, out, fmt);
124 | }
125 |
126 | final long hashFile = hash(file);
127 | final long hashTmp = hash(tmpFile);
128 | if (hashFile == hashTmp) {
129 | return false;
130 | }
131 |
132 | final Path source = tmpFile.toPath();
133 | final Path target = file.toPath();
134 | copy(source, target, REPLACE_EXISTING);
135 | return true;
136 | }
137 |
138 | /**
139 | * Only checks if the input file would be modified by the formatter, without overwriting it.
140 | *
141 | * @param file
142 | * to read
143 | * @param fmt
144 | * format configuration to apply
145 | *
146 | * @return true if the file would be modified by the formatter
147 | *
148 | * @throws DocumentException
149 | * if input XML could not be parsed
150 | * @throws IOException
151 | * if output XML stream could not be written
152 | */
153 | static boolean needsFormatting(final File file, final XmlOutputFormat fmt) throws DocumentException, IOException {
154 | if (file.length() == 0) {
155 | return false;
156 | }
157 |
158 | final File tmpFile = createTempFile(TMP_FILE_PREFIX, ".xml");
159 | tmpFile.deleteOnExit();
160 |
161 | try (InputStream in = Files.newInputStream(file.toPath());
162 | OutputStream out = Files.newOutputStream(tmpFile.toPath())) {
163 | format(in, out, fmt);
164 | }
165 |
166 | final long hashFile = hash(file);
167 | final long hashTmp = hash(tmpFile);
168 | return hashFile != hashTmp;
169 | }
170 |
171 | }
172 |
--------------------------------------------------------------------------------
/src/main/java/au/com/acegi/xmlformat/IOUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * XML Format Maven Plugin (https://github.com/acegi/xml-format-maven-plugin)
3 | *
4 | * Copyright 2011-2025 Acegi Technology Pty Limited.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * https://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package au.com.acegi.xmlformat;
19 |
20 | import java.io.File;
21 | import java.io.IOException;
22 | import java.io.InputStream;
23 | import java.nio.file.Files;
24 | import java.util.zip.CRC32;
25 | import java.util.zip.CheckedInputStream;
26 | import java.util.zip.Checksum;
27 |
28 | /**
29 | * Utility methods for dealing with I/O resources.
30 | */
31 | final class IOUtil {
32 |
33 | private IOUtil() {
34 | }
35 |
36 | /**
37 | * Returns a CRC32 of the provided input stream.
38 | *
39 | * @param in
40 | * to CRC32
41 | *
42 | * @return the CRC32 value
43 | *
44 | * @throws IOException
45 | * if unable to read the input stream
46 | */
47 | @SuppressWarnings("PMD.EmptyWhileStmt")
48 | static long hash(final InputStream in) throws IOException {
49 | final Checksum cksum = new CRC32();
50 | final CheckedInputStream is = new CheckedInputStream(in, cksum);
51 | final byte[] buff = new byte[4_096];
52 | while (is.read(buff) >= 0) {
53 | // CheckInputStream will update its internal checksum
54 | }
55 | return is.getChecksum().getValue();
56 | }
57 |
58 | /**
59 | * Returns a CRC32 of the given file.
60 | *
61 | * @param file
62 | * to CRC32
63 | *
64 | * @return the CRC32 value
65 | *
66 | * @throws IOException
67 | * if unable to read the file
68 | */
69 | static long hash(final File file) throws IOException {
70 | try (InputStream fis = Files.newInputStream(file.toPath())) {
71 | return hash(fis);
72 | }
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/au/com/acegi/xmlformat/LineEnding.java:
--------------------------------------------------------------------------------
1 | /*
2 | * XML Format Maven Plugin (https://github.com/acegi/xml-format-maven-plugin)
3 | *
4 | * Copyright 2011-2025 Acegi Technology Pty Limited.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * https://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package au.com.acegi.xmlformat;
19 |
20 | /**
21 | * Valid line endings for use by {@link XmlFormatPlugin#lineEnding}.
22 | */
23 | public enum LineEnding {
24 |
25 | /**
26 | * Use the system default line ending.
27 | */
28 | SYSTEM(),
29 |
30 | /**
31 | * Use the newline character. Typical on Unix and Unix-like systems.
32 | */
33 | LF("\n"),
34 |
35 | /**
36 | * Use the carriage return and new line characters. Typical on Windows.
37 | */
38 | CRLF("\r\n"),
39 |
40 | /**
41 | * Use the carriage return character.
42 | */
43 | CR("\r");
44 |
45 | private final String chars;
46 |
47 | LineEnding() {
48 | this.chars = System.lineSeparator();
49 | }
50 |
51 | LineEnding(final String value) {
52 | this.chars = value;
53 | }
54 |
55 | /**
56 | * Gets the chars.
57 | *
58 | * @return the chars
59 | */
60 | public String getChars() {
61 | return this.chars;
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/au/com/acegi/xmlformat/XmlCheckPlugin.java:
--------------------------------------------------------------------------------
1 | /*
2 | * XML Format Maven Plugin (https://github.com/acegi/xml-format-maven-plugin)
3 | *
4 | * Copyright 2011-2025 Acegi Technology Pty Limited.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * https://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package au.com.acegi.xmlformat;
19 |
20 | import static au.com.acegi.xmlformat.FormatUtil.needsFormatting;
21 | import static org.apache.maven.plugins.annotations.LifecyclePhase.PROCESS_SOURCES;
22 |
23 | import java.io.File;
24 | import java.io.IOException;
25 |
26 | import org.apache.maven.plugin.MojoExecutionException;
27 | import org.apache.maven.plugin.logging.Log;
28 | import org.apache.maven.plugins.annotations.Mojo;
29 | import org.dom4j.DocumentException;
30 |
31 | /**
32 | * Finds the XML files in a project and only check them: no files are changed, but the build will fail if any file does
33 | * not follow the formatting conventions.
34 | */
35 | @Mojo(name = "xml-check", defaultPhase = PROCESS_SOURCES, threadSafe = true)
36 | public final class XmlCheckPlugin extends AbstractXmlPlugin {
37 |
38 | @Override
39 | protected boolean processFile(final File input, final XmlOutputFormat fmt) throws DocumentException, IOException {
40 | final boolean needsFormatting = needsFormatting(input, fmt);
41 | final Log log = getLog();
42 | if (needsFormatting && log.isErrorEnabled()) {
43 | log.error("[xml-check] Needs formatting:" + input);
44 | } else if (log.isDebugEnabled()) {
45 | log.debug("[xml-check] Correctly formatted: " + input);
46 | }
47 | return needsFormatting;
48 | }
49 |
50 | @Override
51 | protected void afterAllProcessed(final boolean neededFormatting) throws MojoExecutionException {
52 | if (neededFormatting) {
53 | throw new MojoExecutionException(
54 | "[xml-check] At least one XML file needs formatting, see the error logs above)");
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/au/com/acegi/xmlformat/XmlFormatPlugin.java:
--------------------------------------------------------------------------------
1 | /*
2 | * XML Format Maven Plugin (https://github.com/acegi/xml-format-maven-plugin)
3 | *
4 | * Copyright 2011-2025 Acegi Technology Pty Limited.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * https://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package au.com.acegi.xmlformat;
19 |
20 | import static au.com.acegi.xmlformat.FormatUtil.formatInPlace;
21 | import static org.apache.maven.plugins.annotations.LifecyclePhase.PREPARE_PACKAGE;
22 |
23 | import java.io.File;
24 | import java.io.IOException;
25 |
26 | import org.apache.maven.plugins.annotations.Mojo;
27 | import org.dom4j.DocumentException;
28 |
29 | /**
30 | * Finds the XML files in a project and automatically reformats them.
31 | */
32 | @Mojo(name = "xml-format", defaultPhase = PREPARE_PACKAGE, threadSafe = true)
33 | public final class XmlFormatPlugin extends AbstractXmlPlugin {
34 |
35 | @Override
36 | protected boolean processFile(final File input, final XmlOutputFormat fmt) throws DocumentException, IOException {
37 | final boolean changed = formatInPlace(input, fmt);
38 | if (getLog().isDebugEnabled()) {
39 | final String msg = changed ? "Formatted" : "Unchanged";
40 | getLog().debug("[xml-format] " + msg + ": " + input);
41 | }
42 | return changed;
43 | }
44 |
45 | @Override
46 | protected void afterAllProcessed(final boolean neededFormatting) {
47 | // nothing to do
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/au/com/acegi/xmlformat/XmlOutputFormat.java:
--------------------------------------------------------------------------------
1 | /*
2 | * XML Format Maven Plugin (https://github.com/acegi/xml-format-maven-plugin)
3 | *
4 | * Copyright 2011-2025 Acegi Technology Pty Limited.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * https://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package au.com.acegi.xmlformat;
19 |
20 | import org.dom4j.io.OutputFormat;
21 |
22 | /**
23 | * Extended DOM4J configuration.
24 | *
25 | * - Defaults to pretty print.
26 | *
- Adds an option to keep blank lines.
27 | *
28 | */
29 | public class XmlOutputFormat extends OutputFormat {
30 |
31 | private boolean keepBlankLines;
32 |
33 | /**
34 | * Instantiates a new xml output format.
35 | */
36 | public XmlOutputFormat() {
37 | // same as pretty print
38 | setIndentSize(2);
39 | setNewlines(true);
40 | setTrimText(true);
41 | setPadText(true);
42 | }
43 |
44 | /**
45 | * When set to true, preserves at most one blank line between tags, if it was alredy present in the input file.
46 | * Defaults to false
.
47 | *
48 | * @return Whether blank lines are preserved, or not.
49 | */
50 | public boolean isKeepBlankLines() {
51 | return keepBlankLines;
52 | }
53 |
54 | /**
55 | * When set to true, preserves at most one blank line between tags, if it was alredy present in the input file.
56 | *
57 | * @param keepBlankLines
58 | * true to preserve at most one blank line, false to remove all blank lines.
59 | */
60 | public void setKeepBlankLines(final boolean keepBlankLines) {
61 | this.keepBlankLines = keepBlankLines;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/au/com/acegi/xmlformat/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * XML Format Maven Plugin (https://github.com/acegi/xml-format-maven-plugin)
3 | *
4 | * Copyright 2011-2025 Acegi Technology Pty Limited.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * https://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | /**
19 | * XML Formatter Maven Plugin main package.
20 | */
21 | package au.com.acegi.xmlformat;
22 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml:
--------------------------------------------------------------------------------
1 |
2 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | xml-check
28 | xml-format
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/site/markdown/history.md.vm:
--------------------------------------------------------------------------------
1 | #*
2 | * XML Format Maven Plugin (https://github.com/acegi/xml-format-maven-plugin)
3 | *
4 | * Copyright 2011-2025 Acegi Technology Pty Limited.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * https://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *#
18 | This project was originally created in 2011 and was known as the Technical
19 | Software Configuration Management (TSCM) XML Formatter Maven Plugin. It was
20 | first hosted on Google Code
21 | ([archive](https://web.archive.org/web/20141229160234/https://code.google.com/p/xml-formatter/))
22 | by Brian Walsh and Sean Dobberstein. It was never submitted to Maven Central.
23 |
24 | A patch was submitted via Google Code in 2011, but no response was received. The
25 | Google Code repository was therefore cloned on GitHub and the patch applied
26 | there. A temporary build of the plugin was hosted on GitHub to assist others who
27 | might need an XML formatter plugin.
28 |
29 | Five years passed by and, surprisingly, nobody wrote a new XML formatter
30 | plugin. Instead people kept using the "temporary" plugin hosted in the GitHub
31 | repository, making the odd tweak here and there (eg changing the indent from 4
32 | to 2 spaces).
33 |
34 | By June 2016 it seemed about time to delete the original code and rewrite it
35 | from scratch. The plugin was rewritten to use the latest Dom4j support, newest
36 | Maven plugin dependencies (farewell doclets!), higher component cohesion to
37 | facilitate isolated tests, actual unit tests with mocks to ensure the plugin
38 | won't damage complex XML files, deeper customisation options, and integration
39 | with modern open source services such as GitHub (including GitHub Actions),
40 | Codecov and Maven Central. The major version number was bumped up to 3.0.0 to
41 | reflect this rewrite.
42 |
43 | Like to make an improvement? Feel free! Just click the "Fork me on GitHub"
44 | ribbon above and send us a pull request.
45 |
--------------------------------------------------------------------------------
/src/site/markdown/index.md:
--------------------------------------------------------------------------------
1 | This [Maven](https://maven.apache.org/) plugin automatically formats all XML
2 | files in your project. It will skip changing an XML file if it is already in the
3 | correct format.
4 |
5 | Internally it uses [Dom4j](https://dom4j.github.io/)'s advanced formatter,
6 | allowing you to easily control [many settings](xml-format-mojo.html) such as the
7 | indentation level, padding, encoding, XML declaration line, newline characters,
8 | encoding and so on. You can use a comment block or
9 | [CDATA](https://en.wikipedia.org/wiki/CDATA) if you'd like to preserve specific
10 | formatting (eg legal messages).
11 |
12 | This plugin has been tested with large projects that use many XML files for Maven
13 | POMs and
14 | [Simple Binary Encoding](https://github.com/real-logic/simple-binary-encoding)
15 | schemas. The plugin also uses a test suite to verify the correct formatting of
16 | complex XML files (see
17 | [test XML](https://github.com/acegi/xml-format-maven-plugin/tree/master/src/test/resources)).
18 |
19 | Ready to format? Take a look at the [usage instructions](usage.html).
20 |
--------------------------------------------------------------------------------
/src/site/markdown/usage.md.vm:
--------------------------------------------------------------------------------
1 | #*
2 | * XML Format Maven Plugin (https://github.com/acegi/xml-format-maven-plugin)
3 | *
4 | * Copyright 2011-2025 Acegi Technology Pty Limited.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * https://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *#
18 | This plugin available from Maven Central. This means you can simply add it to
19 | your ``pom.xml``, specifying your preferred format configuration. For example:
20 |
21 | ```
22 |
23 | ${project.groupId}
24 | ${project.artifactId}
25 | ${project.version}
26 |
27 |
28 | xml-format
29 |
30 | xml-format
31 |
32 |
33 |
34 | 2
35 |
36 |
37 |
38 |
39 | ```
40 |
41 | The above will cause ``mvn package`` to format all your XML files automatically
42 | during any `verify` phase. You can select a different phase by adding a
43 | `someOther` to the `` element.
44 |
45 | Please see the [xml-format:xml-format](xml-format-mojo.html) page for the
46 | available configuration options.
47 |
48 | You can also configure the plugin to just check formatting, without applying
49 | any changes. It will just fail the build if any file doesn't respect the
50 | conventions. This is mainly useful for CI, to make sure everyone has checked in
51 | formatted files.
52 |
53 | ```
54 |
55 | ${project.groupId}
56 | ${project.artifactId}
57 | ${project.version}
58 |
59 |
60 | xml-format
61 |
62 | xml-check
63 |
64 |
65 |
66 |
67 |
68 | 2
69 |
70 |
71 | ```
72 |
73 | Note that we defined the configuration globally for the plugin, outside of the
74 | execution. This allows you to format the files manually from the command line:
75 |
76 | ```
77 | mvn xml-format:xml-format
78 | ```
79 |
--------------------------------------------------------------------------------
/src/site/site.xml:
--------------------------------------------------------------------------------
1 |
2 |
21 |
22 |
24 |
25 |
26 | org.apache.maven.skins
27 | maven-fluido-skin
28 | 2.1.0
29 |
30 |
31 |
32 | true
33 | true
34 | »
35 |
36 | acegi/xml-format-maven-plugin
37 | right
38 | gray
39 |
40 |
41 | benalexau
42 | true
43 | true
44 |
45 |
46 |
47 |
48 |
49 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/src/test/java/au/com/acegi/xmlformat/FormatUtilTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * XML Format Maven Plugin (https://github.com/acegi/xml-format-maven-plugin)
3 | *
4 | * Copyright 2011-2025 Acegi Technology Pty Limited.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * https://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package au.com.acegi.xmlformat;
19 |
20 | import static java.nio.charset.StandardCharsets.UTF_8;
21 |
22 | import static au.com.acegi.xmlformat.FormatUtil.format;
23 | import static au.com.acegi.xmlformat.FormatUtil.formatInPlace;
24 | import static au.com.acegi.xmlformat.TestUtil.getResource;
25 | import static au.com.acegi.xmlformat.TestUtil.streamToString;
26 | import static au.com.acegi.xmlformat.TestUtil.stringToFile;
27 | import static org.hamcrest.CoreMatchers.is;
28 | import static org.hamcrest.MatcherAssert.assertThat;
29 | import static org.junit.jupiter.api.Assertions.assertThrows;
30 |
31 | import java.io.ByteArrayOutputStream;
32 | import java.io.File;
33 | import java.io.IOException;
34 | import java.io.InputStream;
35 |
36 | import org.dom4j.DocumentException;
37 | import org.junit.jupiter.api.Test;
38 | import org.junit.jupiter.api.io.TempDir;
39 |
40 | /** Tests {@link FormatUtil}. */
41 | public class FormatUtilTest {
42 |
43 | private static final String FORMATTED_XML = "";
44 | private static final String UNFORMATTED_XML = " ";
45 |
46 | @TempDir
47 | private File tmp;
48 |
49 | @Test
50 | void formattedWillNotChange() throws DocumentException, IOException {
51 | inPlaceChange(FORMATTED_XML, false);
52 | }
53 |
54 | @Test
55 | void test1() throws DocumentException, IOException {
56 | final XmlOutputFormat fmt = new XmlOutputFormat();
57 | fmt.setIndentSize(4);
58 | fmt.setNewLineAfterDeclaration(false);
59 | fmt.setPadText(false);
60 | testInOut(1, fmt);
61 | }
62 |
63 | @Test
64 | void test1KeepBlankLines() throws DocumentException, IOException {
65 | final XmlOutputFormat fmt = new XmlOutputFormat();
66 | fmt.setIndentSize(4);
67 | fmt.setNewLineAfterDeclaration(false);
68 | fmt.setPadText(false);
69 | fmt.setKeepBlankLines(true);
70 | testInOut(1, fmt);
71 | }
72 |
73 | @Test
74 | void test2() throws DocumentException, IOException {
75 | final XmlOutputFormat fmt = new XmlOutputFormat();
76 | fmt.setIndentSize(2);
77 | fmt.setNewLineAfterDeclaration(false);
78 | fmt.setPadText(false);
79 | testInOut(2, fmt);
80 | }
81 |
82 | @Test
83 | void test2KeepBlankLines() throws DocumentException, IOException {
84 | final XmlOutputFormat fmt = new XmlOutputFormat();
85 | fmt.setIndentSize(2);
86 | fmt.setNewLineAfterDeclaration(false);
87 | fmt.setPadText(false);
88 | fmt.setKeepBlankLines(true);
89 | testInOut(2, fmt);
90 | }
91 |
92 | @Test
93 | void test3() throws DocumentException, IOException {
94 | final XmlOutputFormat fmt = new XmlOutputFormat();
95 | fmt.setIndentSize(2);
96 | fmt.setNewLineAfterDeclaration(false);
97 | fmt.setPadText(false);
98 | testInOut(3, fmt);
99 | }
100 |
101 | @Test
102 | void test4() throws DocumentException, IOException {
103 | final XmlOutputFormat fmt = new XmlOutputFormat();
104 | fmt.setIndent("\t");
105 | fmt.setNewLineAfterDeclaration(false);
106 | fmt.setPadText(false);
107 | testInOut(4, fmt);
108 | }
109 |
110 | @Test
111 | void test4KeepBlankLines() throws DocumentException, IOException {
112 | final XmlOutputFormat fmt = new XmlOutputFormat();
113 | fmt.setIndent("\t");
114 | fmt.setNewLineAfterDeclaration(false);
115 | fmt.setPadText(false);
116 | fmt.setKeepBlankLines(true);
117 | testInOut(4, fmt);
118 | }
119 |
120 | @Test
121 | void test5() throws DocumentException, IOException {
122 | final XmlOutputFormat fmt = new XmlOutputFormat();
123 | fmt.setIndent(" ");
124 | fmt.setNewLineAfterDeclaration(false);
125 | fmt.setPadText(false);
126 | fmt.setTrimText(true);
127 | testInOut(5, fmt);
128 | }
129 |
130 | /**
131 | * New lines between the XML declaration and the root elements are ignored at the parse level it seems, they don't
132 | * reach the XMLWriter. Not ideal, but believe we can leave with this exception
133 | */
134 | @Test
135 | void test5KeepBlankLines() throws DocumentException, IOException {
136 | final XmlOutputFormat fmt = new XmlOutputFormat();
137 | fmt.setIndent(" ");
138 | // Set to true to keep the new line given keep blank lines will not
139 | fmt.setNewLineAfterDeclaration(true);
140 | fmt.setPadText(false);
141 | fmt.setTrimText(true);
142 | fmt.setKeepBlankLines(true);
143 | testInOut(5, fmt);
144 | }
145 |
146 | /**
147 | * New lines between the XML declaration and the root elements are ignored at the parse level it seems, they don't
148 | * reach the XMLWriter. Not ideal, but believe we can leave with this exception
149 | */
150 | @Test
151 | void test6() throws DocumentException, IOException {
152 | final XmlOutputFormat fmt = new XmlOutputFormat();
153 | fmt.setIndent(" ");
154 | // Set to true to keep the new line given keep blank lines will not
155 | fmt.setNewLineAfterDeclaration(true);
156 | fmt.setPadText(false);
157 | fmt.setTrimText(true);
158 | fmt.setKeepBlankLines(true);
159 | testInOut(6, fmt);
160 | }
161 |
162 | @Test
163 | void testInvalid() throws DocumentException, IOException {
164 | assertThrows(DocumentException.class, () -> {
165 | try (InputStream in = getResource("/invalid.xml")) {
166 | final ByteArrayOutputStream out = new ByteArrayOutputStream();
167 | format(in, out, new XmlOutputFormat());
168 | }
169 | });
170 | }
171 |
172 | @Test
173 | void unformattedWillChange() throws DocumentException, IOException {
174 | inPlaceChange(UNFORMATTED_XML, true);
175 | }
176 |
177 | private void inPlaceChange(final String txt, final boolean shouldChange) throws DocumentException, IOException {
178 | final File file = File.createTempFile("junit", null, tmp);
179 | stringToFile(txt, file);
180 |
181 | final XmlOutputFormat fmt = new XmlOutputFormat();
182 | fmt.setSuppressDeclaration(true);
183 | fmt.setIndent("");
184 | fmt.setNewlines(false);
185 |
186 | final boolean written = formatInPlace(file, fmt);
187 | assertThat(written, is(shouldChange));
188 | }
189 |
190 | private void testInOut(final int id, final XmlOutputFormat fmt) throws DocumentException, IOException {
191 | try (InputStream in = getResource("/test" + id + "-in.xml")) {
192 | final ByteArrayOutputStream out = new ByteArrayOutputStream();
193 | format(in, out, fmt);
194 |
195 | final String received = new String(out.toByteArray(), UTF_8);
196 | final String expected = streamToString(getResource(getOutputFileName(id, fmt)));
197 | assertThat(received, is(expected));
198 | }
199 | }
200 |
201 | private String getOutputFileName(final int id, final XmlOutputFormat fmt) {
202 | if (fmt.isKeepBlankLines()) {
203 | return "/test" + id + "-out-kbl.xml";
204 | }
205 | return "/test" + id + "-out.xml";
206 | }
207 | }
208 |
--------------------------------------------------------------------------------
/src/test/java/au/com/acegi/xmlformat/IOTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * XML Format Maven Plugin (https://github.com/acegi/xml-format-maven-plugin)
3 | *
4 | * Copyright 2011-2025 Acegi Technology Pty Limited.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * https://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package au.com.acegi.xmlformat;
19 |
20 | import static au.com.acegi.xmlformat.IOUtil.hash;
21 | import static au.com.acegi.xmlformat.TestUtil.getResource;
22 | import static org.hamcrest.CoreMatchers.is;
23 | import static org.hamcrest.MatcherAssert.assertThat;
24 |
25 | import java.io.IOException;
26 | import java.io.InputStream;
27 |
28 | import org.junit.jupiter.api.Test;
29 |
30 | /**
31 | * Tests {@link IOUtil}.
32 | */
33 | public class IOTest {
34 |
35 | @Test
36 | void hash1() throws IOException {
37 | testHash("/test1-in.xml", 459_402_491L);
38 | }
39 |
40 | @Test
41 | void hash2() throws IOException {
42 | testHash("/test2-in.xml", 1_687_393_391L);
43 | }
44 |
45 | @Test
46 | void hashInvalid() throws IOException {
47 | testHash("/invalid.xml", 2_274_913_643L);
48 | }
49 |
50 | private void testHash(final String resource, final long expected) throws IOException {
51 | try (InputStream in = getResource(resource)) {
52 | final long hash = hash(in);
53 | assertThat(hash, is(expected));
54 | }
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/test/java/au/com/acegi/xmlformat/TestUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * XML Format Maven Plugin (https://github.com/acegi/xml-format-maven-plugin)
3 | *
4 | * Copyright 2011-2025 Acegi Technology Pty Limited.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * https://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package au.com.acegi.xmlformat;
19 |
20 | import static java.nio.charset.StandardCharsets.UTF_8;
21 |
22 | import static org.hamcrest.CoreMatchers.not;
23 | import static org.hamcrest.CoreMatchers.nullValue;
24 | import static org.hamcrest.MatcherAssert.assertThat;
25 |
26 | import java.io.File;
27 | import java.io.IOException;
28 | import java.io.InputStream;
29 | import java.io.InputStreamReader;
30 | import java.io.OutputStream;
31 | import java.io.OutputStreamWriter;
32 | import java.io.StringWriter;
33 | import java.io.Writer;
34 | import java.nio.file.Files;
35 |
36 | /**
37 | * Utility methods required by the test package.
38 | */
39 | final class TestUtil {
40 |
41 | private TestUtil() {
42 | }
43 |
44 | static String fileToString(final File in) {
45 | try (InputStream is = Files.newInputStream(in.toPath())) {
46 | return streamToString(is);
47 | } catch (final IOException ex) {
48 | throw new IllegalStateException(ex);
49 | }
50 | }
51 |
52 | static InputStream getResource(final String resource) {
53 | final InputStream in = FormatUtilTest.class.getResourceAsStream(resource);
54 | assertThat(resource + " not found", in, not(nullValue()));
55 | return in;
56 | }
57 |
58 | static String streamToString(final InputStream in) {
59 | final StringWriter sw = new StringWriter();
60 | final InputStreamReader reader = new InputStreamReader(in, UTF_8);
61 | final char[] buffer = new char[4_096];
62 | int n;
63 | try {
64 | while (-1 != (n = reader.read(buffer))) {
65 | sw.write(buffer, 0, n);
66 | }
67 | } catch (final IOException ex) {
68 | throw new IllegalStateException(ex);
69 | }
70 | return sw.toString();
71 | }
72 |
73 | static void stringToFile(final String msg, final File out) {
74 | try (OutputStream fos = Files.newOutputStream(out.toPath());
75 | Writer writer = new OutputStreamWriter(fos, UTF_8)) {
76 | writer.append(msg);
77 | } catch (final IOException ex) {
78 | throw new IllegalStateException(ex);
79 | }
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/src/test/java/au/com/acegi/xmlformat/XmlCheckPluginTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * XML Format Maven Plugin (https://github.com/acegi/xml-format-maven-plugin)
3 | *
4 | * Copyright 2011-2025 Acegi Technology Pty Limited.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * https://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package au.com.acegi.xmlformat;
19 |
20 | import static au.com.acegi.xmlformat.TestUtil.fileToString;
21 | import static au.com.acegi.xmlformat.TestUtil.stringToFile;
22 | import static org.hamcrest.CoreMatchers.is;
23 | import static org.hamcrest.MatcherAssert.assertThat;
24 | import static org.junit.jupiter.api.Assertions.fail;
25 | import static org.mockito.ArgumentMatchers.anyString;
26 | import static org.mockito.Mockito.atLeastOnce;
27 | import static org.mockito.Mockito.mock;
28 | import static org.mockito.Mockito.never;
29 | import static org.mockito.Mockito.verify;
30 | import static org.mockito.Mockito.when;
31 |
32 | import java.io.File;
33 | import java.io.IOException;
34 |
35 | import org.apache.maven.plugin.MojoExecutionException;
36 | import org.apache.maven.plugin.MojoFailureException;
37 | import org.apache.maven.plugin.logging.Log;
38 | import org.junit.jupiter.api.Assertions;
39 | import org.junit.jupiter.api.BeforeEach;
40 | import org.junit.jupiter.api.Test;
41 | import org.junit.jupiter.api.io.TempDir;
42 |
43 | /**
44 | * Tests {@link XmlCheckPlugin}.
45 | */
46 | public class XmlCheckPluginTest {
47 |
48 | private static final String EMPTY_FILE_NAME = "empty.xml";
49 | private static final String EMPTY_TXT = "";
50 | private static final String ERR_FILE_NAME = "error.xml";
51 | private static final String ERR_TXT = " hello not closed! ";
52 | private static final String NO_CHG_TXT = " ";
53 | private static final String TO_CHG_FILE_NAME = "my.xml";
54 | private static final String TO_CHG_TXT = " ";
55 |
56 | @TempDir
57 | private File tmp;
58 |
59 | @SuppressWarnings("PMD.ProperLogger")
60 | private Log log;
61 |
62 | private File proj;
63 | private File target;
64 |
65 | @BeforeEach
66 | void before() throws IOException {
67 | proj = newFolder(tmp, "junit");
68 | target = new File(proj, "target");
69 | assertThat(target.mkdir(), is(true));
70 |
71 | final File toChange = new File(proj, TO_CHG_FILE_NAME);
72 | stringToFile(TO_CHG_TXT, toChange);
73 |
74 | final File noChange = new File(target, "exclude-me.xml");
75 | stringToFile(NO_CHG_TXT, noChange);
76 |
77 | final File empty = new File(proj, EMPTY_FILE_NAME);
78 | stringToFile(EMPTY_TXT, empty);
79 |
80 | final File error = new File(proj, ERR_FILE_NAME);
81 | stringToFile(ERR_TXT, error);
82 |
83 | assertThat(fileToString(toChange), is(TO_CHG_TXT));
84 | assertThat(fileToString(noChange), is(NO_CHG_TXT));
85 | assertThat(fileToString(empty), is(EMPTY_TXT));
86 | assertThat(fileToString(error), is(ERR_TXT));
87 |
88 | log = mock(Log.class);
89 | }
90 |
91 | @Test
92 | @SuppressWarnings("PMD.JUnitUseExpected")
93 | void pluginReportsError() throws MojoExecutionException {
94 | final XmlCheckPlugin plugin = new XmlCheckPlugin();
95 | plugin.setLog(log);
96 | when(log.isDebugEnabled()).thenReturn(true);
97 | when(log.isErrorEnabled()).thenReturn(true);
98 |
99 | plugin.setBaseDirectory(proj);
100 | plugin.setIncludes("**/*.xml");
101 | plugin.setTargetDirectory(target);
102 |
103 | Assertions.assertThrows(MojoFailureException.class, () -> {
104 | plugin.execute();
105 | fail("Should have raised exception when handling error");
106 | });
107 |
108 | verify(log, atLeastOnce()).isErrorEnabled();
109 | verify(log, atLeastOnce()).isDebugEnabled();
110 | verify(log, atLeastOnce()).debug(anyString());
111 | }
112 |
113 | @Test
114 | @SuppressWarnings("PMD.JUnitUseExpected")
115 | void pluginReportsFormattingNeeded() throws MojoFailureException {
116 | final XmlCheckPlugin plugin = new XmlCheckPlugin();
117 | plugin.setLog(log);
118 | when(log.isDebugEnabled()).thenReturn(true);
119 | when(log.isErrorEnabled()).thenReturn(true);
120 |
121 | plugin.setBaseDirectory(proj);
122 | plugin.setExcludes("**/" + ERR_FILE_NAME);
123 | plugin.setIncludes("**/*.xml");
124 | plugin.setTargetDirectory(target);
125 |
126 | Assertions.assertThrows(MojoExecutionException.class, () -> {
127 | plugin.execute();
128 | fail("Should have raised exception when encountering non-formatted file");
129 | });
130 |
131 | verify(log, atLeastOnce()).isErrorEnabled();
132 | verify(log, atLeastOnce()).isDebugEnabled();
133 | verify(log, atLeastOnce()).debug(anyString());
134 | }
135 |
136 | @Test
137 | void pluginSucceedsWhenAllFormatted() throws MojoExecutionException, MojoFailureException {
138 | final XmlCheckPlugin plugin = new XmlCheckPlugin();
139 | plugin.setLog(log);
140 | when(log.isDebugEnabled()).thenReturn(true);
141 | when(log.isErrorEnabled()).thenReturn(true);
142 |
143 | plugin.setBaseDirectory(proj);
144 | plugin.setExcludes("**/" + ERR_FILE_NAME, "**/" + TO_CHG_FILE_NAME);
145 | plugin.setIncludes("**/*.xml");
146 | plugin.setTargetDirectory(target);
147 |
148 | plugin.execute();
149 |
150 | verify(log, never()).isErrorEnabled();
151 | verify(log, atLeastOnce()).isDebugEnabled();
152 | verify(log, atLeastOnce()).debug(anyString());
153 | }
154 |
155 | private static File newFolder(final File root, final String... subDirs) throws IOException {
156 | final String subFolder = String.join("/", subDirs);
157 | final File result = new File(root, subFolder);
158 | if (!result.mkdirs()) {
159 | throw new IOException("Couldn't create folders " + root);
160 | }
161 | return result;
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/src/test/java/au/com/acegi/xmlformat/XmlFormatPluginTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * XML Format Maven Plugin (https://github.com/acegi/xml-format-maven-plugin)
3 | *
4 | * Copyright 2011-2025 Acegi Technology Pty Limited.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * https://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package au.com.acegi.xmlformat;
19 |
20 | import static au.com.acegi.xmlformat.TestUtil.fileToString;
21 | import static au.com.acegi.xmlformat.TestUtil.stringToFile;
22 | import static org.hamcrest.CoreMatchers.is;
23 | import static org.hamcrest.CoreMatchers.not;
24 | import static org.hamcrest.MatcherAssert.assertThat;
25 | import static org.junit.jupiter.api.Assertions.fail;
26 | import static org.mockito.ArgumentMatchers.any;
27 | import static org.mockito.ArgumentMatchers.anyString;
28 | import static org.mockito.Mockito.atLeastOnce;
29 | import static org.mockito.Mockito.mock;
30 | import static org.mockito.Mockito.never;
31 | import static org.mockito.Mockito.verify;
32 | import static org.mockito.Mockito.when;
33 |
34 | import java.io.File;
35 | import java.io.IOException;
36 |
37 | import org.apache.maven.plugin.MojoExecutionException;
38 | import org.apache.maven.plugin.MojoFailureException;
39 | import org.apache.maven.plugin.logging.Log;
40 | import org.junit.jupiter.api.Assertions;
41 | import org.junit.jupiter.api.BeforeEach;
42 | import org.junit.jupiter.api.Test;
43 | import org.junit.jupiter.api.io.TempDir;
44 |
45 | /**
46 | * Tests {@link XmlFormatPlugin}.
47 | */
48 | public class XmlFormatPluginTest {
49 |
50 | private static final String EMPTY_FILE_NAME = "empty.xml";
51 | private static final String EMPTY_TXT = "";
52 | private static final String ERR_FILE_NAME = "error.xml";
53 | private static final String ERR_TXT = " hello not closed! ";
54 | private static final String NO_CHG_TXT = " ";
55 | private static final String TO_CHG_TXT = " ";
56 | private static final String INCLUDE_ALL_XML = "**/*.xml";
57 |
58 | @TempDir
59 | private File tmp;
60 | private File error;
61 | @SuppressWarnings("PMD.ProperLogger")
62 | private Log log;
63 | private File noChange;
64 | private File proj;
65 | private File target;
66 | private File toChange;
67 |
68 | @BeforeEach
69 | void before() throws IOException {
70 | proj = newFolder(tmp, "junit");
71 | target = new File(proj, "target");
72 | assertThat(target.mkdir(), is(true));
73 |
74 | toChange = new File(proj, "my.xml");
75 | stringToFile(TO_CHG_TXT, toChange);
76 |
77 | noChange = new File(target, "exclude-me.xml");
78 | stringToFile(NO_CHG_TXT, noChange);
79 |
80 | final File empty = new File(proj, EMPTY_FILE_NAME);
81 | stringToFile(EMPTY_TXT, empty);
82 |
83 | error = new File(proj, ERR_FILE_NAME);
84 | stringToFile(ERR_TXT, error);
85 |
86 | assertThat(fileToString(toChange), is(TO_CHG_TXT));
87 | assertThat(fileToString(noChange), is(NO_CHG_TXT));
88 | assertThat(fileToString(empty), is(EMPTY_TXT));
89 | assertThat(fileToString(error), is(ERR_TXT));
90 |
91 | log = mock(Log.class);
92 | }
93 |
94 | @Test
95 | void pluginExcludesError() throws MojoExecutionException, MojoFailureException {
96 | final XmlFormatPlugin plugin = new XmlFormatPlugin();
97 | plugin.setLog(log);
98 | when(log.isDebugEnabled()).thenReturn(true);
99 | when(log.isErrorEnabled()).thenReturn(true);
100 |
101 | plugin.setBaseDirectory(proj);
102 | plugin.setExcludes("**/" + ERR_FILE_NAME);
103 | plugin.setIncludes(INCLUDE_ALL_XML);
104 | plugin.setTargetDirectory(target);
105 |
106 | plugin.execute();
107 |
108 | verify(log, never()).isErrorEnabled();
109 | verify(log, atLeastOnce()).isDebugEnabled();
110 | verify(log, atLeastOnce()).debug(anyString());
111 |
112 | assertThat(fileToString(toChange), not(TO_CHG_TXT));
113 | assertThat(fileToString(noChange), is(NO_CHG_TXT));
114 | assertThat(fileToString(error), is(ERR_TXT));
115 | }
116 |
117 | @Test
118 | @SuppressWarnings("PMD.JUnitUseExpected")
119 | void pluginReportsError() throws MojoExecutionException {
120 | final XmlFormatPlugin plugin = new XmlFormatPlugin();
121 | plugin.setLog(log);
122 | when(log.isDebugEnabled()).thenReturn(false);
123 | when(log.isErrorEnabled()).thenReturn(true);
124 |
125 | plugin.setBaseDirectory(proj);
126 | plugin.setExcludes("");
127 | plugin.setIncludes(INCLUDE_ALL_XML);
128 | plugin.setTargetDirectory(target);
129 |
130 | Assertions.assertThrows(MojoFailureException.class, () -> {
131 | plugin.execute();
132 | fail("Should have raised exception when handling error");
133 | });
134 |
135 | verify(log, atLeastOnce()).error(anyString(), any(Throwable.class));
136 | verify(log, atLeastOnce()).isDebugEnabled();
137 | verify(log, never()).debug(anyString());
138 |
139 | assertThat(fileToString(toChange), not(TO_CHG_TXT));
140 | assertThat(fileToString(noChange), is(NO_CHG_TXT));
141 | assertThat(fileToString(error), is(ERR_TXT));
142 | }
143 |
144 | @Test
145 | @SuppressWarnings("PMD.JUnitUseExpected")
146 | void pluginSkipTargetFolder() throws MojoExecutionException, MojoFailureException {
147 | final XmlFormatPlugin plugin = new XmlFormatPlugin();
148 | plugin.setLog(log);
149 |
150 | plugin.setSkipTargetFolder(false);
151 | when(log.isDebugEnabled()).thenReturn(true);
152 | when(log.isErrorEnabled()).thenReturn(true);
153 |
154 | plugin.setBaseDirectory(proj);
155 | plugin.setExcludes("**/" + ERR_FILE_NAME);
156 | plugin.setIncludes(INCLUDE_ALL_XML);
157 | plugin.setTargetDirectory(target);
158 |
159 | plugin.execute();
160 |
161 | assertThat(fileToString(toChange), not(TO_CHG_TXT));
162 | assertThat(fileToString(noChange), not(NO_CHG_TXT));
163 | assertThat(fileToString(error), is(ERR_TXT));
164 | }
165 |
166 | @Test
167 | void pluginSkip() throws MojoExecutionException, MojoFailureException {
168 | final XmlFormatPlugin plugin = new XmlFormatPlugin();
169 | plugin.setLog(log);
170 | plugin.setSkip(true);
171 | when(log.isDebugEnabled()).thenReturn(true);
172 | when(log.isInfoEnabled()).thenReturn(true);
173 | when(log.isErrorEnabled()).thenReturn(true);
174 |
175 | plugin.setBaseDirectory(proj);
176 | plugin.setExcludes("**/" + ERR_FILE_NAME);
177 | plugin.setIncludes(INCLUDE_ALL_XML);
178 | plugin.setTargetDirectory(target);
179 |
180 | plugin.execute();
181 |
182 | verify(log, atLeastOnce()).info("[xml-format] Skipped");
183 |
184 | assertThat(fileToString(toChange), is(TO_CHG_TXT));
185 | }
186 |
187 | private static File newFolder(final File root, final String... subDirs) throws IOException {
188 | final String subFolder = String.join("/", subDirs);
189 | final File result = new File(root, subFolder);
190 | if (!result.mkdirs()) {
191 | throw new IOException("Couldn't create folders " + root);
192 | }
193 | return result;
194 | }
195 | }
196 |
--------------------------------------------------------------------------------
/src/test/java/au/com/acegi/xmlformat/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * XML Format Maven Plugin (https://github.com/acegi/xml-format-maven-plugin)
3 | *
4 | * Copyright 2011-2025 Acegi Technology Pty Limited.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * https://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | /**
19 | * XML Formatter Maven Plugin tests.
20 | */
21 | package au.com.acegi.xmlformat;
22 |
--------------------------------------------------------------------------------
/src/test/resources/invalid.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/test/resources/test1-in.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Coco Puff
4 | 10
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/test/resources/test1-out-kbl.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Coco Puff
5 | 10
6 |
7 |
--------------------------------------------------------------------------------
/src/test/resources/test1-out.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Coco Puff
4 | 10
5 |
6 |
--------------------------------------------------------------------------------
/src/test/resources/test2-in.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | 4.0.0 org.sonatype.oss
6 |
7 |
8 | oss-parent
9 | 9
10 |
11 | au.com.acegi.xmlformat
12 |
13 | xml-format-maven-plugin
14 | 1.0.0
15 |
16 | maven-plugin
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/test/resources/test2-out-kbl.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 4.0.0
5 |
6 | org.sonatype.oss
7 |
8 | oss-parent
9 | 9
10 |
11 | au.com.acegi.xmlformat
12 |
13 | xml-format-maven-plugin
14 | 1.0.0
15 |
16 | maven-plugin
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/test/resources/test2-out.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | org.sonatype.oss
6 | oss-parent
7 | 9
8 |
9 | au.com.acegi.xmlformat
10 | xml-format-maven-plugin
11 | 1.0.0
12 | maven-plugin
13 |
14 |
--------------------------------------------------------------------------------
/src/test/resources/test3-in.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 | Coco Puff
8 | 10
9 |
13 |
14 |
--------------------------------------------------------------------------------
/src/test/resources/test3-out.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 | Coco Puff
8 | 10
9 |
13 |
14 |
--------------------------------------------------------------------------------
/src/test/resources/test4-in.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | 4.0.0 org.sonatype.oss
6 |
7 |
8 | oss-parent
9 | 9
10 |
11 | au.com.acegi.xmlformat
12 |
13 | xml-format-maven-plugin
14 | 1.0.0
15 |
16 | maven-plugin
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/test/resources/test4-out-kbl.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 4.0.0
5 |
6 | org.sonatype.oss
7 |
8 | oss-parent
9 | 9
10 |
11 | au.com.acegi.xmlformat
12 |
13 | xml-format-maven-plugin
14 | 1.0.0
15 |
16 | maven-plugin
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/test/resources/test4-out.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | org.sonatype.oss
6 | oss-parent
7 | 9
8 |
9 | au.com.acegi.xmlformat
10 | xml-format-maven-plugin
11 | 1.0.0
12 | maven-plugin
13 |
14 |
--------------------------------------------------------------------------------
/src/test/resources/test5-in.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | blah
8 | blah
9 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/test/resources/test5-out-kbl.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | blah
5 | blah
6 |
11 |
12 |
--------------------------------------------------------------------------------
/src/test/resources/test5-out.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | blah
4 | blah
5 |
10 |
11 |
--------------------------------------------------------------------------------
/src/test/resources/test6-in.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ${project.build.directory}/reports/json/
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/test/resources/test6-out-kbl.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ${project.build.directory}/reports/json/
5 |
6 |
--------------------------------------------------------------------------------
/src/test/resources/test6-out.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | ${project.build.directory}/reports/json/
4 |
5 |
--------------------------------------------------------------------------------