You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否创建可替代其他注解的自定义注解?以Lombok@NoArgsConstructor为例

如何用自定义注解替代Lombok的@NoArgsConstructor(access = AccessLevel.PROTECTED)

当然可以实现这种替代需求!虽然Java注解本身不支持继承,但我们可以借助编译期注解处理器——尤其是利用Lombok自身的扩展机制——来达成目标。下面我会给出两种可行的方案,你可以根据自己的场景选择:

方案一:基于Lombok扩展(推荐,省力)

这种方法直接复用Lombok已经写好的构造器生成逻辑,只需要让Lombok识别你的自定义注解等同于@NoArgsConstructor(access = AccessLevel.PROTECTED)即可。

步骤1:定义你的自定义注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE) // 仅在编译期生效,不需要保留到字节码
public @interface myConstructor {
}

步骤2:编写Lombok注解处理器

我们需要写一个自定义的Handler,让Lombok处理@myConstructor时,生成和@NoArgsConstructor(access=PROTECTED)完全一样的代码:

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
import lombok.javac.JavacAnnotationHandler;
import lombok.javac.JavacNode;
import lombok.javac.handlers.JavacNoArgsConstructorHandler;

@HandlerPriority(1) // 设置优先级,确保优先处理我们的注解
public class MyConstructorHandler extends JavacAnnotationHandler<myConstructor> {
    @Override
    public void handle(AnnotationValues<myConstructor> annotation, myConstructor ast, JavacNode annotationNode) {
        // 构造一个默认的NoArgsConstructor实例,指定access为PROTECTED
        NoArgsConstructor proxyAnnotation = new NoArgsConstructor() {
            @Override
            public AccessLevel access() {
                return AccessLevel.PROTECTED;
            }

            @Override
            public Class<? extends java.lang.annotation.Annotation> annotationType() {
                return NoArgsConstructor.class;
            }

            // 其他属性返回Lombok默认值
            @Override
            public String staticName() { return ""; }
            @Override
            public boolean force() { return false; }
            @Override
            public boolean onConstructor() { return false; }
        };

        // 调用Lombok原生的NoArgsConstructor处理器来生成代码
        JavacAnnotationHandler<NoArgsConstructor> handler = new JavacNoArgsConstructorHandler();
        handler.handle(AnnotationValues.of(proxyAnnotation), proxyAnnotation, annotationNode);
    }
}

步骤3:注册处理器

在你的项目资源目录下创建META-INF/services/lombok.core.AnnotationHandler文件,添加一行处理器的全类名:

com.yourpackage.lombok.MyConstructorHandler

(注意替换成你实际的包路径)

这样配置后,当你在类上标记@myConstructor时,Lombok就会自动生成一个protected权限的无参构造器,效果和直接使用@NoArgsConstructor(access = AccessLevel.PROTECTED)完全一致。

方案二:自定义独立注解处理器(更灵活)

如果你不想依赖Lombok的扩展机制,也可以自己写一个完整的注解处理器,直接生成构造器代码。这种方式需要处理字节码生成的细节,适合需要高度自定义的场景。

步骤1:定义注解(和方案一相同)

步骤2:编写注解处理器

可以借助JavaPoet库来简化代码生成(需要在项目中引入JavaPoet依赖):

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import java.util.Set;

@SupportedAnnotationTypes("com.yourpackage.myConstructor")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class MyConstructorProcessor extends AbstractProcessor {
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        for (TypeElement element : annotations) {
            // 遍历所有被@myConstructor标记的类
            roundEnv.getElementsAnnotatedWith(element).forEach(classElement -> {
                // 生成protected无参构造器
                MethodSpec constructor = MethodSpec.constructorBuilder()
                        .addModifiers(Modifier.PROTECTED)
                        .build();

                // 创建类的TypeSpec,添加构造器
                TypeSpec modifiedClass = TypeSpec.classBuilder(classElement.getSimpleName())
                        .addModifiers(classElement.getModifiers())
                        .addMethod(constructor)
                        .build();

                // 生成Java文件
                try {
                    JavaFile.builder(classElement.getEnclosingElement().toString(), modifiedClass)
                            .build()
                            .writeTo(processingEnv.getFiler());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
        return true;
    }
}

步骤3:注册处理器

同样需要在META-INF/services/javax.annotation.processing.Processor文件中注册你的处理器:

com.yourpackage.MyConstructorProcessor

注意事项

  • 两种方案的注解都必须设置@Retention(RetentionPolicy.SOURCE),因为我们只需要在编译期处理,不需要保留到运行时。
  • 方案一需要确保项目正确引入Lombok依赖,并且IDE开启了Lombok的注解处理支持。
  • 方案二如果使用JavaPoet,需要添加对应的Maven/Gradle依赖。

内容的提问来源于stack exchange,提问作者user1156544

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 07:59:25