Model for Maven POM (Project Object Model)
—
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.
The primary class responsible for merging Maven models, handling inheritance from parent POMs and profile integration.
public class ModelMerger {
// Primary public merge method
public void merge(Model target, Model source, boolean sourceDominant, Map<?, ?> hints);
// Protected specific merge methods (for subclassing)
protected void mergeModel(Model target, Model source, boolean sourceDominant, Map<?, ?> hints);
protected void mergeModelBase(ModelBase target, ModelBase source, boolean sourceDominant, Map<?, ?> hints);
protected void mergeParent(Parent target, Parent source, boolean sourceDominant, Map<?, ?> hints);
protected void mergeBuild(Build target, Build source, boolean sourceDominant, Map<?, ?> hints);
protected void mergeBuildBase(BuildBase target, BuildBase source, boolean sourceDominant, Map<?, ?> hints);
protected void mergeProfile(Profile target, Profile source, boolean sourceDominant, Map<?, ?> hints);
// Protected dependency merging methods
protected void mergeDependency(Dependency target, Dependency source, boolean sourceDominant, Map<?, ?> hints);
protected void mergeDependencyManagement(DependencyManagement target, DependencyManagement source, boolean sourceDominant, Map<?, ?> hints);
// Protected plugin merging methods
protected void mergePlugin(Plugin target, Plugin source, boolean sourceDominant, Map<?, ?> hints);
protected void mergePluginManagement(PluginManagement target, PluginManagement source, boolean sourceDominant, Map<?, ?> hints);
protected void mergePluginExecution(PluginExecution target, PluginExecution source, boolean sourceDominant, Map<?, ?> hints);
// Protected repository merging methods
protected void mergeRepository(Repository target, Repository source, boolean sourceDominant, Map<?, ?> hints);
protected void mergeDistributionManagement(DistributionManagement target, DistributionManagement source, boolean sourceDominant, Map<?, ?> hints);
// Protected project information merging methods
protected void mergeOrganization(Organization target, Organization source, boolean sourceDominant, Map<?, ?> hints);
protected void mergeDeveloper(Developer target, Developer source, boolean sourceDominant, Map<?, ?> hints);
protected void mergeLicense(License target, License source, boolean sourceDominant, Map<?, ?> hints);
protected void mergeScm(Scm target, Scm source, boolean sourceDominant, Map<?, ?> hints);
// Protected activation merging methods
protected void mergeActivation(Activation target, Activation source, boolean sourceDominant, Map<?, ?> hints);
protected void mergeActivationProperty(ActivationProperty target, ActivationProperty source, boolean sourceDominant, Map<?, ?> hints);
protected void mergeActivationOS(ActivationOS target, ActivationOS source, boolean sourceDominant, Map<?, ?> hints);
protected void mergeActivationFile(ActivationFile target, ActivationFile source, boolean sourceDominant, Map<?, ?> hints);
}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.
Basic Usage Example:
import org.apache.maven.model.Model;
import org.apache.maven.model.merge.ModelMerger;
import java.util.HashMap;
import java.util.Map;
// Load parent and child models
Model parentModel = readParentPom();
Model childModel = readChildPom();
// Create merger and hints
ModelMerger merger = new ModelMerger();
Map<String, Object> hints = new HashMap<>();
// Merge parent into child (child properties take precedence)
merger.merge(childModel, parentModel, false, hints);
// Now childModel contains merged configuration
System.out.println("Merged project: " + childModel.getArtifactId());target: The model being merged into (typically the child model)
source: The model being merged from (typically the parent model)
sourceDominant: Controls merge precedence
false: Target values take precedence (typical for child over parent)true: Source values take precedence (used for profile merging)
hints: Map providing merge customization options// Typical parent-child POM inheritance
public void mergeParentInternal(Model child, Model parent) {
ModelMerger merger = new ModelMerger();
Map<String, Object> hints = new HashMap<>();
// Child overrides parent (sourceDominant = false)
merger.merge(child, parent, false, hints);
// Handle coordinate inheritance
if (child.getGroupId() == null) {
child.setGroupId(parent.getGroupId());
}
if (child.getVersion() == null) {
child.setVersion(parent.getVersion());
}
}// Merge active profiles into main model
public void mergeActiveProfiles(Model model, List<Profile> activeProfiles) {
ModelMerger merger = new ModelMerger();
Map<String, Object> hints = new HashMap<>();
for (Profile profile : activeProfiles) {
// Profile values override model values (sourceDominant = true)
merger.mergeModelBase(model, profile, true, hints);
// Merge profile build into model build
if (profile.getBuild() != null) {
if (model.getBuild() == null) {
model.setBuild(new Build());
}
merger.mergeBuildBase(model.getBuild(), profile.getBuild(), true, hints);
}
}
}The hints map can control specific merge behaviors:
Map<String, Object> hints = new HashMap<>();
// Custom merge strategies for specific elements
hints.put("merge.dependencies", "append"); // Append rather than replace
hints.put("merge.plugins", "combine"); // Combine configurations
hints.put("merge.properties", "override"); // Override properties
ModelMerger merger = new ModelMerger();
merger.merge(target, source, false, hints);Different elements use different merge strategies:
Override Strategy (default for most scalar values):
Append Strategy (used for lists like dependencies):
Combine Strategy (used for plugin configurations):
try {
ModelMerger merger = new ModelMerger();
merger.merge(childModel, parentModel, false, hints);
} catch (Exception e) {
// Handle merge conflicts or errors
System.err.println("Model merge failed: " + e.getMessage());
// Usually indicates circular inheritance or malformed models
}import org.apache.maven.model.Model;
import org.apache.maven.model.Profile;
import org.apache.maven.model.merge.ModelMerger;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import java.util.*;
public class ModelMergeExample {
public void performCompleteInheritance(String childPomPath, String parentPomPath,
List<String> activeProfileIds) throws Exception {
MavenXpp3Reader reader = new MavenXpp3Reader();
ModelMerger merger = new ModelMerger();
// Read models
Model childModel = reader.read(new FileReader(childPomPath));
Model parentModel = reader.read(new FileReader(parentPomPath));
// 1. Merge parent into child
Map<String, Object> hints = new HashMap<>();
merger.merge(childModel, parentModel, false, hints);
// 2. Handle coordinate inheritance
if (childModel.getGroupId() == null) {
childModel.setGroupId(parentModel.getGroupId());
}
if (childModel.getVersion() == null) {
childModel.setVersion(parentModel.getVersion());
}
// 3. Merge active profiles
for (Profile profile : childModel.getProfiles()) {
if (activeProfileIds.contains(profile.getId())) {
merger.mergeModelBase(childModel, profile, true, hints);
if (profile.getBuild() != null) {
if (childModel.getBuild() == null) {
childModel.setBuild(new Build());
}
merger.mergeBuildBase(childModel.getBuild(), profile.getBuild(), true, hints);
}
}
}
// Result: childModel now contains complete effective POM
System.out.println("Effective POM created for: " + childModel.getId());
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-apache-maven--maven-model