Skip to content

Commit f97c405

Browse files
committed
[MNG-5102] Add support for POM mixins
1 parent adc13ea commit f97c405

File tree

2 files changed

+145
-90
lines changed

2 files changed

+145
-90
lines changed

api/maven-api-model/src/main/mdo/maven.mdo

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,20 @@
113113
</association>
114114
</field>
115115

116+
<!-- ====================================================================== -->
117+
<!-- Mixins -->
118+
<!-- ====================================================================== -->
119+
120+
<field xdoc.separator="blank">
121+
<name>mixins</name>
122+
<version>4.1.0+</version>
123+
<description>Mixins...</description>
124+
<association>
125+
<type>Parent</type>
126+
<multiplicity>*</multiplicity>
127+
</association>
128+
</field>
129+
116130
<!-- ====================================================================== -->
117131
<!-- groupId/artifactId/Version/Packaging -->
118132
<!-- ====================================================================== -->

maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java

Lines changed: 131 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,27 @@ private void activateFileModel(
719719
}
720720
}
721721

722+
static class Lineage {
723+
final Model model;
724+
final List<Lineage> parents;
725+
726+
Lineage(Model model, List<Lineage> parents) {
727+
this.model = model;
728+
this.parents = parents;
729+
}
730+
731+
List<Model> getAllModels() {
732+
List<Model> models = new ArrayList<>();
733+
doGetModels(models);
734+
return models;
735+
}
736+
737+
void doGetModels(List<Model> models) {
738+
models.add(model);
739+
parents.forEach(p -> p.doGetModels(models));
740+
}
741+
}
742+
722743
@SuppressWarnings("checkstyle:methodlength")
723744
private Model readEffectiveModel(
724745
final ModelBuildingRequest request,
@@ -746,100 +767,126 @@ private Model readEffectiveModel(
746767
profileActivationContext.setUserProperties(profileProps);
747768
}
748769

749-
Collection<String> parentIds = new LinkedHashSet<>();
770+
LinkedHashSet<String> parentIds = new LinkedHashSet<>();
771+
Lineage lineage =
772+
getLineage(request, result, problems, resultData, superData, profileActivationContext, true, parentIds);
750773

751-
List<Model> lineage = new ArrayList<>();
774+
Model tmpModel = lineage.model;
775+
for (Profile activeProfile : activeExternalProfiles) {
776+
profileInjector.injectProfile(tmpModel, activeProfile, request, problems);
777+
}
778+
result.setEffectiveModel(tmpModel);
752779

753-
for (ModelData currentData = resultData; ; ) {
754-
String modelId = currentData.getId();
755-
result.addModelId(modelId);
780+
problems.setSource(result.getRawModel());
781+
checkPluginVersions(lineage, request, problems);
756782

757-
Model rawModel = currentData.getModel();
758-
result.setRawModel(modelId, rawModel);
783+
// inheritance assembly
784+
Model resultModel = assembleInheritance(lineage, request, problems);
759785

760-
profileActivationContext.setProjectProperties(rawModel.getProperties());
761-
problems.setSource(rawModel);
762-
List<Profile> activePomProfiles =
763-
profileSelector.getActiveProfiles(rawModel.getProfiles(), profileActivationContext, problems);
764-
result.setActivePomProfiles(modelId, activePomProfiles);
786+
// consider caching inherited model
765787

766-
Model tmpModel = rawModel.clone();
788+
problems.setSource(resultModel);
789+
problems.setRootModel(resultModel);
767790

768-
problems.setSource(tmpModel);
791+
// model interpolation
792+
resultModel = interpolateModel(resultModel, request, problems);
769793

770-
// model normalization
771-
tmpModel = new Model(modelNormalizer.mergeDuplicates(tmpModel.getDelegate(), request, problems));
794+
// url normalization
795+
modelUrlNormalizer.normalize(resultModel, request);
772796

773-
profileActivationContext.setProjectProperties(tmpModel.getProperties());
797+
result.setEffectiveModel(resultModel);
774798

775-
Map<String, Activation> interpolatedActivations =
776-
getInterpolatedActivations(rawModel, profileActivationContext, problems);
777-
injectProfileActivations(tmpModel, interpolatedActivations);
799+
// Now the fully interpolated model is available: reconfigure the resolver
800+
configureResolver(request.getModelResolver(), resultModel, problems, true);
778801

779-
// profile injection
780-
for (Profile activeProfile : result.getActivePomProfiles(modelId)) {
781-
profileInjector.injectProfile(tmpModel, activeProfile, request, problems);
782-
}
802+
return resultModel;
803+
}
783804

784-
if (currentData == resultData) {
785-
for (Profile activeProfile : activeExternalProfiles) {
786-
profileInjector.injectProfile(tmpModel, activeProfile, request, problems);
787-
}
788-
result.setEffectiveModel(tmpModel);
789-
}
805+
private Lineage getLineage(
806+
ModelBuildingRequest request,
807+
DefaultModelBuildingResult result,
808+
DefaultModelProblemCollector problems,
809+
ModelData resultData,
810+
ModelData superData,
811+
DefaultProfileActivationContext profileActivationContext,
812+
boolean firstLevel,
813+
LinkedHashSet<String> parentIds)
814+
throws ModelBuildingException {
790815

791-
lineage.add(tmpModel);
816+
ModelData currentData = resultData;
792817

793-
if (currentData == superData) {
794-
break;
795-
}
818+
String modelId = currentData.getId();
819+
result.addModelId(modelId);
796820

797-
configureResolver(request.getModelResolver(), tmpModel, problems);
821+
Model rawModel = currentData.getModel();
822+
result.setRawModel(modelId, rawModel);
798823

799-
ModelData parentData =
800-
readParent(currentData.getModel(), currentData.getSource(), request, result, problems);
824+
profileActivationContext.setProjectProperties(rawModel.getProperties());
825+
problems.setSource(rawModel);
826+
List<Profile> activePomProfiles =
827+
profileSelector.getActiveProfiles(rawModel.getProfiles(), profileActivationContext, problems);
828+
result.setActivePomProfiles(modelId, activePomProfiles);
801829

802-
if (parentData == null) {
803-
currentData = superData;
804-
} else if (!parentIds.add(parentData.getId())) {
805-
StringBuilder message = new StringBuilder("The parents form a cycle: ");
806-
for (String parentId : parentIds) {
807-
message.append(parentId).append(" -> ");
808-
}
809-
message.append(parentData.getId());
830+
Model tmpModel = rawModel.clone();
810831

811-
problems.add(new ModelProblemCollectorRequest(ModelProblem.Severity.FATAL, ModelProblem.Version.BASE)
812-
.setMessage(message.toString()));
832+
problems.setSource(tmpModel);
813833

814-
throw problems.newModelBuildingException();
815-
} else {
816-
currentData = parentData;
817-
}
818-
}
834+
// model normalization
835+
tmpModel = new Model(modelNormalizer.mergeDuplicates(tmpModel.getDelegate(), request, problems));
819836

820-
problems.setSource(result.getRawModel());
821-
checkPluginVersions(lineage, request, problems);
837+
profileActivationContext.setProjectProperties(tmpModel.getProperties());
822838

823-
// inheritance assembly
824-
Model resultModel = assembleInheritance(lineage, request, problems);
839+
Map<String, Activation> interpolatedActivations =
840+
getInterpolatedActivations(rawModel, profileActivationContext, problems);
841+
injectProfileActivations(tmpModel, interpolatedActivations);
825842

826-
// consider caching inherited model
843+
// profile injection
844+
for (Profile activeProfile : result.getActivePomProfiles(modelId)) {
845+
profileInjector.injectProfile(tmpModel, activeProfile, request, problems);
846+
}
847+
if (firstLevel) {
848+
for (Profile activeProfile : result.getActiveExternalProfiles()) {
849+
profileInjector.injectProfile(tmpModel, activeProfile, request, problems);
850+
}
851+
result.setEffectiveModel(tmpModel);
852+
}
827853

828-
problems.setSource(resultModel);
829-
problems.setRootModel(resultModel);
854+
if (currentData == superData) {
855+
return new Lineage(tmpModel, Collections.emptyList());
856+
}
830857

831-
// model interpolation
832-
resultModel = interpolateModel(resultModel, request, problems);
858+
configureResolver(request.getModelResolver(), tmpModel, problems, false);
833859

834-
// url normalization
835-
modelUrlNormalizer.normalize(resultModel, request);
860+
List<Lineage> parents = new ArrayList<>();
836861

837-
result.setEffectiveModel(resultModel);
862+
List<Parent> list = new ArrayList<>();
863+
list.add(currentData.getModel().getParent());
864+
list.addAll(currentData.getModel().getMixins());
865+
for (Parent parent : list) {
838866

839-
// Now the fully interpolated model is available: reconfigure the resolver
840-
configureResolver(request.getModelResolver(), resultModel, problems, true);
867+
ModelData parentData =
868+
readParent(currentData.getModel(), parent, currentData.getSource(), request, result, problems);
869+
if (parents.isEmpty() && parentData == null) {
870+
parentData = superData;
871+
}
872+
LinkedHashSet<String> newParentIds = new LinkedHashSet<>(parentIds.size() + 1);
873+
newParentIds.addAll(parentIds);
874+
if (!newParentIds.add(parentData.getId())) {
875+
StringBuilder message = new StringBuilder("The parents form a cycle: ");
876+
for (String parentId : newParentIds) {
877+
message.append(parentId).append(" -> ");
878+
}
879+
message.append(parentData.getId());
880+
problems.add(
881+
new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE).setMessage(message.toString()));
841882

842-
return resultModel;
883+
throw problems.newModelBuildingException();
884+
}
885+
parents.add(getLineage(
886+
request, result, problems, parentData, superData, profileActivationContext, false, newParentIds));
887+
}
888+
889+
return new Lineage(tmpModel, parents);
843890
}
844891

845892
private Map<String, Activation> getInterpolatedActivations(
@@ -1179,10 +1226,6 @@ private DefaultProfileActivationContext getProfileActivationContext(ModelBuildin
11791226
return context;
11801227
}
11811228

1182-
private void configureResolver(ModelResolver modelResolver, Model model, DefaultModelProblemCollector problems) {
1183-
configureResolver(modelResolver, model, problems, false);
1184-
}
1185-
11861229
private void configureResolver(
11871230
ModelResolver modelResolver,
11881231
Model model,
@@ -1208,8 +1251,7 @@ private void configureResolver(
12081251
}
12091252
}
12101253

1211-
private void checkPluginVersions(
1212-
List<Model> lineage, ModelBuildingRequest request, ModelProblemCollector problems) {
1254+
private void checkPluginVersions(Lineage lineage, ModelBuildingRequest request, ModelProblemCollector problems) {
12131255
if (request.getValidationLevel() < ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
12141256
return;
12151257
}
@@ -1218,8 +1260,9 @@ private void checkPluginVersions(
12181260
Map<String, String> versions = new HashMap<>();
12191261
Map<String, String> managedVersions = new HashMap<>();
12201262

1221-
for (int i = lineage.size() - 1; i >= 0; i--) {
1222-
Model model = lineage.get(i);
1263+
List<Model> models = lineage.getAllModels();
1264+
Collections.reverse(models);
1265+
for (Model model : models) {
12231266
Build build = model.getBuild();
12241267
if (build != null) {
12251268
for (Plugin plugin : build.getPlugins()) {
@@ -1249,12 +1292,11 @@ private void checkPluginVersions(
12491292
}
12501293
}
12511294

1252-
private Model assembleInheritance(
1253-
List<Model> lineage, ModelBuildingRequest request, ModelProblemCollector problems) {
1254-
org.apache.maven.api.model.Model parent =
1255-
lineage.get(lineage.size() - 1).getDelegate();
1256-
for (int i = lineage.size() - 2; i >= 0; i--) {
1257-
Model child = lineage.get(i);
1295+
private Model assembleInheritance(Lineage lineage, ModelBuildingRequest request, ModelProblemCollector problems) {
1296+
List<Model> models = lineage.getAllModels();
1297+
org.apache.maven.api.model.Model parent = models.get(models.size() - 1).getDelegate();
1298+
for (int i = models.size() - 2; i >= 0; i--) {
1299+
Model child = models.get(i);
12581300
parent = inheritanceAssembler.assembleModelInheritance(child.getDelegate(), parent, request, problems);
12591301
}
12601302
return new Model(parent);
@@ -1329,18 +1371,18 @@ private Model interpolateModel(Model model, ModelBuildingRequest request, ModelP
13291371

13301372
private ModelData readParent(
13311373
Model childModel,
1374+
Parent parent,
13321375
Source childSource,
13331376
ModelBuildingRequest request,
13341377
ModelBuildingResult result,
13351378
DefaultModelProblemCollector problems)
13361379
throws ModelBuildingException {
13371380
ModelData parentData = null;
13381381

1339-
Parent parent = childModel.getParent();
13401382
if (parent != null) {
1341-
parentData = readParentLocally(childModel, childSource, request, result, problems);
1383+
parentData = readParentLocally(childModel, parent, childSource, request, result, problems);
13421384
if (parentData == null) {
1343-
parentData = readParentExternally(childModel, request, result, problems);
1385+
parentData = readParentExternally(childModel, parent, request, result, problems);
13441386
}
13451387

13461388
Model parentModel = parentData.getModel();
@@ -1357,17 +1399,17 @@ private ModelData readParent(
13571399

13581400
private ModelData readParentLocally(
13591401
Model childModel,
1402+
Parent parent,
13601403
Source childSource,
13611404
ModelBuildingRequest request,
13621405
ModelBuildingResult result,
13631406
DefaultModelProblemCollector problems)
13641407
throws ModelBuildingException {
1365-
final Parent parent = childModel.getParent();
13661408
final ModelSource candidateSource;
13671409
final Model candidateModel;
13681410
final WorkspaceModelResolver resolver = request.getWorkspaceModelResolver();
13691411
if (resolver == null) {
1370-
candidateSource = getParentPomFile(childModel, childSource);
1412+
candidateSource = getParentPomFile(parent, childSource);
13711413

13721414
if (candidateSource == null) {
13731415
return null;
@@ -1480,12 +1522,12 @@ private boolean rawChildVersionReferencesParent(String rawChildModelVersion) {
14801522
|| rawChildModelVersion.equals("${project.parent.version}");
14811523
}
14821524

1483-
private ModelSource getParentPomFile(Model childModel, Source source) {
1525+
private ModelSource getParentPomFile(Parent parent, Source source) {
14841526
if (!(source instanceof ModelSource2)) {
14851527
return null;
14861528
}
14871529

1488-
String parentPath = childModel.getParent().getRelativePath();
1530+
String parentPath = parent.getRelativePath();
14891531

14901532
if (parentPath == null || parentPath.length() <= 0) {
14911533
return null;
@@ -1496,14 +1538,13 @@ private ModelSource getParentPomFile(Model childModel, Source source) {
14961538

14971539
private ModelData readParentExternally(
14981540
Model childModel,
1541+
Parent parent,
14991542
ModelBuildingRequest request,
15001543
ModelBuildingResult result,
15011544
DefaultModelProblemCollector problems)
15021545
throws ModelBuildingException {
15031546
problems.setSource(childModel);
15041547

1505-
Parent parent = childModel.getParent();
1506-
15071548
String groupId = parent.getGroupId();
15081549
String artifactId = parent.getArtifactId();
15091550
String version = parent.getVersion();

0 commit comments

Comments
 (0)