This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git

commit e7eef9d34f15a5da5c36f51fea11dc645875d143
Author: rfscholte <[email protected]>
AuthorDate: Fri Oct 30 12:39:23 2020 +0100

    [MNG-6999] Chained (consumer) XMLFilters can result in "floating" comments
---
 .../aether/ConsumerModelSourceTransformer.java     |  13 +-
 .../aether/ConsumerModelSourceTransformerTest.java |  70 ++++++++++
 .../apache/maven/project/ProjectBuilderTest.java   |  88 +++++-------
 .../test/resources/projects/transform/after.pom    |  83 ++++++++++++
 .../test/resources/projects/transform/before.pom   |  86 ++++++++++++
 .../building/AbstractModelSourceTransformer.java   |  64 +++++----
 .../building/BuildModelSourceTransformer.java      |  11 +-
 .../building/DefaultBuildPomXMLFilterFactory.java  |   6 +-
 .../DefaultInheritanceAssemblerTest.java           |   7 +-
 .../xml/sax/filter/AbstractEventXMLFilter.java     |   6 +-
 .../maven/xml/sax/filter/AbstractSAXFilter.java    |   9 +-
 .../maven/xml/sax/filter/BuildPomXMLFilter.java    |   3 +-
 .../xml/sax/filter/BuildPomXMLFilterFactory.java   |  36 ++---
 .../maven/xml/sax/filter/CiFriendlyXMLFilter.java  |  10 ++
 .../maven/xml/sax/filter/ConsumerPomXMLFilter.java |   8 +-
 .../sax/filter/ConsumerPomXMLFilterFactory.java    |   5 +-
 .../maven/xml/sax/filter/FastForwardFilter.java    |   4 +-
 .../maven/xml/sax/filter/ModulesXMLFilter.java     |   4 +-
 .../xml/sax/filter/RelativePathXMLFilter.java      |   4 +-
 .../apache/maven/xml/sax/ChainedFilterTest.java    | 150 +++++++++++++++++++++
 .../xml/sax/filter/AbstractXMLFilterTests.java     | 116 +++++++++-------
 .../xml/sax/filter/ConsumerPomXMLFilterTest.java   |  23 +++-
 .../maven/xml/sax/filter/ModulesXMLFilterTest.java |  10 +-
 .../maven/xml/sax/filter/ParentXMLFilterTest.java  |   7 +-
 .../sax/filter/ReactorDependencyXMLFilterTest.java |   9 +-
 25 files changed, 647 insertions(+), 185 deletions(-)

diff --git 
a/maven-core/src/main/java/org/apache/maven/internal/aether/ConsumerModelSourceTransformer.java
 
b/maven-core/src/main/java/org/apache/maven/internal/aether/ConsumerModelSourceTransformer.java
index 728c78e..d81571d 100644
--- 
a/maven-core/src/main/java/org/apache/maven/internal/aether/ConsumerModelSourceTransformer.java
+++ 
b/maven-core/src/main/java/org/apache/maven/internal/aether/ConsumerModelSourceTransformer.java
@@ -23,6 +23,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.function.Consumer;
 
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.stream.XMLInputFactory;
@@ -37,18 +38,21 @@ import javax.xml.transform.sax.TransformerHandler;
 import org.apache.maven.model.building.AbstractModelSourceTransformer;
 import org.apache.maven.model.building.DefaultBuildPomXMLFilterFactory;
 import org.apache.maven.model.building.TransformerContext;
-import org.apache.maven.xml.Factories;
 import org.apache.maven.xml.internal.DefaultConsumerPomXMLFilterFactory;
 import org.apache.maven.xml.sax.filter.AbstractSAXFilter;
 import org.xml.sax.SAXException;
+import org.xml.sax.ext.LexicalHandler;
 
 class ConsumerModelSourceTransformer extends AbstractModelSourceTransformer
 {
     @Override
-    protected AbstractSAXFilter getSAXFilter( Path pomFile, TransformerContext 
context )
+    protected AbstractSAXFilter getSAXFilter( Path pomFile, 
+                                              TransformerContext context,
+                                              Consumer<LexicalHandler> 
lexicalHandlerConsumer )
         throws TransformerConfigurationException, SAXException, 
ParserConfigurationException
     {
-        return new DefaultConsumerPomXMLFilterFactory( new 
DefaultBuildPomXMLFilterFactory( context ) ).get( pomFile );
+        return new DefaultConsumerPomXMLFilterFactory( new 
DefaultBuildPomXMLFilterFactory( context,
+                                                                        
lexicalHandlerConsumer ) ).get( pomFile );
     }
     
     /**
@@ -65,8 +69,7 @@ class ConsumerModelSourceTransformer extends 
AbstractModelSourceTransformer
     {
         final TransformerHandler transformerHandler;
         
-        final SAXTransformerFactory transformerFactory =
-                        (SAXTransformerFactory) 
Factories.newTransformerFactory();
+        final SAXTransformerFactory transformerFactory = 
getTransformerFactory();
         
         // Keep same encoding+version
         try ( InputStream input = Files.newInputStream( pomFile ) )
diff --git 
a/maven-core/src/test/java/org/apache/maven/internal/aether/ConsumerModelSourceTransformerTest.java
 
b/maven-core/src/test/java/org/apache/maven/internal/aether/ConsumerModelSourceTransformerTest.java
new file mode 100644
index 0000000..2828610d
--- /dev/null
+++ 
b/maven-core/src/test/java/org/apache/maven/internal/aether/ConsumerModelSourceTransformerTest.java
@@ -0,0 +1,70 @@
+package org.apache.maven.internal.aether;
+
+/*
+ * 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.
+ */
+
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.apache.maven.model.Model;
+import org.apache.maven.model.building.TransformerContext;
+import org.junit.Test;
+import org.xmlunit.assertj.XmlAssert;
+
+public class ConsumerModelSourceTransformerTest
+{
+    private ConsumerModelSourceTransformer transformer = new 
ConsumerModelSourceTransformer();
+
+    @Test
+    public void transform() throws Exception
+    {
+        Path beforePomFile = Paths.get( 
"src/test/resources/projects/transform/before.pom").toAbsolutePath();
+        Path afterPomFile = Paths.get( 
"src/test/resources/projects/transform/after.pom").toAbsolutePath();
+
+        try( InputStream expected = Files.newInputStream( afterPomFile ); 
+             InputStream result = transformer.transform( beforePomFile, new 
NoTransformerContext() ) )
+        {
+            XmlAssert.assertThat( result ).and( expected ).areIdentical();
+        }
+    }
+
+    private static class NoTransformerContext implements TransformerContext
+    {
+        @Override
+        public String getUserProperty( String key )
+        {
+            return null;
+        }
+        
+        @Override
+        public Model getRawModel( String groupId, String artifactId )
+            throws IllegalStateException
+        {
+            return null;
+        }
+        
+        @Override
+        public Model getRawModel( Path p )
+        {
+            return null;
+        }
+    }
+}
diff --git 
a/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java 
b/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java
index bb9e58b..74c19a8 100644
--- a/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java
+++ b/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java
@@ -25,6 +25,7 @@ import static org.hamcrest.Matchers.empty;
 import static org.hamcrest.Matchers.greaterThan;
 import static org.hamcrest.Matchers.hasKey;
 import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThrows;
 
 import java.io.File;
 import java.nio.file.Files;
@@ -91,15 +92,11 @@ public class ProjectBuilderTest
         ProjectBuildingRequest configuration = new 
DefaultProjectBuildingRequest();
         configuration.setRepositorySession( 
mavenSession.getRepositorySession() );
 
-        try
-        {
-            lookup( org.apache.maven.project.ProjectBuilder.class ).build( 
pomFile, configuration );
-            fail();
-        }
-        catch ( ProjectBuildingException e )
-        {
-            // this is expected
-        }
+        ProjectBuildingException e = assertThrows( 
ProjectBuildingException.class,
+                      () -> lookup( 
org.apache.maven.project.ProjectBuilder.class ).build( pomFile, configuration ) 
);
+        assertThat( e.getMessage(),
+                    containsString( "[ERROR] 'dependencies.dependency.version' 
for org.apache.maven.its:a:jar is missing. "
+                        + "@ line 9, column 17" ) );
     }
 
     public void testResolveDependencies()
@@ -115,7 +112,9 @@ public class ProjectBuilderTest
         ProjectBuildingResult result = lookup( 
org.apache.maven.project.ProjectBuilder.class ).build( pomFile, configuration );
         assertEquals( 1, result.getProject().getArtifacts().size() );
         // multi projects build entry point
-        List<ProjectBuildingResult> results = lookup( 
org.apache.maven.project.ProjectBuilder.class ).build( 
Collections.singletonList( pomFile ), false, configuration );
+        List<ProjectBuildingResult> results =
+            lookup( org.apache.maven.project.ProjectBuilder.class ).build( 
Collections.singletonList( pomFile ), false,
+                                                                           
configuration );
         assertEquals( 1, results.size() );
         MavenProject mavenProject = results.get( 0 ).getProject();
         assertEquals( 1, mavenProject.getArtifacts().size() );
@@ -192,32 +191,25 @@ public class ProjectBuilderTest
             lookup( org.apache.maven.project.ProjectBuilder.class );
 
         // single project build entry point
-        try
-        {
-            projectBuilder.build( pomFile, configuration );
-        }
-        catch ( ProjectBuildingException ex )
-        {
-            assertEquals( 1, ex.getResults().size() );
-            MavenProject project = ex.getResults().get( 0 ).getProject();
-            assertNotNull( project );
-            assertEquals( "testArtifactMissingVersion", 
project.getArtifactId() );
-            assertEquals( pomFile, project.getFile() );
-        }
+        ProjectBuildingException ex1 =
+            assertThrows( ProjectBuildingException.class, () -> 
projectBuilder.build( pomFile, configuration ) );
+
+        assertEquals( 1, ex1.getResults().size() );
+        MavenProject project1 = ex1.getResults().get( 0 ).getProject();
+        assertNotNull( project1 );
+        assertEquals( "testArtifactMissingVersion", project1.getArtifactId() );
+        assertEquals( pomFile, project1.getFile() );
 
         // multi projects build entry point
-        try
-        {
-            projectBuilder.build( Collections.singletonList( pomFile ), false, 
configuration );
-        }
-        catch ( ProjectBuildingException ex )
-        {
-            assertEquals( 1, ex.getResults().size() );
-            MavenProject project = ex.getResults().get( 0 ).getProject();
-            assertNotNull( project );
-            assertEquals( "testArtifactMissingVersion", 
project.getArtifactId() );
-            assertEquals( pomFile, project.getFile() );
-        }
+        ProjectBuildingException ex2 =
+            assertThrows( ProjectBuildingException.class,
+                          () -> projectBuilder.build( 
Collections.singletonList( pomFile ), false, configuration ) );
+
+        assertEquals( 1, ex2.getResults().size() );
+        MavenProject project2 = ex2.getResults().get( 0 ).getProject();
+        assertNotNull( project2 );
+        assertEquals( "testArtifactMissingVersion", project2.getArtifactId() );
+        assertEquals( pomFile, project2.getFile() );
     }
 
     public void testReadInvalidPom()
@@ -232,27 +224,17 @@ public class ProjectBuilderTest
             lookup( org.apache.maven.project.ProjectBuilder.class );
 
         // single project build entry point
-        try
-        {
-            projectBuilder.build( pomFile, configuration );
-        }
-        catch ( Exception ex )
-        {
-             assertThat( ex.getMessage(), containsString( "expected START_TAG 
or END_TAG not TEXT" ) );
-        }
+        Exception ex = assertThrows( Exception.class, () -> 
projectBuilder.build( pomFile, configuration ) );
+        assertThat( ex.getMessage(), containsString( "expected START_TAG or 
END_TAG not TEXT" ) );
 
         // multi projects build entry point
-        try
-        {
-            projectBuilder.build( Collections.singletonList( pomFile ), false, 
configuration );
-        }
-        catch ( ProjectBuildingException ex )
-        {
-            assertEquals( 1, ex.getResults().size() );
-            assertNotNull( ex.getResults().get( 0 ).getPomFile() );
-            assertThat( ex.getResults().get( 0 ).getProblems().size(), 
greaterThan( 0 ) );
-            assertThat( ex.getMessage(), containsString( "expected START_TAG 
or END_TAG not TEXT" ) );
-        }
+        ProjectBuildingException pex =
+            assertThrows( ProjectBuildingException.class,
+                          () -> projectBuilder.build( 
Collections.singletonList( pomFile ), false, configuration ) );
+        assertEquals( 1, pex.getResults().size() );
+        assertNotNull( pex.getResults().get( 0 ).getPomFile() );
+        assertThat( pex.getResults().get( 0 ).getProblems().size(), 
greaterThan( 0 ) );
+        assertThat( pex.getMessage(), containsString( "expected START_TAG or 
END_TAG not TEXT" ) );
     }
 
     public void testReadParentAndChildWithRegularVersionSetParentFile()
diff --git a/maven-core/src/test/resources/projects/transform/after.pom 
b/maven-core/src/test/resources/projects/transform/after.pom
new file mode 100644
index 0000000..a66fca8
--- /dev/null
+++ b/maven-core/src/test/resources/projects/transform/after.pom
@@ -0,0 +1,83 @@
+<?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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
https://maven.apache.org/xsd/maven-4.0.0.xsd";>
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>test</groupId>
+  <artifactId>test</artifactId>
+  <version>0.1-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  
+
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>2.1</version>
+          <configuration>
+            <source>  1.5  </source>
+            <target xml:space="preserve">  1.5  </target>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>test</id>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+  <profiles>
+    <profile>
+      <id>default</id>
+      <activation>
+        <activeByDefault>true</activeByDefault>
+      </activation>
+      <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+      </properties>
+    </profile>
+    <profile>
+      <id>file</id>
+      <activation>
+        <file>
+          <exists>simple.xml</exists>
+        </file>
+      </activation>
+      <properties>
+        <profile.file>activated</profile.file>
+      </properties>
+    </profile>
+  </profiles>
+</project>
diff --git a/maven-core/src/test/resources/projects/transform/before.pom 
b/maven-core/src/test/resources/projects/transform/before.pom
new file mode 100644
index 0000000..c6b2bc2
--- /dev/null
+++ b/maven-core/src/test/resources/projects/transform/before.pom
@@ -0,0 +1,86 @@
+<?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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
https://maven.apache.org/xsd/maven-4.0.0.xsd";>
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>test</groupId>
+  <artifactId>test</artifactId>
+  <version>0.1-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <modules>
+    <module>lib</module> <!-- the library -->
+    <module>app</module> <!-- the application -->
+  </modules>
+
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>2.1</version>
+          <configuration>
+            <source>  1.5  </source>
+            <target xml:space="preserve">  1.5  </target>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>test</id>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+  <profiles>
+    <profile>
+      <id>default</id>
+      <activation>
+        <activeByDefault>true</activeByDefault>
+      </activation>
+      <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+      </properties>
+    </profile>
+    <profile>
+      <id>file</id>
+      <activation>
+        <file>
+          <exists>simple.xml</exists>
+        </file>
+      </activation>
+      <properties>
+        <profile.file>activated</profile.file>
+      </properties>
+    </profile>
+  </profiles>
+</project>
diff --git 
a/maven-model-builder/src/main/java/org/apache/maven/model/building/AbstractModelSourceTransformer.java
 
b/maven-model-builder/src/main/java/org/apache/maven/model/building/AbstractModelSourceTransformer.java
index 6f0f5d4..b4e8698 100644
--- 
a/maven-model-builder/src/main/java/org/apache/maven/model/building/AbstractModelSourceTransformer.java
+++ 
b/maven-model-builder/src/main/java/org/apache/maven/model/building/AbstractModelSourceTransformer.java
@@ -19,22 +19,25 @@ package org.apache.maven.model.building;
  * under the License.
  */
 
-import java.io.FileInputStream;
 import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.PipedInputStream;
 import java.io.PipedOutputStream;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
 
 import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Transformer;
 import javax.xml.transform.TransformerConfigurationException;
 import javax.xml.transform.TransformerException;
 import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.sax.SAXResult;
 import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.sax.SAXTransformerFactory;
 import javax.xml.transform.sax.TransformerHandler;
 import javax.xml.transform.stream.StreamResult;
 
@@ -44,6 +47,7 @@ import org.apache.maven.xml.sax.filter.AbstractSAXFilter;
 import org.xml.sax.ErrorHandler;
 import org.xml.sax.SAXException;
 import org.xml.sax.SAXParseException;
+import org.xml.sax.ext.LexicalHandler;
 
 /**
  * Offers a transformation implementation based on PipelineStreams.
@@ -59,7 +63,9 @@ public abstract class AbstractModelSourceTransformer
     
     private final TransformerFactory transformerFactory = 
Factories.newTransformerFactory();
                     
-    protected abstract AbstractSAXFilter getSAXFilter( Path pomFile, 
TransformerContext context )
+    protected abstract AbstractSAXFilter getSAXFilter( Path pomFile, 
+                                                       TransformerContext 
context,
+                                                       
Consumer<LexicalHandler> lexicalHandlerConsumer )
         throws TransformerConfigurationException, SAXException, 
ParserConfigurationException;
 
     protected OutputStream filterOutputStream( OutputStream outputStream, Path 
pomFile )
@@ -67,6 +73,11 @@ public abstract class AbstractModelSourceTransformer
         return outputStream;
     }
     
+    public SAXTransformerFactory getTransformerFactory()
+    {
+        return ( SAXTransformerFactory ) transformerFactory;
+    }
+    
     protected TransformerHandler getTransformerHandler( Path pomFile )
         throws IOException, 
org.apache.maven.model.building.TransformerException
     {
@@ -79,10 +90,29 @@ public abstract class AbstractModelSourceTransformer
     {
         final TransformerHandler transformerHandler = getTransformerHandler( 
pomFile );
 
+        final PipedOutputStream pout = new PipedOutputStream();
+        
+        OutputStream out = filterOutputStream( pout, pomFile );
+
+        final javax.xml.transform.Result result;
+        final Consumer<LexicalHandler> lexConsumer;
+        if ( transformerHandler == null )
+        {
+            result = new StreamResult( out );
+            lexConsumer = null;
+        }
+        else
+        {
+            result = new SAXResult( transformerHandler );
+            lexConsumer = l -> ( (SAXResult) result ).setLexicalHandler( new 
CommentRenormalizer( l ) );
+            transformerHandler.setResult( new StreamResult( out ) );
+        }
+
+        final Transformer transformer;
         final AbstractSAXFilter filter;
         try
         {
-            filter = getSAXFilter( pomFile, context );
+            filter = getSAXFilter( pomFile, context, lexConsumer );
             filter.setLexicalHandler( transformerHandler );
             // By default errors are written to stderr.
             // Hence set custom errorHandler to reduce noice 
@@ -109,6 +139,7 @@ public abstract class AbstractModelSourceTransformer
                     throw exception;
                 }
             } );
+            transformer = transformerFactory.newTransformer();
         }
         catch ( TransformerConfigurationException | SAXException | 
ParserConfigurationException e )
         {
@@ -116,33 +147,16 @@ public abstract class AbstractModelSourceTransformer
         }
         
         final SAXSource transformSource =
-            new SAXSource( filter,
-                           new org.xml.sax.InputSource( new FileInputStream( 
pomFile.toFile() ) ) );
-
-        final PipedOutputStream pout = new PipedOutputStream();
-        final PipedInputStream pipedInputStream = new PipedInputStream( pout );
-        
-        OutputStream out = filterOutputStream( pout, pomFile );
-
-        final javax.xml.transform.Result result; 
-        if ( transformerHandler == null )
-        {
-            result = new StreamResult( out );
-        }
-        else
-        {
-            result = new SAXResult( transformerHandler );
-            ( (SAXResult) result ).setLexicalHandler( new CommentRenormalizer( 
transformerHandler ) );
-            transformerHandler.setResult( new StreamResult( out ) );
-        }
+            new SAXSource( filter, new org.xml.sax.InputSource( 
Files.newInputStream( pomFile ) ) );
 
         IOExceptionHandler eh = new IOExceptionHandler();
 
+        
         Thread transformThread = new Thread( () -> 
         {
             try ( PipedOutputStream pos = pout )
             {
-                transformerFactory.newTransformer().transform( 
transformSource, result );
+                transformer.transform( transformSource, result );
             }
             catch ( TransformerException | IOException e )
             {
@@ -152,8 +166,8 @@ public abstract class AbstractModelSourceTransformer
         transformThread.setUncaughtExceptionHandler( eh );
         transformThread.setDaemon( true );
         transformThread.start();
-
-        return new ThreadAwareInputStream( pipedInputStream, eh );
+        
+        return new ThreadAwareInputStream( new PipedInputStream( pout ), eh );
     }
 
     private static class IOExceptionHandler
diff --git 
a/maven-model-builder/src/main/java/org/apache/maven/model/building/BuildModelSourceTransformer.java
 
b/maven-model-builder/src/main/java/org/apache/maven/model/building/BuildModelSourceTransformer.java
index dbf9211..44d4c26 100644
--- 
a/maven-model-builder/src/main/java/org/apache/maven/model/building/BuildModelSourceTransformer.java
+++ 
b/maven-model-builder/src/main/java/org/apache/maven/model/building/BuildModelSourceTransformer.java
@@ -23,6 +23,7 @@ import java.io.FilterOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.file.Path;
+import java.util.function.Consumer;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -35,6 +36,7 @@ import 
org.apache.maven.xml.sax.filter.BuildPomXMLFilterFactory;
 import org.apache.maven.xml.sax.filter.BuildPomXMLFilterListener;
 import org.eclipse.sisu.Nullable;
 import org.xml.sax.SAXException;
+import org.xml.sax.ext.LexicalHandler;
 
 /**
  * ModelSourceTransformer for the build pom
@@ -50,11 +52,14 @@ class BuildModelSourceTransformer extends 
AbstractModelSourceTransformer
     @Nullable
     private BuildPomXMLFilterListener xmlFilterListener;
     
-    protected AbstractSAXFilter getSAXFilter( Path pomFile, TransformerContext 
context )
+    protected AbstractSAXFilter getSAXFilter( Path pomFile,
+                                              TransformerContext context,
+                                              Consumer<LexicalHandler> 
lexicalHandlerConsumer )
         throws TransformerConfigurationException, SAXException, 
ParserConfigurationException
     {
-        BuildPomXMLFilterFactory buildPomXMLFilterFactory = new 
DefaultBuildPomXMLFilterFactory( context );
-        
+        BuildPomXMLFilterFactory buildPomXMLFilterFactory =
+            new DefaultBuildPomXMLFilterFactory( context, 
lexicalHandlerConsumer );
+
         return buildPomXMLFilterFactory.get( pomFile );
     }
     
diff --git 
a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultBuildPomXMLFilterFactory.java
 
b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultBuildPomXMLFilterFactory.java
index 3de90de..8f9f6ae 100644
--- 
a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultBuildPomXMLFilterFactory.java
+++ 
b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultBuildPomXMLFilterFactory.java
@@ -23,11 +23,13 @@ package org.apache.maven.model.building;
 import java.nio.file.Path;
 import java.util.Optional;
 import java.util.function.BiFunction;
+import java.util.function.Consumer;
 import java.util.function.Function;
 
 import org.apache.maven.model.Model;
 import org.apache.maven.xml.sax.filter.BuildPomXMLFilterFactory;
 import org.apache.maven.xml.sax.filter.RelativeProject;
+import org.xml.sax.ext.LexicalHandler;
 
 /**
  * 
@@ -38,8 +40,10 @@ public class DefaultBuildPomXMLFilterFactory extends 
BuildPomXMLFilterFactory
 {
     private final TransformerContext context;
     
-    public DefaultBuildPomXMLFilterFactory( TransformerContext context )
+    public DefaultBuildPomXMLFilterFactory( TransformerContext context,
+                                            Consumer<LexicalHandler> 
lexicalHandlerConsumer )
     {
+        super( lexicalHandlerConsumer );
         this.context = context;
     }
     
diff --git 
a/maven-model-builder/src/test/java/org/apache/maven/model/inheritance/DefaultInheritanceAssemblerTest.java
 
b/maven-model-builder/src/test/java/org/apache/maven/model/inheritance/DefaultInheritanceAssemblerTest.java
index 9924471..131b762 100644
--- 
a/maven-model-builder/src/test/java/org/apache/maven/model/inheritance/DefaultInheritanceAssemblerTest.java
+++ 
b/maven-model-builder/src/test/java/org/apache/maven/model/inheritance/DefaultInheritanceAssemblerTest.java
@@ -28,6 +28,7 @@ import org.apache.maven.model.io.DefaultModelWriter;
 import org.apache.maven.model.io.ModelWriter;
 import org.apache.maven.xml.sax.filter.AbstractSAXFilter;
 import org.xml.sax.SAXException;
+import org.xml.sax.ext.LexicalHandler;
 import org.xmlunit.matchers.CompareMatcher;
 
 import junit.framework.TestCase;
@@ -35,11 +36,12 @@ import junit.framework.TestCase;
 import java.io.File;
 import java.io.IOException;
 import java.nio.file.Path;
+import java.util.function.Consumer;
 
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.transform.TransformerConfigurationException;
 
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 
 /**
  * @author Hervé Boutemy
@@ -63,7 +65,8 @@ public class DefaultInheritanceAssemblerTest
         reader.setTransformer( new AbstractModelSourceTransformer()
         {
             @Override
-            protected AbstractSAXFilter getSAXFilter( Path pomFile, 
TransformerContext context )
+            protected AbstractSAXFilter getSAXFilter( Path pomFile, 
TransformerContext context,
+                                                      Consumer<LexicalHandler> 
lexicalHandlerConsumer )
                 throws TransformerConfigurationException, SAXException, 
ParserConfigurationException
             {
                 return null;
diff --git 
a/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/AbstractEventXMLFilter.java
 
b/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/AbstractEventXMLFilter.java
index f5246b1..9ef6917 100644
--- 
a/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/AbstractEventXMLFilter.java
+++ 
b/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/AbstractEventXMLFilter.java
@@ -29,8 +29,6 @@ import org.apache.maven.xml.sax.SAXEventFactory;
 import org.xml.sax.Attributes;
 import org.xml.sax.Locator;
 import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.ext.LexicalHandler;
 
 /**
  * Builds up a list of SAXEvents, which will be executed with {@link 
#executeEvents()}
@@ -64,9 +62,9 @@ abstract class AbstractEventXMLFilter extends 
AbstractSAXFilter
         super();
     }
 
-    <T extends XMLReader & LexicalHandler> AbstractEventXMLFilter( T parent )
+    AbstractEventXMLFilter( AbstractSAXFilter parent )
     {
-        setParent( parent );
+        super( parent );
     }
 
     private SAXEventFactory getEventFactory()
diff --git 
a/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/AbstractSAXFilter.java
 
b/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/AbstractSAXFilter.java
index 454ae83..b930f77 100644
--- 
a/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/AbstractSAXFilter.java
+++ 
b/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/AbstractSAXFilter.java
@@ -20,7 +20,6 @@ package org.apache.maven.xml.sax.filter;
  */
 
 import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
 import org.xml.sax.ext.LexicalHandler;
 import org.xml.sax.helpers.XMLFilterImpl;
 
@@ -36,15 +35,15 @@ public class AbstractSAXFilter extends XMLFilterImpl 
implements LexicalHandler
 {
     private LexicalHandler lexicalHandler;
     
-    AbstractSAXFilter()
+    public AbstractSAXFilter()
     {
         super();
     }
 
-    public <T extends XMLReader & LexicalHandler> AbstractSAXFilter( T parent )
+    public AbstractSAXFilter( AbstractSAXFilter parent )
     {
-        setParent( parent );
-        setLexicalHandler( parent );
+        super( parent );
+        parent.setLexicalHandler( this );
     }
     
     public LexicalHandler getLexicalHandler()
diff --git 
a/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/BuildPomXMLFilter.java
 
b/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/BuildPomXMLFilter.java
index 14bcf70..56b30e8 100644
--- 
a/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/BuildPomXMLFilter.java
+++ 
b/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/BuildPomXMLFilter.java
@@ -20,7 +20,6 @@ package org.apache.maven.xml.sax.filter;
  */
 
 import org.xml.sax.XMLReader;
-import org.xml.sax.ext.LexicalHandler;
 
 /**
  * Filter to adjust pom on filesystem before being processed for effective pom.
@@ -39,7 +38,7 @@ public class BuildPomXMLFilter extends AbstractSAXFilter
         super();
     }
 
-    <T extends XMLReader & LexicalHandler> BuildPomXMLFilter( T parent )
+    BuildPomXMLFilter( AbstractSAXFilter parent )
     {
         super( parent );
     }
diff --git 
a/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/BuildPomXMLFilterFactory.java
 
b/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/BuildPomXMLFilterFactory.java
index 6f3f319..23dc240 100644
--- 
a/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/BuildPomXMLFilterFactory.java
+++ 
b/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/BuildPomXMLFilterFactory.java
@@ -22,12 +22,11 @@ package org.apache.maven.xml.sax.filter;
 import java.nio.file.Path;
 import java.util.Optional;
 import java.util.function.BiFunction;
+import java.util.function.Consumer;
 import java.util.function.Function;
 
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.sax.SAXTransformerFactory;
 
 import org.apache.maven.xml.Factories;
 import org.xml.sax.SAXException;
@@ -42,6 +41,18 @@ import org.xml.sax.ext.LexicalHandler;
  */
 public class BuildPomXMLFilterFactory
 {
+    private final Consumer<LexicalHandler> lexicalHandlerConsumer;
+    
+    public BuildPomXMLFilterFactory()
+    {
+        this( null ); 
+    }
+    
+    public BuildPomXMLFilterFactory( Consumer<LexicalHandler> 
lexicalHandlerConsumer )
+    {
+        this.lexicalHandlerConsumer = lexicalHandlerConsumer;
+    }
+
     /**
      * 
      * @param projectFile will be used by ConsumerPomXMLFilter to get the 
right filter
@@ -55,14 +66,17 @@ public class BuildPomXMLFilterFactory
     {
         AbstractSAXFilter parent = new AbstractSAXFilter();
         parent.setParent( getXMLReader() );
-        parent.setLexicalHandler( getLexicalHander() );
+        if ( lexicalHandlerConsumer != null )
+        {
+            lexicalHandlerConsumer.accept( parent );
+        }
 
         if ( getDependencyKeyToVersionMapper() != null )
         {
             ReactorDependencyXMLFilter reactorDependencyXMLFilter =
                 new ReactorDependencyXMLFilter( 
getDependencyKeyToVersionMapper() );
             reactorDependencyXMLFilter.setParent( parent );
-            reactorDependencyXMLFilter.setLexicalHandler( parent );
+            parent.setLexicalHandler( reactorDependencyXMLFilter );
             parent = reactorDependencyXMLFilter;
         }
 
@@ -71,7 +85,7 @@ public class BuildPomXMLFilterFactory
             ParentXMLFilter parentFilter = new ParentXMLFilter( 
getRelativePathMapper() );
             parentFilter.setProjectPath( projectFile.getParent() );
             parentFilter.setParent( parent );
-            parentFilter.setLexicalHandler( parent );
+            parent.setLexicalHandler( parentFilter );
             parent = parentFilter;
         }
 
@@ -85,18 +99,6 @@ public class BuildPomXMLFilterFactory
         return xmlReader;
     }
     
-    private LexicalHandler getLexicalHander() throws 
TransformerConfigurationException 
-    {
-        TransformerFactory transformerFactory = 
Factories.newTransformerFactory();
-        if ( transformerFactory instanceof SAXTransformerFactory )
-        {
-            SAXTransformerFactory saxTransformerFactory = 
(SAXTransformerFactory) transformerFactory;
-            return saxTransformerFactory.newTransformerHandler();
-        }
-        throw new TransformerConfigurationException( "Failed to get 
LexicalHandler via TransformerFactory:"
-            + " it is not an instance of SAXTransformerFactory" );
-    }
-    
     /**
      * @return the mapper or {@code null} if relativePaths don't need to be 
mapped
      */
diff --git 
a/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/CiFriendlyXMLFilter.java
 
b/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/CiFriendlyXMLFilter.java
index 4375f18..9c2da0e 100644
--- 
a/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/CiFriendlyXMLFilter.java
+++ 
b/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/CiFriendlyXMLFilter.java
@@ -39,6 +39,16 @@ class CiFriendlyXMLFilter
     
     private boolean parseVersion;
     
+    CiFriendlyXMLFilter()
+    {
+        super();
+    }
+
+    CiFriendlyXMLFilter( AbstractSAXFilter parent )
+    {
+        super( parent );
+    }
+
     public CiFriendlyXMLFilter setChangelist( String changelist )
     {
         replaceChain = replaceChain.andThen( t -> t.replace( "${changelist}", 
changelist ) );
diff --git 
a/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/ConsumerPomXMLFilter.java
 
b/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/ConsumerPomXMLFilter.java
index 1c227a7..b2a8ec1 100644
--- 
a/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/ConsumerPomXMLFilter.java
+++ 
b/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/ConsumerPomXMLFilter.java
@@ -35,7 +35,7 @@ import org.xml.sax.ext.LexicalHandler;
  */
 public class ConsumerPomXMLFilter extends AbstractSAXFilter
 {
-    <T extends XMLReader & LexicalHandler> ConsumerPomXMLFilter( T filter )
+    ConsumerPomXMLFilter( AbstractSAXFilter filter )
     {
         super( filter );
     }
@@ -51,4 +51,10 @@ public class ConsumerPomXMLFilter extends AbstractSAXFilter
             super.setParent( parent );
         }
     }
+    
+    @Override
+    public LexicalHandler getLexicalHandler()
+    {
+        return ( (AbstractSAXFilter) getParent() ).getLexicalHandler();
+    }
 }
diff --git 
a/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/ConsumerPomXMLFilterFactory.java
 
b/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/ConsumerPomXMLFilterFactory.java
index f7751d2..298a84c 100644
--- 
a/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/ConsumerPomXMLFilterFactory.java
+++ 
b/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/ConsumerPomXMLFilterFactory.java
@@ -46,18 +46,17 @@ public class ConsumerPomXMLFilterFactory
     {
         BuildPomXMLFilter parent = buildPomXMLFilterFactory.get( projectPath );
         
+        
         // Ensure that xs:any elements aren't touched by next filters
         AbstractSAXFilter filter = new FastForwardFilter( parent );
         
-        CiFriendlyXMLFilter ciFriendlyFilter = new CiFriendlyXMLFilter();
+        CiFriendlyXMLFilter ciFriendlyFilter = new CiFriendlyXMLFilter( filter 
);
         getChangelist().ifPresent( ciFriendlyFilter::setChangelist  );
         getRevision().ifPresent( ciFriendlyFilter::setRevision );
         getSha1().ifPresent( ciFriendlyFilter::setSha1 );
         
         if ( ciFriendlyFilter.isSet() )
         {
-            ciFriendlyFilter.setParent( parent );
-            ciFriendlyFilter.setLexicalHandler( parent );
             filter = ciFriendlyFilter;
         }
         
diff --git 
a/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/FastForwardFilter.java
 
b/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/FastForwardFilter.java
index 0100e6b..5c4a363 100644
--- 
a/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/FastForwardFilter.java
+++ 
b/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/FastForwardFilter.java
@@ -26,8 +26,6 @@ import org.xml.sax.Attributes;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.SAXException;
 import org.xml.sax.XMLFilter;
-import org.xml.sax.XMLReader;
-import org.xml.sax.ext.LexicalHandler;
 
 /**
  * This filter will skip all following filters and write directly to the 
output.
@@ -61,7 +59,7 @@ class FastForwardFilter extends AbstractSAXFilter
         super();
     }
 
-    <T extends XMLReader & LexicalHandler> FastForwardFilter( T parent )
+    FastForwardFilter( AbstractSAXFilter parent )
     {
         super( parent );
     }
diff --git 
a/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/ModulesXMLFilter.java 
b/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/ModulesXMLFilter.java
index 261c853..ad1a6c3 100644
--- 
a/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/ModulesXMLFilter.java
+++ 
b/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/ModulesXMLFilter.java
@@ -21,8 +21,6 @@ package org.apache.maven.xml.sax.filter;
 
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.ext.LexicalHandler;
 
 /**
  * Remove all modules, this is just buildtime information
@@ -42,7 +40,7 @@ class ModulesXMLFilter
         super();
     }
 
-    <T extends XMLReader & LexicalHandler> ModulesXMLFilter( T parent )
+    ModulesXMLFilter( AbstractSAXFilter parent )
     {
         super( parent );
     }
diff --git 
a/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/RelativePathXMLFilter.java
 
b/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/RelativePathXMLFilter.java
index 25f2137..573c3f0 100644
--- 
a/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/RelativePathXMLFilter.java
+++ 
b/maven-xml/src/main/java/org/apache/maven/xml/sax/filter/RelativePathXMLFilter.java
@@ -21,8 +21,6 @@ package org.apache.maven.xml.sax.filter;
 
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.ext.LexicalHandler;
 
 /**
  * Remove relativePath element, has no value for consumer pom
@@ -42,7 +40,7 @@ class RelativePathXMLFilter
         super();
     }
 
-    <T extends XMLReader & LexicalHandler> RelativePathXMLFilter( T parent )
+    RelativePathXMLFilter( AbstractSAXFilter parent )
     {
         super( parent );
     }
diff --git 
a/maven-xml/src/test/java/org/apache/maven/xml/sax/ChainedFilterTest.java 
b/maven-xml/src/test/java/org/apache/maven/xml/sax/ChainedFilterTest.java
new file mode 100644
index 0000000..9af2e7c
--- /dev/null
+++ b/maven-xml/src/test/java/org/apache/maven/xml/sax/ChainedFilterTest.java
@@ -0,0 +1,150 @@
+package org.apache.maven.xml.sax;
+
+/*
+ * 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.
+ */
+
+import static org.xmlunit.assertj.XmlAssert.assertThat;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+
+import javax.xml.transform.Transformer;
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TransformerHandler;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.maven.xml.Factories;
+import org.apache.maven.xml.sax.filter.AbstractSAXFilter;
+import org.junit.Test;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * A small example of a pipeline of 2 XML Filters, to understand how to get 
the expected result
+ * 
+ * @author Robert Scholte
+ * @since 3.7.0
+ */
+public class ChainedFilterTest
+{
+
+    @Test
+    public void test()
+        throws Exception
+    {
+        String input = "<project><!-- aBc --><name>dEf</name></project>";
+
+        SAXTransformerFactory transformerFactory = (SAXTransformerFactory) 
Factories.newTransformerFactory();
+        TransformerHandler transformerHandler = 
transformerFactory.newTransformerHandler();
+
+        Writer writer = new StringWriter();
+        StreamResult result = new StreamResult( writer );
+        transformerHandler.setResult( result );
+
+        SAXResult transformResult = new SAXResult( transformerHandler );
+
+        // Watch the order of filters! In reverse order the values would be 
'AweSome'
+        AbstractSAXFilter filter = new Awesome();
+        
+        // AbstractSAXFilter doesn't have a constructor with XMLReader, 
otherwise the LexicalHandler pipeline will be broken
+        filter.setParent( Factories.newXMLReader() );
+        
+        // LexicalHandler of transformerResult must be the first filter
+        transformResult.setLexicalHandler( filter );
+
+        filter = new ChangeCase( filter );
+        // LexicalHandler on last filter must be the transformerHandler
+        filter.setLexicalHandler( transformerHandler );
+
+        SAXSource transformSource = new SAXSource( filter, new InputSource( 
new StringReader( input ) ) );
+
+        Transformer transformer = transformerFactory.newTransformer();
+        transformer.transform( transformSource, transformResult );
+
+        String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+            + "<project><!--AWESOME--><name>awesome</name></project>";
+        assertThat( writer.toString() ).and( expected ).areIdentical();
+    }
+
+    static class ChangeCase
+        extends AbstractSAXFilter
+    {
+
+        public ChangeCase()
+        {
+            super();
+        }
+
+        public ChangeCase( AbstractSAXFilter parent )
+        {
+            super( parent );
+        }
+
+        @Override
+        public void comment( char[] ch, int start, int length )
+            throws SAXException
+        {
+            String s = new String( ch, start, length ).toUpperCase();
+            super.comment( s.toCharArray(), 0, s.length() );
+        }
+
+        @Override
+        public void characters( char[] ch, int start, int length )
+            throws SAXException
+        {
+            String s = new String( ch, start, length ).toLowerCase();
+            super.characters( s.toCharArray(), 0, s.length() );
+        }
+    }
+
+    static class Awesome
+        extends AbstractSAXFilter
+    {
+
+        public Awesome()
+        {
+            super();
+        }
+
+        public Awesome( AbstractSAXFilter parent )
+        {
+            super( parent );
+        }
+
+        @Override
+        public void comment( char[] ch, int start, int length )
+            throws SAXException
+        {
+            String s = "AweSome";
+            super.comment( s.toCharArray(), 0, s.length() );
+        }
+
+        @Override
+        public void characters( char[] ch, int start, int length )
+            throws SAXException
+        {
+            String s = "AweSome";
+            super.characters( s.toCharArray(), 0, s.length() );
+        }
+    }
+
+}
diff --git 
a/maven-xml/src/test/java/org/apache/maven/xml/sax/filter/AbstractXMLFilterTests.java
 
b/maven-xml/src/test/java/org/apache/maven/xml/sax/filter/AbstractXMLFilterTests.java
index f01f268..862cb76 100644
--- 
a/maven-xml/src/test/java/org/apache/maven/xml/sax/filter/AbstractXMLFilterTests.java
+++ 
b/maven-xml/src/test/java/org/apache/maven/xml/sax/filter/AbstractXMLFilterTests.java
@@ -24,6 +24,7 @@ import java.io.StringReader;
 import java.io.StringWriter;
 import java.io.Writer;
 import java.net.ContentHandler;
+import java.util.function.Consumer;
 
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.transform.OutputKeys;
@@ -43,25 +44,14 @@ import org.xml.sax.ext.LexicalHandler;
 
 public abstract class AbstractXMLFilterTests
 {
-    public AbstractXMLFilterTests()
+    protected AbstractSAXFilter getFilter() throws TransformerException, 
SAXException, ParserConfigurationException
     {
-        super();
+        throw new UnsupportedOperationException( "Override one of the 
getFilter() methods" );
     }
     
-    protected abstract AbstractSAXFilter getFilter() throws 
TransformerException, SAXException, ParserConfigurationException;
-    
-    private void setParent( AbstractSAXFilter filter ) throws SAXException, 
ParserConfigurationException
+    protected AbstractSAXFilter getFilter( Consumer<LexicalHandler> result )  
throws TransformerException, SAXException, ParserConfigurationException
     {
-        if( filter.getParent() == null )
-        {
-            XMLReader r = Factories.newXMLReader();
-            
-            AbstractSAXFilter perChar = new PerCharXMLFilter();
-            perChar.setParent( r );
-            
-            filter.setParent( perChar );
-            filter.setFeature( "http://xml.org/sax/features/namespaces";, true 
);
-        }
+        return getFilter();
     }
     
     protected String omitXmlDeclaration() {
@@ -78,33 +68,54 @@ public abstract class AbstractXMLFilterTests
         return transform( new StringReader( input ) );
     }
 
-    protected String transform( Reader input ) throws TransformerException, 
SAXException, ParserConfigurationException
-    {
-        AbstractSAXFilter filter = getFilter();
-        setParent( filter );
-
-        return transform( input, filter );
-    }
-    
+    /**
+     * Use this method only for testing a single filter.
+     * 
+     * @param input
+     * @param filter
+     * @return
+     * @throws TransformerException
+     * @throws SAXException
+     * @throws ParserConfigurationException
+     */
     protected String transform( String input, AbstractSAXFilter filter ) 
         throws TransformerException, SAXException, ParserConfigurationException
     {
         setParent( filter );
+        
+        SAXTransformerFactory transformerFactory = (SAXTransformerFactory) 
Factories.newTransformerFactory();
+        TransformerHandler transformerHandler = 
transformerFactory.newTransformerHandler();
+        
+        transformerHandler.getTransformer().setOutputProperty( 
OutputKeys.OMIT_XML_DECLARATION, omitXmlDeclaration() );
+        if ( indentAmount() != null )
+        {
+            transformerHandler.getTransformer().setOutputProperty( 
OutputKeys.INDENT, "yes" );
+            transformerHandler.getTransformer().setOutputProperty( 
"{http://xml.apache.org/xslt}indent-amount";,
+                                                                   
indentAmount() );
+        }
+        
+        Transformer transformer = transformerFactory.newTransformer();
+        
+        Writer writer = new StringWriter();
+        StreamResult result = new StreamResult( writer );
+        transformerHandler.setResult( result );
 
-        filter = new PerCharXMLFilter( filter );
+        SAXResult transformResult = new SAXResult( transformerHandler );
+        SAXSource transformSource = new SAXSource( filter, new InputSource( 
new StringReader( input ) ) );
+        
+        transformResult.setLexicalHandler( filter );
+        transformer.transform( transformSource, transformResult );
+
+        return writer.toString();
 
-        return transform( new StringReader( input ), filter );
     }
 
-    protected String transform( Reader input, AbstractSAXFilter filter )
+    protected String transform( Reader input )
         throws TransformerException, SAXException, ParserConfigurationException
     {
-        Writer writer = new StringWriter();
-        StreamResult result = new StreamResult( writer );
-
         SAXTransformerFactory transformerFactory = (SAXTransformerFactory) 
Factories.newTransformerFactory();
         TransformerHandler transformerHandler = 
transformerFactory.newTransformerHandler();
-        filter.setLexicalHandler( transformerHandler );
+        
         transformerHandler.getTransformer().setOutputProperty( 
OutputKeys.OMIT_XML_DECLARATION, omitXmlDeclaration() );
         if ( indentAmount() != null )
         {
@@ -112,18 +123,43 @@ public abstract class AbstractXMLFilterTests
             transformerHandler.getTransformer().setOutputProperty( 
"{http://xml.apache.org/xslt}indent-amount";,
                                                                    
indentAmount() );
         }
-        transformerHandler.setResult( result );
-        Transformer transformer = transformerFactory.newTransformer();
         
-        SAXSource transformSource = new SAXSource( filter, new InputSource( 
input ) );
+        Transformer transformer = transformerFactory.newTransformer();
+
+        Writer writer = new StringWriter();
+        StreamResult result = new StreamResult( writer );
+        transformerHandler.setResult( result );
 
         SAXResult transformResult = new SAXResult( transformerHandler );
-        transformResult.setLexicalHandler( filter );
+        
+        AbstractSAXFilter filter = getFilter( l -> 
transformResult.setLexicalHandler( l ) );
+        setParent( filter );
+        
+        filter = new PerCharXMLFilter( filter );
+
+        filter.setLexicalHandler( transformerHandler );
+        
+        SAXSource transformSource = new SAXSource( filter, new InputSource( 
input ) );
+        
         transformer.transform( transformSource, transformResult );
 
         return writer.toString();
     }
     
+    private void setParent( AbstractSAXFilter filter ) throws SAXException, 
ParserConfigurationException
+    {
+        if( filter.getParent() == null )
+        {
+            XMLReader r = Factories.newXMLReader();
+            
+            AbstractSAXFilter perChar = new PerCharXMLFilter();
+            perChar.setParent( r );
+            
+            filter.setParent( perChar );
+            filter.setFeature( "http://xml.org/sax/features/namespaces";, true 
);
+        }
+    }
+
     /**
      * From {@link ContentHandler}
      * <q>Your code should not assume that algorithms using char-at-a-time 
idioms will be working in characterunits; 
@@ -141,7 +177,7 @@ public abstract class AbstractXMLFilterTests
             super();
         }
         
-        public <T extends XMLReader & LexicalHandler> PerCharXMLFilter( T 
parent )
+        public PerCharXMLFilter( AbstractSAXFilter parent )
         {
             super( parent );
         }
@@ -157,16 +193,6 @@ public abstract class AbstractXMLFilterTests
         }
         
         @Override
-        public void comment( char[] ch, int start, int length )
-            throws SAXException
-        {
-            for ( int i = 0; i < length; i++ )
-            {
-                super.comment( ch, start + i, 1 );
-            }
-        }
-        
-        @Override
         public void ignorableWhitespace( char[] ch, int start, int length )
             throws SAXException
         {
diff --git 
a/maven-xml/src/test/java/org/apache/maven/xml/sax/filter/ConsumerPomXMLFilterTest.java
 
b/maven-xml/src/test/java/org/apache/maven/xml/sax/filter/ConsumerPomXMLFilterTest.java
index 16d458b..c5cfc18 100644
--- 
a/maven-xml/src/test/java/org/apache/maven/xml/sax/filter/ConsumerPomXMLFilterTest.java
+++ 
b/maven-xml/src/test/java/org/apache/maven/xml/sax/filter/ConsumerPomXMLFilterTest.java
@@ -25,6 +25,7 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Optional;
 import java.util.function.BiFunction;
+import java.util.function.Consumer;
 import java.util.function.Function;
 
 import javax.xml.parsers.ParserConfigurationException;
@@ -32,6 +33,7 @@ import javax.xml.transform.TransformerConfigurationException;
 
 import org.junit.Test;
 import org.xml.sax.SAXException;
+import org.xml.sax.ext.LexicalHandler;
 
 public class ConsumerPomXMLFilterTest extends AbstractXMLFilterTests
 {
@@ -42,9 +44,10 @@ public class ConsumerPomXMLFilterTest extends 
AbstractXMLFilterTests
     }
     
     @Override
-    protected AbstractSAXFilter getFilter() throws SAXException, 
ParserConfigurationException, TransformerConfigurationException
+    protected AbstractSAXFilter getFilter( Consumer<LexicalHandler> 
lexicalHandlerConsumer )
+        throws SAXException, ParserConfigurationException, 
TransformerConfigurationException
     {
-        final BuildPomXMLFilterFactory buildPomXMLFilterFactory = new 
BuildPomXMLFilterFactory()
+        final BuildPomXMLFilterFactory buildPomXMLFilterFactory = new 
BuildPomXMLFilterFactory( lexicalHandlerConsumer )
         {
             @Override
             protected Function<Path, Optional<RelativeProject>> 
getRelativePathMapper()
@@ -231,5 +234,21 @@ public class ConsumerPomXMLFilterTest extends 
AbstractXMLFilterTests
         String actual = transform( input );
         assertThat( actual ).and( expected ).areIdentical();
     }
+    
+    @Test
+    public void lexicalHandler() throws Exception
+    {
+        String input = "<project><!--before--><modules>"
+                        + "<!--pre-in-->"
+                        + "<module><!--in-->ab</module>"
+                        + "<module>../cd</module>"
+                        + "<!--post-in-->"
+                        + "</modules>"
+                        + "<!--after--></project>";
+        String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + 
+                        "<project><!--before--><!--after--></project>";
+        String actual = transform( input );
+        assertThat( actual ).and( expected ).areIdentical();
+    }
 
 }
diff --git 
a/maven-xml/src/test/java/org/apache/maven/xml/sax/filter/ModulesXMLFilterTest.java
 
b/maven-xml/src/test/java/org/apache/maven/xml/sax/filter/ModulesXMLFilterTest.java
index 552b721..103794c 100644
--- 
a/maven-xml/src/test/java/org/apache/maven/xml/sax/filter/ModulesXMLFilterTest.java
+++ 
b/maven-xml/src/test/java/org/apache/maven/xml/sax/filter/ModulesXMLFilterTest.java
@@ -21,15 +21,19 @@ package org.apache.maven.xml.sax.filter;
 
 import static org.xmlunit.assertj.XmlAssert.assertThat;
 
-import org.apache.maven.xml.sax.filter.ModulesXMLFilter;
+import java.util.function.Consumer;
+
 import org.junit.Test;
+import org.xml.sax.ext.LexicalHandler;
 
 public class ModulesXMLFilterTest extends AbstractXMLFilterTests {
 
        @Override
-       protected ModulesXMLFilter getFilter()
+       protected ModulesXMLFilter getFilter( Consumer<LexicalHandler> 
lexicalHandlerConsumer )
        {
-           return new ModulesXMLFilter();
+           ModulesXMLFilter filter = new ModulesXMLFilter();
+           lexicalHandlerConsumer.accept( filter );
+           return filter;
        }
        
        @Test
diff --git 
a/maven-xml/src/test/java/org/apache/maven/xml/sax/filter/ParentXMLFilterTest.java
 
b/maven-xml/src/test/java/org/apache/maven/xml/sax/filter/ParentXMLFilterTest.java
index bb00222..eee0359 100644
--- 
a/maven-xml/src/test/java/org/apache/maven/xml/sax/filter/ParentXMLFilterTest.java
+++ 
b/maven-xml/src/test/java/org/apache/maven/xml/sax/filter/ParentXMLFilterTest.java
@@ -23,25 +23,26 @@ import static org.junit.Assert.assertEquals;
 
 import java.nio.file.Paths;
 import java.util.Optional;
+import java.util.function.Consumer;
 
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.transform.TransformerException;
 
-import org.apache.maven.xml.sax.filter.ParentXMLFilter;
-import org.apache.maven.xml.sax.filter.RelativeProject;
 import org.junit.Test;
 import org.xml.sax.SAXException;
+import org.xml.sax.ext.LexicalHandler;
 
 public class ParentXMLFilterTest extends AbstractXMLFilterTests
 {
     @Override
-    protected ParentXMLFilter getFilter()
+    protected ParentXMLFilter getFilter( Consumer<LexicalHandler> 
lexicalHandlerConsumer )
         throws TransformerException, SAXException, ParserConfigurationException
     {
         ParentXMLFilter filter = new ParentXMLFilter( x -> Optional.of( new 
RelativeProject( "GROUPID", 
                                                                                
            "ARTIFACTID",
                                                                                
            "1.0.0" ) ) );
         filter.setProjectPath( Paths.get( "pom.xml").toAbsolutePath() );
+        lexicalHandlerConsumer.accept( filter );
         
         return filter;
     }
diff --git 
a/maven-xml/src/test/java/org/apache/maven/xml/sax/filter/ReactorDependencyXMLFilterTest.java
 
b/maven-xml/src/test/java/org/apache/maven/xml/sax/filter/ReactorDependencyXMLFilterTest.java
index db6606c..49f7354 100644
--- 
a/maven-xml/src/test/java/org/apache/maven/xml/sax/filter/ReactorDependencyXMLFilterTest.java
+++ 
b/maven-xml/src/test/java/org/apache/maven/xml/sax/filter/ReactorDependencyXMLFilterTest.java
@@ -20,19 +20,24 @@ package org.apache.maven.xml.sax.filter;
  */
 import static org.xmlunit.assertj.XmlAssert.assertThat;
 
+import java.util.function.Consumer;
+
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.transform.TransformerException;
 
 import org.junit.Test;
 import org.xml.sax.SAXException;
+import org.xml.sax.ext.LexicalHandler;
 
 public class ReactorDependencyXMLFilterTest extends AbstractXMLFilterTests
 {
     @Override
-    protected ReactorDependencyXMLFilter getFilter()
+    protected ReactorDependencyXMLFilter getFilter( Consumer<LexicalHandler> 
lexicalHandlerConsumer )
         throws TransformerException, SAXException, ParserConfigurationException
     {
-        return new ReactorDependencyXMLFilter( (g, a) -> "1.0.0" );
+        ReactorDependencyXMLFilter filter = new ReactorDependencyXMLFilter( 
(g, a) -> "1.0.0" );
+        lexicalHandlerConsumer.accept( filter );
+        return filter;
     }
 
     @Test

Reply via email to