Dependency Alignment
DomTrip can detect how your project manages dependency versions and add or transform dependencies
to follow those conventions consistently. This is powered by the AlignOptions configuration
and the convention detection API.
Convention Detection
DomTrip analyzes your POM to detect three aspects of your dependency versioning strategy:
String pom = """
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-project</artifactId>
<version>1.0.0</version>
<properties>
<slf4j.version>2.0.7</slf4j.version>
<guava.version>32.1.2-jre</guava.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
</dependencies>
</project>
""";
PomEditor editor = new PomEditor(Document.of(pom));
// Detect individual conventions
AlignOptions.VersionStyle style = editor.dependencies().detectVersionStyle();
// MANAGED (most dependencies are version-less)
AlignOptions.VersionSource source = editor.dependencies().detectVersionSource();
// PROPERTY (versions use ${...} references)
AlignOptions.PropertyNamingConvention naming = editor.dependencies().detectPropertyNamingConvention();
// DOT_SUFFIX (e.g., "slf4j.version")
// Detect all conventions at once
AlignOptions detected = editor.dependencies().detectConventions();
What Gets Detected
| Convention | Values | Description |
|---|---|---|
| VersionStyle | INLINE, MANAGED |
Whether versions are on dependencies directly or in <dependencyManagement> |
| VersionSource | LITERAL, PROPERTY |
Whether versions are literal values (5.9.2) or property references (${junit.version}) |
| PropertyNamingConvention | DOT_SUFFIX, DASH_SUFFIX, CAMEL_CASE, DOT_PREFIX |
How version properties are named |
Property Naming Examples
| Convention | Example |
|---|---|
DOT_SUFFIX |
junit-jupiter.version |
DASH_SUFFIX |
junit-jupiter-version |
CAMEL_CASE |
junitJupiterVersion |
DOT_PREFIX |
version.junit-jupiter |
Adding Aligned Dependencies
Use addAligned() to add dependencies that automatically follow your project's conventions:
String pom = """
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-project</artifactId>
<version>1.0.0</version>
<properties>
<slf4j.version>2.0.7</slf4j.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
</dependencies>
</project>
""";
PomEditor editor = new PomEditor(Document.of(pom));
// Add a dependency aligned with auto-detected conventions
// Detects: MANAGED + PROPERTY + DOT_SUFFIX → creates property and managed entry
Coordinates jackson = Coordinates.of("com.fasterxml.jackson.core", "jackson-core", "2.15.2");
editor.dependencies().addAligned(jackson);
// Add with explicit options
Coordinates junit = Coordinates.of("org.junit.jupiter", "junit-jupiter", "5.10.0");
editor.dependencies()
.addAligned(junit, AlignOptions.builder().scope("test").build());
// Force a specific style regardless of detected conventions
Coordinates mockito = Coordinates.of("org.mockito", "mockito-core", "5.5.0");
editor.dependencies()
.addAligned(
mockito,
AlignOptions.builder()
.versionStyle(AlignOptions.VersionStyle.INLINE)
.versionSource(AlignOptions.VersionSource.LITERAL)
.scope("test")
.build());
Aligning Existing Dependencies
Transform existing dependencies to match a target convention:
String pom = """
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-project</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.2-jre</version>
</dependency>
</dependencies>
</project>
""";
PomEditor editor = new PomEditor(Document.of(pom));
// Align an existing dependency to use managed + property style
Coordinates guava = Coordinates.of("com.google.guava", "guava", null);
editor.dependencies()
.alignDependency(
guava,
AlignOptions.builder()
.versionStyle(AlignOptions.VersionStyle.MANAGED)
.versionSource(AlignOptions.VersionSource.PROPERTY)
.namingConvention(AlignOptions.PropertyNamingConvention.DOT_SUFFIX)
.build());
// Result: version moved to dependencyManagement with ${guava.version} property
Aligning All Dependencies
Apply conventions consistently across all dependencies in a single call:
String pom = """
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-project</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.2-jre</version>
</dependency>
</dependencies>
</project>
""";
PomEditor editor = new PomEditor(Document.of(pom));
// Align all dependencies to use managed + property style
int changed = editor.dependencies()
.alignAllDependencies(AlignOptions.builder()
.versionStyle(AlignOptions.VersionStyle.MANAGED)
.versionSource(AlignOptions.VersionSource.PROPERTY)
.build());
Updating Managed Dependencies (Aligned)
Use updateManagedDependencyAligned() to add or update entries in <dependencyManagement>
while following the project's detected conventions. Where updateManagedDependency() stores
the version string you pass in directly, this method creates version properties when the
project convention calls for them:
String pom = """
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-project</artifactId>
<version>1.0.0</version>
<properties>
<slf4j.version>2.0.7</slf4j.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
</dependencies>
</project>
""";
PomEditor editor = new PomEditor(Document.of(pom));
// Add a new managed dependency following auto-detected conventions
// Detects PROPERTY + DOT_SUFFIX → creates property and uses ${...} reference
Coordinates jackson = Coordinates.of("com.fasterxml.jackson.core", "jackson-core", "2.15.2");
editor.dependencies().updateManagedDependencyAligned(true, jackson);
// Use explicit options to force property-backed version
Coordinates guava = Coordinates.of("com.google.guava", "guava", "33.0.0-jre");
editor.dependencies()
.updateManagedDependencyAligned(
true,
guava,
AlignOptions.builder()
.versionSource(AlignOptions.VersionSource.PROPERTY)
.namingConvention(AlignOptions.PropertyNamingConvention.DOT_SUFFIX)
.build());
// Use explicit property name to update an existing managed dependency
Coordinates slf4j = Coordinates.of("org.slf4j", "slf4j-api", "2.0.13");
editor.dependencies()
.updateManagedDependencyAligned(
false,
slf4j,
AlignOptions.builder().propertyName("slf4j.version").build());
AlignOptions
AlignOptions controls how alignment operations behave. Use the builder for explicit control,
or AlignOptions.defaults() to auto-detect everything.
Builder API
// Auto-detect all conventions
AlignOptions options = AlignOptions.defaults();
// Force managed + property style
AlignOptions options = AlignOptions.builder()
.versionStyle(AlignOptions.VersionStyle.MANAGED)
.versionSource(AlignOptions.VersionSource.PROPERTY)
.build();
// Force specific property name
AlignOptions options = AlignOptions.builder()
.versionSource(AlignOptions.VersionSource.PROPERTY)
.propertyName("junit.version")
.build();
// Custom property naming pattern
AlignOptions options = AlignOptions.builder()
.versionSource(AlignOptions.VersionSource.PROPERTY)
.propertyNameGenerator(coords ->
coords.groupId() + "." + coords.artifactId() + ".version")
.build();
// Add as test dependency
AlignOptions options = AlignOptions.builder()
.scope("test")
.build();
Option Fields
| Field | Type | Description |
|---|---|---|
versionStyle |
VersionStyle |
INLINE or MANAGED; null = auto-detect |
versionSource |
VersionSource |
LITERAL or PROPERTY; null = auto-detect |
namingConvention |
PropertyNamingConvention |
Property naming pattern; null = auto-detect |
propertyName |
String |
Explicit property name override |
propertyNameGenerator |
Function<Coordinates, String> |
Custom property name generator |
scope |
String |
Maven dependency scope (e.g., "test") |
Precedence
When resolving property names, the precedence is:
- Explicit
propertyName(highest) - Custom
propertyNameGenerator namingConvention- Auto-detected convention (lowest)
Next Steps
- Cross-POM Alignment - Move versions to parent POMs
- Profile-Scoped Operations - Manage profile-specific dependencies
- Exclusion Management - Add and remove dependency exclusions