[ARCHETYPE-637] Fix PomUtils pretty-print issue on Java 9+
As of Java 9, the Transformer class's pretty-print feature doesn't define the actual format. Therefore, whitespace-only nodes will be outputted as well. This has been discussed in this [JDK bug ticket](https://bugs.openjdk.java.net/browse/JDK-8262285?attachmentViewMode=list). Also, [Java 9's release note](https://www.oracle.com/java/technologies/javase/9-notes.html) has explained this in the xml/jaxp section.
If we want our pretty-print method to always generate the same format under various Java versions, we need to provide a stylesheet file.
ref:
https://bugs.openjdk.java.net/browse/JDK-8262285?attachmentViewMode=list
https://www.baeldung.com/java-pretty-print-xml#pretty-printing-xml-with-the-transformer-class
Co-authored-by: Moderne <team@moderne.io>
---
https://issues.apache.org/jira/browse/ARCHETYPE-637
diff --git a/archetype-common/src/main/java/org/apache/maven/archetype/common/util/PomUtils.java b/archetype-common/src/main/java/org/apache/maven/archetype/common/util/PomUtils.java
index caea494..a1b0b6f 100644
--- a/archetype-common/src/main/java/org/apache/maven/archetype/common/util/PomUtils.java
+++ b/archetype-common/src/main/java/org/apache/maven/archetype/common/util/PomUtils.java
@@ -38,6 +38,8 @@
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+import java.io.InputStream;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
@@ -127,14 +129,17 @@
tf.setAttribute( XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "" );
tf.setAttribute( "indent-number", 2 );
- Transformer tr = tf.newTransformer();
- tr.setOutputProperty( OutputKeys.INDENT, "yes" );
- tr.setOutputProperty( OutputKeys.METHOD, "xml" );
- tr.setOutputProperty( OutputKeys.ENCODING, "UTF-8" );
- tr.setOutputProperty( "{http://xml.apache.org/xslt}indent-amount", "2" );
- document.getDomConfig().setParameter( "infoset", Boolean.TRUE );
- document.getDocumentElement().normalize();
- tr.transform( new DOMSource( document ), new StreamResult( fileWriter ) );
+ try ( InputStream xsl = PomUtils.class.getResourceAsStream( "/prettyprint.xsl" ) )
+ {
+ final Transformer tr = tf.newTransformer( new StreamSource( xsl ) );
+ tr.setOutputProperty( OutputKeys.INDENT, "yes" );
+ tr.setOutputProperty( OutputKeys.METHOD, "xml" );
+ tr.setOutputProperty( OutputKeys.ENCODING, "UTF-8" );
+ tr.setOutputProperty( "{http://xml.apache.org/xslt}indent-amount", "2" );
+ document.getDomConfig().setParameter( "infoset", Boolean.TRUE );
+ document.getDocumentElement().normalize();
+ tr.transform( new DOMSource( document ), new StreamResult( fileWriter ) );
+ }
return true;
}
else
diff --git a/archetype-common/src/main/resources/prettyprint.xsl b/archetype-common/src/main/resources/prettyprint.xsl
new file mode 100644
index 0000000..b365960
--- /dev/null
+++ b/archetype-common/src/main/resources/prettyprint.xsl
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <xsl:strip-space elements="*"/>
+ <xsl:output method="xml" encoding="UTF-8"/>
+
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()"/>
+ </xsl:copy>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/archetype-common/src/test/java/org/apache/maven/archetype/common/TestPomManager.java b/archetype-common/src/test/java/org/apache/maven/archetype/common/TestPomManager.java
new file mode 100644
index 0000000..c2fe362
--- /dev/null
+++ b/archetype-common/src/test/java/org/apache/maven/archetype/common/TestPomManager.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.maven.archetype.common;
+
+import java.io.File;
+import java.net.URL;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.io.FileUtils;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestPomManager {
+
+ //ref: https://www.baeldung.com/java-pretty-print-xml
+ //https://bugs.openjdk.java.net/browse/JDK-8262285?attachmentViewMode=list
+ @Test
+ public void testAddModule() throws Exception {
+ PomManager pomManager = new DefaultPomManager();
+
+ URL pom = getClass().getResource("/projects/generate-9/pom.xml.sample");
+ File pomFileSrc = new File(pom.toURI());
+ File pomFile = new File(pomFileSrc.getAbsolutePath() + "-copied.xml");
+ FileUtils.copyFile(pomFileSrc, pomFile);
+ final int moduleNumber = 4;
+ for (int i = 0; i < moduleNumber; i++ ) {
+ pomManager.addModule(pomFile, "test" + i);
+ }
+ String fileText = FileUtils.readFileToString( pomFile, "UTF-8" );
+ Pattern pattern = Pattern.compile("(^[ ]+[\\r\\n]+){"+moduleNumber + "}", Pattern.MULTILINE);
+ Matcher matcher = pattern.matcher(fileText);
+ Assert.assertFalse(matcher.find());
+ }
+
+}