0
# Model Merging
1
2
Model inheritance and merging capabilities for parent-child POM relationships and profile integration. The ModelMerger class provides sophisticated merging logic that handles Maven's inheritance and composition patterns.
3
4
## Capabilities
5
6
### ModelMerger
7
8
The primary class responsible for merging Maven models, handling inheritance from parent POMs and profile integration.
9
10
```java { .api }
11
public class ModelMerger {
12
// Primary public merge method
13
public void merge(Model target, Model source, boolean sourceDominant, Map<?, ?> hints);
14
15
// Protected specific merge methods (for subclassing)
16
protected void mergeModel(Model target, Model source, boolean sourceDominant, Map<?, ?> hints);
17
protected void mergeModelBase(ModelBase target, ModelBase source, boolean sourceDominant, Map<?, ?> hints);
18
protected void mergeParent(Parent target, Parent source, boolean sourceDominant, Map<?, ?> hints);
19
protected void mergeBuild(Build target, Build source, boolean sourceDominant, Map<?, ?> hints);
20
protected void mergeBuildBase(BuildBase target, BuildBase source, boolean sourceDominant, Map<?, ?> hints);
21
protected void mergeProfile(Profile target, Profile source, boolean sourceDominant, Map<?, ?> hints);
22
23
// Protected dependency merging methods
24
protected void mergeDependency(Dependency target, Dependency source, boolean sourceDominant, Map<?, ?> hints);
25
protected void mergeDependencyManagement(DependencyManagement target, DependencyManagement source, boolean sourceDominant, Map<?, ?> hints);
26
27
// Protected plugin merging methods
28
protected void mergePlugin(Plugin target, Plugin source, boolean sourceDominant, Map<?, ?> hints);
29
protected void mergePluginManagement(PluginManagement target, PluginManagement source, boolean sourceDominant, Map<?, ?> hints);
30
protected void mergePluginExecution(PluginExecution target, PluginExecution source, boolean sourceDominant, Map<?, ?> hints);
31
32
// Protected repository merging methods
33
protected void mergeRepository(Repository target, Repository source, boolean sourceDominant, Map<?, ?> hints);
34
protected void mergeDistributionManagement(DistributionManagement target, DistributionManagement source, boolean sourceDominant, Map<?, ?> hints);
35
36
// Protected project information merging methods
37
protected void mergeOrganization(Organization target, Organization source, boolean sourceDominant, Map<?, ?> hints);
38
protected void mergeDeveloper(Developer target, Developer source, boolean sourceDominant, Map<?, ?> hints);
39
protected void mergeLicense(License target, License source, boolean sourceDominant, Map<?, ?> hints);
40
protected void mergeScm(Scm target, Scm source, boolean sourceDominant, Map<?, ?> hints);
41
42
// Protected activation merging methods
43
protected void mergeActivation(Activation target, Activation source, boolean sourceDominant, Map<?, ?> hints);
44
protected void mergeActivationProperty(ActivationProperty target, ActivationProperty source, boolean sourceDominant, Map<?, ?> hints);
45
protected void mergeActivationOS(ActivationOS target, ActivationOS source, boolean sourceDominant, Map<?, ?> hints);
46
protected void mergeActivationFile(ActivationFile target, ActivationFile source, boolean sourceDominant, Map<?, ?> hints);
47
}
48
```
49
50
**Note**: Most specific merge methods are `protected` and intended for subclassing the ModelMerger. For typical usage, developers should use the main public `merge()` method which internally calls the appropriate protected methods.
51
52
**Basic Usage Example:**
53
54
```java
55
import org.apache.maven.model.Model;
56
import org.apache.maven.model.merge.ModelMerger;
57
import java.util.HashMap;
58
import java.util.Map;
59
60
// Load parent and child models
61
Model parentModel = readParentPom();
62
Model childModel = readChildPom();
63
64
// Create merger and hints
65
ModelMerger merger = new ModelMerger();
66
Map<String, Object> hints = new HashMap<>();
67
68
// Merge parent into child (child properties take precedence)
69
merger.merge(childModel, parentModel, false, hints);
70
71
// Now childModel contains merged configuration
72
System.out.println("Merged project: " + childModel.getArtifactId());
73
```
74
75
### Merge Parameters
76
77
**`target`**: The model being merged into (typically the child model)
78
**`source`**: The model being merged from (typically the parent model)
79
**`sourceDominant`**: Controls merge precedence
80
- `false`: Target values take precedence (typical for child over parent)
81
- `true`: Source values take precedence (used for profile merging)
82
**`hints`**: Map providing merge customization options
83
84
### Parent-Child Inheritance
85
86
```java
87
// Typical parent-child POM inheritance
88
public void mergeParentInternal(Model child, Model parent) {
89
ModelMerger merger = new ModelMerger();
90
Map<String, Object> hints = new HashMap<>();
91
92
// Child overrides parent (sourceDominant = false)
93
merger.merge(child, parent, false, hints);
94
95
// Handle coordinate inheritance
96
if (child.getGroupId() == null) {
97
child.setGroupId(parent.getGroupId());
98
}
99
if (child.getVersion() == null) {
100
child.setVersion(parent.getVersion());
101
}
102
}
103
```
104
105
### Profile Merging
106
107
```java
108
// Merge active profiles into main model
109
public void mergeActiveProfiles(Model model, List<Profile> activeProfiles) {
110
ModelMerger merger = new ModelMerger();
111
Map<String, Object> hints = new HashMap<>();
112
113
for (Profile profile : activeProfiles) {
114
// Profile values override model values (sourceDominant = true)
115
merger.mergeModelBase(model, profile, true, hints);
116
117
// Merge profile build into model build
118
if (profile.getBuild() != null) {
119
if (model.getBuild() == null) {
120
model.setBuild(new Build());
121
}
122
merger.mergeBuildBase(model.getBuild(), profile.getBuild(), true, hints);
123
}
124
}
125
}
126
```
127
128
### Advanced Merging Options
129
130
The hints map can control specific merge behaviors:
131
132
```java
133
Map<String, Object> hints = new HashMap<>();
134
135
// Custom merge strategies for specific elements
136
hints.put("merge.dependencies", "append"); // Append rather than replace
137
hints.put("merge.plugins", "combine"); // Combine configurations
138
hints.put("merge.properties", "override"); // Override properties
139
140
ModelMerger merger = new ModelMerger();
141
merger.merge(target, source, false, hints);
142
```
143
144
### Merge Strategies
145
146
Different elements use different merge strategies:
147
148
**Override Strategy** (default for most scalar values):
149
- Target value used if present, otherwise source value
150
151
**Append Strategy** (used for lists like dependencies):
152
- Items from both target and source are combined
153
- Duplicates handled based on element key (e.g., groupId:artifactId for dependencies)
154
155
**Combine Strategy** (used for plugin configurations):
156
- XML configurations are merged at the DOM level
157
- Child elements override parent elements with same name
158
159
### Error Handling
160
161
```java
162
try {
163
ModelMerger merger = new ModelMerger();
164
merger.merge(childModel, parentModel, false, hints);
165
} catch (Exception e) {
166
// Handle merge conflicts or errors
167
System.err.println("Model merge failed: " + e.getMessage());
168
// Usually indicates circular inheritance or malformed models
169
}
170
```
171
172
### Complete Integration Example
173
174
```java
175
import org.apache.maven.model.Model;
176
import org.apache.maven.model.Profile;
177
import org.apache.maven.model.merge.ModelMerger;
178
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
179
import java.util.*;
180
181
public class ModelMergeExample {
182
183
public void performCompleteInheritance(String childPomPath, String parentPomPath,
184
List<String> activeProfileIds) throws Exception {
185
186
MavenXpp3Reader reader = new MavenXpp3Reader();
187
ModelMerger merger = new ModelMerger();
188
189
// Read models
190
Model childModel = reader.read(new FileReader(childPomPath));
191
Model parentModel = reader.read(new FileReader(parentPomPath));
192
193
// 1. Merge parent into child
194
Map<String, Object> hints = new HashMap<>();
195
merger.merge(childModel, parentModel, false, hints);
196
197
// 2. Handle coordinate inheritance
198
if (childModel.getGroupId() == null) {
199
childModel.setGroupId(parentModel.getGroupId());
200
}
201
if (childModel.getVersion() == null) {
202
childModel.setVersion(parentModel.getVersion());
203
}
204
205
// 3. Merge active profiles
206
for (Profile profile : childModel.getProfiles()) {
207
if (activeProfileIds.contains(profile.getId())) {
208
merger.mergeModelBase(childModel, profile, true, hints);
209
210
if (profile.getBuild() != null) {
211
if (childModel.getBuild() == null) {
212
childModel.setBuild(new Build());
213
}
214
merger.mergeBuildBase(childModel.getBuild(), profile.getBuild(), true, hints);
215
}
216
}
217
}
218
219
// Result: childModel now contains complete effective POM
220
System.out.println("Effective POM created for: " + childModel.getId());
221
}
222
}
223
```
224
225
### Key Merge Rules
226
227
1. **Scalar Values**: Child overrides parent unless child value is null
228
2. **Lists**: Combined with duplicates removed based on element key
229
3. **Maps/Properties**: Child properties override parent properties
230
4. **Plugin Configurations**: DOM-level merging with child elements taking precedence
231
5. **Profiles**: Profile values override model values when active
232
6. **Coordinates**: groupId and version inherited from parent if not specified in child