mirror of https://github.com/apache/maven.git
[MNG-6946] Build/consumer incorrectly transforms name of artifactId
This commit is contained in:
parent
a945ca4ed3
commit
76427d2320
|
@ -21,14 +21,13 @@ package org.apache.maven.xml;
|
|||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXNotRecognizedException;
|
||||
import org.xml.sax.SAXNotSupportedException;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.XMLReaderFactory;
|
||||
|
||||
/**
|
||||
* Creates XML related factories with OWASP advices applied
|
||||
|
@ -56,46 +55,9 @@ public final class Factories
|
|||
return tf;
|
||||
}
|
||||
|
||||
public static SAXParserFactory newSAXParserFactory()
|
||||
{
|
||||
SAXParserFactory spf = SAXParserFactory.newInstance();
|
||||
|
||||
try
|
||||
{
|
||||
// Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-general-entities
|
||||
// Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-general-entities
|
||||
|
||||
// Using the SAXParserFactory's setFeature
|
||||
spf.setFeature( "http://xml.org/sax/features/external-general-entities", false );
|
||||
|
||||
// Xerces 2 only - http://xerces.apache.org/xerces-j/features.html#external-general-entities
|
||||
spf.setFeature( "http://apache.org/xml/features/disallow-doctype-decl", true );
|
||||
}
|
||||
catch ( ParserConfigurationException e )
|
||||
{
|
||||
// Tried an unsupported feature.
|
||||
}
|
||||
catch ( SAXNotRecognizedException e )
|
||||
{
|
||||
// Tried an unknown feature.
|
||||
}
|
||||
catch ( SAXNotSupportedException e )
|
||||
{
|
||||
// Tried a feature known to the parser but unsupported.
|
||||
}
|
||||
return spf;
|
||||
}
|
||||
|
||||
public static SAXParser newSAXParser() throws ParserConfigurationException, SAXException
|
||||
{
|
||||
SAXParser saxParser = newSAXParserFactory().newSAXParser();
|
||||
|
||||
return saxParser;
|
||||
}
|
||||
|
||||
public static XMLReader newXMLReader() throws SAXException, ParserConfigurationException
|
||||
{
|
||||
XMLReader reader = newSAXParser().getXMLReader();
|
||||
XMLReader reader = XMLReaderFactory.createXMLReader();
|
||||
|
||||
try
|
||||
{
|
||||
|
|
|
@ -20,6 +20,8 @@ package org.apache.maven.xml.sax.filter;
|
|||
*/
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
|
||||
import org.apache.maven.xml.sax.SAXEvent;
|
||||
|
@ -44,7 +46,7 @@ abstract class AbstractEventXMLFilter extends AbstractSAXFilter
|
|||
|
||||
// characters BEFORE startElement must get state of startingElement
|
||||
// this way removing based on state keeps correct formatting
|
||||
private SAXEvent characters;
|
||||
private List<SAXEvent> charactersSegments = new ArrayList<>();
|
||||
|
||||
private boolean lockCharacters = false;
|
||||
|
||||
|
@ -82,18 +84,20 @@ abstract class AbstractEventXMLFilter extends AbstractSAXFilter
|
|||
if ( isParsing() )
|
||||
{
|
||||
final String eventState = getState();
|
||||
final SAXEvent charactersEvent = characters;
|
||||
|
||||
if ( !lockCharacters && charactersEvent != null )
|
||||
if ( !lockCharacters )
|
||||
{
|
||||
saxEvents.add( () ->
|
||||
charactersSegments.stream().forEach( e ->
|
||||
{
|
||||
if ( acceptEvent( eventState ) )
|
||||
saxEvents.add( () ->
|
||||
{
|
||||
charactersEvent.execute();
|
||||
}
|
||||
if ( acceptEvent( eventState ) )
|
||||
{
|
||||
e.execute();
|
||||
}
|
||||
} );
|
||||
} );
|
||||
characters = null;
|
||||
charactersSegments.clear();
|
||||
}
|
||||
|
||||
saxEvents.add( () ->
|
||||
|
@ -126,18 +130,17 @@ abstract class AbstractEventXMLFilter extends AbstractSAXFilter
|
|||
protected final void executeEvents() throws SAXException
|
||||
{
|
||||
final String eventState = getState();
|
||||
final SAXEvent charactersEvent = characters;
|
||||
if ( charactersEvent != null )
|
||||
charactersSegments.stream().forEach( e ->
|
||||
{
|
||||
saxEvents.add( () ->
|
||||
{
|
||||
if ( acceptEvent( eventState ) )
|
||||
{
|
||||
charactersEvent.execute();
|
||||
e.execute();
|
||||
}
|
||||
} );
|
||||
characters = null;
|
||||
}
|
||||
} );
|
||||
charactersSegments.clear();
|
||||
|
||||
// not with streams due to checked SAXException
|
||||
while ( !saxEvents.isEmpty() )
|
||||
|
@ -204,7 +207,7 @@ abstract class AbstractEventXMLFilter extends AbstractSAXFilter
|
|||
}
|
||||
else if ( isParsing() )
|
||||
{
|
||||
this.characters = getEventFactory().characters( ch, start, length );
|
||||
this.charactersSegments.add( getEventFactory().characters( ch, start, length ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -126,5 +126,19 @@ public class AbstractSAXFilter extends XMLFilterImpl implements LexicalHandler
|
|||
lexicalHandler.comment( ch, start, length );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected static String nullSafeAppend( String originalValue, String charSegment )
|
||||
{
|
||||
if ( originalValue == null )
|
||||
{
|
||||
return charSegment;
|
||||
}
|
||||
else
|
||||
{
|
||||
return originalValue + charSegment;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -21,10 +21,11 @@ package org.apache.maven.xml.sax.filter;
|
|||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Resolves all ci-friendly properties occurrences
|
||||
* Resolves all ci-friendly properties occurrences between version-tags
|
||||
*
|
||||
* @author Robert Scholte
|
||||
* @since 3.7.0
|
||||
|
@ -34,6 +35,10 @@ class CiFriendlyXMLFilter
|
|||
{
|
||||
private Function<String, String> replaceChain = Function.identity();
|
||||
|
||||
private String characters;
|
||||
|
||||
private boolean parseVersion;
|
||||
|
||||
public CiFriendlyXMLFilter setChangelist( String changelist )
|
||||
{
|
||||
replaceChain = replaceChain.andThen( t -> t.replace( "${changelist}", changelist ) );
|
||||
|
@ -64,20 +69,49 @@ class CiFriendlyXMLFilter
|
|||
public void characters( char[] ch, int start, int length )
|
||||
throws SAXException
|
||||
{
|
||||
String text = new String( ch, start, length );
|
||||
|
||||
// assuming this has the best performance
|
||||
if ( text.contains( "${" ) )
|
||||
if ( parseVersion )
|
||||
{
|
||||
String newText = replaceChain.apply( text );
|
||||
|
||||
super.characters( newText.toCharArray(), 0, newText.length() );
|
||||
this.characters = nullSafeAppend( characters, new String( ch, start, length ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
super.characters( ch, start, length );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startElement( String uri, String localName, String qName, Attributes atts )
|
||||
throws SAXException
|
||||
{
|
||||
if ( !parseVersion && "version".equals( localName ) )
|
||||
{
|
||||
parseVersion = true;
|
||||
}
|
||||
|
||||
super.startElement( uri, localName, qName, atts );
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void endElement( String uri, String localName, String qName )
|
||||
throws SAXException
|
||||
{
|
||||
if ( parseVersion )
|
||||
{
|
||||
// assuming this has the best performance
|
||||
if ( characters != null && characters.contains( "${" ) )
|
||||
{
|
||||
char[] ch = replaceChain.apply( characters ).toCharArray();
|
||||
super.characters( ch, 0, ch.length );
|
||||
}
|
||||
else
|
||||
{
|
||||
char[] ch = characters.toCharArray();
|
||||
super.characters( ch, 0, ch.length );
|
||||
}
|
||||
characters = null;
|
||||
parseVersion = false;
|
||||
}
|
||||
|
||||
super.endElement( uri, localName, qName );
|
||||
}
|
||||
}
|
|
@ -120,19 +120,21 @@ class ParentXMLFilter
|
|||
{
|
||||
final String eventState = state;
|
||||
|
||||
final String charSegment = new String( ch, start, length );
|
||||
|
||||
switch ( eventState )
|
||||
{
|
||||
case "parent":
|
||||
parentWhitespace = new String( ch, start, length );
|
||||
parentWhitespace = nullSafeAppend( parentWhitespace, charSegment );
|
||||
break;
|
||||
case "relativePath":
|
||||
relativePath = new String( ch, start, length );
|
||||
relativePath = nullSafeAppend( relativePath, charSegment );
|
||||
break;
|
||||
case "groupId":
|
||||
groupId = new String( ch, start, length );
|
||||
groupId = nullSafeAppend( groupId, charSegment );
|
||||
break;
|
||||
case "artifactId":
|
||||
artifactId = new String( ch, start, length );
|
||||
artifactId = nullSafeAppend( artifactId, charSegment );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -39,7 +39,7 @@ public class ReactorDependencyXMLFilter extends AbstractEventXMLFilter
|
|||
private String state;
|
||||
|
||||
// whiteSpace after <dependency>, to be used to position <version>
|
||||
private String dependencyWhitespace = "";
|
||||
private String dependencyWhitespace;
|
||||
|
||||
private boolean hasVersion;
|
||||
|
||||
|
@ -79,16 +79,17 @@ public class ReactorDependencyXMLFilter extends AbstractEventXMLFilter
|
|||
if ( parsingDependency )
|
||||
{
|
||||
final String eventState = state;
|
||||
String value = new String( ch, start, length );
|
||||
switch ( eventState )
|
||||
{
|
||||
case "dependency":
|
||||
dependencyWhitespace = new String( ch, start, length );
|
||||
dependencyWhitespace = nullSafeAppend( dependencyWhitespace, value );
|
||||
break;
|
||||
case "groupId":
|
||||
groupId = new String( ch, start, length );
|
||||
groupId = nullSafeAppend( groupId, value );
|
||||
break;
|
||||
case "artifactId":
|
||||
artifactId = new String( ch, start, length );
|
||||
artifactId = nullSafeAppend( artifactId, value );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -115,8 +116,12 @@ public class ReactorDependencyXMLFilter extends AbstractEventXMLFilter
|
|||
{
|
||||
try ( Includer i = super.include() )
|
||||
{
|
||||
super.characters( dependencyWhitespace.toCharArray(), 0,
|
||||
dependencyWhitespace.length() );
|
||||
if ( dependencyWhitespace != null )
|
||||
{
|
||||
super.characters( dependencyWhitespace.toCharArray(), 0,
|
||||
dependencyWhitespace.length() );
|
||||
|
||||
}
|
||||
String versionQName = SAXEventUtils.renameQName( qName, "version" );
|
||||
|
||||
super.startElement( uri, "version", versionQName, null );
|
||||
|
@ -131,6 +136,7 @@ public class ReactorDependencyXMLFilter extends AbstractEventXMLFilter
|
|||
|
||||
// reset
|
||||
hasVersion = false;
|
||||
dependencyWhitespace = null;
|
||||
groupId = null;
|
||||
artifactId = null;
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.io.Reader;
|
|||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.net.ContentHandler;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.OutputKeys;
|
||||
|
@ -35,10 +36,10 @@ 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.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.ext.LexicalHandler;
|
||||
|
||||
public abstract class AbstractXMLFilterTests
|
||||
{
|
||||
|
@ -55,7 +56,10 @@ public abstract class AbstractXMLFilterTests
|
|||
{
|
||||
XMLReader r = Factories.newXMLReader();
|
||||
|
||||
filter.setParent( r );
|
||||
AbstractSAXFilter perChar = new PerCharXMLFilter();
|
||||
perChar.setParent( r );
|
||||
|
||||
filter.setParent( perChar );
|
||||
filter.setFeature( "http://xml.org/sax/features/namespaces", true );
|
||||
}
|
||||
}
|
||||
|
@ -86,6 +90,9 @@ public abstract class AbstractXMLFilterTests
|
|||
throws TransformerException, SAXException, ParserConfigurationException
|
||||
{
|
||||
setParent( filter );
|
||||
|
||||
filter = new PerCharXMLFilter( filter );
|
||||
|
||||
return transform( new StringReader( input ), filter );
|
||||
}
|
||||
|
||||
|
@ -107,7 +114,7 @@ public abstract class AbstractXMLFilterTests
|
|||
}
|
||||
transformerHandler.setResult( result );
|
||||
Transformer transformer = transformerFactory.newTransformer();
|
||||
|
||||
|
||||
SAXSource transformSource = new SAXSource( filter, new InputSource( input ) );
|
||||
|
||||
SAXResult transformResult = new SAXResult( transformerHandler );
|
||||
|
@ -116,4 +123,57 @@ public abstract class AbstractXMLFilterTests
|
|||
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* From {@link ContentHandler}
|
||||
* <q>Your code should not assume that algorithms using char-at-a-time idioms will be working in characterunits;
|
||||
* in some cases they will split characters. This is relevant wherever XML permits arbitrary characters, such as
|
||||
* attribute values,processing instruction data, and comments as well as in data reported from this method. It's
|
||||
* also generally relevant whenever Java code manipulates internationalized text; the issue isn't unique to XML.</q>
|
||||
*
|
||||
* @author Robert Scholte
|
||||
*/
|
||||
class PerCharXMLFilter
|
||||
extends AbstractSAXFilter
|
||||
{
|
||||
public PerCharXMLFilter()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public <T extends XMLReader & LexicalHandler> PerCharXMLFilter( T parent )
|
||||
{
|
||||
super( parent );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void characters( char[] ch, int start, int length )
|
||||
throws SAXException
|
||||
{
|
||||
for ( int i = 0; i < length; i++ )
|
||||
{
|
||||
super.characters( ch, start + i, 1 );
|
||||
}
|
||||
}
|
||||
|
||||
@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
|
||||
{
|
||||
for ( int i = 0; i < length; i++ )
|
||||
{
|
||||
super.ignorableWhitespace( ch, start + i, 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package org.apache.maven.xml.sax.filter;
|
||||
|
||||
/*
|
||||
* 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.junit.Assert.assertEquals;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
public class CiFriendlyXMLFilterTest extends AbstractXMLFilterTests
|
||||
{
|
||||
private CiFriendlyXMLFilter filter;
|
||||
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
filter = new CiFriendlyXMLFilter();
|
||||
filter.setChangelist( "CHANGELIST" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractSAXFilter getFilter()
|
||||
throws TransformerException, SAXException, ParserConfigurationException
|
||||
{
|
||||
return filter;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void changelist() throws Exception
|
||||
{
|
||||
String input = "<project>"
|
||||
+ " <groupId>GROUPID</groupId>"
|
||||
+ " <artifactId>ARTIFACTID</artifactId>"
|
||||
+ "<version>${changelist}</version>"
|
||||
+ "</project>";
|
||||
String expected = "<project>"
|
||||
+ " <groupId>GROUPID</groupId>"
|
||||
+ " <artifactId>ARTIFACTID</artifactId>"
|
||||
+ "<version>CHANGELIST</version>"
|
||||
+ "</project>";
|
||||
|
||||
String actual = transform( input );
|
||||
|
||||
assertEquals( expected, actual );
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue