From ac0fd8a1b761cfada2a7f032a4fa1fb703ca72ef Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 24 Jan 2026 03:33:01 +0000 Subject: [PATCH 1/4] Initial plan From 3cd9b6f195c660ca86acc9c09df61beb66da4f01 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+copilot@users.noreply.github.com> Date: Sat, 24 Jan 2026 03:42:19 +0000 Subject: [PATCH 2/4] feat: Add expandWildcardImports support for Maven plugin - infrastructure changes --- .../spotless/maven/AbstractSpotlessMojo.java | 32 +++++++++++++- .../spotless/maven/ArtifactResolver.java | 30 +++++++++++++ .../spotless/maven/FormatterConfig.java | 9 +++- .../spotless/maven/FormatterFactory.java | 2 +- .../spotless/maven/FormatterStepConfig.java | 10 ++++- .../maven/java/ExpandWildcardImports.java | 33 ++++++++++++++ .../diffplug/spotless/maven/java/Java.java | 4 ++ .../java/ExpandWildcardImportsStepTest.java | 44 +++++++++++++++++++ 8 files changed, 160 insertions(+), 4 deletions(-) create mode 100644 plugin-maven/src/main/java/com/diffplug/spotless/maven/java/ExpandWildcardImports.java create mode 100644 plugin-maven/src/test/java/com/diffplug/spotless/maven/java/ExpandWildcardImportsStepTest.java diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/AbstractSpotlessMojo.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/AbstractSpotlessMojo.java index 26c3e602c4..7df24bba00 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/AbstractSpotlessMojo.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/AbstractSpotlessMojo.java @@ -27,6 +27,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -403,7 +404,36 @@ private FormatterConfig getFormatterConfig() { FileLocator fileLocator = getFileLocator(); final Optional optionalRatchetFrom = Optional.ofNullable(this.ratchetFrom) .filter(ratchet -> !RATCHETFROM_NONE.equals(ratchet)); - return new FormatterConfig(baseDir, encoding, lineEndings, optionalRatchetFrom, provisioner, p2Provisioner, fileLocator, formatterStepFactories, Optional.ofNullable(setLicenseHeaderYearsFromGitHistory), lintSuppressions); + Optional> projectClasspath = computeTypeSolverClasspath(resolver); + return new FormatterConfig(baseDir, encoding, lineEndings, optionalRatchetFrom, provisioner, p2Provisioner, fileLocator, formatterStepFactories, Optional.ofNullable(setLicenseHeaderYearsFromGitHistory), lintSuppressions, projectClasspath); + } + + private Optional> computeTypeSolverClasspath(ArtifactResolver resolver) { + Set classpath = new LinkedHashSet<>(); + + // Add source roots (directories containing .java files for JavaParserTypeSolver) + for (String sourceRoot : project.getCompileSourceRoots()) { + File dir = new File(sourceRoot); + if (dir.exists()) { + classpath.add(dir); + } + } + for (String sourceRoot : project.getTestCompileSourceRoots()) { + File dir = new File(sourceRoot); + if (dir.exists()) { + classpath.add(dir); + } + } + + // Resolve dependency JARs via RepositorySystem (for JarTypeSolver) + try { + Set dependencyJars = resolver.resolveProjectDependencies(project, repositories); + classpath.addAll(dependencyJars); + } catch (Exception e) { + getLog().warn("Could not resolve project dependencies for expandWildcardImports: " + e.getMessage()); + } + + return Optional.of(classpath); } private FileLocator getFileLocator() { diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/ArtifactResolver.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/ArtifactResolver.java index d94238b752..59df3fe5af 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/ArtifactResolver.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/ArtifactResolver.java @@ -21,11 +21,13 @@ import java.io.File; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Set; import org.apache.maven.plugin.logging.Log; +import org.apache.maven.project.MavenProject; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.artifact.Artifact; @@ -89,6 +91,34 @@ private DependencyResult resolveDependencies(DependencyRequest dependencyRequest } } + /** + * Resolves all dependencies (all scopes) of the given Maven project using the + * specified artifact repositories. Returns the set of resolved JAR files. + */ + public Set resolveProjectDependencies(MavenProject project, List artifactRepositories) { + List dependencies = project.getDependencies().stream() + .map(d -> new Dependency( + new DefaultArtifact(d.getGroupId(), d.getArtifactId(), d.getClassifier(), d.getType(), d.getVersion()), + d.getScope())) + .collect(toList()); + + if (dependencies.isEmpty()) { + return Collections.emptySet(); + } + + CollectRequest collectRequest = new CollectRequest(dependencies, null, artifactRepositories); + DependencyRequest dependencyRequest = new DependencyRequest(collectRequest, null); + DependencyResult dependencyResult = resolveDependencies(dependencyRequest); + + return dependencyResult.getArtifactResults() + .stream() + .map(ArtifactResult::getArtifact) + .filter(Objects::nonNull) + .map(Artifact::getFile) + .filter(Objects::nonNull) + .collect(toSet()); + } + private void logResolved(ArtifactResult artifactResult) { if (log.isDebugEnabled()) { log.debug("Resolved artifact: " + artifactResult); diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterConfig.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterConfig.java index 66fa572a25..224bba1f7f 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterConfig.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterConfig.java @@ -20,6 +20,7 @@ import java.io.File; import java.util.List; import java.util.Optional; +import java.util.Set; import com.diffplug.spotless.LineEnding; import com.diffplug.spotless.LintSuppression; @@ -37,9 +38,10 @@ public class FormatterConfig { private final List globalStepFactories; private final Optional spotlessSetLicenseHeaderYearsFromGitHistory; private final List lintSuppressions; + private final Optional> projectClasspath; public FormatterConfig(File baseDir, String encoding, LineEnding lineEndings, Optional ratchetFrom, Provisioner provisioner, - P2Provisioner p2Provisioner, FileLocator fileLocator, List globalStepFactories, Optional spotlessSetLicenseHeaderYearsFromGitHistory, List lintSuppressions) { + P2Provisioner p2Provisioner, FileLocator fileLocator, List globalStepFactories, Optional spotlessSetLicenseHeaderYearsFromGitHistory, List lintSuppressions, Optional> projectClasspath) { this.encoding = encoding; this.lineEndings = lineEndings; this.ratchetFrom = ratchetFrom; @@ -49,6 +51,7 @@ public FormatterConfig(File baseDir, String encoding, LineEnding lineEndings, Op this.globalStepFactories = globalStepFactories; this.spotlessSetLicenseHeaderYearsFromGitHistory = spotlessSetLicenseHeaderYearsFromGitHistory; this.lintSuppressions = lintSuppressions; + this.projectClasspath = projectClasspath; } public String getEncoding() { @@ -86,4 +89,8 @@ public FileLocator getFileLocator() { public List getLintSuppressions() { return unmodifiableList(lintSuppressions); } + + public Optional> getProjectClasspath() { + return projectClasspath; + } } diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterFactory.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterFactory.java index 05c207d6d4..555fecf294 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterFactory.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterFactory.java @@ -185,7 +185,7 @@ Optional ratchetFrom(FormatterConfig config) { } private FormatterStepConfig stepConfig(Charset encoding, FormatterConfig config) { - return new FormatterStepConfig(encoding, licenseHeaderDelimiter(), ratchetFrom(config), config.getProvisioner(), config.getP2Provisioner(), config.getFileLocator(), config.getSpotlessSetLicenseHeaderYearsFromGitHistory()); + return new FormatterStepConfig(encoding, licenseHeaderDelimiter(), ratchetFrom(config), config.getProvisioner(), config.getP2Provisioner(), config.getFileLocator(), config.getSpotlessSetLicenseHeaderYearsFromGitHistory(), config.getProjectClasspath()); } private static List gatherStepFactories(List allGlobal, List allConfigured) { diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterStepConfig.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterStepConfig.java index 139b3f0a69..ca4eb6955b 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterStepConfig.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterStepConfig.java @@ -15,8 +15,10 @@ */ package com.diffplug.spotless.maven; +import java.io.File; import java.nio.charset.Charset; import java.util.Optional; +import java.util.Set; import com.diffplug.spotless.Provisioner; import com.diffplug.spotless.extra.P2Provisioner; @@ -30,8 +32,9 @@ public class FormatterStepConfig { private final P2Provisioner p2Provisioner; private final FileLocator fileLocator; private final Optional spotlessSetLicenseHeaderYearsFromGitHistory; + private final Optional> projectClasspath; - public FormatterStepConfig(Charset encoding, String licenseHeaderDelimiter, Optional ratchetFrom, Provisioner provisioner, P2Provisioner p2Provisioner, FileLocator fileLocator, Optional spotlessSetLicenseHeaderYearsFromGitHistory) { + public FormatterStepConfig(Charset encoding, String licenseHeaderDelimiter, Optional ratchetFrom, Provisioner provisioner, P2Provisioner p2Provisioner, FileLocator fileLocator, Optional spotlessSetLicenseHeaderYearsFromGitHistory, Optional> projectClasspath) { this.encoding = encoding; this.licenseHeaderDelimiter = licenseHeaderDelimiter; this.ratchetFrom = ratchetFrom; @@ -39,6 +42,7 @@ public FormatterStepConfig(Charset encoding, String licenseHeaderDelimiter, Opti this.p2Provisioner = p2Provisioner; this.fileLocator = fileLocator; this.spotlessSetLicenseHeaderYearsFromGitHistory = spotlessSetLicenseHeaderYearsFromGitHistory; + this.projectClasspath = projectClasspath; } public Charset getEncoding() { @@ -68,4 +72,8 @@ public FileLocator getFileLocator() { public Optional spotlessSetLicenseHeaderYearsFromGitHistory() { return spotlessSetLicenseHeaderYearsFromGitHistory; } + + public Optional> getProjectClasspath() { + return projectClasspath; + } } diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/ExpandWildcardImports.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/ExpandWildcardImports.java new file mode 100644 index 0000000000..5c0170da67 --- /dev/null +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/ExpandWildcardImports.java @@ -0,0 +1,33 @@ +/* + * Copyright 2025 DiffPlug + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.diffplug.spotless.maven.java; + +import java.io.File; +import java.util.Collections; +import java.util.Set; + +import com.diffplug.spotless.FormatterStep; +import com.diffplug.spotless.java.ExpandWildcardImportsStep; +import com.diffplug.spotless.maven.FormatterStepConfig; +import com.diffplug.spotless.maven.FormatterStepFactory; + +public class ExpandWildcardImports implements FormatterStepFactory { + @Override + public FormatterStep newFormatterStep(FormatterStepConfig config) { + Set classpath = config.getProjectClasspath().orElse(Collections.emptySet()); + return ExpandWildcardImportsStep.create(classpath, config.getProvisioner()); + } +} diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java index 53e2e90ddd..fe6e2633ac 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java @@ -79,6 +79,10 @@ public void addForbidWildcardImports(ForbidWildcardImports forbidWildcardImports addStepFactory(forbidWildcardImports); } + public void addExpandWildcardImports(ExpandWildcardImports expandWildcardImports) { + addStepFactory(expandWildcardImports); + } + public void addForbidModuleImports(ForbidModuleImports forbidModuleImports) { addStepFactory(forbidModuleImports); } diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/ExpandWildcardImportsStepTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/ExpandWildcardImportsStepTest.java new file mode 100644 index 0000000000..922eca8041 --- /dev/null +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/ExpandWildcardImportsStepTest.java @@ -0,0 +1,44 @@ +/* + * Copyright 2025-2026 DiffPlug + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.diffplug.spotless.maven.java; + +import org.junit.jupiter.api.Test; + +import com.diffplug.spotless.maven.MavenIntegrationHarness; + +class ExpandWildcardImportsStepTest extends MavenIntegrationHarness { + + @Test + void expandWildcardImports() throws Exception { + writePomWithJavaSteps(""); + + // Create supporting classes in source roots so JavaParserTypeSolver can resolve them + setFile("src/main/java/foo/bar/AnotherClassInSamePackage.java") + .toResource("java/expandwildcardimports/AnotherClassInSamePackage.test"); + setFile("src/main/java/foo/bar/baz/AnotherImportedClass.java") + .toResource("java/expandwildcardimports/AnotherImportedClass.test"); + // Source for the annotation used in the test (resolves via source root, not JAR) + setFile("src/main/java/org/example/SomeAnnotation.java") + .toContent("package org.example;\n\npublic @interface SomeAnnotation {}\n"); + + String path = "src/main/java/foo/bar/JavaClassWithWildcards.java"; + setFile(path).toResource("java/expandwildcardimports/JavaClassWithWildcardsUnformatted.test"); + + mavenRunner().withArguments("spotless:apply").runNoError(); + + assertFile(path).sameAsResource("java/expandwildcardimports/JavaClassWithWildcardsFormatted.test"); + } +} From a669197d7766ed7389061c68b204e489bbf19420 Mon Sep 17 00:00:00 2001 From: tavori <230928651+tavori@users.noreply.github.com> Date: Thu, 14 May 2026 16:14:35 +0800 Subject: [PATCH 3/4] fix: add change log for plugin-maven --- plugin-maven/CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 7fa2b3f5ab..5a6572d022 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -5,6 +5,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added - Add `` option to ``, allowing users to override the JavaParser version pulled in transitively by Cleanthat. ([#2903](https://github.com/diffplug/spotless/pull/2903)) +- Add a `expandWildcardImports` API for java ([#2829](https://github.com/diffplug/spotless/pull/2930)) ### Fixed - Fix non-idempotent formatting when `importOrder()` is combined with `greclipse()`: a single catch-all group no longer strips blank lines that `greclipse()` independently inserted between import groups. ([#2914](https://github.com/diffplug/spotless/pull/2914)) ### Changes From 9aec1a255877b73ec36d31875f4829595accee27 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Thu, 14 May 2026 09:15:58 -0700 Subject: [PATCH 4/4] spotlessApply --- .../main/java/com/diffplug/spotless/maven/ArtifactResolver.java | 2 +- .../com/diffplug/spotless/maven/java/ExpandWildcardImports.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/ArtifactResolver.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/ArtifactResolver.java index 59df3fe5af..de63047fb9 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/ArtifactResolver.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/ArtifactResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2025 DiffPlug + * Copyright 2016-2026 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/ExpandWildcardImports.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/ExpandWildcardImports.java index 5c0170da67..c49d1d5c8a 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/ExpandWildcardImports.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/ExpandWildcardImports.java @@ -1,5 +1,5 @@ /* - * Copyright 2025 DiffPlug + * Copyright 2025-2026 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License.