lombok-remover — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited lombok-remover (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Replaces every Lombok annotation in a Java project with idiomatic, hand-written Java code, then removes the Lombok dependency from all POM files.
find . -name "*.java" | xargs grep -l "import lombok\." | sort
find . -name "pom.xml" | sortCollect the full list of affected Java files and POM files upfront.
For every affected Java file, read it fully and build a mental model of:
final/non-final, nullability annotations@Accessors(chain = true) or @Accessors(prefix = ...) modifiers@Builder.Default field defaults@Singular collections in buildersdo NOT convert to a record unless the user explicitly asks
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).
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.
For each file:
import lombok.* and specific import lombok.XYZ statements},unless hand-written methods already exist at the bottom (in which case insert before them)
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.
✅ 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.@Getter / @SetterOn 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()== instead of Objects.equalsAdd import java.util.Objects; if not already present.
@NoArgsConstructorpublic ClassName() {
}@NoArgsConstructor(access = AccessLevel.PROTECTED) → use protected. @NoArgsConstructor(force = true) → initialize final fields to their default zero values.
@AllArgsConstructorpublic ClassName(Type1 field1, Type2 field2) {
this.field1 = field1;
this.field2 = field2;
}Include all non-static fields in declaration order. Respect access attribute.
@RequiredArgsConstructorGenerate a constructor for all final fields and all fields annotated @NonNull (that are not initialized at declaration). Same body pattern as @AllArgsConstructor.
@DataEquivalent to: @Getter + @Setter (non-final fields) + @ToString + @EqualsAndHashCode + @RequiredArgsConstructor.
Generate all of those in this order: constructor, getters, setters, equals, hashCode, toString.
@ValueEquivalent to: make class final, make all fields private final, @Getter + @ToString + @EqualsAndHashCode + @AllArgsConstructor.
No setters. The class declaration gains final if not already present.
@BuilderGenerate 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.
@SuperBuilderSame 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 / @WitherFor 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| Annotation | Generated field |
|---|---|
@Slf4j | private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ClassName.class); |
@Log4j2 | private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(ClassName.class); |
@Log | private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(ClassName.class.getName()); |
@CommonsLog | private 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.
@Accessorschain = true → setters return this instead of voidprefix = {"m_"} → strip the prefix when computing getter/setter namesfluent = 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.
@NonNullOn 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();
}@SneakyThrowsWrap 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.
@DelegateImplement 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.
exists, skip generating that one and log a note.
callSuper shoulddefault to true for @EqualsAndHashCode / @ToString. Lombok's default is false — preserve that unless callSuper = true was explicitly set.
// TODO: review equals/hashCode for JPA entity comment whenthe class has @Entity or @Table.
@Getter on anabstract class generates abstract getters only if the field is abstract (unusual).
lombok.config file overrides defaults(e.g. lombok.addLombokGeneratedAnnotation, lombok.accessors.chain). Read it if present.
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.
When generating code, ensure all required imports are present and no unused Lombok imports remain. Common imports to add:
java.util.Objects — for equals / hashCodejava.util.Arrays — for array fields in toStringjava.util.Collections — for @Singular builder fields~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.