[MNG-7063] Infinite loop using Shade plugin and JUnit 5 dependency

Signed-off-by: rfscholte <rfscholte@apache.org>
This commit is contained in:
Guillaume Nodet 2021-02-14 15:52:04 +01:00 committed by rfscholte
parent f820b41aed
commit 619973b91c
10 changed files with 601 additions and 706 deletions

View File

@ -71,6 +71,7 @@
import org.apache.maven.model.building.TransformerContext;
import org.apache.maven.model.resolution.ModelResolver;
import org.apache.maven.repository.internal.ArtifactDescriptorUtils;
import org.apache.maven.repository.internal.DefaultModelCache;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.util.Os;
import org.codehaus.plexus.util.StringUtils;
@ -92,9 +93,6 @@ public class DefaultProjectBuilder
implements ProjectBuilder
{
public static final String DISABLE_GLOBAL_MODEL_CACHE_SYSTEM_PROPERTY =
"maven.defaultProjectBuilder.disableGlobalModelCache";
@Inject
private Logger logger;
@ -119,8 +117,6 @@ public class DefaultProjectBuilder
@Inject
private ProjectDependenciesResolver dependencyResolver;
private final ReactorModelCache modelCache = new ReactorModelCache();
// ----------------------------------------------------------------------
// MavenProjectBuilder Implementation
// ----------------------------------------------------------------------
@ -130,12 +126,7 @@ public ProjectBuildingResult build( File pomFile, ProjectBuildingRequest request
throws ProjectBuildingException
{
return build( pomFile, new FileModelSource( pomFile ),
new InternalConfig( request, null, useGlobalModelCache() ? getModelCache() : null, null ) );
}
private boolean useGlobalModelCache()
{
return !Boolean.getBoolean( DISABLE_GLOBAL_MODEL_CACHE_SYSTEM_PROPERTY );
new InternalConfig( request, null, null ) );
}
@Override
@ -143,7 +134,7 @@ public ProjectBuildingResult build( ModelSource modelSource, ProjectBuildingRequ
throws ProjectBuildingException
{
return build( null, modelSource,
new InternalConfig( request, null, useGlobalModelCache() ? getModelCache() : null, null ) );
new InternalConfig( request, null, null ) );
}
private ProjectBuildingResult build( File pomFile, ModelSource modelSource, InternalConfig config )
@ -288,7 +279,7 @@ private ModelBuildingRequest getModelBuildingRequest( InternalConfig config )
request.setUserProperties( configuration.getUserProperties() );
request.setBuildStartTime( configuration.getBuildStartTime() );
request.setModelResolver( resolver );
request.setModelCache( config.modelCache );
request.setModelCache( DefaultModelCache.newInstance( config.session ) );
request.setTransformerContextBuilder( config.transformerContextBuilder );
return request;
@ -309,7 +300,7 @@ public ProjectBuildingResult build( Artifact artifact, boolean allowStubModel, P
pomArtifact = ArtifactDescriptorUtils.toPomArtifact( pomArtifact );
InternalConfig config =
new InternalConfig( request, null, useGlobalModelCache() ? getModelCache() : null, null );
new InternalConfig( request, null, null );
boolean localProject;
@ -382,8 +373,7 @@ public List<ProjectBuildingResult> build( List<File> pomFiles, boolean recursive
final ReactorModelPool modelPool = poolBuilder.build();
InternalConfig config =
new InternalConfig( request, modelPool, useGlobalModelCache() ? getModelCache() : new ReactorModelCache(),
modelBuilder.newTransformerContextBuilder() );
new InternalConfig( request, modelPool, modelBuilder.newTransformerContextBuilder() );
Map<File, MavenProject> projectIndex = new HashMap<>( 256 );
@ -1023,16 +1013,13 @@ class InternalConfig
private final ReactorModelPool modelPool;
private final ReactorModelCache modelCache;
private final TransformerContextBuilder transformerContextBuilder;
InternalConfig( ProjectBuildingRequest request, ReactorModelPool modelPool, ReactorModelCache modelCache,
InternalConfig( ProjectBuildingRequest request, ReactorModelPool modelPool,
TransformerContextBuilder transformerContextBuilder )
{
this.request = request;
this.modelPool = modelPool;
this.modelCache = modelCache;
this.transformerContextBuilder = transformerContextBuilder;
session =
@ -1044,9 +1031,4 @@ class InternalConfig
}
private ReactorModelCache getModelCache()
{
return this.modelCache;
}
}

View File

@ -1,160 +0,0 @@
package org.apache.maven.project;
/*
* 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 org.apache.maven.building.Source;
import org.apache.maven.model.building.ModelCache;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
/**
* A simple model cache used to accelerate model building during a reactor build.
*
* @author Benjamin Bentmann
*/
class ReactorModelCache
implements ModelCache
{
private final Map<Object, Object> models = new ConcurrentHashMap<>( 256 );
@Override
public Object get( String groupId, String artifactId, String version, String tag )
{
return models.get( new GavCacheKey( groupId, artifactId, version, tag ) );
}
@Override
public void put( String groupId, String artifactId, String version, String tag, Object data )
{
models.put( new GavCacheKey( groupId, artifactId, version, tag ), data );
}
@Override
public Object get( Source source, String tag )
{
return models.get( new SourceCacheKey( source, tag ) );
}
@Override
public void put( Source source, String tag, Object data )
{
models.put( new SourceCacheKey( source, tag ), data );
}
private static final class GavCacheKey
{
private final String groupId;
private final String artifactId;
private final String version;
private final String tag;
private final int hashCode;
GavCacheKey( String groupId, String artifactId, String version, String tag )
{
this.groupId = ( groupId != null ) ? groupId : "";
this.artifactId = ( artifactId != null ) ? artifactId : "";
this.version = ( version != null ) ? version : "";
this.tag = ( tag != null ) ? tag : "";
this.hashCode = Objects.hash( groupId, artifactId, version, tag );
}
@Override
public boolean equals( Object obj )
{
if ( this == obj )
{
return true;
}
if ( !( obj instanceof GavCacheKey ) )
{
return false;
}
GavCacheKey that = (GavCacheKey) obj;
return artifactId.equals( that.artifactId ) && groupId.equals( that.groupId )
&& version.equals( that.version ) && tag.equals( that.tag );
}
@Override
public int hashCode()
{
return hashCode;
}
}
private static final class SourceCacheKey
{
private final Source source;
private final String tag;
private final int hashCode;
SourceCacheKey( Source source, String tag )
{
this.source = source;
this.tag = tag;
this.hashCode = Objects.hash( source, tag );
}
@Override
public int hashCode()
{
return hashCode;
}
@Override
public boolean equals( Object obj )
{
if ( this == obj )
{
return true;
}
if ( !( obj instanceof SourceCacheKey ) )
{
return false;
}
SourceCacheKey other = (SourceCacheKey) obj;
if ( !Objects.equals( this.source, other.source ) )
{
return false;
}
if ( !Objects.equals( this.tag, other.tag ) )
{
return false;
}
return true;
}
}
}

View File

@ -150,7 +150,6 @@ public void testDontResolveDependencies()
@Test
public void testReadModifiedPoms() throws Exception {
String initialValue = System.setProperty( DefaultProjectBuilder.DISABLE_GLOBAL_MODEL_CACHE_SYSTEM_PROPERTY, Boolean.toString( true ) );
// TODO a similar test should be created to test the dependency management (basically all usages
// of DefaultModelBuilder.getCache() are affected by MNG-6530
@ -177,14 +176,6 @@ public void testReadModifiedPoms() throws Exception {
}
finally
{
if ( initialValue == null )
{
System.clearProperty( DefaultProjectBuilder.DISABLE_GLOBAL_MODEL_CACHE_SYSTEM_PROPERTY );
}
else
{
System.setProperty( DefaultProjectBuilder.DISABLE_GLOBAL_MODEL_CACHE_SYSTEM_PROPERTY, initialValue );
}
FileUtils.deleteDirectory( tempDir.toFile() );
}
}

View File

@ -83,6 +83,7 @@
import org.codehaus.plexus.logging.LoggerManager;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import org.eclipse.aether.DefaultRepositoryCache;
import org.eclipse.aether.transfer.TransferListener;
import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
@ -975,6 +976,11 @@ private int execute( CliRequest cliRequest )
{
MavenExecutionRequest request = executionRequestPopulator.populateDefaults( cliRequest.request );
if ( cliRequest.request.getRepositoryCache() == null )
{
cliRequest.request.setRepositoryCache( new DefaultRepositoryCache() );
}
eventSpyDispatcher.onEvent( request );
MavenExecutionResult result = maven.execute( request );

View File

@ -22,7 +22,6 @@
import static org.apache.maven.model.building.Result.error;
import static org.apache.maven.model.building.Result.newResult;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
@ -52,21 +51,15 @@
import org.apache.maven.feature.Features;
import org.apache.maven.model.Activation;
import org.apache.maven.model.Build;
import org.apache.maven.model.BuildBase;
import org.apache.maven.model.CiManagement;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.DependencyManagement;
import org.apache.maven.model.InputLocation;
import org.apache.maven.model.InputSource;
import org.apache.maven.model.Model;
import org.apache.maven.model.ModelBase;
import org.apache.maven.model.Parent;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginContainer;
import org.apache.maven.model.PluginManagement;
import org.apache.maven.model.Profile;
import org.apache.maven.model.ReportPlugin;
import org.apache.maven.model.Reporting;
import org.apache.maven.model.Repository;
import org.apache.maven.model.building.ModelProblem.Severity;
import org.apache.maven.model.building.ModelProblem.Version;
@ -275,7 +268,6 @@ public ModelBuildingResult build( ModelBuildingRequest request )
return build( request, new LinkedHashSet<>() );
}
@SuppressWarnings( "checkstyle:methodlength" )
protected ModelBuildingResult build( ModelBuildingRequest request, Collection<String> importIds )
throws ModelBuildingException
{
@ -388,7 +380,7 @@ private Model readEffectiveModel( final ModelBuildingRequest request, final Defa
List<Model> lineage = new ArrayList<>();
for ( ModelData currentData = resultData; currentData != null; )
for ( ModelData currentData = resultData; ; )
{
String modelId = currentData.getId();
result.addModelId( modelId );
@ -586,18 +578,38 @@ public Result<? extends Model> buildRawModel( File pomFile, int validationLevel,
}
}
@SuppressWarnings( "checkstyle:methodlength" )
private Model readFileModel( ModelBuildingRequest request,
DefaultModelProblemCollector problems )
throws ModelBuildingException
{
ModelSource modelSource = request.getModelSource();
Model model = getModelFromCache( modelSource, request.getModelCache() );
if ( model != null )
Model model = fromCache( request.getModelCache(), modelSource, ModelCacheTag.FILE );
if ( model == null )
{
return model;
model = doReadFileModel( modelSource, request, problems );
intoCache( request.getModelCache(), modelSource, ModelCacheTag.FILE, model );
}
if ( modelSource instanceof FileModelSource )
{
if ( request.getTransformerContextBuilder() instanceof DefaultTransformerContextBuilder )
{
DefaultTransformerContextBuilder contextBuilder =
(DefaultTransformerContextBuilder) request.getTransformerContextBuilder();
contextBuilder.putSource( getGroupId( model ), model.getArtifactId(), modelSource );
}
}
return model;
}
@SuppressWarnings( "checkstyle:methodlength" )
private Model doReadFileModel( ModelSource modelSource, ModelBuildingRequest request,
DefaultModelProblemCollector problems )
throws ModelBuildingException
{
Model model;
problems.setSource( modelSource.getLocation() );
try
{
@ -640,18 +652,10 @@ private Model readFileModel( ModelBuildingRequest request,
throw e;
}
if ( modelSource instanceof FileModelSource )
{
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 ) );
}
Severity severity = ( modelSource instanceof FileModelSource ) ? Severity.ERROR : Severity.WARNING;
problems.add( new ModelProblemCollectorRequest( severity, Version.V20 )
.setMessage( "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage() )
.setException( e ) );
}
if ( source != null )
@ -700,17 +704,6 @@ private Model readFileModel( ModelBuildingRequest request,
throw problems.newModelBuildingException();
}
intoCache( request.getModelCache(), modelSource, ModelCacheTag.FILE, model );
if ( modelSource instanceof FileModelSource )
{
if ( request.getTransformerContextBuilder() instanceof DefaultTransformerContextBuilder )
{
DefaultTransformerContextBuilder contextBuilder =
(DefaultTransformerContextBuilder) request.getTransformerContextBuilder();
contextBuilder.putSource( getGroupId( model ), model.getArtifactId(), modelSource );
}
}
return model;
}
@ -722,7 +715,7 @@ private Model readRawModel( ModelBuildingRequest request, DefaultModelProblemCol
ModelData cachedData = fromCache( request.getModelCache(), modelSource, ModelCacheTag.RAW );
if ( cachedData != null )
{
return cachedData.getModel();
return cachedData.getModel();
}
Model rawModel;
@ -774,37 +767,11 @@ else if ( request.getFileModel() == null )
String version = getVersion( rawModel );
ModelData modelData = new ModelData( modelSource, rawModel, groupId, artifactId, version );
intoCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.RAW, modelData );
intoCache( request.getModelCache(), modelSource, ModelCacheTag.RAW, modelData );
return rawModel;
}
private Model getModelFromCache( Source source, ModelCache cache )
{
Model model;
if ( source instanceof ArtifactModelSource )
{
ArtifactModelSource artifactModelSource = ( ArtifactModelSource ) source;
ModelData modelData = fromCache( cache, artifactModelSource.getGroupId(),
artifactModelSource.getArtifactId(),
artifactModelSource.getVersion(), ModelCacheTag.RAW );
if ( modelData != null )
{
model = modelData.getModel();
}
else
{
model = null;
}
}
else
{
model = fromCache( cache, source, ModelCacheTag.FILE );
}
return model;
}
private String getGroupId( Model model )
{
String groupId = model.getGroupId();
@ -1014,75 +981,21 @@ private ModelData readParent( Model childModel, Source childSource, ModelBuildin
ModelData parentData = null;
Parent parent = childModel.getParent();
if ( parent != null )
{
Source expectedParentSource = getParentPomFile( childModel, childSource );
if ( expectedParentSource != null )
{
ModelData candidateData = readParentLocally( childModel, childSource, request, result, problems );
if ( candidateData != null )
{
/*
* NOTE: This is a sanity check of the cache hit. If the cached parent POM was locally resolved,
* the child's GAV should match with that parent, too. If it doesn't, we ignore the cache and
* resolve externally, to mimic the behavior if the cache didn't exist in the first place.
* Otherwise, the cache would obscure a bad POM.
*/
try
{
VersionRange parentVersion = VersionRange.createFromVersionSpec( parent.getVersion() );
ArtifactVersion actualVersion = new DefaultArtifactVersion( candidateData.getVersion() );
if ( parent.getGroupId().equals( candidateData.getGroupId() )
&& parent.getArtifactId().equals( candidateData.getArtifactId() )
&& parentVersion.containsVersion( actualVersion ) )
{
parentData = candidateData;
}
}
catch ( InvalidVersionSpecificationException e )
{
// This should already been blocked during validation
}
}
}
parentData = readParentLocally( childModel, childSource, request, result, problems );
if ( parentData == null )
{
ModelData candidateData = fromCache( request.getModelCache(),
parent.getGroupId(), parent.getArtifactId(),
parent.getVersion(), ModelCacheTag.RAW );
if ( candidateData != null && candidateData.getSource() instanceof ArtifactModelSource )
{
// ArtifactModelSource means repositorySource
parentData = candidateData;
}
else
{
parentData = readParentExternally( childModel, request, result, problems );
intoCache( request.getModelCache(),
parentData.getGroupId(), parentData.getArtifactId(),
parentData.getVersion(), ModelCacheTag.RAW, parentData );
}
parentData = readParentExternally( childModel, request, result, problems );
}
if ( parentData != null )
Model parentModel = parentData.getModel();
if ( !"pom".equals( parentModel.getPackaging() ) )
{
Model parentModel = parentData.getModel();
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" ) ) );
}
}
@ -1106,14 +1019,8 @@ private ModelData readParentLocally( Model childModel, Source childSource, Model
return null;
}
ModelBuildingRequest candidateBuildRequest = new FilterModelBuildingRequest( request )
{
@Override
public ModelSource getModelSource()
{
return candidateSource;
}
};
ModelBuildingRequest candidateBuildRequest = new DefaultModelBuildingRequest( request )
.setModelSource( candidateSource );
candidateModel = readRawModel( candidateBuildRequest, problems );
}
@ -1127,7 +1034,7 @@ public ModelSource getModelSource()
catch ( UnresolvableModelException e )
{
problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ) //
.setMessage( e.getMessage() ).setLocation( parent.getLocation( "" ) ).setException( e ) );
.setMessage( e.getMessage() ).setLocation( parent.getLocation( "" ) ).setException( e ) );
throw problems.newModelBuildingException();
}
if ( candidateModel == null )
@ -1143,11 +1050,7 @@ public ModelSource getModelSource()
// before because with parents as ranges it will never work in this scenario.
//
String groupId = candidateModel.getGroupId();
if ( groupId == null && candidateModel.getParent() != null )
{
groupId = candidateModel.getParent().getGroupId();
}
String groupId = getGroupId( candidateModel );
String artifactId = candidateModel.getArtifactId();
if ( groupId == null || !groupId.equals( parent.getGroupId() ) || artifactId == null
@ -1169,11 +1072,7 @@ public ModelSource getModelSource()
return null;
}
String version = candidateModel.getVersion();
if ( version == null && candidateModel.getParent() != null )
{
version = candidateModel.getParent().getVersion();
}
String version = getVersion( candidateModel );
if ( version != null && parent.getVersion() != null && !version.equals( parent.getVersion() ) )
{
try
@ -1303,25 +1202,10 @@ private ModelData readParentExternally( Model childModel, ModelBuildingRequest r
}
int validationLevel = Math.min( request.getValidationLevel(), ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 );
ModelBuildingRequest lenientRequest = new FilterModelBuildingRequest( request )
{
@Override
public int getValidationLevel()
{
return validationLevel;
}
@Override
public ModelSource getModelSource()
{
return modelSource;
}
@Override
public Model getFileModel()
{
return null;
}
};
ModelBuildingRequest lenientRequest = new DefaultModelBuildingRequest( request )
.setValidationLevel( validationLevel )
.setFileModel( null )
.setModelSource( modelSource );
Model parentModel = readRawModel( lenientRequest, problems );
@ -1358,7 +1242,6 @@ private Model getSuperModel()
return superPomProvider.getSuperModel( "4.0.0" ).clone();
}
@SuppressWarnings( "checkstyle:methodlength" )
private void importDependencyManagement( Model model, ModelBuildingRequest request,
DefaultModelProblemCollector problems, Collection<String> importIds )
{
@ -1373,11 +1256,6 @@ private void importDependencyManagement( Model model, ModelBuildingRequest reque
importIds.add( importing );
final WorkspaceModelResolver workspaceResolver = request.getWorkspaceModelResolver();
final ModelResolver modelResolver = request.getModelResolver();
ModelBuildingRequest importRequest = null;
List<DependencyManagement> importMgmts = null;
for ( Iterator<Dependency> it = depMgmt.getDependencies().iterator(); it.hasNext(); )
@ -1391,148 +1269,18 @@ private void importDependencyManagement( Model model, ModelBuildingRequest reque
it.remove();
String groupId = dependency.getGroupId();
String artifactId = dependency.getArtifactId();
String version = dependency.getVersion();
DependencyManagement importMgmt = loadDependencyManagement( model, request, problems,
dependency, importIds );
if ( groupId == null || groupId.length() <= 0 )
if ( importMgmt != null )
{
problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
.setMessage( "'dependencyManagement.dependencies.dependency.groupId' for "
+ dependency.getManagementKey() + " is missing." )
.setLocation( dependency.getLocation( "" ) ) );
continue;
}
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( "" ) ) );
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( "" ) ) );
continue;
}
String imported = groupId + ':' + artifactId + ':' + version;
if ( importIds.contains( imported ) )
{
String message = "The dependencies of type=pom and with scope=import form a cycle: ";
for ( String modelId : importIds )
if ( importMgmts == null )
{
message += modelId + " -> ";
}
message += imported;
problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).setMessage( message ) );
continue;
}
DependencyManagement importMgmt = fromCache( request.getModelCache(), groupId, artifactId, version,
ModelCacheTag.IMPORT );
if ( importMgmt == null )
{
if ( workspaceResolver == null && modelResolver == null )
{
throw new NullPointerException( String.format(
"request.workspaceModelResolver and request.modelResolver cannot be null"
+ " (parent POM %s and POM %s)",
ModelProblemUtils.toId( groupId, artifactId, version ),
ModelProblemUtils.toSourceHint( model ) ) );
importMgmts = new ArrayList<>();
}
Model importModel = null;
if ( workspaceResolver != null )
{
try
{
importModel = workspaceResolver.resolveEffectiveModel( groupId, artifactId, version );
}
catch ( UnresolvableModelException e )
{
problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE )
.setMessage( e.getMessage() ).setException( e ) );
continue;
}
}
// no workspace resolver or workspace resolver returned null (i.e. model not in workspace)
if ( importModel == null )
{
final ModelSource importSource;
try
{
importSource = modelResolver.resolveModel( dependency );
}
catch ( UnresolvableModelException e )
{
StringBuilder buffer = new StringBuilder( 256 );
buffer.append( "Non-resolvable import POM" );
if ( !containsCoordinates( e.getMessage(), groupId, artifactId, version ) )
{
buffer.append( ' ' ).append( ModelProblemUtils.toId( groupId, artifactId, version ) );
}
buffer.append( ": " ).append( e.getMessage() );
problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
.setMessage( buffer.toString() ).setLocation( dependency.getLocation( "" ) )
.setException( e ) );
continue;
}
if ( importRequest == null )
{
importRequest = new DefaultModelBuildingRequest();
importRequest.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
importRequest.setModelCache( request.getModelCache() );
importRequest.setSystemProperties( request.getSystemProperties() );
importRequest.setUserProperties( request.getUserProperties() );
importRequest.setLocationTracking( request.isLocationTracking() );
}
importRequest.setModelSource( importSource );
importRequest.setModelResolver( modelResolver.newCopy() );
final ModelBuildingResult importResult;
try
{
importResult = build( importRequest, importIds );
}
catch ( ModelBuildingException e )
{
problems.addAll( e.getProblems() );
continue;
}
problems.addAll( importResult.getProblems() );
importModel = importResult.getEffectiveModel();
}
importMgmt = importModel.getDependencyManagement();
if ( importMgmt == null )
{
importMgmt = new DependencyManagement();
}
intoCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT, importMgmt );
importMgmts.add( importMgmt );
}
if ( importMgmts == null )
{
importMgmts = new ArrayList<>();
}
importMgmts.add( importMgmt );
}
importIds.remove( importing );
@ -1540,12 +1288,166 @@ private void importDependencyManagement( Model model, ModelBuildingRequest reque
dependencyManagementImporter.importManagement( model, importMgmts, request, problems );
}
private DependencyManagement loadDependencyManagement( Model model, ModelBuildingRequest request,
DefaultModelProblemCollector problems,
Dependency dependency,
Collection<String> importIds )
{
String groupId = dependency.getGroupId();
String artifactId = dependency.getArtifactId();
String version = dependency.getVersion();
if ( groupId == null || groupId.length() <= 0 )
{
problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
.setMessage( "'dependencyManagement.dependencies.dependency.groupId' for "
+ dependency.getManagementKey() + " is missing." )
.setLocation( dependency.getLocation( "" ) ) );
return null;
}
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( "" ) ) );
return null;
}
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( "" ) ) );
return null;
}
String imported = groupId + ':' + artifactId + ':' + version;
if ( importIds.contains( imported ) )
{
String message = "The dependencies of type=pom and with scope=import form a cycle: ";
for ( String modelId : importIds )
{
message += modelId + " -> ";
}
message += imported;
problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).setMessage( message ) );
return null;
}
DependencyManagement importMgmt = fromCache( request.getModelCache(), groupId, artifactId, version,
ModelCacheTag.IMPORT );
if ( importMgmt == null )
{
importMgmt = doLoadDependencyManagement( model, request, problems, dependency,
groupId, artifactId, version, importIds );
if ( importMgmt != null )
{
intoCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT, importMgmt );
}
}
return importMgmt;
}
@SuppressWarnings( "checkstyle:parameternumber" )
private DependencyManagement doLoadDependencyManagement( Model model, ModelBuildingRequest request,
DefaultModelProblemCollector problems,
Dependency dependency,
String groupId,
String artifactId,
String version,
Collection<String> importIds )
{
DependencyManagement importMgmt;
final WorkspaceModelResolver workspaceResolver = request.getWorkspaceModelResolver();
final ModelResolver modelResolver = request.getModelResolver();
if ( workspaceResolver == null && modelResolver == null )
{
throw new NullPointerException( String.format(
"request.workspaceModelResolver and request.modelResolver cannot be null (parent POM %s and POM %s)",
ModelProblemUtils.toId( groupId, artifactId, version ),
ModelProblemUtils.toSourceHint( model ) ) );
}
Model importModel = null;
if ( workspaceResolver != null )
{
try
{
importModel = workspaceResolver.resolveEffectiveModel( groupId, artifactId, version );
}
catch ( UnresolvableModelException e )
{
problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE )
.setMessage( e.getMessage() ).setException( e ) );
return null;
}
}
// no workspace resolver or workspace resolver returned null (i.e. model not in workspace)
if ( importModel == null )
{
final ModelSource importSource;
try
{
importSource = modelResolver.resolveModel( dependency );
}
catch ( UnresolvableModelException e )
{
StringBuilder buffer = new StringBuilder( 256 );
buffer.append( "Non-resolvable import POM" );
if ( !containsCoordinates( e.getMessage(), groupId, artifactId, version ) )
{
buffer.append( ' ' ).append( ModelProblemUtils.toId( groupId, artifactId, version ) );
}
buffer.append( ": " ).append( e.getMessage() );
problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
.setMessage( buffer.toString() ).setLocation( dependency.getLocation( "" ) )
.setException( e ) );
return null;
}
final ModelBuildingResult importResult;
try
{
ModelBuildingRequest importRequest = new DefaultModelBuildingRequest( request )
.setTwoPhaseBuilding( false )
.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL )
.setModelSource( importSource )
.setModelResolver( modelResolver.newCopy() );
importResult = build( importRequest, importIds );
}
catch ( ModelBuildingException e )
{
problems.addAll( e.getProblems() );
return null;
}
problems.addAll( importResult.getProblems() );
importModel = importResult.getEffectiveModel();
}
importMgmt = importModel.getDependencyManagement();
if ( importMgmt == null )
{
importMgmt = new DependencyManagement();
}
return importMgmt;
}
private <T> void intoCache( ModelCache modelCache, String groupId, String artifactId, String version,
ModelCacheTag<T> tag, T data )
{
if ( modelCache != null )
{
modelCache.put( groupId, artifactId, version, tag.getName(), tag.intoCache( data ) );
modelCache.put( groupId, artifactId, version, tag, data );
}
}
@ -1553,7 +1455,7 @@ private <T> void intoCache( ModelCache modelCache, Source source, ModelCacheTag<
{
if ( modelCache != null )
{
modelCache.put( source, tag.getName(), tag.intoCache( data ) );
modelCache.put( source, tag, data );
}
}
@ -1562,11 +1464,7 @@ private static <T> T fromCache( ModelCache modelCache, String groupId, String ar
{
if ( modelCache != null )
{
Object data = modelCache.get( groupId, artifactId, version, tag.getName() );
if ( data != null )
{
return tag.fromCache( tag.getType().cast( data ) );
}
return modelCache.get( groupId, artifactId, version, tag );
}
return null;
}
@ -1575,11 +1473,7 @@ private static <T> T fromCache( ModelCache modelCache, Source source, ModelCache
{
if ( modelCache != null )
{
Object data = modelCache.get( source, tag.getName() );
if ( data != null )
{
return tag.fromCache( tag.getType().cast( data ) );
}
return modelCache.get( source, tag );
}
return null;
}
@ -1633,158 +1527,6 @@ protected boolean hasFatalErrors( ModelProblemCollectorExt problems )
}
}
/**
* As long as Maven controls the BuildPomXMLFilter, the entities that need merging are known.
* All others can simply be copied from source to target to restore the locationTracker
*
* @author Robert Scholte
* @since 4.0.0
*/
class FileToRawModelMerger extends ModelMerger
{
@Override
protected void mergeBuild_Extensions( Build target, Build source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergeBuildBase_Resources( BuildBase target, BuildBase source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergeBuildBase_TestResources( BuildBase target, BuildBase source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergeCiManagement_Notifiers( CiManagement target, CiManagement source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergeDependencyManagement_Dependencies( DependencyManagement target, DependencyManagement source,
boolean sourceDominant, Map<Object, Object> context )
{
Iterator<Dependency> sourceIterator = source.getDependencies().iterator();
target.getDependencies().stream().forEach( t -> mergeDependency( t, sourceIterator.next(), sourceDominant,
context ) );
}
@Override
protected void mergeDependency_Exclusions( Dependency target, Dependency source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergeModel_Contributors( Model target, Model source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergeModel_Developers( Model target, Model source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergeModel_Licenses( Model target, Model source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergeModel_MailingLists( Model target, Model source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergeModel_Profiles( Model target, Model source, boolean sourceDominant,
Map<Object, Object> context )
{
Iterator<Profile> sourceIterator = source.getProfiles().iterator();
target.getProfiles().stream().forEach( t -> mergeProfile( t, sourceIterator.next(), sourceDominant,
context ) );
}
@Override
protected void mergeModelBase_Dependencies( ModelBase target, ModelBase source, boolean sourceDominant,
Map<Object, Object> context )
{
Iterator<Dependency> sourceIterator = source.getDependencies().iterator();
target.getDependencies().stream().forEach( t -> mergeDependency( t, sourceIterator.next(), sourceDominant,
context ) );
}
@Override
protected void mergeModelBase_PluginRepositories( ModelBase target, ModelBase source, boolean sourceDominant,
Map<Object, Object> context )
{
target.setPluginRepositories( source.getPluginRepositories() );
}
@Override
protected void mergeModelBase_Repositories( ModelBase target, ModelBase source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergePlugin_Dependencies( Plugin target, Plugin source, boolean sourceDominant,
Map<Object, Object> context )
{
Iterator<Dependency> sourceIterator = source.getDependencies().iterator();
target.getDependencies().stream().forEach( t -> mergeDependency( t, sourceIterator.next(), sourceDominant,
context ) );
}
@Override
protected void mergePlugin_Executions( Plugin target, Plugin source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergeReporting_Plugins( Reporting target, Reporting source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergeReportPlugin_ReportSets( ReportPlugin target, ReportPlugin source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergePluginContainer_Plugins( PluginContainer target, PluginContainer source,
boolean sourceDominant, Map<Object, Object> context )
{
// don't merge
}
}
/**
* Builds up the transformer context.
* After the buildplan is ready, the build()-method returns the immutable context useful during distribution.
@ -1841,15 +1583,8 @@ private Model findRawModel( String groupId, String artifactId )
{
try
{
ModelBuildingRequest gaBuildingRequest = new FilterModelBuildingRequest( request )
{
@Override
public ModelSource getModelSource()
{
return (ModelSource) source;
}
};
ModelBuildingRequest gaBuildingRequest = new DefaultModelBuildingRequest( request )
.setModelSource( (ModelSource) source );
return readRawModel( gaBuildingRequest, problems );
}
catch ( ModelBuildingException e )

View File

@ -102,6 +102,7 @@ public DefaultModelBuildingRequest( ModelBuildingRequest request )
setModelResolver( request.getModelResolver() );
setModelBuildingListener( request.getModelBuildingListener() );
setModelCache( request.getModelCache() );
setWorkspaceModelResolver( request.getWorkspaceModelResolver() );
setTransformerContextBuilder( request.getTransformerContextBuilder() );
}

View File

@ -0,0 +1,190 @@
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.util.Iterator;
import java.util.Map;
import org.apache.maven.model.Build;
import org.apache.maven.model.BuildBase;
import org.apache.maven.model.CiManagement;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.DependencyManagement;
import org.apache.maven.model.Model;
import org.apache.maven.model.ModelBase;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginContainer;
import org.apache.maven.model.Profile;
import org.apache.maven.model.ReportPlugin;
import org.apache.maven.model.Reporting;
import org.apache.maven.model.merge.ModelMerger;
/**
* As long as Maven controls the BuildPomXMLFilter, the entities that need merging are known.
* All others can simply be copied from source to target to restore the locationTracker
*
* @author Robert Scholte
* @since 4.0.0
*/
class FileToRawModelMerger extends ModelMerger
{
@Override
protected void mergeBuild_Extensions( Build target, Build source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergeBuildBase_Resources( BuildBase target, BuildBase source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergeBuildBase_TestResources( BuildBase target, BuildBase source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergeCiManagement_Notifiers( CiManagement target, CiManagement source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergeDependencyManagement_Dependencies( DependencyManagement target, DependencyManagement source,
boolean sourceDominant, Map<Object, Object> context )
{
Iterator<Dependency> sourceIterator = source.getDependencies().iterator();
target.getDependencies().stream().forEach( t -> mergeDependency( t, sourceIterator.next(), sourceDominant,
context ) );
}
@Override
protected void mergeDependency_Exclusions( Dependency target, Dependency source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergeModel_Contributors( Model target, Model source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergeModel_Developers( Model target, Model source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergeModel_Licenses( Model target, Model source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergeModel_MailingLists( Model target, Model source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergeModel_Profiles( Model target, Model source, boolean sourceDominant,
Map<Object, Object> context )
{
Iterator<Profile> sourceIterator = source.getProfiles().iterator();
target.getProfiles().stream().forEach( t -> mergeProfile( t, sourceIterator.next(), sourceDominant,
context ) );
}
@Override
protected void mergeModelBase_Dependencies( ModelBase target, ModelBase source, boolean sourceDominant,
Map<Object, Object> context )
{
Iterator<Dependency> sourceIterator = source.getDependencies().iterator();
target.getDependencies().stream().forEach( t -> mergeDependency( t, sourceIterator.next(), sourceDominant,
context ) );
}
@Override
protected void mergeModelBase_PluginRepositories( ModelBase target, ModelBase source, boolean sourceDominant,
Map<Object, Object> context )
{
target.setPluginRepositories( source.getPluginRepositories() );
}
@Override
protected void mergeModelBase_Repositories( ModelBase target, ModelBase source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergePlugin_Dependencies( Plugin target, Plugin source, boolean sourceDominant,
Map<Object, Object> context )
{
Iterator<Dependency> sourceIterator = source.getDependencies().iterator();
target.getDependencies().stream().forEach( t -> mergeDependency( t, sourceIterator.next(), sourceDominant,
context ) );
}
@Override
protected void mergePlugin_Executions( Plugin target, Plugin source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergeReporting_Plugins( Reporting target, Reporting source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergeReportPlugin_ReportSets( ReportPlugin target, ReportPlugin source, boolean sourceDominant,
Map<Object, Object> context )
{
// don't merge
}
@Override
protected void mergePluginContainer_Plugins( PluginContainer target, PluginContainer source,
boolean sourceDominant, Map<Object, Object> context )
{
// don't merge
}
}

View File

@ -82,4 +82,60 @@ default Object get( Source path, String tag )
*/
Object get( String groupId, String artifactId, String version, String tag );
/**
* Puts the specified data into the cache.
*
* @param path The path of the cache record, must not be {@code null}.
* @param tag The tag of the cache record, must not be {@code null}.
* @param data The data to store in the cache, must not be {@code null}.
* @since 3.7.0
*/
default <T> void put( Source path, ModelCacheTag<T> tag, T data )
{
put( path, tag.getName(), tag.intoCache( data ) );
}
/**
* Gets the specified data from the cache.
*
* @param path The path of the cache record, must not be {@code null}.
* @param tag The tag of the cache record, must not be {@code null}.
* @return The requested data or {@code null} if none was present in the cache.
* @since 3.7.0
*/
default <T> T get( Source path, ModelCacheTag<T> tag )
{
Object obj = get( path, tag.getName() );
return ( obj != null ) ? tag.fromCache( tag.getType().cast( obj ) ) : null;
}
/**
* Puts the specified data into the cache.
*
* @param groupId The group id of the cache record, must not be {@code null}.
* @param artifactId The artifact id of the cache record, must not be {@code null}.
* @param version The version of the cache record, must not be {@code null}.
* @param tag The tag of the cache record, must not be {@code null}.
* @param data The data to store in the cache, must not be {@code null}.
*/
default <T> void put( String groupId, String artifactId, String version, ModelCacheTag<T> tag, T data )
{
put( groupId, artifactId, version, tag.getName(), tag.intoCache( data ) );
}
/**
* Gets the specified data from the cache.
*
* @param groupId The group id of the cache record, must not be {@code null}.
* @param artifactId The artifact id of the cache record, must not be {@code null}.
* @param version The version of the cache record, must not be {@code null}.
* @param tag The tag of the cache record, must not be {@code null}.
* @return The requested data or {@code null} if none was present in the cache.
*/
default <T> T get( String groupId, String artifactId, String version, ModelCacheTag<T> tag )
{
Object obj = get( groupId, artifactId, version, tag.getName() );
return ( obj != null ) ? tag.fromCache( tag.getType().cast( obj ) ) : null;
}
}

View File

@ -26,7 +26,6 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.maven.model.building.DefaultModelBuilder.FileToRawModelMerger;
import org.apache.maven.model.merge.ModelMerger;
import org.junit.jupiter.api.Test;

View File

@ -19,8 +19,12 @@
* under the License.
*/
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.maven.building.Source;
import org.apache.maven.model.building.ModelCache;
import org.eclipse.aether.RepositoryCache;
import org.eclipse.aether.RepositorySystemSession;
/**
@ -28,68 +32,107 @@
*
* @author Benjamin Bentmann
*/
class DefaultModelCache
public class DefaultModelCache
implements ModelCache
{
private final RepositorySystemSession session;
private static final String KEY = DefaultModelCache.class.getName();
private final RepositoryCache cache;
private final Map<Object, Object> cache;
public static ModelCache newInstance( RepositorySystemSession session )
{
Map<Object, Object> cache;
if ( session.getCache() == null )
{
return null;
cache = new ConcurrentHashMap<>();
}
else
{
return new DefaultModelCache( session );
cache = ( Map ) session.getCache().get( session, KEY );
if ( cache == null )
{
cache = new ConcurrentHashMap<>();
session.getCache().put( session, KEY, cache );
}
}
return new DefaultModelCache( cache );
}
private DefaultModelCache( RepositorySystemSession session )
private DefaultModelCache( Map<Object, Object> cache )
{
this.session = session;
this.cache = session.getCache();
this.cache = cache;
}
public Object get( Source path, String tag )
{
return get( new SourceCacheKey( path, tag ) );
}
public void put( Source path, String tag, Object data )
{
put( new SourceCacheKey( path, tag ), data );
}
public Object get( String groupId, String artifactId, String version, String tag )
{
return cache.get( session, new Key( groupId, artifactId, version, tag ) );
return get( new GavCacheKey( groupId, artifactId, version, tag ) );
}
public void put( String groupId, String artifactId, String version, String tag, Object data )
{
cache.put( session, new Key( groupId, artifactId, version, tag ), data );
put( new GavCacheKey( groupId, artifactId, version, tag ), data );
}
static class Key
protected Object get( Object key )
{
return cache.get( key );
}
protected void put( Object key, Object data )
{
cache.put( key, data );
}
static class GavCacheKey
{
private final String groupId;
private final String artifactId;
private final String version;
private final String gav;
private final String tag;
private final int hash;
Key( String groupId, String artifactId, String version, String tag )
GavCacheKey( String groupId, String artifactId, String version, String tag )
{
this.groupId = groupId;
this.artifactId = artifactId;
this.version = version;
this.tag = tag;
this( gav( groupId, artifactId, version ), tag );
}
int h = 17;
h = h * 31 + this.groupId.hashCode();
h = h * 31 + this.artifactId.hashCode();
h = h * 31 + this.version.hashCode();
h = h * 31 + this.tag.hashCode();
hash = h;
GavCacheKey( String gav, String tag )
{
this.gav = gav;
this.tag = tag;
this.hash = Objects.hash( gav, tag );
}
private static String gav( String groupId, String artifactId, String version )
{
StringBuilder sb = new StringBuilder();
if ( groupId != null )
{
sb.append( groupId );
}
sb.append( ":" );
if ( artifactId != null )
{
sb.append( artifactId );
}
sb.append( ":" );
if ( version != null )
{
sb.append( version );
}
return sb.toString();
}
@Override
@ -103,10 +146,8 @@ public boolean equals( Object obj )
{
return false;
}
Key that = (Key) obj;
return artifactId.equals( that.artifactId ) && groupId.equals( that.groupId )
&& version.equals( that.version ) && tag.equals( that.tag );
GavCacheKey that = (GavCacheKey) obj;
return Objects.equals( this.gav, that.gav ) && Objects.equals( this.tag, that.tag );
}
@Override
@ -115,5 +156,59 @@ public int hashCode()
return hash;
}
@Override
public String toString()
{
return "GavCacheKey{"
+ "gav='" + gav + '\''
+ ", tag='" + tag + '\''
+ '}';
}
}
private static final class SourceCacheKey
{
private final Source source;
private final String tag;
private final int hash;
SourceCacheKey( Source source, String tag )
{
this.source = source;
this.tag = tag;
this.hash = Objects.hash( source, tag );
}
@Override
public String toString()
{
return "SourceCacheKey{"
+ "source=" + source
+ ", tag='" + tag + '\''
+ '}';
}
@Override
public boolean equals( Object obj )
{
if ( this == obj )
{
return true;
}
if ( null == obj || !getClass().equals( obj.getClass() ) )
{
return false;
}
SourceCacheKey that = (SourceCacheKey) obj;
return Objects.equals( this.source, that.source ) && Objects.equals( this.tag, that.tag );
}
@Override
public int hashCode()
{
return hash;
}
}
}