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
