Skip to content

Add shortenFullyQualifiedTypes step (fixes #2945) - #3005

Open
maxandersen wants to merge 1 commit into
diffplug:mainfrom
maxandersen:removeFullyQualifiedNames
Open

Add shortenFullyQualifiedTypes step (fixes #2945)#3005
maxandersen wants to merge 1 commit into
diffplug:mainfrom
maxandersen:removeFullyQualifiedNames

Conversation

@maxandersen

@maxandersen maxandersen commented Jul 31, 2026

Copy link
Copy Markdown

headsup - I used llm to generate this; first time contributing to this area but did a quick read and seemed to match similar operations and been using it in my own workflows so it at least works for my usecases :)

Summary

Adds a new Java formatter step that replaces fully qualified type names with simple names and adds the required imports. Designed to clean up LLM-generated code and other sources that use inline FQNs unnecessarily.

Before

public class UserService {
    private final java.util.Map<String, java.util.List<String>> cache = new java.util.HashMap<>();
    public java.util.List<String> getUsers(java.util.function.Predicate<String> filter) throws java.io.IOException {
        java.util.List<String> result = new java.util.ArrayList<>();
        return result;
    }
}

After

import java.io.IOException;
import java.util.*;
import java.util.function.Predicate;

public class UserService {
    private final Map<String, List<String>> cache = new HashMap<>();
    public List<String> getUsers(Predicate<String> filter) throws IOException {
        List<String> result = new ArrayList<>();
        return result;
    }
}

Implementation

  • Uses JavaParser for AST-based type identification (no regex false positives from strings, comments, or non-type contexts)
  • Position-based text replacement preserves original formatting exactly
  • Configured with BLEEDING_EDGE language level to support Java 14–25 syntax
  • Deduplicates AST visits (JavaParser visits instanceof pattern nodes twice)

Safety

Skips rewriting when:

  • Two different FQNs map to the same simple name (conflict)
  • An existing import already claims the simple name for a different type
  • The file can't be parsed (returns input unchanged)
  • java.lang.* types (shortened without import)
  • Same-package types (shortened without import)

Usage

Gradle:

spotless {
    java {
        shortenFullyQualifiedTypes()
        importOrder()
        removeUnusedImports()
    }
}

Maven:

<java>
    <shortenFullyQualifiedTypes/>
    <importOrder/>
    <removeUnusedImports/>
</java>

Tests

16 tests covering: basic shortening, conflict detection, existing import conflicts, java.lang handling, same-package handling, idempotency, and Java 14–25 syntax (instanceof patterns, switch patterns, records, sealed classes, text blocks, var+generics, lambda casts).

Fixes #2945

Adds a new Java formatter step that replaces fully qualified type names
with simple names and adds the required imports. For example:

    java.util.List<String> items = new java.util.ArrayList<>();

becomes:

    import java.util.List;
    import java.util.ArrayList;
    ...
    List<String> items = new ArrayList<>();

Uses JavaParser for AST-based type identification — no false positives
from strings, comments, or non-type contexts. Position-based text
replacement preserves original formatting.

Safety: skips when simple names conflict (two FQNs → same short name),
when an existing import claims the name for a different type, and when
the file can't be parsed. java.lang and same-package types are shortened
without adding imports.

Tested with Java 14–25 syntax: instanceof pattern matching, switch
patterns, records, sealed classes, text blocks, var with generics,
and lambda casts (16 tests).

Wired into both Gradle (shortenFullyQualifiedTypes()) and Maven
(<shortenFullyQualifiedTypes/>), designed to run before importOrder()
and removeUnusedImports().

New files:
- lib/.../java/ShortenFullyQualifiedTypesStep.java (step class)
- lib/.../glue/javaparser/ShortenQualifiedTypesFormatterFunc.java (glue)
- plugin-maven/.../java/ShortenFullyQualifiedTypes.java (Maven factory)
- testlib/.../java/ShortenFullyQualifiedTypesStepTest.java (16 tests)

Modified:
- plugin-gradle/.../JavaExtension.java (+shortenFullyQualifiedTypes())
- plugin-maven/.../java/Java.java (+addShortenFullyQualifiedTypes())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add formatter step to shorten unnecessary fully qualified class names

1 participant