agentsclimarketplace

Lombok remover

Skill litsec/claude-code-skills/plugins/lombok-remover/skills/lombok-remover

Scan a Java project and replace all Lombok annotations with equivalent hand-written Java code. Use this skill whenever the user wants to remove Lombok, de-lombok a project, replace Lombok annotations, migrate away from Lombok, or eliminate the Lombok dependency. Also trigger when the user says things like "get rid of Lombok", "expand Lombok", or "make Lombok explicit". Handles all common Lombok annotations (@Data, @Builder, @Value, @Getter, @Setter, @ToString, @EqualsAndHashCode, @RequiredArgsConstructor, @AllArgsConstructor, @NoArgsConstructor, @Slf4j, @With, @Accessors, etc.), updates POM files to remove the Lombok dependency, and preserves existing code style throughout.From its SKILL.md

Install
npx -y skills add litsec/claude-code-skills --skill lombok-remover

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

13.0 KB, ~2.9k tokens by cl100k_base, as published. Nobody here has run it

Lombok Remover

Replaces every Lombok annotation in a Java project with idiomatic, hand-written Java code, then removes the Lombok dependency from all POM files.


Workflow

1. Discover scope

find . -name "*.java" | xargs grep -l "import lombok\." | sort
find . -name "pom.xml" | sort

Collect the full list of affected Java files and POM files upfront.

2. Analyse each file before touching it

For every affected Java file, read it fully and build a mental model of:

  • Which Lombok annotations are present (may be multiple per class)
  • Which fields exist, their types, final/non-final, nullability annotations
  • Whether the class already has any hand-written methods that would conflict
  • Any @Accessors(chain = true) or @Accessors(prefix = ...) modifiers
  • Any @Builder.Default field defaults
  • Any @Singular collections in builders
  • Whether the class is a record candidate (all-final fields, no mutation) — note it but do NOT convert to a record unless the user explicitly asks

3. Generate replacements

Apply the rules in the Annotation Reference section below. Generate complete, correctly indented Java for each annotation removed. Match the file's existing indentation style (spaces vs tabs, indent width).

4. Show a plan, then apply

Before editing any file, print a concise summary:

Files to modify: 12
─────────────────────────────────────────────────
 File                          Annotations removed
─────────────────────────────────────────────────
 src/.../UserService.java      @Slf4j
 src/.../User.java             @Data, @Builder
 src/.../AddressDto.java       @Value
 ...
─────────────────────────────────────────────────
POM files: 2  (lombok dependency will be removed)

Ask the user to confirm before proceeding. If they say yes, apply all changes.

5. Edit files

For each file:

  1. Remove all import lombok.* and specific import lombok.XYZ statements

  2. Remove all Lombok annotations from the class / fields

  3. Insert generated methods at the end of the class body, before the closing }, unless hand-written methods already exist at the bottom (in which case insert before them)

  4. For getters and setters, also provide Javadoc according to the style of the project being updated.

  5. Do not reformat unrelated code

6. Update POMs

In each pom.xml, remove the <dependency> block for org.projectlombok:lombok and any associated <annotationProcessorPaths> entry for Lombok in the maven-compiler-plugin configuration.

7. Print a final change log

✅ Done
──────────────────────────────────────────────────────────────
Modified 12 Java files, 2 POM files
Removed annotations: @Data ×4, @Builder ×3, @Value ×2, @Slf4j ×6, @Getter ×1
──────────────────────────────────────────────────────────────
Next steps:
  • Run `mvn compile` to verify the project builds cleanly.
  • Review generated equals/hashCode if the class participates in collections or JPA.

Annotation Reference

@Getter / @Setter

On a field:

// @Getter on field  →
public FieldType getFieldName() { return this.fieldName; }

// @Setter on field  →
public void setFieldName(final FieldType fieldName) { this.fieldName = fieldName; }

On a class: generate getter (and setter for non-final) for every non-static field.

Boolean fields: use isX() instead of getX() when the type is boolean (primitive).

Access levels: @Getter(AccessLevel.PROTECTED) etc. → use the matching Java modifier. AccessLevel.NONE → skip that field entirely.

Provide Javadoc for inserted getters and setters according to the style of the project being updated.


@ToString

@Override
public String toString() {
    return "ClassName{" +
            "field1=" + field1 +
            ", field2='" + field2 + '\'' +
            '}';
}
  • @ToString(exclude = {"field2"}) / @ToString.Exclude → omit those fields
  • @ToString(onlyExplicitlyIncluded = true) + @ToString.Include → include only marked fields
  • @ToString(callSuper = true) → prepend super.toString() + ", "

Quote String fields with ' as shown; for arrays use Arrays.toString(field).


@EqualsAndHashCode

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    ClassName other = (ClassName) o;
    return Objects.equals(field1, other.field1) &&
           Objects.equals(field2, other.field2);
}

@Override
public int hashCode() {
    return Objects.hash(field1, field2);
}
  • @EqualsAndHashCode(exclude = {...}) / @EqualsAndHashCode.Exclude → omit those fields
  • @EqualsAndHashCode(onlyExplicitlyIncluded = true) + @EqualsAndHashCode.Include → only marked
  • @EqualsAndHashCode(callSuper = true) → chain to super.equals() / super.hashCode()
  • Primitive fields: use == instead of Objects.equals

Add import java.util.Objects; if not already present.


@NoArgsConstructor

public ClassName() {
}

@NoArgsConstructor(access = AccessLevel.PROTECTED) → use protected. @NoArgsConstructor(force = true) → initialize final fields to their default zero values.


@AllArgsConstructor

public ClassName(Type1 field1, Type2 field2) {
    this.field1 = field1;
    this.field2 = field2;
}

Include all non-static fields in declaration order. Respect access attribute.


@RequiredArgsConstructor

Generate a constructor for all final fields and all fields annotated @NonNull (that are not initialized at declaration). Same body pattern as @AllArgsConstructor.


@Data

Equivalent to: @Getter + @Setter (non-final fields) + @ToString + @EqualsAndHashCode + @RequiredArgsConstructor.

Generate all of those in this order: constructor, getters, setters, equals, hashCode, toString.


@Value

Equivalent to: make class final, make all fields private final, @Getter + @ToString + @EqualsAndHashCode + @AllArgsConstructor.

No setters. The class declaration gains final if not already present.


@Builder

Generate a static inner Builder class:

public static Builder builder() {
    return new Builder();
}

public static final class Builder {
    private Type1 field1;
    private Type2 field2;

    private Builder() {}

    public Builder field1(Type1 field1) {
        this.field1 = field1;
        return this;
    }

    public Builder field2(Type2 field2) {
        this.field2 = field2;
        return this;
    }

    public ClassName build() {
        return new ClassName(field1, field2);
    }
}

// Private all-args constructor used by Builder:
private ClassName(Type1 field1, Type2 field2) {
    this.field1 = field1;
    this.field2 = field2;
}

@Builder.Default: the field's declared initializer becomes the default in the Builder field declaration (e.g. private List<String> tags = new ArrayList<>();).

@Singular: generate an add method and a addAll method, plus initialize the field to an empty mutable list/set/map in the Builder, and make the build() call Collections.unmodifiableList(new ArrayList<>(tags)).

@Builder(toBuilder = true): add a toBuilder() instance method that pre-populates a new Builder from this.


@SuperBuilder

Same as @Builder but uses an abstract base builder pattern to support inheritance. This is complex — generate the abstract BaseBranchBuilder / concrete builder pair as Lombok does. Flag it clearly in the change log as requiring extra review.


@With / @Wither

For each annotated field, generate a copy-constructor-style "wither":

public ClassName withFieldName(FieldType fieldName) {
    return new ClassName(/* all fields, replacing fieldName */);
}

Requires an all-args constructor to be present (or generated).


@Slf4j / @Log / @Log4j2 / @CommonsLog

AnnotationGenerated field
@Slf4jprivate static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ClassName.class);
@Log4j2private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(ClassName.class);
@Logprivate static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(ClassName.class.getName());
@CommonsLogprivate static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(ClassName.class);

Insert as the first field in the class body. Add the corresponding import.


@Accessors

  • chain = true → setters return this instead of void
  • prefix = {"m_"} → strip the prefix when computing getter/setter names
  • fluent = true → getters and setters use the bare field name with no get/set prefix, and setters return this

Apply these modifiers to every getter/setter generated for this class.


@NonNull

On a parameter or field: insert a null check at the top of the constructor/setter body:

if (fieldName == null) throw new NullPointerException("fieldName is marked non-null but is null");

Keep any JSR-305 / JetBrains / Jakarta @NonNull annotations that are used for static analysis — only remove the lombok.NonNull import/annotation.


@Cleanup

// @Cleanup InputStream in = new FileInputStream(file);
// becomes:
InputStream in = new FileInputStream(file);
try {
    // ... rest of the original block ...
} finally {
    if (in != null) in.close();
}

@SneakyThrows

Wrap the method body in a try-catch that rethrows via an unchecked wrapper:

try {
    // original body
} catch (Exception e) {
    throw new RuntimeException(e);
}

Add // TODO: review exception handling (was @SneakyThrows) comment.


@Delegate

Implement every method of the delegated type by forwarding to the delegate field. This may generate many methods — note the count in the change log and add a // Generated by lombok-remover: @Delegate comment block.


Edge Cases

  • Existing hand-written methods: if a getter/setter/toString/equals/hashCode already exists, skip generating that one and log a note.
  • Inheritance: if the class extends another class, check whether callSuper should default to true for @EqualsAndHashCode / @ToString. Lombok's default is false — preserve that unless callSuper = true was explicitly set.
  • JPA entities: add a // TODO: review equals/hashCode for JPA entity comment when the class has @Entity or @Table.
  • Records: do not convert to records unless asked.
  • Interfaces / abstract classes: handle appropriately — e.g. @Getter on an abstract class generates abstract getters only if the field is abstract (unusual).
  • Lombok config (lombok.config): check if a lombok.config file overrides defaults (e.g. lombok.addLombokGeneratedAnnotation, lombok.accessors.chain). Read it if present.

POM Cleanup

Remove:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    ...
</dependency>

And if present in maven-compiler-plugin:

<annotationProcessorPaths>
    <path>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </path>
</annotationProcessorPaths>

If the <annotationProcessorPaths> block becomes empty after removal, remove the block too. If <compilerArgs> only contained Lombok-related args, clean those up as well.


Required Imports

When generating code, ensure all required imports are present and no unused Lombok imports remain. Common imports to add:

  • java.util.Objects — for equals / hashCode
  • java.util.Arrays — for array fields in toString
  • java.util.Collections — for @Singular builder fields
  • Logger class imports — for log field generation

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 326,512. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.