CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-apache-maven--maven-model

Model for Maven POM (Project Object Model)

Pending
Overview
Eval results
Files

model-merging.mddocs/

Model Merging

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.

Capabilities

ModelMerger

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());

Merge Parameters

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

Parent-Child Inheritance

// 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());
    }
}

Profile Merging

// 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);
        }
    }
}

Advanced Merging Options

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);

Merge Strategies

Different elements use different merge strategies:

Override Strategy (default for most scalar values):

  • Target value used if present, otherwise source value

Append Strategy (used for lists like dependencies):

  • Items from both target and source are combined
  • Duplicates handled based on element key (e.g., groupId:artifactId for dependencies)

Combine Strategy (used for plugin configurations):

  • XML configurations are merged at the DOM level
  • Child elements override parent elements with same name

Error Handling

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
}

Complete Integration Example

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());
    }
}

Key Merge Rules

  1. Scalar Values: Child overrides parent unless child value is null
  2. Lists: Combined with duplicates removed based on element key
  3. Maps/Properties: Child properties override parent properties
  4. Plugin Configurations: DOM-level merging with child elements taking precedence
  5. Profiles: Profile values override model values when active
  6. Coordinates: groupId and version inherited from parent if not specified in child

Install with Tessl CLI

npx tessl i tessl/maven-org-apache-maven--maven-model

docs

build-config.md

core-model.md

dependencies.md

index.md

model-merging.md

profiles.md

project-metadata.md

repositories.md

utility-classes.md

xml-io.md

tile.json