You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by sc...@apache.org on 2017/01/31 23:45:13 UTC
[06/15] maven git commit: [MNG-5971] Imported dependencies should be
available to inheritance processing
[MNG-5971] Imported dependencies should be available to inheritance processing
o Updated the 'DefaultDependencyManagementImporter' to stop ignoring import
dependency conflicts silently. Such conflicts need to be resolved manually by
adding the conflicting dependency to the pom manually.
o Updated to add support for an 'include' scope in dependency management
processed before inheritance and interpolation.
o Re-formatted 'DefaultModelBuilder'.
o Documentation updates.
Project: http://git-wip-us.apache.org/repos/asf/maven/repo
Commit: http://git-wip-us.apache.org/repos/asf/maven/commit/b6367816
Tree: http://git-wip-us.apache.org/repos/asf/maven/tree/b6367816
Diff: http://git-wip-us.apache.org/repos/asf/maven/diff/b6367816
Branch: refs/heads/DEPMGMT-IT
Commit: b6367816824c4c569a768dde33d4539f91ea7de6
Parents: f9a426c
Author: Christian Schulte <sc...@apache.org>
Authored: Thu Feb 18 14:07:02 2016 +0100
Committer: Christian Schulte <sc...@apache.org>
Committed: Wed Feb 1 00:39:54 2017 +0100
----------------------------------------------------------------------
.../model/building/DefaultModelBuilder.java | 384 ++++++++++++++-----
.../building/DefaultModelBuildingResult.java | 26 +-
.../model/building/ModelBuildingResult.java | 12 +
.../DefaultDependencyManagementImporter.java | 213 +++++++++-
maven-model-builder/src/site/apt/index.apt | 12 +-
5 files changed, 527 insertions(+), 120 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/maven/blob/b6367816/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
----------------------------------------------------------------------
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 69e95ab..e26fcbc 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
@@ -24,6 +24,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
@@ -82,6 +83,7 @@ import static org.apache.maven.model.building.Result.newResult;
public class DefaultModelBuilder
implements ModelBuilder
{
+
@Requirement
private ModelProcessor modelProcessor;
@@ -248,8 +250,8 @@ public class DefaultModelBuilder
DefaultProfileActivationContext profileActivationContext = getProfileActivationContext( request );
problems.setSource( "(external profiles)" );
- List<Profile> activeExternalProfiles = profileSelector.getActiveProfiles( request.getProfiles(),
- profileActivationContext, problems );
+ List<Profile> activeExternalProfiles =
+ profileSelector.getActiveProfiles( request.getProfiles(), profileActivationContext, problems );
result.setActiveExternalProfiles( activeExternalProfiles );
@@ -296,8 +298,9 @@ public class DefaultModelBuilder
profileActivationContext.setProjectProperties( tmpModel.getProperties() );
- List<Profile> activePomProfiles = profileSelector.getActiveProfiles( rawModel.getProfiles(),
- profileActivationContext, problems );
+ List<Profile> activePomProfiles =
+ profileSelector.getActiveProfiles( rawModel.getProfiles(), profileActivationContext, problems );
+
currentData.setActiveProfiles( activePomProfiles );
Map<String, Activation> interpolatedActivations = getProfileActivations( rawModel, false );
@@ -332,13 +335,13 @@ public class DefaultModelBuilder
}
else if ( currentData == resultData )
{ // First iteration - add initial id after version resolution.
- currentData.setGroupId( currentData.getRawModel().getGroupId() == null ? parentData.getGroupId()
- : currentData.getRawModel()
- .getGroupId() );
+ currentData.setGroupId( currentData.getRawModel().getGroupId() == null
+ ? parentData.getGroupId()
+ : currentData.getRawModel().getGroupId() );
- currentData.setVersion( currentData.getRawModel().getVersion() == null ? parentData.getVersion()
- : currentData.getRawModel()
- .getVersion() );
+ currentData.setVersion( currentData.getRawModel().getVersion() == null
+ ? parentData.getVersion()
+ : currentData.getRawModel().getVersion() );
currentData.setArtifactId( currentData.getRawModel().getArtifactId() );
parentIds.add( currentData.getId() );
@@ -357,8 +360,9 @@ public class DefaultModelBuilder
}
message += parentData.getId();
- problems.add( new ModelProblemCollectorRequest( ModelProblem.Severity.FATAL, ModelProblem.Version.BASE )
- .setMessage( message ) );
+ problems.add( new ModelProblemCollectorRequest( ModelProblem.Severity.FATAL,
+ ModelProblem.Version.BASE ).
+ setMessage( message ) );
throw problems.newModelBuildingException();
}
@@ -371,24 +375,34 @@ public class DefaultModelBuilder
problems.setSource( inputModel );
checkPluginVersions( lineage, request, problems );
- // inheritance assembly
- assembleInheritance( lineage, request, problems );
+ // [MNG-4052] import scope dependencies prefer to download pom rather than find it in the current project
+ // [MNG-5971] Imported dependencies should be available to inheritance processing
+ //
+ // This first phase of model building is used for building models holding just enough information to map
+ // groupId:artifactId:version to pom files and to provide modules to build. For this, inheritance and
+ // interpolation needs to be performed. A temporary model is built in phase 1 applying inheritance and
+ // interpolation to fill in those values but is not returned. The rest of the model building takes place in
+ // phase 2.
+ final DefaultModelProblemCollector intermediateProblems = new DefaultModelProblemCollector( result );
+ final List<Model> intermediateLineage = new ArrayList<>( lineage.size() );
+ for ( final ModelData modelData : lineage )
+ {
+ intermediateLineage.add( modelData.getModel().clone() );
+ }
+ assembleInheritance( intermediateLineage, request, intermediateProblems );
+
+ Model intermediateModel = intermediateLineage.get( 0 );
+ intermediateModel = interpolateModel( intermediateModel, request, intermediateProblems );
Model resultModel = resultData.getModel();
+ resultModel.setGroupId( intermediateModel.getGroupId() );
+ resultModel.setArtifactId( intermediateModel.getArtifactId() );
+ resultModel.setVersion( intermediateModel.getVersion() );
+
problems.setSource( resultModel );
problems.setRootModel( resultModel );
- // model interpolation
- resultModel = interpolateModel( resultModel, request, problems );
- resultData.setModel( resultModel );
-
- // url normalization
- modelUrlNormalizer.normalize( resultModel, request );
-
- // Now the fully interpolated model is available: reconfigure the resolver
- configureResolver( request.getModelResolver(), resultModel, problems, true );
-
resultData.setGroupId( resultModel.getGroupId() );
resultData.setArtifactId( resultModel.getArtifactId() );
resultData.setVersion( resultModel.getVersion() );
@@ -402,6 +416,7 @@ public class DefaultModelBuilder
result.addModelId( modelId );
result.setActivePomProfiles( modelId, currentData.getActiveProfiles() );
result.setRawModel( modelId, currentData.getRawModel() );
+ result.setEffectiveModel( modelId, currentData.getModel() );
}
if ( !request.isTwoPhaseBuilding() )
@@ -416,20 +431,40 @@ public class DefaultModelBuilder
public ModelBuildingResult build( ModelBuildingRequest request, ModelBuildingResult result )
throws ModelBuildingException
{
- return build( request, result, new LinkedHashSet<String>() );
- }
-
- private ModelBuildingResult build( ModelBuildingRequest request, ModelBuildingResult result,
- Collection<String> imports )
- throws ModelBuildingException
- {
// phase 2
Model resultModel = result.getEffectiveModel();
+ // Reset to on-disk values to not suppress any warnings from phase 1.
+ resultModel.setGroupId( result.getRawModel().getGroupId() );
+ resultModel.setArtifactId( result.getRawModel().getArtifactId() );
+ resultModel.setVersion( result.getRawModel().getVersion() );
+
DefaultModelProblemCollector problems = new DefaultModelProblemCollector( result );
problems.setSource( resultModel );
problems.setRootModel( resultModel );
+ final List<Model> lineage = new ArrayList<>( result.getModelIds().size() );
+
+ for ( final String modelId : result.getModelIds() )
+ {
+ lineage.add( result.getEffectiveModel( modelId ) );
+ }
+
+ // [MNG-5971] Imported dependencies should be available to inheritance processing
+ processImports( lineage, "include", "pom", request, problems );
+ problems.setSource( resultModel );
+
+ // inheritance assembly
+ assembleInheritance( lineage, request, problems );
+
+ resultModel = interpolateModel( resultModel, request, problems );
+
+ // url normalization
+ modelUrlNormalizer.normalize( resultModel, request );
+
+ // Now the fully interpolated model is available: reconfigure the resolver
+ configureResolver( request.getModelResolver(), resultModel, problems, true );
+
// model path translation
modelPathTranslator.alignToBaseDirectory( resultModel, resultModel.getProjectDirectory(), request );
@@ -449,8 +484,7 @@ public class DefaultModelBuilder
lifecycleBindingsInjector.injectLifecycleBindings( resultModel, request, problems );
}
- // dependency management import
- importDependencyManagement( resultModel, request, problems, imports );
+ this.importDependencyManagement( resultModel, "import", request, problems, new HashSet<String>() );
// dependency management injection
dependencyManagementInjector.injectManagement( resultModel, request, problems );
@@ -483,10 +517,13 @@ public class DefaultModelBuilder
@Override
public Result<? extends Model> buildRawModel( File pomFile, int validationLevel, boolean locationTracking )
{
- final ModelBuildingRequest request = new DefaultModelBuildingRequest().setValidationLevel( validationLevel )
- .setLocationTracking( locationTracking );
+ final ModelBuildingRequest request = new DefaultModelBuildingRequest().
+ setValidationLevel( validationLevel ).
+ setLocationTracking( locationTracking );
+
final DefaultModelProblemCollector collector =
new DefaultModelProblemCollector( new DefaultModelBuildingResult() );
+
try
{
return newResult( readModel( null, pomFile, request, collector ), collector.getProblems() );
@@ -551,15 +588,17 @@ public class DefaultModelBuilder
if ( pomFile != null )
{
- problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.V20 )
- .setMessage( "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage() )
- .setException( e ) );
+ problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.V20 ).
+ setMessage( "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage() ).
+ setException( e ) );
+
}
else
{
- problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.V20 )
- .setMessage( "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage() )
- .setException( e ) );
+ problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.V20 ).
+ setMessage( "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage() ).
+ setException( e ) );
+
}
}
@@ -571,14 +610,16 @@ public class DefaultModelBuilder
}
catch ( ModelParseException e )
{
- problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE )
- .setMessage( "Non-parseable POM " + modelSource.getLocation() + ": " + e.getMessage() )
- .setException( e ) );
+ problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ).
+ setMessage( "Non-parseable POM " + modelSource.getLocation() + ": " + e.getMessage() ).
+ setException( e ) );
+
throw problems.newModelBuildingException();
}
catch ( IOException e )
{
String msg = e.getMessage();
+
if ( msg == null || msg.length() <= 0 )
{
// NOTE: There's java.nio.charset.MalformedInputException and sun.io.MalformedInputException
@@ -591,14 +632,18 @@ public class DefaultModelBuilder
msg = e.getClass().getSimpleName();
}
}
- problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE )
- .setMessage( "Non-readable POM " + modelSource.getLocation() + ": " + msg ).setException( e ) );
+
+ problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ).
+ setMessage( "Non-readable POM " + modelSource.getLocation() + ": " + msg ).
+ setException( e ) );
+
throw problems.newModelBuildingException();
}
model.setPomFile( pomFile );
problems.setSource( model );
+
modelValidator.validateRawModel( model, request, problems );
if ( hasFatalErrors( problems ) )
@@ -647,9 +692,11 @@ public class DefaultModelBuilder
}
catch ( InvalidRepositoryException e )
{
- problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
- .setMessage( "Invalid repository " + repository.getId() + ": " + e.getMessage() )
- .setLocation( repository.getLocation( "" ) ).setException( e ) );
+ problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).
+ setMessage( "Invalid repository " + repository.getId() + ": " + e.getMessage() ).
+ setLocation( repository.getLocation( "" ) ).
+ setException( e ) );
+
}
}
}
@@ -701,21 +748,150 @@ public class DefaultModelBuilder
if ( versions.get( key ) == null && managedVersions.get( key ) == null )
{
InputLocation location = plugins.get( key ).getLocation( "" );
- problems
- .add( new ModelProblemCollectorRequest( Severity.WARNING, Version.V20 )
- .setMessage( "'build.plugins.plugin.version' for " + key + " is missing." )
- .setLocation( location ) );
+ problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.V20 ).
+ setMessage( "'build.plugins.plugin.version' for " + key + " is missing." ).
+ setLocation( location ) );
+
}
}
}
- private void assembleInheritance( List<ModelData> lineage, ModelBuildingRequest request,
+ private void processImports( final List<Model> lineage, final String scope, final String packaging,
+ final ModelBuildingRequest request, final DefaultModelProblemCollector problems )
+ {
+ // [MNG-5971] Imported dependencies should be available to inheritance processing
+ // It's not possible to support all ${project.xyz} properties in dependency management import declarations
+ // because import processing is performed before the final inheritance processing is performed. So the set of
+ // ${project.xyz} properties supported in dependency management import declarations is limited.
+
+ final List<Model> intermediateLineage = new ArrayList<>( lineage.size() );
+
+ for ( int i = 0, s0 = lineage.size(); i < s0; i++ )
+ {
+ intermediateLineage.add( lineage.get( i ).clone() );
+ }
+
+ for ( int i = intermediateLineage.size() - 2; i >= 0; i-- )
+ {
+ final Model parent = intermediateLineage.get( i + 1 );
+ final Model child = intermediateLineage.get( i );
+
+ if ( child.getGroupId() == null )
+ {
+ // Support ${project.groupId} in dependency management import declarations.
+ child.setGroupId( parent.getGroupId() );
+ }
+ if ( child.getVersion() == null )
+ {
+ // Support ${project.version} in dependency management import declarations.
+ child.setVersion( parent.getVersion() );
+ }
+
+ final Properties properties = new Properties();
+ properties.putAll( parent.getProperties() );
+ properties.putAll( child.getProperties() );
+ child.setProperties( properties );
+
+ final List<Repository> repositories = new ArrayList<>();
+ repositories.addAll( child.getRepositories() );
+
+ for ( final Repository parentRepository : parent.getRepositories() )
+ {
+ if ( !repositories.contains( parentRepository ) )
+ {
+ repositories.add( parentRepository );
+ }
+ }
+
+ child.setRepositories( repositories );
+ }
+
+ final Properties effectiveProperties = intermediateLineage.get( 0 ).getProperties();
+
+ final DefaultModelProblemCollector intermediateProblems =
+ new DefaultModelProblemCollector( new DefaultModelBuildingResult() );
+
+ // Interpolates the intermediate model.
+ // MNG-6079: Uses the effective properties of the result model to support property overriding.
+ for ( int i = 0, s0 = intermediateLineage.size(); i < s0; i++ )
+ {
+ final Model model = intermediateLineage.get( i );
+ model.setProperties( effectiveProperties );
+ intermediateProblems.setSource( model );
+ this.interpolateModel( model, request, intermediateProblems );
+ }
+
+ // Exchanges 'include' scope dependencies in the original lineage with possibly interpolated values.
+ for ( int i = 0, s0 = lineage.size(); i < s0; i++ )
+ {
+ final Model model = lineage.get( i );
+
+ if ( model.getDependencyManagement() != null )
+ {
+ for ( int j = 0, s1 = model.getDependencyManagement().getDependencies().size(); j < s1; j++ )
+ {
+ final Dependency dependency = model.getDependencyManagement().getDependencies().get( j );
+
+ if ( scope.equals( dependency.getScope() ) && packaging.equals( dependency.getType() ) )
+ {
+ final Dependency interpolated =
+ intermediateLineage.get( i ).getDependencyManagement().getDependencies().get( j );
+
+ model.getDependencyManagement().getDependencies().set( j, interpolated );
+ }
+ }
+ }
+ }
+
+ // [MNG-4488] [regression] Parent POMs resolved from repository are validated in strict mode
+ ModelBuildingRequest lenientRequest = request;
+ if ( request.getValidationLevel() > ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 )
+ {
+ lenientRequest = new FilterModelBuildingRequest( request )
+ {
+
+ @Override
+ public int getValidationLevel()
+ {
+ return ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0;
+ }
+
+ };
+ }
+
+ // Sets up the resolver to use the effective repositories to support repository overriding.
+ if ( lenientRequest.getModelResolver() != null )
+ {
+ for ( Repository repository : intermediateLineage.get( 0 ).getRepositories() )
+ {
+ try
+ {
+ lenientRequest.getModelResolver().addRepository( repository, true );
+ }
+ catch ( InvalidRepositoryException e )
+ {
+ problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
+ .setMessage( "Invalid repository " + repository.getId() + ": " + e.getMessage() )
+ .setLocation( repository.getLocation( "" ) ).setException( e ) );
+
+ }
+ }
+ }
+
+ // Imports dependencies into the original model using the effective repositories.
+ for ( int i = 0, s0 = lineage.size(); i < s0; i++ )
+ {
+ this.importDependencyManagement( lineage.get( i ), scope, lenientRequest, problems, new HashSet<String>() );
+ }
+ }
+
+ private void assembleInheritance( List<Model> lineage, ModelBuildingRequest request,
ModelProblemCollector problems )
{
for ( int i = lineage.size() - 2; i >= 0; i-- )
{
- Model parent = lineage.get( i + 1 ).getModel();
- Model child = lineage.get( i ).getModel();
+ Model parent = lineage.get( i + 1 );
+ Model child = lineage.get( i );
inheritanceAssembler.assembleModelInheritance( child, parent, request, problems );
}
}
@@ -815,7 +991,7 @@ public class DefaultModelBuilder
ModelSource expectedParentSource = getParentPomFile( childModel, childSource );
if ( expectedParentSource instanceof ModelSource2
- && !pomFile.toURI().equals( ( (ModelSource2) expectedParentSource ).getLocationURI() ) )
+ && !pomFile.toURI().equals( ( (ModelSource2) expectedParentSource ).getLocationURI() ) )
{
parentData = readParentExternally( childModel, request, problems );
}
@@ -826,10 +1002,11 @@ public class DefaultModelBuilder
if ( !"pom".equals( parentModel.getPackaging() ) )
{
- problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
- .setMessage( "Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint( parentModel )
- + ", must be \"pom\" but is \"" + parentModel.getPackaging() + "\"" )
- .setLocation( parentModel.getLocation( "packaging" ) ) );
+ problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).
+ setMessage( "Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint( parentModel )
+ + ", must be \"pom\" but is \"" + parentModel.getPackaging() + "\"" ).
+ setLocation( parentModel.getLocation( "packaging" ) ) );
+
}
}
else
@@ -871,11 +1048,15 @@ public class DefaultModelBuilder
{
candidateModel =
resolver.resolveRawModel( parent.getGroupId(), parent.getArtifactId(), parent.getVersion() );
+
}
catch ( UnresolvableModelException e )
{
- problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ) //
- .setMessage( e.getMessage().toString() ).setLocation( parent.getLocation( "" ) ).setException( e ) );
+ problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ).
+ setMessage( e.getMessage().toString() ).
+ setLocation( parent.getLocation( "" ) ).
+ setException( e ) );
+
throw problems.newModelBuildingException();
}
if ( candidateModel == null )
@@ -890,7 +1071,6 @@ public class DefaultModelBuilder
// have a model that is suitable, yet more checks are done here and the one for the version is problematic
// before because with parents as ranges it will never work in this scenario.
//
-
String groupId = candidateModel.getGroupId();
if ( groupId == null && candidateModel.getParent() != null )
{
@@ -904,7 +1084,7 @@ public class DefaultModelBuilder
}
if ( groupId == null || !groupId.equals( parent.getGroupId() ) || artifactId == null
- || !artifactId.equals( parent.getArtifactId() ) )
+ || !artifactId.equals( parent.getArtifactId() ) )
{
StringBuilder buffer = new StringBuilder( 256 );
buffer.append( "'parent.relativePath'" );
@@ -917,8 +1097,10 @@ public class DefaultModelBuilder
buffer.append( parent.getArtifactId() ).append( ", please verify your project structure" );
problems.setSource( childModel );
- problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.BASE )
- .setMessage( buffer.toString() ).setLocation( parent.getLocation( "" ) ) );
+ problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.BASE ).
+ setMessage( buffer.toString() ).
+ setLocation( parent.getLocation( "" ) ) );
+
return null;
}
if ( version != null && parent.getVersion() != null && !version.equals( parent.getVersion() ) )
@@ -972,7 +1154,6 @@ public class DefaultModelBuilder
/*
* if ( version == null || !version.equals( parent.getVersion() ) ) { return null; }
*/
-
ModelData parentData = new ModelData( candidateSource, candidateModel, groupId, artifactId, version );
return parentData;
@@ -1010,7 +1191,8 @@ public class DefaultModelBuilder
ModelResolver modelResolver = request.getModelResolver();
Validate.notNull( modelResolver, "request.modelResolver cannot be null (parent POM %s and POM %s)",
- ModelProblemUtils.toId( groupId, artifactId, version ), ModelProblemUtils.toSourceHint( childModel ) );
+ ModelProblemUtils.toId( groupId, artifactId, version ),
+ ModelProblemUtils.toSourceHint( childModel ) );
ModelSource modelSource;
try
@@ -1042,8 +1224,11 @@ public class DefaultModelBuilder
}
}
- problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE )
- .setMessage( buffer.toString() ).setLocation( parent.getLocation( "" ) ).setException( e ) );
+ problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ).
+ setMessage( buffer.toString() ).
+ setLocation( parent.getLocation( "" ) ).
+ setException( e ) );
+
throw problems.newModelBuildingException();
}
@@ -1052,11 +1237,13 @@ public class DefaultModelBuilder
{
lenientRequest = new FilterModelBuildingRequest( request )
{
+
@Override
public int getValidationLevel()
{
return ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0;
}
+
};
}
@@ -1066,17 +1253,18 @@ public class DefaultModelBuilder
{
if ( childModel.getVersion() == null )
{
- problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 )
- .setMessage( "Version must be a constant" ).setLocation( childModel.getLocation( "" ) ) );
+ problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 ).
+ setMessage( "Version must be a constant" ).
+ setLocation( childModel.getLocation( "" ) ) );
}
else
{
if ( childModel.getVersion().contains( "${" ) )
{
- problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 )
- .setMessage( "Version must be a constant" )
- .setLocation( childModel.getLocation( "version" ) ) );
+ problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 ).
+ setMessage( "Version must be a constant" ).
+ setLocation( childModel.getLocation( "version" ) ) );
}
}
@@ -1095,7 +1283,7 @@ public class DefaultModelBuilder
return superPomProvider.getSuperModel( "4.0.0" ).clone();
}
- private void importDependencyManagement( Model model, ModelBuildingRequest request,
+ private void importDependencyManagement( Model model, String scope, ModelBuildingRequest request,
DefaultModelProblemCollector problems, Collection<String> importIds )
{
DependencyManagement depMngt = model.getDependencyManagement();
@@ -1105,6 +1293,8 @@ public class DefaultModelBuilder
return;
}
+ problems.setSource( model );
+
String importing = model.getGroupId() + ':' + model.getArtifactId() + ':' + model.getVersion();
importIds.add( importing );
@@ -1118,7 +1308,7 @@ public class DefaultModelBuilder
{
Dependency dependency = it.next();
- if ( !"pom".equals( dependency.getType() ) || !"import".equals( dependency.getScope() ) )
+ if ( !"pom".equals( dependency.getType() ) || !scope.equals( dependency.getScope() ) )
{
continue;
}
@@ -1139,18 +1329,20 @@ public class DefaultModelBuilder
}
if ( artifactId == null || artifactId.length() <= 0 )
{
- problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
- .setMessage( "'dependencyManagement.dependencies.dependency.artifactId' for "
- + dependency.getManagementKey() + " is missing." )
- .setLocation( dependency.getLocation( "" ) ) );
+ problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).
+ setMessage( "'dependencyManagement.dependencies.dependency.artifactId' for "
+ + dependency.getManagementKey() + " is missing." ).
+ setLocation( dependency.getLocation( "" ) ) );
+
continue;
}
if ( version == null || version.length() <= 0 )
{
- problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
- .setMessage( "'dependencyManagement.dependencies.dependency.version' for "
- + dependency.getManagementKey() + " is missing." )
- .setLocation( dependency.getLocation( "" ) ) );
+ problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).
+ setMessage( "'dependencyManagement.dependencies.dependency.version' for "
+ + dependency.getManagementKey() + " is missing." ).
+ setLocation( dependency.getLocation( "" ) ) );
+
continue;
}
@@ -1158,14 +1350,13 @@ public class DefaultModelBuilder
if ( importIds.contains( imported ) )
{
- String message = "The dependencies of type=pom and with scope=import form a cycle: ";
+ String message = "The dependencies of type=pom and scope=" + scope + " form a cycle: ";
for ( String modelId : importIds )
{
message += modelId + " -> ";
}
message += imported;
problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).setMessage( message ) );
-
continue;
}
@@ -1178,9 +1369,10 @@ public class DefaultModelBuilder
{
throw new NullPointerException( String.format(
"request.workspaceModelResolver and request.modelResolver cannot be null"
- + " (parent POM %s and POM %s)",
+ + " (parent POM %s and POM %s)",
ModelProblemUtils.toId( groupId, artifactId, version ),
ModelProblemUtils.toSourceHint( model ) ) );
+
}
Model importModel = null;
@@ -1192,8 +1384,10 @@ public class DefaultModelBuilder
}
catch ( UnresolvableModelException e )
{
- problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE )
- .setMessage( e.getMessage().toString() ).setException( e ) );
+ problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ).
+ setMessage( e.getMessage().toString() ).
+ setException( e ) );
+
continue;
}
}
@@ -1426,9 +1620,11 @@ public class DefaultModelBuilder
private boolean containsCoordinates( String message, String groupId, String artifactId, String version )
{
- return message != null && ( groupId == null || message.contains( groupId ) )
- && ( artifactId == null || message.contains( artifactId ) )
- && ( version == null || message.contains( version ) );
+ return message != null
+ && ( groupId == null || message.contains( groupId ) )
+ && ( artifactId == null || message.contains( artifactId ) )
+ && ( version == null || message.contains( version ) );
+
}
protected boolean hasModelErrors( ModelProblemCollectorExt problems )
http://git-wip-us.apache.org/repos/asf/maven/blob/b6367816/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingResult.java
----------------------------------------------------------------------
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingResult.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingResult.java
index 7bf45b5..fe1c7ae 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingResult.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingResult.java
@@ -39,11 +39,13 @@ class DefaultModelBuildingResult
private Model effectiveModel;
- private List<String> modelIds;
+ private final List<String> modelIds;
- private Map<String, Model> rawModels;
+ private final Map<String, Model> rawModels;
- private Map<String, List<Profile>> activePomProfiles;
+ private final Map<String, Model> effectiveModels;
+
+ private final Map<String, List<Profile>> activePomProfiles;
private List<Profile> activeExternalProfiles;
@@ -56,6 +58,7 @@ class DefaultModelBuildingResult
activePomProfiles = new HashMap<>();
activeExternalProfiles = new ArrayList<>();
problems = new ArrayList<>();
+ effectiveModels = new HashMap<>();
}
@Override
@@ -110,6 +113,23 @@ class DefaultModelBuildingResult
}
@Override
+ public Model getEffectiveModel( final String modelId )
+ {
+ return this.effectiveModels.get( modelId );
+ }
+
+ public DefaultModelBuildingResult setEffectiveModel( final String modelId, final Model model )
+ {
+ // Intentionally notNull because Super POM may not contain a modelId
+ Validate.notNull( modelId, "modelId must not be null" );
+ Validate.notNull( model, "model must not be null" );
+
+ this.effectiveModels.put( modelId, model );
+
+ return this;
+ }
+
+ @Override
public List<Profile> getActivePomProfiles( String modelId )
{
return activePomProfiles.get( modelId );
http://git-wip-us.apache.org/repos/asf/maven/blob/b6367816/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingResult.java
----------------------------------------------------------------------
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingResult.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingResult.java
index 44b1295..b21a670 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingResult.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingResult.java
@@ -69,6 +69,18 @@ public interface ModelBuildingResult
Model getRawModel( String modelId );
/**
+ * Gets the effective model for a given identifier. The model identifier should be from the collection obtained by
+ * {@link #getModelIds()}. As a special case, an empty string can be used as the identifier for the super POM.
+ *
+ * @param modelId The identifier of the desired effective model, must not be {@code null}.
+ *
+ * @return The effective model or {@code null} if the specified model id does not refer to a known model.
+ *
+ * @since 3.6
+ */
+ Model getEffectiveModel( String modelId );
+
+ /**
* Gets the profiles from the specified model that were active during model building. The model identifier should be
* from the collection obtained by {@link #getModelIds()}. As a special case, an empty string can be used as the
* identifier for the super POM.
http://git-wip-us.apache.org/repos/asf/maven/blob/b6367816/maven-model-builder/src/main/java/org/apache/maven/model/composition/DefaultDependencyManagementImporter.java
----------------------------------------------------------------------
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/composition/DefaultDependencyManagementImporter.java b/maven-model-builder/src/main/java/org/apache/maven/model/composition/DefaultDependencyManagementImporter.java
index d895913..b8caaa7 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/composition/DefaultDependencyManagementImporter.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/composition/DefaultDependencyManagementImporter.java
@@ -20,15 +20,20 @@ package org.apache.maven.model.composition;
*/
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-
import org.apache.maven.model.Dependency;
import org.apache.maven.model.DependencyManagement;
+import org.apache.maven.model.Exclusion;
+import org.apache.maven.model.InputLocation;
+import org.apache.maven.model.InputSource;
import org.apache.maven.model.Model;
import org.apache.maven.model.building.ModelBuildingRequest;
+import org.apache.maven.model.building.ModelProblem;
import org.apache.maven.model.building.ModelProblemCollector;
+import org.apache.maven.model.building.ModelProblemCollectorRequest;
import org.codehaus.plexus.component.annotations.Component;
/**
@@ -42,41 +47,215 @@ public class DefaultDependencyManagementImporter
{
@Override
- public void importManagement( Model target, List<? extends DependencyManagement> sources,
- ModelBuildingRequest request, ModelProblemCollector problems )
+ public void importManagement( final Model target, final List<? extends DependencyManagement> sources,
+ final ModelBuildingRequest request, final ModelProblemCollector problems )
{
if ( sources != null && !sources.isEmpty() )
{
- Map<String, Dependency> dependencies = new LinkedHashMap<>();
+ final Map<String, Dependency> targetDependencies = new LinkedHashMap<>();
+ final DependencyManagement targetDependencyManagement = target.getDependencyManagement() != null
+ ? target.getDependencyManagement()
+ : new DependencyManagement();
+
+ target.setDependencyManagement( targetDependencyManagement );
+
+ for ( final Dependency targetDependency : targetDependencyManagement.getDependencies() )
+ {
+ targetDependencies.put( targetDependency.getManagementKey(), targetDependency );
+ }
- DependencyManagement depMngt = target.getDependencyManagement();
+ final Map<String, List<Dependency>> sourceDependencies = new LinkedHashMap<>();
- if ( depMngt != null )
+ for ( final DependencyManagement source : sources )
{
- for ( Dependency dependency : depMngt.getDependencies() )
+ for ( final Dependency sourceDependency : source.getDependencies() )
{
- dependencies.put( dependency.getManagementKey(), dependency );
+ if ( !targetDependencies.containsKey( sourceDependency.getManagementKey() ) )
+ {
+ List<Dependency> conflictCanditates =
+ sourceDependencies.get( sourceDependency.getManagementKey() );
+
+ if ( conflictCanditates == null )
+ {
+ conflictCanditates = new ArrayList<>( source.getDependencies().size() );
+ sourceDependencies.put( sourceDependency.getManagementKey(), conflictCanditates );
+ }
+
+ conflictCanditates.add( sourceDependency );
+ }
}
}
- else
+
+ for ( final List<Dependency> conflictCanditates : sourceDependencies.values() )
{
- depMngt = new DependencyManagement();
- target.setDependencyManagement( depMngt );
+ final List<Dependency> conflictingDependencies = removeRedundantDependencies( conflictCanditates );
+
+ // First declaration wins. This is what makes the conflict resolution indeterministic because this
+ // solely relies on the order of declaration. There is no such thing as the "first" declaration.
+ targetDependencyManagement.getDependencies().add( conflictingDependencies.get( 0 ) );
+
+ // As of Maven 3.6, we print a warning about such conflicting imports using validation level Maven 3.1.
+ if ( conflictingDependencies.size() > 1 )
+ {
+ final StringBuilder conflictsBuilder = new StringBuilder( conflictingDependencies.size() * 128 );
+
+ for ( final Dependency dependency : conflictingDependencies )
+ {
+ final InputLocation location = dependency.getLocation( "" );
+
+ if ( location != null )
+ {
+ final InputSource inputSource = location.getSource();
+
+ if ( inputSource != null )
+ {
+ conflictsBuilder.append( ", '" ).append( inputSource.getModelId() ).append( '\'' );
+ }
+ }
+ }
+
+ problems.add( new ModelProblemCollectorRequest(
+ effectiveSeverity( request.getValidationLevel(),
+ ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1 ),
+ ModelProblem.Version.V20 ).
+ setMessage( String.format(
+ "Dependency '%1$s' has conflicting dependency management in model '%2$s'%3$s%4$s. "
+ + "To resolve the conflicts, declare the dependency management for dependency '%1$s' "
+ + "directly in the dependency management of model '%2$s' to override what gets "
+ + "imported. If the Maven version in use supports it, add exclusions for the "
+ + "conflicting dependencies or use the include scope feature to rearrange the "
+ + "causing dependencies in the inheritance hierarchy applying standard override logic "
+ + "based on artifact coordinates. Without resolving the conflicts, your build relies "
+ + "on indeterministic behaviour.",
+ conflictingDependencies.get( 0 ).getManagementKey(), target.getId(),
+ target.getPomFile() != null
+ ? " @ '" + target.getPomFile().getAbsolutePath() + "' "
+ : " ", conflictsBuilder.length() > 0
+ ? "(" + conflictsBuilder.substring( 2 ) + ")"
+ : "" ) ) );
+
+ }
}
+ }
+ }
+
+ private static List<Dependency> removeRedundantDependencies( final List<Dependency> candidateDependencies )
+ {
+ final List<Dependency> resultDependencies = new ArrayList<>( candidateDependencies.size() );
- for ( DependencyManagement source : sources )
+ while ( !candidateDependencies.isEmpty() )
+ {
+ final Dependency resultDependency = candidateDependencies.remove( 0 );
+ resultDependencies.add( resultDependency );
+
+ // Removes redundant dependencies.
+ for ( final Iterator<Dependency> it = candidateDependencies.iterator(); it.hasNext(); )
{
- for ( Dependency dependency : source.getDependencies() )
+ final Dependency candidateDependency = it.next();
+ boolean redundant = true;
+
+ redundancy_check:
{
- String key = dependency.getManagementKey();
- if ( !dependencies.containsKey( key ) )
+ if ( !( resultDependency.getOptional() != null
+ ? resultDependency.getOptional().equals( candidateDependency.getOptional() )
+ : candidateDependency.getOptional() == null ) )
+ {
+ redundant = false;
+ break redundancy_check;
+ }
+
+ if ( !( effectiveScope( resultDependency ).equals( effectiveScope( candidateDependency ) ) ) )
+ {
+ redundant = false;
+ break redundancy_check;
+ }
+
+ if ( !( resultDependency.getSystemPath() != null
+ ? resultDependency.getSystemPath().equals( candidateDependency.getSystemPath() )
+ : candidateDependency.getSystemPath() == null ) )
{
- dependencies.put( key, dependency );
+ redundant = false;
+ break redundancy_check;
}
+
+ if ( !( resultDependency.getVersion() != null
+ ? resultDependency.getVersion().equals( candidateDependency.getVersion() )
+ : candidateDependency.getVersion() == null ) )
+ {
+ redundant = false;
+ break redundancy_check;
+ }
+
+ for ( int i = 0, s0 = resultDependency.getExclusions().size(); i < s0; i++ )
+ {
+ final Exclusion resultExclusion = resultDependency.getExclusions().get( i );
+
+ if ( !containsExclusion( candidateDependency.getExclusions(), resultExclusion ) )
+ {
+ redundant = false;
+ break redundancy_check;
+ }
+ }
+
+ for ( int i = 0, s0 = candidateDependency.getExclusions().size(); i < s0; i++ )
+ {
+ final Exclusion candidateExclusion = candidateDependency.getExclusions().get( i );
+
+ if ( !containsExclusion( resultDependency.getExclusions(), candidateExclusion ) )
+ {
+ redundant = false;
+ break redundancy_check;
+ }
+ }
+ }
+
+ if ( redundant )
+ {
+ it.remove();
}
}
+ }
+
+ return resultDependencies;
+ }
+
+ private static boolean containsExclusion( final List<Exclusion> exclusions, final Exclusion exclusion )
+ {
+ for ( int i = 0, s0 = exclusions.size(); i < s0; i++ )
+ {
+ final Exclusion current = exclusions.get( i );
+
+ if ( ( exclusion.getArtifactId() != null
+ ? exclusion.getArtifactId().equals( current.getArtifactId() )
+ : current.getArtifactId() == null )
+ && ( exclusion.getGroupId() != null
+ ? exclusion.getGroupId().equals( current.getGroupId() )
+ : current.getGroupId() == null ) )
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
- depMngt.setDependencies( new ArrayList<>( dependencies.values() ) );
+ private static String effectiveScope( final Dependency dependency )
+ {
+ return dependency.getScope() == null
+ ? "compile"
+ : dependency.getScope();
+
+ }
+
+ private static ModelProblem.Severity effectiveSeverity( final int validationLevel, final int errorThreshold )
+ {
+ if ( validationLevel < errorThreshold )
+ {
+ return ModelProblem.Severity.WARNING;
+ }
+ else
+ {
+ return ModelProblem.Severity.ERROR;
}
}
http://git-wip-us.apache.org/repos/asf/maven/blob/b6367816/maven-model-builder/src/site/apt/index.apt
----------------------------------------------------------------------
diff --git a/maven-model-builder/src/site/apt/index.apt b/maven-model-builder/src/site/apt/index.apt
index 9a645f4..73690d5 100644
--- a/maven-model-builder/src/site/apt/index.apt
+++ b/maven-model-builder/src/site/apt/index.apt
@@ -57,6 +57,12 @@ Maven Model Builder
** parent resolution until {{{./super-pom.html}super-pom}}
+ []
+
+ * phase 2, with optional plugin processing
+
+ ** dependency management import (for dependencies of type <<<pom>>> in the <<<\<dependencyManagement\>>>> section)
+
** inheritance assembly: <<<InheritanceAssembler>>> ({{{./apidocs/org/apache/maven/model/inheritance/InheritanceAssembler.html}javadoc}}),
with its <<<DefaultInheritanceAssembler>>> implementation
({{{./xref/org/apache/maven/model/inheritance/DefaultInheritanceAssembler.html}source}}). Notice that
@@ -70,10 +76,6 @@ Maven Model Builder
with its <<<DefaultUrlNormalizer>>> implementation
({{{./xref/org/apache/maven/model/path/DefaultUrlNormalizer.html}source}})
- []
-
- * phase 2, with optional plugin processing
-
** model path translation: <<<ModelPathTranslator>>> ({{{./apidocs/org/apache/maven/model/path/ModelPathTranslator.html}javadoc}}),
with its <<<DefaultModelPathTranslator>>> implementation
({{{./xref/org/apache/maven/model/path/DefaultModelPathTranslator.html}source}})
@@ -86,8 +88,6 @@ Maven Model Builder
with its <<<DefaultLifecycleBindingsInjector>>> implementation
({{{./xref/org/apache/maven/model/plugin/DefaultLifecycleBindingsInjector.html}source}})
- ** dependency management import (for dependencies of type <<<pom>>> in the <<<\<dependencyManagement\>>>> section)
-
** dependency management injection: <<<DependencyManagementInjector>>> ({{{./apidocs/org/apache/maven/model/management/DependencyManagementInjector.html}javadoc}}),
with its <<<DefaultDependencyManagementInjector>>> implementation
({{{./xref/org/apache/maven/model/management/DefaultDependencyManagementInjector.html}source}})