You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by rf...@apache.org on 2019/08/26 14:35:16 UTC
[maven] branch MNG-6656 updated: [MNG-6656] Support versionless
parent
This is an automated email from the ASF dual-hosted git repository.
rfscholte pushed a commit to branch MNG-6656
in repository https://gitbox.apache.org/repos/asf/maven.git
The following commit(s) were added to refs/heads/MNG-6656 by this push:
new a684370 [MNG-6656] Support versionless parent
a684370 is described below
commit a6843705d184bcf7267df1e6ae421cb257bd5093
Author: rfscholte <rf...@apache.org>
AuthorDate: Mon Aug 26 16:35:08 2019 +0200
[MNG-6656] Support versionless parent
---
.../DefaultRepositorySystemSessionFactory.java | 8 +-
.../internal/DefaultBuildPomXMLFilterFactory.java | 34 ++-
.../maven/model/building/DefaultModelBuilder.java | 23 +-
.../model/building/DefaultModelCacheManager.java | 38 +--
.../maven/model/building/ModelCacheManager.java | 38 +++
.../org/apache/maven/model/building/ModelData.java | 23 +-
.../model/validation/DefaultModelValidator.java | 8 +-
.../maven/xml/filter/BuildPomXMLFilterFactory.java | 35 ++-
.../xml/filter/ConsumerPomXMLFilterFactory.java | 6 +-
.../apache/maven/xml/filter/ParentXMLFilter.java | 313 +++++++++++++++++++++
.../apache/maven/xml/filter/RelativeProject.java | 56 ++++
.../maven/xml/filter/AbstractXMLFilterTests.java | 30 +-
.../maven/xml/filter/ConsumerPomXMLFilterTest.java | 11 +-
.../maven/xml/filter/ParentXMLFilterTest.java | 185 ++++++++++++
pom.xml | 27 +-
15 files changed, 752 insertions(+), 83 deletions(-)
diff --git a/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java b/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java
index 20bd449..e4f8439 100644
--- a/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java
+++ b/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java
@@ -34,6 +34,7 @@ import java.util.Properties;
import javax.inject.Inject;
import javax.inject.Named;
+import javax.inject.Provider;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
@@ -114,7 +115,8 @@ public class DefaultRepositorySystemSessionFactory
MavenRepositorySystem mavenRepositorySystem;
@Inject
- private ConsumerPomXMLFilterFactory consumerPomXMLFilterFactory;
+ @Nullable
+ private Provider<ConsumerPomXMLFilterFactory> consumerPomXMLFilterFactory;
public DefaultRepositorySystemSession newRepositorySession( MavenExecutionRequest request )
{
@@ -286,7 +288,6 @@ public class DefaultRepositorySystemSessionFactory
public InputStream transformData( File file )
throws IOException, TransformException
{
- System.out.println( "transforming " + file.getAbsolutePath() );
final PipedOutputStream pipedOutputStream = new PipedOutputStream();
final PipedInputStream pipedInputStream = new PipedInputStream( pipedOutputStream );
@@ -294,8 +295,7 @@ public class DefaultRepositorySystemSessionFactory
try
{
transformSource =
- new SAXSource( consumerPomXMLFilterFactory.get( artifact.getGroupId(),
- artifact.getArtifactId() ),
+ new SAXSource( consumerPomXMLFilterFactory.get().get( file.toPath() ),
new InputSource( new FileReader( file ) ) );
}
catch ( SAXException | ParserConfigurationException e )
diff --git a/maven-core/src/main/java/org/apache/maven/xml/internal/DefaultBuildPomXMLFilterFactory.java b/maven-core/src/main/java/org/apache/maven/xml/internal/DefaultBuildPomXMLFilterFactory.java
index 0b51da2..cdded2b 100644
--- a/maven-core/src/main/java/org/apache/maven/xml/internal/DefaultBuildPomXMLFilterFactory.java
+++ b/maven-core/src/main/java/org/apache/maven/xml/internal/DefaultBuildPomXMLFilterFactory.java
@@ -19,16 +19,20 @@ package org.apache.maven.xml.internal;
* under the License.
*/
+
+import java.nio.file.Path;
import java.util.Optional;
+import java.util.function.Function;
import javax.inject.Inject;
import javax.inject.Named;
-//import javax.inject.Provider;
import javax.inject.Singleton;
import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.building.ModelCacheManager;
import org.apache.maven.xml.filter.BuildPomXMLFilterFactory;
-import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement;
+import org.apache.maven.xml.filter.RelativeProject;
/**
*
@@ -37,12 +41,14 @@ import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement;
*/
@Named
@Singleton
-@IgnoreJRERequirement( )
public class DefaultBuildPomXMLFilterFactory extends BuildPomXMLFilterFactory
{
private MavenSession session;
@Inject
+ private ModelCacheManager rawModelCache;
+
+ @Inject
public DefaultBuildPomXMLFilterFactory( MavenSession session )
{
this.session = session;
@@ -66,4 +72,26 @@ public class DefaultBuildPomXMLFilterFactory extends BuildPomXMLFilterFactory
return Optional.ofNullable( session.getUserProperties().getProperty( "sha1" ) );
}
+ @Override
+ protected Function<Path, Optional<RelativeProject>> getRelativePathMapper()
+ {
+ return p -> Optional.ofNullable( rawModelCache.get( p ) ).map( m -> toRelativeProject( m ) );
+ }
+
+ private RelativeProject toRelativeProject( final Model m )
+ {
+ String groupId = m.getGroupId();
+ if ( groupId == null && m.getParent() != null )
+ {
+ groupId = m.getParent().getGroupId();
+ }
+
+ String version = m.getVersion();
+ if ( version == null && m.getParent() != null )
+ {
+ version = m.getParent().getVersion();
+ }
+
+ return new RelativeProject( groupId, m.getArtifactId(), version );
+ }
}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
index 1fea6dd..0b0a615 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
@@ -51,6 +51,7 @@ import javax.xml.transform.stream.StreamResult;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
import org.apache.maven.artifact.versioning.VersionRange;
+import org.apache.maven.building.FileSource;
import org.apache.maven.model.Activation;
import org.apache.maven.model.Build;
import org.apache.maven.model.Dependency;
@@ -154,7 +155,12 @@ public class DefaultModelBuilder
private ReportingConverter reportingConverter;
@Inject
+ @Nullable
private Provider<BuildPomXMLFilterFactory> buildPomXMLFilterFactory;
+
+ @Inject
+ @Nullable
+ private ModelCacheManager modelCacheManager;
public DefaultModelBuilder setModelProcessor( ModelProcessor modelProcessor )
{
@@ -294,7 +300,11 @@ public class DefaultModelBuilder
{
inputModel = readModel( request.getModelSource(), request.getPomFile(), request, problems );
}
-
+ if ( modelCacheManager != null && request.getPomFile() != null )
+ {
+ modelCacheManager.put( request.getPomFile().toPath(), inputModel );
+ }
+
problems.setRootModel( inputModel );
ModelData resultData = new ModelData( request.getModelSource(), inputModel );
@@ -755,7 +765,7 @@ public class DefaultModelBuilder
}
// re-read model from file
- if ( Boolean.getBoolean( "maven.experimental.buildconsumer" ) )
+ if ( Boolean.getBoolean( "maven.experimental.buildconsumer" ) && !lineage.get( 0 ).isExternal() )
{
try
{
@@ -791,9 +801,12 @@ public class DefaultModelBuilder
final PipedOutputStream pipedOutputStream = new PipedOutputStream();
final PipedInputStream pipedInputStream = new PipedInputStream( pipedOutputStream );
+
+ // Should always be FileSource for reactor poms
+ FileSource source = (FileSource) modelData.getSource();
final SAXSource transformSource =
- new SAXSource( buildPomXMLFilterFactory.get().get( modelData.getGroupId(), modelData.getArtifactId() ),
+ new SAXSource( buildPomXMLFilterFactory.get().get( source.getFile().toPath() ),
new org.xml.sax.InputSource( modelData.getSource().getInputStream() ) );
final StreamResult result = new StreamResult( pipedOutputStream );
@@ -1103,6 +1116,8 @@ public class DefaultModelBuilder
*/
ModelData parentData = new ModelData( candidateSource, candidateModel, groupId, artifactId, version );
+
+ parentData.setExternal( false );
return parentData;
}
@@ -1220,6 +1235,8 @@ public class DefaultModelBuilder
ModelData parentData = new ModelData( modelSource, parentModel, parent.getGroupId(), parent.getArtifactId(),
parent.getVersion() );
+ parentData.setExternal( true );
+
return parentData;
}
diff --git a/maven-core/src/main/java/org/apache/maven/xml/internal/DefaultBuildPomXMLFilterFactory.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelCacheManager.java
similarity index 50%
copy from maven-core/src/main/java/org/apache/maven/xml/internal/DefaultBuildPomXMLFilterFactory.java
copy to maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelCacheManager.java
index 0b51da2..9a87805 100644
--- a/maven-core/src/main/java/org/apache/maven/xml/internal/DefaultBuildPomXMLFilterFactory.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelCacheManager.java
@@ -1,4 +1,4 @@
-package org.apache.maven.xml.internal;
+package org.apache.maven.model.building;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,16 +19,15 @@ package org.apache.maven.xml.internal;
* under the License.
*/
-import java.util.Optional;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
-import javax.inject.Inject;
import javax.inject.Named;
-//import javax.inject.Provider;
import javax.inject.Singleton;
-import org.apache.maven.execution.MavenSession;
-import org.apache.maven.xml.filter.BuildPomXMLFilterFactory;
-import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement;
+import org.apache.maven.model.Model;
/**
*
@@ -37,33 +36,20 @@ import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement;
*/
@Named
@Singleton
-@IgnoreJRERequirement( )
-public class DefaultBuildPomXMLFilterFactory extends BuildPomXMLFilterFactory
+public class DefaultModelCacheManager implements ModelCacheManager
{
- private MavenSession session;
+ private static final Map<Path, Model> RAWMODELCACHE = Collections.synchronizedMap( new HashMap<Path, Model>() );
- @Inject
- public DefaultBuildPomXMLFilterFactory( MavenSession session )
- {
- this.session = session;
- }
-
- @Override
- protected Optional<String> getChangelist()
- {
- return Optional.ofNullable( session.getUserProperties().getProperty( "changelist" ) );
- }
-
@Override
- protected Optional<String> getRevision()
+ public void put( Path p, Model t )
{
- return Optional.ofNullable( session.getUserProperties().getProperty( "revision" ) );
+ RAWMODELCACHE.put( p, t );
}
@Override
- protected Optional<String> getSha1()
+ public Model get( Path p )
{
- return Optional.ofNullable( session.getUserProperties().getProperty( "sha1" ) );
+ return RAWMODELCACHE.get( p );
}
}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCacheManager.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCacheManager.java
new file mode 100644
index 0000000..6619607
--- /dev/null
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCacheManager.java
@@ -0,0 +1,38 @@
+package org.apache.maven.model.building;
+
+/*
+ * 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.nio.file.Path;
+
+import org.apache.maven.model.Model;
+
+/**
+ * Registers models for usage later on
+ *
+ * @author Robert Scholte
+ * @since 3.7.0
+ */
+public interface ModelCacheManager
+{
+ void put( Path p, Model t );
+
+ Model get( Path p );
+
+}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelData.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelData.java
index 1f39ad4..2d093c6 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelData.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelData.java
@@ -45,6 +45,8 @@ class ModelData
private String artifactId;
private String version;
+
+ private boolean external = true;
/**
* Creates a new container for the specified model.
@@ -200,6 +202,25 @@ class ModelData
}
/**
+ *
+ * @return {@code false} if model is part of reactor, otherwise {@code true}
+ */
+ public boolean isExternal()
+ {
+ return external;
+ }
+
+ /**
+ * Set to {@code false} if model is part of reactor, otherwise {@code true}
+ *
+ * @param external
+ */
+ public void setExternal( boolean external )
+ {
+ this.external = external;
+ }
+
+ /**
* Gets the effective identifier of the model in the form {@code <groupId>:<artifactId>:<version>}.
*
* @return The effective identifier of the model, never {@code null}.
@@ -212,7 +233,7 @@ class ModelData
return buffer.toString();
}
-
+
@Override
public String toString()
{
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/validation/DefaultModelValidator.java b/maven-model-builder/src/main/java/org/apache/maven/model/validation/DefaultModelValidator.java
index cfa6e20..15a5587 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/validation/DefaultModelValidator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/validation/DefaultModelValidator.java
@@ -98,8 +98,12 @@ public class DefaultModelValidator
validateStringNotEmpty( "parent.artifactId", problems, Severity.FATAL, Version.BASE, parent.getArtifactId(),
parent );
- validateStringNotEmpty( "parent.version", problems, Severity.FATAL, Version.BASE, parent.getVersion(),
- parent );
+ // resolvedModel will assign version based on relativePath
+ if ( !Boolean.getBoolean( "maven.experimental.buildconsumer" ) )
+ {
+ validateStringNotEmpty( "parent.version", problems, Severity.FATAL, Version.BASE, parent.getVersion(),
+ parent );
+ }
if ( equals( parent.getGroupId(), m.getGroupId() ) && equals( parent.getArtifactId(), m.getArtifactId() ) )
{
diff --git a/maven-xml/src/main/java/org/apache/maven/xml/filter/BuildPomXMLFilterFactory.java b/maven-xml/src/main/java/org/apache/maven/xml/filter/BuildPomXMLFilterFactory.java
index 03cad01..7a3f52a 100644
--- a/maven-xml/src/main/java/org/apache/maven/xml/filter/BuildPomXMLFilterFactory.java
+++ b/maven-xml/src/main/java/org/apache/maven/xml/filter/BuildPomXMLFilterFactory.java
@@ -19,7 +19,9 @@ package org.apache.maven.xml.filter;
* under the License.
*/
+import java.nio.file.Path;
import java.util.Optional;
+import java.util.function.Function;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
@@ -35,23 +37,31 @@ import org.xml.sax.XMLReader;
*/
public abstract class BuildPomXMLFilterFactory
{
- public final BuildPomXMLFilter get( String groupId, String artifactId )
+ public final BuildPomXMLFilter get( Path projectFile )
throws SAXException, ParserConfigurationException
{
- CiFriendlyXMLFilter filter = new CiFriendlyXMLFilter();
- getChangelist().ifPresent( filter::setChangelist );
- getRevision().ifPresent( filter::setRevision );
- getSha1().ifPresent( filter::setSha1 );
+ XMLReader parent = getParent();
- if ( filter.isSet() )
+ if ( getRelativePathMapper() != null )
{
- filter.setParent( getParent() );
- return new BuildPomXMLFilter( filter );
+ ParentXMLFilter parentFilter = new ParentXMLFilter( getRelativePathMapper() );
+ parentFilter.setProjectPath( projectFile.getParent() );
+ parentFilter.setParent( parent );
+ parent = parentFilter;
}
- else
+
+ CiFriendlyXMLFilter ciFriendlyFilter = new CiFriendlyXMLFilter();
+ getChangelist().ifPresent( ciFriendlyFilter::setChangelist );
+ getRevision().ifPresent( ciFriendlyFilter::setRevision );
+ getSha1().ifPresent( ciFriendlyFilter::setSha1 );
+
+ if ( ciFriendlyFilter.isSet() )
{
- return new BuildPomXMLFilter( getParent() );
+ ciFriendlyFilter.setParent( parent );
+ parent = ciFriendlyFilter;
}
+
+ return new BuildPomXMLFilter( parent );
}
protected XMLReader getParent() throws SAXException, ParserConfigurationException
@@ -67,4 +77,9 @@ public abstract class BuildPomXMLFilterFactory
protected abstract Optional<String> getRevision();
protected abstract Optional<String> getSha1();
+
+ /**
+ * @return the mapper or {@code null} if relativePaths don't need to be mapped
+ */
+ protected abstract Function<Path, Optional<RelativeProject>> getRelativePathMapper();
}
diff --git a/maven-xml/src/main/java/org/apache/maven/xml/filter/ConsumerPomXMLFilterFactory.java b/maven-xml/src/main/java/org/apache/maven/xml/filter/ConsumerPomXMLFilterFactory.java
index c185fdf..dfea9ba 100644
--- a/maven-xml/src/main/java/org/apache/maven/xml/filter/ConsumerPomXMLFilterFactory.java
+++ b/maven-xml/src/main/java/org/apache/maven/xml/filter/ConsumerPomXMLFilterFactory.java
@@ -19,6 +19,8 @@ package org.apache.maven.xml.filter;
* under the License.
*/
+import java.nio.file.Path;
+
import javax.inject.Inject;
import javax.inject.Provider;
import javax.xml.parsers.ParserConfigurationException;
@@ -47,10 +49,10 @@ public abstract class ConsumerPomXMLFilterFactory
this.buildPomXMLFilterFactory = buildPomXMLFilterFactory;
}
- public final ConsumerPomXMLFilter get( String groupId, String artifactId )
+ public final ConsumerPomXMLFilter get( Path projectPath )
throws SAXException, ParserConfigurationException
{
- XMLFilter parent = buildPomXMLFilterFactory.get().get( groupId, artifactId );
+ XMLFilter parent = buildPomXMLFilterFactory.get().get( projectPath );
// Ensure that xs:any elements aren't touched by next filters
XMLReader filter = new FastForwardFilter( parent );
diff --git a/maven-xml/src/main/java/org/apache/maven/xml/filter/ParentXMLFilter.java b/maven-xml/src/main/java/org/apache/maven/xml/filter/ParentXMLFilter.java
new file mode 100644
index 0000000..244ecc5
--- /dev/null
+++ b/maven-xml/src/main/java/org/apache/maven/xml/filter/ParentXMLFilter.java
@@ -0,0 +1,313 @@
+package org.apache.maven.xml.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 java.nio.file.Path;
+import java.nio.file.Paths;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Function;
+
+import org.apache.maven.xml.SAXEvent;
+import org.apache.maven.xml.SAXEventFactory;
+import org.apache.maven.xml.SAXEventUtils;
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.XMLFilterImpl;
+
+/**
+ * <p>
+ * Transforms relativePath to version.
+ * We could decide to simply allow {@code <parent/>}, but let's require the GA for now for checking
+ * </p>
+ *
+ * @author Robert Scholte
+ */
+class ParentXMLFilter
+ extends XMLFilterImpl
+{
+ private boolean parsingParent = false;
+
+ // states
+ private String state;
+
+ private String groupId;
+
+ private String artifactId;
+
+ private String relativePath;
+
+ private boolean hasVersion;
+
+ private Optional<RelativeProject> resolvedParent;
+
+ private char[] linebreak;
+
+ private List<SAXEvent> saxEvents = new ArrayList<>();
+
+ private SAXEventFactory eventFactory;
+
+ private final Function<Path, Optional<RelativeProject>> relativePathMapper;
+
+ private Path projectPath;
+
+ /**
+ *
+ *
+ * @param relativePathMapper
+ */
+ ParentXMLFilter( Function<Path, Optional<RelativeProject>> relativePathMapper )
+ {
+ this.relativePathMapper = relativePathMapper;
+ }
+
+ public void setProjectPath( Path projectPath )
+ {
+ this.projectPath = projectPath;
+ }
+
+ private SAXEventFactory getEventFactory()
+ {
+ if ( eventFactory == null )
+ {
+ eventFactory = SAXEventFactory.newInstance( getContentHandler() );
+ }
+ return eventFactory;
+ }
+
+ private void processEvent( final SAXEvent event )
+ throws SAXException
+ {
+ if ( parsingParent )
+ {
+ final String eventState = state;
+
+ saxEvents.add( () ->
+ {
+ if ( !( "relativePath".equals( eventState ) && resolvedParent.isPresent() ) )
+ {
+ event.execute();
+ }
+ } );
+ }
+ else
+ {
+ event.execute();
+ }
+ }
+
+ @Override
+ public void startElement( String uri, final String localName, String qName, Attributes atts )
+ throws SAXException
+ {
+ if ( !parsingParent && "parent".equals( localName ) )
+ {
+ parsingParent = true;
+ }
+
+ if ( parsingParent )
+ {
+ state = localName;
+
+ hasVersion |= "version".equals( localName );
+ }
+
+ processEvent( getEventFactory().startElement( uri, localName, qName, atts ) );
+ }
+
+ @Override
+ public void characters( char[] ch, int start, int length )
+ throws SAXException
+ {
+ if ( parsingParent )
+ {
+ final String eventState = state;
+
+ switch ( eventState )
+ {
+ case "parent":
+ int l;
+ for ( l = length ; l >= 0; l-- )
+ {
+ int i = start + l - 1;
+ if ( ch[i] == '\n' || ch[i] == '\r' )
+ {
+ break;
+ }
+ }
+
+ linebreak = new char[l];
+ System.arraycopy( ch, start, linebreak, 0, l );
+ break;
+ case "relativePath":
+ relativePath = new String( ch, start, length );
+ break;
+ case "groupId":
+ groupId = new String( ch, start, length );
+ break;
+ case "artifactId":
+ artifactId = new String( ch, start, length );
+ break;
+ default:
+ break;
+ }
+ }
+
+ processEvent( getEventFactory().characters( ch, start, length ) );
+ }
+
+ @Override
+ public void endDocument()
+ throws SAXException
+ {
+ processEvent( getEventFactory().endDocument() );
+ }
+
+ @Override
+ public void endElement( String uri, final String localName, String qName )
+ throws SAXException
+ {
+ if ( parsingParent )
+ {
+ switch ( localName )
+ {
+ case "parent":
+ if ( !hasVersion || relativePath != null )
+ {
+ resolvedParent =
+ resolveRelativePath( Paths.get( Objects.toString( relativePath, "../pom.xml" ) ) );
+ }
+
+ // not with streams due to checked SAXException
+ for ( SAXEvent saxEvent : saxEvents )
+ {
+ saxEvent.execute();
+ }
+
+ if ( !hasVersion && resolvedParent.isPresent() )
+ {
+ String versionQName = SAXEventUtils.renameQName( qName, "version" );
+
+ getEventFactory().startElement( uri, "version", versionQName, null ).execute();
+
+ String resolvedParentVersion = resolvedParent.get().getVersion();
+
+ getEventFactory().characters( resolvedParentVersion.toCharArray(), 0,
+ resolvedParentVersion.length() ).execute();
+
+ getEventFactory().endElement( uri, "version", versionQName ).execute();
+
+ if ( linebreak != null )
+ {
+ getEventFactory().characters( linebreak, 0, linebreak.length ).execute();
+ }
+ }
+
+ parsingParent = false;
+ break;
+ default:
+ break;
+ }
+ }
+
+ processEvent( getEventFactory().endElement( uri, localName, qName ) );
+
+ // for this simple structure resetting to parent it sufficient
+ state = "parent";
+ }
+
+ @Override
+ public void endPrefixMapping( String prefix )
+ throws SAXException
+ {
+ processEvent( getEventFactory().endPrefixMapping( prefix ) );
+ }
+
+ @Override
+ public void ignorableWhitespace( char[] ch, int start, int length )
+ throws SAXException
+ {
+ processEvent( getEventFactory().ignorableWhitespace( ch, start, length ) );
+ }
+
+ @Override
+ public void processingInstruction( String target, String data )
+ throws SAXException
+ {
+ processEvent( getEventFactory().processingInstruction( target, data ) );
+
+ }
+
+ @Override
+ public void setDocumentLocator( Locator locator )
+ {
+ try
+ {
+ processEvent( getEventFactory().setDocumentLocator( locator ) );
+ }
+ catch ( SAXException e )
+ {
+ // noop
+ }
+ }
+
+ @Override
+ public void skippedEntity( String name )
+ throws SAXException
+ {
+ processEvent( getEventFactory().skippedEntity( name ) );
+ }
+
+ @Override
+ public void startDocument()
+ throws SAXException
+ {
+ processEvent( getEventFactory().startDocument() );
+ }
+
+ @Override
+ public void startPrefixMapping( String prefix, String uri )
+ throws SAXException
+ {
+ processEvent( getEventFactory().startPrefixMapping( prefix, uri ) );
+ }
+
+ protected Optional<RelativeProject> resolveRelativePath( Path relativePath )
+ {
+ Optional<RelativeProject> mappedProject =
+ relativePathMapper.apply( projectPath.resolve( relativePath ).normalize() );
+
+ if ( mappedProject.isPresent() )
+ {
+ RelativeProject project = mappedProject.get();
+
+ if ( Objects.equals( groupId, project.getGroupId() )
+ && Objects.equals( artifactId, project.getArtifactId() ) )
+ {
+ return mappedProject;
+ }
+ }
+ return Optional.empty();
+ }
+}
diff --git a/maven-xml/src/main/java/org/apache/maven/xml/filter/RelativeProject.java b/maven-xml/src/main/java/org/apache/maven/xml/filter/RelativeProject.java
new file mode 100644
index 0000000..bbceff3
--- /dev/null
+++ b/maven-xml/src/main/java/org/apache/maven/xml/filter/RelativeProject.java
@@ -0,0 +1,56 @@
+package org.apache.maven.xml.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.
+ */
+
+/**
+ *
+ * @author Robert Scholte
+ * @since 3.7.0
+ */
+public class RelativeProject
+{
+ private String groupId;
+
+ private String artifactId;
+
+ private String version;
+
+ public RelativeProject( String groupId, String artifactId, String version )
+ {
+ this.groupId = groupId;
+ this.artifactId = artifactId;
+ this.version = version;
+ }
+
+ public String getGroupId()
+ {
+ return groupId;
+ }
+
+ public String getArtifactId()
+ {
+ return artifactId;
+ }
+
+ public String getVersion()
+ {
+ return version;
+ }
+}
diff --git a/maven-xml/src/test/java/org/apache/maven/xml/filter/AbstractXMLFilterTests.java b/maven-xml/src/test/java/org/apache/maven/xml/filter/AbstractXMLFilterTests.java
index 4ee0e31..e406f6c 100644
--- a/maven-xml/src/test/java/org/apache/maven/xml/filter/AbstractXMLFilterTests.java
+++ b/maven-xml/src/test/java/org/apache/maven/xml/filter/AbstractXMLFilterTests.java
@@ -46,22 +46,38 @@ public abstract class AbstractXMLFilterTests
protected abstract XMLFilter getFilter() throws TransformerException, SAXException, ParserConfigurationException;
+ private void setParent( XMLFilter filter ) throws SAXException, ParserConfigurationException
+ {
+ if( filter.getParent() == null )
+ {
+ filter.setParent( SAXParserFactory.newInstance().newSAXParser().getXMLReader() );
+ filter.setFeature( "http://xml.org/sax/features/namespaces", true );
+ }
+ }
protected String transform( String input )
throws TransformerException, SAXException, ParserConfigurationException
{
return transform( new StringReader( input ) );
}
+
+ protected String transform( Reader input ) throws TransformerException, SAXException, ParserConfigurationException
+ {
+ XMLFilter filter = getFilter();
+ setParent( filter );
+ return transform( input, filter );
+ }
- protected String transform( Reader input )
+ protected String transform( String input, XMLFilter filter )
+ throws TransformerException, SAXException, ParserConfigurationException
+ {
+ setParent( filter );
+ return transform( new StringReader( input ), filter );
+ }
+
+ protected String transform( Reader input, XMLFilter filter )
throws TransformerException, SAXException, ParserConfigurationException
{
- XMLFilter filter = getFilter();
- if( filter.getParent() == null )
- {
- filter.setParent( SAXParserFactory.newInstance().newSAXParser().getXMLReader() );
- filter.setFeature( "http://xml.org/sax/features/namespaces", true );
- }
Writer writer = new StringWriter();
StreamResult result = new StreamResult( writer );
diff --git a/maven-xml/src/test/java/org/apache/maven/xml/filter/ConsumerPomXMLFilterTest.java b/maven-xml/src/test/java/org/apache/maven/xml/filter/ConsumerPomXMLFilterTest.java
index 8fe2d67..b02589e 100644
--- a/maven-xml/src/test/java/org/apache/maven/xml/filter/ConsumerPomXMLFilterTest.java
+++ b/maven-xml/src/test/java/org/apache/maven/xml/filter/ConsumerPomXMLFilterTest.java
@@ -21,7 +21,10 @@ package org.apache.maven.xml.filter;
import static org.xmlunit.assertj.XmlAssert.assertThat;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.Optional;
+import java.util.function.Function;
import javax.inject.Provider;
import javax.xml.parsers.ParserConfigurationException;
@@ -54,6 +57,12 @@ public class ConsumerPomXMLFilterTest extends AbstractXMLFilterTests
{
return Optional.of( "CL" );
}
+
+ @Override
+ protected Function<Path, Optional<RelativeProject>> getRelativePathMapper()
+ {
+ return null;
+ }
};
Provider<BuildPomXMLFilterFactory> provider = new Provider<BuildPomXMLFilterFactory>()
@@ -68,7 +77,7 @@ public class ConsumerPomXMLFilterTest extends AbstractXMLFilterTests
XMLFilter filter = new ConsumerPomXMLFilterFactory( provider )
{
- }.get( "G", "A" );
+ }.get( Paths.get( "pom.xml" ) );
filter.setFeature( "http://xml.org/sax/features/namespaces", true );
return filter;
}
diff --git a/maven-xml/src/test/java/org/apache/maven/xml/filter/ParentXMLFilterTest.java b/maven-xml/src/test/java/org/apache/maven/xml/filter/ParentXMLFilterTest.java
new file mode 100644
index 0000000..aa70b0d
--- /dev/null
+++ b/maven-xml/src/test/java/org/apache/maven/xml/filter/ParentXMLFilterTest.java
@@ -0,0 +1,185 @@
+package org.apache.maven.xml.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 java.nio.file.Paths;
+import java.util.Optional;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+
+import org.junit.Test;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLFilter;
+
+public class ParentXMLFilterTest extends AbstractXMLFilterTests
+{
+ @Override
+ protected XMLFilter getFilter()
+ 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() );
+
+ return filter;
+ }
+
+ @Test
+ public void testMinimum() throws Exception
+ {
+ String input = "<parent/>";
+ String expected = input;
+ String actual = transform( input );
+ assertEquals( expected, actual );
+ }
+
+ @Test
+ public void testNoRelativePath() throws Exception
+ {
+ String input = "<parent>"
+ + "<groupId>GROUPID</groupId>"
+ + "<artifactId>ARTIFACTID</artifactId>"
+ + "<version>VERSION</version>"
+ + "</parent>";
+ String expected = input;
+
+ String actual = transform( input );
+
+ assertEquals( expected, actual );
+ }
+
+ @Test
+ public void testDefaultRelativePath() throws Exception
+ {
+ String input = "<parent>"
+ + "<groupId>GROUPID</groupId>"
+ + "<artifactId>ARTIFACTID</artifactId>"
+ + "</parent>";
+ String expected = "<parent>"
+ + "<groupId>GROUPID</groupId>"
+ + "<artifactId>ARTIFACTID</artifactId>"
+ + "<version>1.0.0</version>"
+ + "</parent>";
+
+ String actual = transform( input );
+
+ assertEquals( expected, actual );
+ }
+
+ @Test
+ public void testNoVersion() throws Exception
+ {
+ String input = "<parent>"
+ + "<groupId>GROUPID</groupId>"
+ + "<artifactId>ARTIFACTID</artifactId>"
+ + "<relativePath>RELATIVEPATH</relativePath>"
+ + "</parent>";
+ String expected = "<parent>"
+ + "<groupId>GROUPID</groupId>"
+ + "<artifactId>ARTIFACTID</artifactId>"
+ + "<version>1.0.0</version>"
+ + "</parent>";
+
+ String actual = transform( input );
+
+ assertEquals( expected, actual );
+ }
+
+ @Test
+ public void testInvalidRelativePath() throws Exception
+ {
+ ParentXMLFilter filter = new ParentXMLFilter( x -> Optional.ofNullable( null ) );
+ filter.setProjectPath( Paths.get( "pom.xml").toAbsolutePath() );
+
+ String input = "<parent>"
+ + "<groupId>GROUPID</groupId>"
+ + "<artifactId>ARTIFACTID</artifactId>"
+ + "<relativePath>RELATIVEPATH</relativePath>"
+ + "</parent>";
+ String expected = input;
+
+ String actual = transform( input, filter );
+
+ assertEquals( expected, actual );
+ }
+
+ @Test
+ public void testRelativePathAndVersion() throws Exception
+ {
+ String input = "<parent>"
+ + "<groupId>GROUPID</groupId>"
+ + "<artifactId>ARTIFACTID</artifactId>"
+ + "<relativePath>RELATIVEPATH</relativePath>"
+ + "<version>1.0.0</version>"
+ + "</parent>";
+ String expected = "<parent>"
+ + "<groupId>GROUPID</groupId>"
+ + "<artifactId>ARTIFACTID</artifactId>"
+ + "<version>1.0.0</version>"
+ + "</parent>";
+
+ String actual = transform( input );
+
+ assertEquals( expected, actual );
+ }
+
+ @Test
+ public void testWithWeirdNamespace() throws Exception
+ {
+ String input = "<relativePath:parent xmlns:relativePath=\"relativePath\">"
+ + "<relativePath:groupId>GROUPID</relativePath:groupId>"
+ + "<relativePath:artifactId>ARTIFACTID</relativePath:artifactId>"
+ + "<relativePath:relativePath>RELATIVEPATH</relativePath:relativePath>"
+ + "</relativePath:parent>";
+ String expected = "<relativePath:parent xmlns:relativePath=\"relativePath\">"
+ + "<relativePath:groupId>GROUPID</relativePath:groupId>"
+ + "<relativePath:artifactId>ARTIFACTID</relativePath:artifactId>"
+ + "<relativePath:version>1.0.0</relativePath:version>"
+ + "</relativePath:parent>";
+
+ String actual = transform( input );
+
+ assertEquals( expected, actual );
+ }
+
+
+ @Test
+ public void testIndent() throws Exception
+ {
+ String input = "<parent>\n"
+ + " <groupId>GROUPID</groupId>\n"
+ + " <artifactId>ARTIFACTID</artifactId>\n"
+ + " </parent>";
+ // transformer is responsible for line separator and indents
+ String expected = "<parent>" + System.lineSeparator()
+ + " <groupId>GROUPID</groupId>" + System.lineSeparator()
+ + " <artifactId>ARTIFACTID</artifactId>" + System.lineSeparator()
+ + " <version>1.0.0</version>" + System.lineSeparator()
+ + "</parent>";
+
+ String actual = transform( input );
+
+ assertEquals( expected, actual );
+ }
+}
diff --git a/pom.xml b/pom.xml
index bed2633..5c23389 100644
--- a/pom.xml
+++ b/pom.xml
@@ -47,8 +47,8 @@ under the License.
<properties>
<maven.version>3.0.5</maven.version>
- <maven.compiler.source>1.7</maven.compiler.source>
- <maven.compiler.target>1.7</maven.compiler.target>
+ <maven.compiler.source>1.8</maven.compiler.source>
+ <maven.compiler.target>1.8</maven.compiler.target>
<classWorldsVersion>2.6.0</classWorldsVersion>
<commonsCliVersion>1.4</commonsCliVersion>
<commonsLangVersion>3.8.1</commonsLangVersion>
@@ -455,27 +455,6 @@ under the License.
<pluginManagement>
<plugins>
<plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-enforcer-plugin</artifactId>
- <executions>
- <execution>
- <id>enforce-bytecode-version</id>
- <goals>
- <goal>enforce</goal>
- </goals>
- <configuration>
- <rules>
- <enforceBytecodeVersion>
- <excludes>
- <exclude>org.apache.maven:maven-xml</exclude> <!-- Java 8 compatible -->
- </excludes>
- </enforceBytecodeVersion>
- </rules>
- </configuration>
- </execution>
- </executions>
- </plugin>
- <plugin>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-component-metadata</artifactId>
<version>${plexusVersion}</version>
@@ -604,7 +583,7 @@ under the License.
<configuration>
<signature>
<groupId>org.codehaus.mojo.signature</groupId>
- <artifactId>java17</artifactId>
+ <artifactId>java18</artifactId>
<version>1.0</version>
</signature>
</configuration>