OpenRewrite Maven parsing and refactoring library that provides Maven POM file parsing, analysis, and automated refactoring capabilities
—
Utility classes for common Maven operations including Maven wrapper support and dependency visualization.
Utilities for working with Maven wrapper scripts and configuration.
/**
* Utilities for working with Maven wrapper (mvnw) scripts
*/
public class MavenWrapper {
/**
* Check if project has Maven wrapper
* @param projectRoot Project root directory
* @return true if Maven wrapper exists
*/
public static boolean hasMavenWrapper(Path projectRoot);
/**
* Get Maven wrapper version from project
* @param projectRoot Project root directory
* @return Maven wrapper version or null if not found
*/
public static @Nullable String getWrapperVersion(Path projectRoot);
/**
* Update Maven wrapper to specified version
* @param projectRoot Project root directory
* @param version New Maven version
* @throws IOException if update fails
*/
public static void updateWrapper(Path projectRoot, String version) throws IOException;
/**
* Create Maven wrapper in project
* @param projectRoot Project root directory
* @param mavenVersion Maven version to use
* @throws IOException if creation fails
*/
public static void createWrapper(Path projectRoot, String mavenVersion) throws IOException;
/**
* Get Maven wrapper properties
* @param projectRoot Project root directory
* @return Properties from wrapper configuration
*/
public static Properties getWrapperProperties(Path projectRoot);
}Usage Examples:
Path projectRoot = Paths.get("/path/to/maven/project");
// Check for Maven wrapper
if (MavenWrapper.hasMavenWrapper(projectRoot)) {
String version = MavenWrapper.getWrapperVersion(projectRoot);
System.out.println("Maven wrapper version: " + version);
// Update wrapper to newer version
MavenWrapper.updateWrapper(projectRoot, "3.9.4");
} else {
// Create new Maven wrapper
MavenWrapper.createWrapper(projectRoot, "3.9.4");
}
// Get wrapper configuration
Properties props = MavenWrapper.getWrapperProperties(projectRoot);
String distributionUrl = props.getProperty("distributionUrl");
System.out.println("Distribution URL: " + distributionUrl);Utility for downloading Maven artifacts from repositories.
/**
* Utility for downloading Maven artifacts from repositories
*/
public class MavenArtifactDownloader {
/**
* Create downloader with default configuration
*/
public MavenArtifactDownloader();
/**
* Create downloader with custom repositories
* @param repositories List of Maven repositories to use
*/
public MavenArtifactDownloader(List<MavenRepository> repositories);
/**
* Create downloader with configuration
* @param repositories List of Maven repositories
* @param cache Optional artifact cache
* @param timeout Download timeout in milliseconds
*/
public MavenArtifactDownloader(List<MavenRepository> repositories,
@Nullable MavenArtifactCache cache,
int timeout);
}Key Methods:
/**
* Download artifact JAR file
* @param gav Group:Artifact:Version coordinate
* @return Downloaded artifact bytes
* @throws MavenDownloadingException if download fails
*/
public byte[] downloadArtifact(GroupArtifactVersion gav) throws MavenDownloadingException;
/**
* Download artifact with classifier
* @param gav Group:Artifact:Version coordinate
* @param classifier Artifact classifier (e.g., "sources", "javadoc")
* @return Downloaded artifact bytes
* @throws MavenDownloadingException if download fails
*/
public byte[] downloadArtifact(GroupArtifactVersion gav, String classifier) throws MavenDownloadingException;
/**
* Download artifact POM file
* @param gav Group:Artifact:Version coordinate
* @return Downloaded POM content
* @throws MavenDownloadingException if download fails
*/
public String downloadPom(GroupArtifactVersion gav) throws MavenDownloadingException;
/**
* Download artifact metadata
* @param ga Group:Artifact coordinate
* @return Maven metadata information
* @throws MavenDownloadingException if download fails
*/
public MavenMetadata downloadMetadata(GroupArtifact ga) throws MavenDownloadingException;
/**
* Check if artifact exists in repositories
* @param gav Group:Artifact:Version coordinate
* @return true if artifact exists
*/
public boolean artifactExists(GroupArtifactVersion gav);
/**
* Get available versions for artifact
* @param ga Group:Artifact coordinate
* @return List of available versions
* @throws MavenDownloadingException if retrieval fails
*/
public List<String> getAvailableVersions(GroupArtifact ga) throws MavenDownloadingException;Usage Examples:
// Create repositories
List<MavenRepository> repos = Arrays.asList(
MavenRepository.builder()
.id("central")
.uri("https://repo1.maven.org/maven2/")
.releases(true)
.snapshots(false)
.build(),
MavenRepository.builder()
.id("snapshots")
.uri("https://oss.sonatype.org/content/repositories/snapshots/")
.releases(false)
.snapshots(true)
.build()
);
// Create downloader
MavenArtifactDownloader downloader = new MavenArtifactDownloader(repos);
// Download specific artifact
GroupArtifactVersion gav = new GroupArtifactVersion("org.junit.jupiter", "junit-jupiter", "5.8.2");
try {
byte[] artifactBytes = downloader.downloadArtifact(gav);
System.out.println("Downloaded artifact: " + artifactBytes.length + " bytes");
// Download sources
byte[] sourcesBytes = downloader.downloadArtifact(gav, "sources");
System.out.println("Downloaded sources: " + sourcesBytes.length + " bytes");
// Download POM
String pomContent = downloader.downloadPom(gav);
System.out.println("Downloaded POM:\n" + pomContent);
} catch (MavenDownloadingException e) {
System.err.println("Download failed: " + e.getMessage());
}
// Check artifact availability
GroupArtifact ga = new GroupArtifact("org.springframework", "spring-core");
if (downloader.artifactExists(new GroupArtifactVersion(ga.getGroupId(), ga.getArtifactId(), "5.3.21"))) {
List<String> versions = downloader.getAvailableVersions(ga);
System.out.println("Available versions: " + versions);
}Recipe to visualize Maven dependencies as DOT graph format for Graphviz.
/**
* Recipe to generate DOT graph representation of Maven dependencies
*/
public class PrintMavenAsDot extends Recipe {
/**
* Create recipe with default configuration
*/
public PrintMavenAsDot();
/**
* Create recipe with scope filter
* @param scope Optional scope to limit visualization (e.g., "compile", "test")
*/
public PrintMavenAsDot(@Nullable String scope);
/**
* Create recipe with full configuration
* @param scope Optional scope filter
* @param includeTransitive Include transitive dependencies
* @param maxDepth Maximum dependency depth to visualize
*/
public PrintMavenAsDot(@Nullable String scope, boolean includeTransitive, int maxDepth);
}Usage Examples:
// Generate DOT graph for all dependencies
PrintMavenAsDot dotGenerator = new PrintMavenAsDot();
RecipeRun run = dotGenerator.run(List.of(pomDocument), ctx);
// Get generated DOT content
List<PrintMavenAsDot.DotGraph> graphs = run.getDataTable(PrintMavenAsDot.DotGraph.class);
for (PrintMavenAsDot.DotGraph graph : graphs) {
String dotContent = graph.getDotContent();
// Save to file
Files.write(Paths.get("dependencies.dot"), dotContent.getBytes());
// Or render with Graphviz
Process graphviz = Runtime.getRuntime().exec("dot -Tpng -o dependencies.png");
try (OutputStream out = graphviz.getOutputStream()) {
out.write(dotContent.getBytes());
}
graphviz.waitFor();
}
// Generate focused graph for compile dependencies only
PrintMavenAsDot compileGraph = new PrintMavenAsDot("compile", true, 3);
RecipeRun compileRun = compileGraph.run(List.of(pomDocument), ctx);Utility for version retention policies and cleanup operations.
/**
* Utility for managing version retention policies
*/
public class RetainVersions {
/**
* Create retention policy with default settings
*/
public RetainVersions();
/**
* Create retention policy with configuration
* @param retainCount Number of versions to retain
* @param retainDays Number of days to retain versions
* @param retainSnapshots Whether to retain snapshot versions
*/
public RetainVersions(int retainCount, int retainDays, boolean retainSnapshots);
}Key Methods:
/**
* Get versions to retain based on policy
* @param availableVersions List of available versions
* @return List of versions that should be retained
*/
public List<String> getVersionsToRetain(List<String> availableVersions);
/**
* Get versions to delete based on policy
* @param availableVersions List of available versions
* @return List of versions that can be deleted
*/
public List<String> getVersionsToDelete(List<String> availableVersions);
/**
* Check if version should be retained
* @param version Version to check
* @param availableVersions All available versions
* @return true if version should be retained
*/
public boolean shouldRetain(String version, List<String> availableVersions);Usage Examples:
// Create retention policy: keep 5 latest versions, 30 days, no snapshots
RetainVersions policy = new RetainVersions(5, 30, false);
List<String> availableVersions = Arrays.asList(
"1.0.0", "1.1.0", "1.2.0", "1.3.0", "1.4.0", "1.5.0",
"2.0.0-SNAPSHOT", "1.6.0", "1.7.0"
);
List<String> toRetain = policy.getVersionsToRetain(availableVersions);
List<String> toDelete = policy.getVersionsToDelete(availableVersions);
System.out.println("Retain: " + toRetain);
System.out.println("Delete: " + toDelete);/**
* Additional helper methods for MavenSettings
*/
public class MavenSettings {
/**
* Load settings from default location (~/.m2/settings.xml)
* @return MavenSettings instance or null if not found
*/
public static @Nullable MavenSettings loadDefault();
/**
* Load settings from specific file
* @param settingsFile Path to settings.xml file
* @return MavenSettings instance
* @throws IOException if file cannot be read
*/
public static MavenSettings load(Path settingsFile) throws IOException;
/**
* Merge global and user settings
* @param globalSettings Global settings (from Maven installation)
* @param userSettings User settings (from ~/.m2/settings.xml)
* @return Merged settings
*/
public static MavenSettings merge(@Nullable MavenSettings globalSettings,
@Nullable MavenSettings userSettings);
/**
* Get effective repositories (including mirrors)
* @return List of effective repositories
*/
public List<MavenRepository> getEffectiveRepositories();
/**
* Get server authentication for repository
* @param repositoryId Repository ID
* @return Server configuration or null if not found
*/
public @Nullable Server getServer(String repositoryId);
/**
* Resolve property placeholders in settings
* @param value Value that may contain placeholders
* @return Resolved value
*/
public String resolveProperty(String value);
}Comparator for ordering Maven POM elements according to Maven conventions.
/**
* Comparator for ordering Maven POM elements according to standard conventions
* Used to maintain proper element ordering when adding new elements
*/
public class MavenTagInsertionComparator implements Comparator<Content> {
/**
* Create comparator for specific parent tag
* @param parentTagName Name of parent tag (e.g., "dependencies", "plugins")
*/
public MavenTagInsertionComparator(String parentTagName);
@Override
public int compare(Content c1, Content c2);
/**
* Get standard ordering for Maven POM elements
* @return Map of element names to their priority order
*/
public static Map<String, Integer> getStandardOrdering();
}Usage Examples:
// Use comparator when adding dependencies
MavenTagInsertionComparator comparator = new MavenTagInsertionComparator("dependencies");
// Sort existing dependencies
List<Xml.Tag> dependencies = getDependencyTags();
dependencies.sort((tag1, tag2) -> comparator.compare(tag1, tag2));
// Insert new dependency in correct position
Xml.Tag newDependency = createDependencyTag("org.junit.jupiter", "junit-jupiter", "5.8.2");
int insertPosition = Collections.binarySearch(dependencies, newDependency, comparator);
if (insertPosition < 0) {
insertPosition = -insertPosition - 1;
}
dependencies.add(insertPosition, newDependency);Test assertions for Maven-related functionality.
/**
* Test assertions for Maven-related functionality
* Used in testing Maven transformations and analysis
*/
public class Assertions {
/**
* Assert that POM contains dependency
* @param pom POM to check
* @param groupId Expected group ID
* @param artifactId Expected artifact ID
*/
public static void assertHasDependency(Pom pom, String groupId, String artifactId);
/**
* Assert that POM contains dependency with version
* @param pom POM to check
* @param groupId Expected group ID
* @param artifactId Expected artifact ID
* @param version Expected version
*/
public static void assertHasDependency(Pom pom, String groupId, String artifactId, String version);
/**
* Assert that POM contains plugin
* @param pom POM to check
* @param groupId Expected plugin group ID
* @param artifactId Expected plugin artifact ID
*/
public static void assertHasPlugin(Pom pom, String groupId, String artifactId);
/**
* Assert that POM contains property
* @param pom POM to check
* @param key Expected property key
* @param value Expected property value
*/
public static void assertHasProperty(Pom pom, String key, String value);
/**
* Assert that dependency has scope
* @param dependency Dependency to check
* @param expectedScope Expected scope
*/
public static void assertDependencyScope(Dependency dependency, Scope expectedScope);
/**
* Assert that dependencies are in correct order
* @param dependencies List of dependencies to check
*/
public static void assertDependencyOrder(List<Dependency> dependencies);
}Usage Examples:
// In tests
@Test
public void testAddDependency() {
AddDependency recipe = new AddDependency("org.junit.jupiter", "junit-jupiter", "5.8.2",
null, "test", null, null, null, null, null, null, null);
RecipeRun run = recipe.run(List.of(pomDocument), ctx);
Pom resultPom = getResultPom(run);
// Assert dependency was added
Assertions.assertHasDependency(resultPom, "org.junit.jupiter", "junit-jupiter");
Assertions.assertHasDependency(resultPom, "org.junit.jupiter", "junit-jupiter", "5.8.2");
// Assert dependency has correct scope
Dependency junitDep = resultPom.getDependencies().stream()
.filter(dep -> dep.getArtifactId().equals("junit-jupiter"))
.findFirst()
.orElse(null);
assertNotNull(junitDep);
Assertions.assertDependencyScope(junitDep, Scope.Test);
}/**
* Factory class for creating Maven-specific traits
*/
public class Traits {
/**
* Create trait for Maven dependency elements
* @param element Source element
* @return MavenDependency trait
*/
public static MavenDependency mavenDependency(SourceFile element);
/**
* Create trait for Maven plugin elements
* @param element Source element
* @return MavenPlugin trait
*/
public static MavenPlugin mavenPlugin(SourceFile element);
}
/**
* Trait for Maven dependency elements
*/
public class MavenDependency {
/**
* Get dependency coordinate
*/
public GroupArtifactVersion getCoordinate();
/**
* Get dependency scope
*/
public Scope getScope();
/**
* Check if dependency is optional
*/
public boolean isOptional();
/**
* Get dependency exclusions
*/
public List<GroupArtifact> getExclusions();
}
/**
* Trait for Maven plugin elements
*/
public class MavenPlugin {
/**
* Get plugin coordinate
*/
public GroupArtifactVersion getCoordinate();
/**
* Get plugin configuration
*/
public @Nullable Object getConfiguration();
/**
* Get plugin executions
*/
public List<PluginExecution> getExecutions();
}/**
* Comprehensive example using multiple utilities together
*/
public class MavenProjectAnalyzer {
public void analyzeProject(Path projectRoot) throws Exception {
// Check for Maven wrapper
if (MavenWrapper.hasMavenWrapper(projectRoot)) {
String wrapperVersion = MavenWrapper.getWrapperVersion(projectRoot);
System.out.println("Maven wrapper version: " + wrapperVersion);
}
// Load Maven settings
MavenSettings settings = MavenSettings.loadDefault();
List<MavenRepository> repositories = settings != null ?
settings.getEffectiveRepositories() :
Collections.singletonList(MavenRepository.MAVEN_CENTRAL);
// Set up artifact downloader
MavenArtifactDownloader downloader = new MavenArtifactDownloader(repositories);
// Parse POM with caching
InMemoryMavenPomCache pomCache = new InMemoryMavenPomCache();
MavenParser parser = MavenParser.builder()
.pomCache(pomCache)
.build();
Path pomFile = projectRoot.resolve("pom.xml");
String pomContent = Files.readString(pomFile);
ExecutionContext ctx = new InMemoryExecutionContext();
List<SourceFile> parsed = parser.parse(ctx, pomContent);
Xml.Document pomDoc = (Xml.Document) parsed.get(0);
MavenResolutionResult result = pomDoc.getMarkers()
.findFirst(MavenResolutionResult.class)
.orElse(null);
if (result != null) {
ResolvedPom resolvedPom = result.getPom();
// Generate dependency visualization
PrintMavenAsDot dotGenerator = new PrintMavenAsDot("compile", true, 3);
RecipeRun dotRun = dotGenerator.run(List.of(pomDoc), ctx);
List<PrintMavenAsDot.DotGraph> graphs = dotRun.getDataTable(PrintMavenAsDot.DotGraph.class);
if (!graphs.isEmpty()) {
Files.write(projectRoot.resolve("dependencies.dot"),
graphs.get(0).getDotContent().getBytes());
}
// Check for outdated dependencies
for (ResolvedDependency dep : resolvedPom.getDependencies()) {
GroupArtifact ga = new GroupArtifact(dep.getGroupId(), dep.getArtifactId());
List<String> availableVersions = downloader.getAvailableVersions(ga);
// Use retention policy to identify latest versions
RetainVersions policy = new RetainVersions(1, Integer.MAX_VALUE, false);
List<String> latest = policy.getVersionsToRetain(availableVersions);
if (!latest.isEmpty() && !latest.get(0).equals(dep.getVersion())) {
System.out.println("Outdated dependency: " + dep.getGroupId() + ":" +
dep.getArtifactId() + " (" + dep.getVersion() +
" -> " + latest.get(0) + ")");
}
}
}
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-openrewrite--rewrite-maven